Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring sync reasoner #105

Merged
merged 5 commits into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,54 @@ pytest -p no:warnings -x # Running 142 tests ~ 30 secs

## Examples

### Exploring OWL Ontology

<details><summary> Click me! </summary>

```python
from owlapy.owl_ontology_manager import SyncOntologyManager

ontology_path = "KGs/Family/father.owl"
onto = SyncOntologyManager().load_ontology(ontology_path)

print({owl_class.reminder for owl_class in onto.classes_in_signature()})
# {'Thing', 'female', 'male', 'person'}

print({individual.reminder for individual in onto.individuals_in_signature()})
# {'michelle', 'stefan', 'martin', 'anna', 'heinz', 'markus'}

print({object_property.reminder for object_property in onto.object_properties_in_signature()})
# {'hasChild'}

for owl_subclass_of_axiom in onto.get_tbox_axioms():
print(owl_subclass_of_axiom)

# OWLEquivalentClassesAxiom([OWLClass(IRI('http://example.com/father#', 'male')), OWLObjectComplementOf(OWLClass(IRI('http://example.com/father#', 'female')))],[])
# OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://example.com/father#', 'female')),super_class=OWLClass(IRI('http://example.com/father#', 'person')),annotations=[])
# OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://example.com/father#', 'male')),super_class=OWLClass(IRI('http://example.com/father#', 'person')),annotations=[])
# OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://example.com/father#', 'person')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#', 'Thing')),annotations=[])
# OWLObjectPropertyRangeAxiom(OWLObjectProperty(IRI('http://example.com/father#', 'hasChild')),OWLClass(IRI('http://example.com/father#', 'person')),[])
# OWLObjectPropertyDomainAxiom(OWLObjectProperty(IRI('http://example.com/father#', 'hasChild')),OWLClass(IRI('http://example.com/father#', 'person')),[])


for axiom in onto.get_abox_axioms():
print(axiom)

# OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://example.com/father#', 'anna')),class_expression=OWLClass(IRI('http://example.com/father#', 'female')),annotations=[])
# OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://example.com/father#', 'michelle')),class_expression=OWLClass(IRI('http://example.com/father#', 'female')),annotations=[])
# OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://example.com/father#', 'martin')),class_expression=OWLClass(IRI('http://example.com/father#', 'male')),annotations=[])
# OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://example.com/father#', 'markus')),class_expression=OWLClass(IRI('http://example.com/father#', 'male')),annotations=[])
# OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://example.com/father#', 'heinz')),class_expression=OWLClass(IRI('http://example.com/father#', 'male')),annotations=[])
# OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://example.com/father#', 'stefan')),class_expression=OWLClass(IRI('http://example.com/father#', 'male')),annotations=[])
# OWLObjectPropertyAssertionAxiom(subject=OWLNamedIndividual(IRI('http://example.com/father#', 'markus')),property_=OWLObjectProperty(IRI('http://example.com/father#', 'hasChild')),object_=OWLNamedIndividual(IRI('http://example.com/father#', 'anna')),annotations=[])
# OWLObjectPropertyAssertionAxiom(subject=OWLNamedIndividual(IRI('http://example.com/father#', 'martin')),property_=OWLObjectProperty(IRI('http://example.com/father#', 'hasChild')),object_=OWLNamedIndividual(IRI('http://example.com/father#', 'heinz')),annotations=[])
# OWLObjectPropertyAssertionAxiom(subject=OWLNamedIndividual(IRI('http://example.com/father#', 'stefan')),property_=OWLObjectProperty(IRI('http://example.com/father#', 'hasChild')),object_=OWLNamedIndividual(IRI('http://example.com/father#', 'markus')),annotations=[])
# OWLObjectPropertyAssertionAxiom(subject=OWLNamedIndividual(IRI('http://example.com/father#', 'anna')),property_=OWLObjectProperty(IRI('http://example.com/father#', 'hasChild')),object_=OWLNamedIndividual(IRI('http://example.com/father#', 'heinz')),annotations=[])

```

</details>

### Creating OWL Class Expressions
<details><summary> Click me! </summary>

Expand Down
10 changes: 9 additions & 1 deletion owlapy/owl_axiom.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,13 @@ def __init__(self, sub_class: OWLClassExpression, super_class: OWLClassExpressio
self._super_class = super_class
super().__init__(annotations=annotations)

@property
def sub_class(self) -> OWLClassExpression:
return self._sub_class
@property
def super_class(self) -> OWLClassExpression:
return self._super_class

def get_sub_class(self) -> OWLClassExpression:
return self._sub_class

Expand All @@ -533,7 +540,8 @@ def __eq__(self, other):
if type(other) is type(self):
return self._super_class == other._super_class and self._sub_class == other._sub_class \
and self._annotations == other._annotations
return NotImplemented
else:
return False

def __hash__(self):
return hash((self._super_class, self._sub_class, *self._annotations))
Expand Down
5 changes: 3 additions & 2 deletions owlapy/owl_individual.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ def __init__(self, iri: Union[IRI, str]):
self._iri = iri
else:
self._iri = IRI.create(iri)

@property
def iri(self) -> IRI:
return self._iri

@property
def str(self):
return self._iri.as_str()
@property
def reminder(self):
return self._iri.reminder
13 changes: 9 additions & 4 deletions owlapy/owl_ontology.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ def __eq__(self, other):

def _check_expression(expr: OWLObject, ontology: AbstractOWLOntology, world: owlready2.namespace.World):
"""
@TODO:CD: Documentation
Creates all entities (individuals, classes, properties) that appear in the given (complex) class expression
and do not exist in the given ontology yet

Expand Down Expand Up @@ -1035,7 +1034,6 @@ def _get_imports_enum(self, include_imports_closure: bool):
else:
imports = Imports.EXCLUDED
return imports

def get_signature(self, include_imports_closure: bool = True):
"""Gets the entities that are in the signature of this ontology.

Expand All @@ -1045,6 +1043,7 @@ def get_signature(self, include_imports_closure: bool = True):
Returns:
Entities in signature.
"""
# @TODO: CD: Is this class method redundant given that we have the individuals_in_signature ?
return self.mapper.map_(self.owlapi_ontology.getSignature(self._get_imports_enum(include_imports_closure)))

def get_abox_axioms(self, include_imports_closure: bool = True) -> Iterable[OWLAxiom]:
Expand All @@ -1056,7 +1055,6 @@ def get_abox_axioms(self, include_imports_closure: bool = True) -> Iterable[OWLA
Returns:
ABox axioms.
"""

return self.mapper.map_(self.owlapi_ontology.getABoxAxioms(self._get_imports_enum(include_imports_closure)))

def get_tbox_axioms(self, include_imports_closure: bool = True) -> Iterable[OWLAxiom]:
Expand Down Expand Up @@ -1100,7 +1098,14 @@ def __hash__(self):
return int(self.owlapi_ontology.getOntologyID().hashCode())

def __repr__(self):
return f'SyncOntology({self.manager}, {self.path}, {self.new})'
return (f'SyncOntology:'
f'\t|Tbox|={len(self.get_tbox_axioms())}'
f'\t|Abox|={len(self.get_abox_axioms())}'
f'\t|Individuals|={len(self.individuals_in_signature())}'
f'\t|Classes|={len(self.classes_in_signature())}'
f'\t|Object Properties|={len(self.object_properties_in_signature())}'
f'\t|Data Properties|={len(self.data_properties_in_signature())}'
f'\n{self.manager}\tPath:{self.path}\tNew:{self.new}')


OWLREADY2_FACET_KEYS = MappingProxyType({
Expand Down
5 changes: 2 additions & 3 deletions owlapy/owl_ontology_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,7 @@ def apply_change(self, change: AbstractOWLOntologyChange):
ont_x.imported_ontologies.append(
self._world.get_ontology(change.get_import_declaration().str))
else:
# TODO XXX
raise NotImplementedError
raise NotImplementedError("Change is not yet implemented.")

def save_world(self):
"""Saves the actual state of the quadstore in the SQLite3 file.
Expand Down Expand Up @@ -139,4 +138,4 @@ def get_owlapi_manager(self):
return self.owlapi_manager

def apply_change(self, change: AbstractOWLOntologyChange):
raise NotImplementedError()
raise NotImplementedError("A change cannot be applied at the moment.")
4 changes: 4 additions & 0 deletions owlapy/owl_property.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ class OWLObjectProperty(OWLObjectPropertyExpression, OWLProperty):

_iri: IRI

@property
def reminder(self):
return self._iri.reminder

def get_named_property(self) -> 'OWLObjectProperty':
# documented in parent
return self
Expand Down
99 changes: 50 additions & 49 deletions owlapy/owl_reasoner.py
Original file line number Diff line number Diff line change
Expand Up @@ -1013,53 +1013,9 @@ def __init__(self, ontology: Union[SyncOntology, str], reasoner="HermiT"):

self._owlapi_manager = self.manager.get_owlapi_manager()
self._owlapi_ontology = self.ontology.get_owlapi_ontology()
# super().__init__(self.ontology)
self.mapper = self.ontology.mapper
from org.semanticweb.owlapi.util import (InferredClassAssertionAxiomGenerator, InferredSubClassAxiomGenerator,
InferredEquivalentClassAxiomGenerator,
InferredDisjointClassesAxiomGenerator,
InferredEquivalentDataPropertiesAxiomGenerator,
InferredEquivalentObjectPropertyAxiomGenerator,
InferredInverseObjectPropertiesAxiomGenerator,
InferredSubDataPropertyAxiomGenerator,
InferredSubObjectPropertyAxiomGenerator,
InferredDataPropertyCharacteristicAxiomGenerator,
InferredObjectPropertyCharacteristicAxiomGenerator)

self.inference_types_mapping = {"InferredClassAssertionAxiomGenerator": InferredClassAssertionAxiomGenerator(),
"InferredSubClassAxiomGenerator": InferredSubClassAxiomGenerator(),
"InferredDisjointClassesAxiomGenerator": InferredDisjointClassesAxiomGenerator(),
"InferredEquivalentClassAxiomGenerator": InferredEquivalentClassAxiomGenerator(),
"InferredInverseObjectPropertiesAxiomGenerator": InferredInverseObjectPropertiesAxiomGenerator(),
"InferredEquivalentDataPropertiesAxiomGenerator": InferredEquivalentDataPropertiesAxiomGenerator(),
"InferredEquivalentObjectPropertyAxiomGenerator": InferredEquivalentObjectPropertyAxiomGenerator(),
"InferredSubDataPropertyAxiomGenerator": InferredSubDataPropertyAxiomGenerator(),
"InferredSubObjectPropertyAxiomGenerator": InferredSubObjectPropertyAxiomGenerator(),
"InferredDataPropertyCharacteristicAxiomGenerator": InferredDataPropertyCharacteristicAxiomGenerator(),
"InferredObjectPropertyCharacteristicAxiomGenerator": InferredObjectPropertyCharacteristicAxiomGenerator(),
}

# () Create a reasoner using the ontology
if reasoner == "HermiT":
from org.semanticweb.HermiT import ReasonerFactory
self._owlapi_reasoner = ReasonerFactory().createReasoner(self._owlapi_ontology)
assert self._owlapi_reasoner.getReasonerName() == "HermiT"
elif reasoner == "JFact":
from uk.ac.manchester.cs.jfact import JFactFactory
self._owlapi_reasoner = JFactFactory().createReasoner(self._owlapi_ontology)
elif reasoner == "Pellet":
from openllet.owlapi import PelletReasonerFactory
self._owlapi_reasoner = PelletReasonerFactory().createReasoner(self._owlapi_ontology)
elif reasoner == "Openllet":
from openllet.owlapi import OpenlletReasonerFactory
self._owlapi_reasoner = OpenlletReasonerFactory().getInstance().createReasoner(self._owlapi_ontology)
elif reasoner == "Structural":
from org.semanticweb.owlapi.reasoner.structural import StructuralReasonerFactory
self._owlapi_reasoner = StructuralReasonerFactory().createReasoner(self._owlapi_ontology)
else:
raise NotImplementedError("Not implemented")

self.reasoner = reasoner
self.inference_types_mapping = import_and_include_axioms_generators()
self._owlapi_reasoner = initialize_reasoner(reasoner,self._owlapi_ontology)

def _instances(self, ce: OWLClassExpression, direct=False) -> Set[OWLNamedIndividual]:
"""
Expand Down Expand Up @@ -1378,11 +1334,11 @@ def disjoint_data_properties(self, p: OWLDataProperty):
yield from [self.mapper.map_(pe) for pe in
self._owlapi_reasoner.getDisjointDataProperties(self.mapper.map_(p)).getFlattened()]

def types(self, i: OWLNamedIndividual, direct: bool = False):
def types(self, individual: OWLNamedIndividual, direct: bool = False):
"""Gets the named classes which are (potentially direct) types of the specified named individual.

Args:
i: The individual whose types are to be retrieved.
individual: The individual whose types are to be retrieved.
direct: Specifies if the direct types should be retrieved (True), or if all types should be retrieved
(False).

Expand All @@ -1392,7 +1348,7 @@ def types(self, i: OWLNamedIndividual, direct: bool = False):
entails ClassAssertion(C, ind).
"""
yield from [self.mapper.map_(ind) for ind in
self._owlapi_reasoner.getTypes(self.mapper.map_(i), direct).getFlattened()]
self._owlapi_reasoner.getTypes(self.mapper.map_(individual), direct).getFlattened()]

def has_consistent_ontology(self) -> bool:
"""
Expand Down Expand Up @@ -1544,3 +1500,48 @@ def unsatisfiable_classes(self):

def get_root_ontology(self) -> AbstractOWLOntology:
return self.ontology

def initialize_reasoner(reasoner:str, owlapi_ontology):
# () Create a reasoner using the ontology
if reasoner == "HermiT":
from org.semanticweb.HermiT import ReasonerFactory
owlapi_reasoner = ReasonerFactory().createReasoner(owlapi_ontology)
assert owlapi_reasoner.getReasonerName() == "HermiT"
elif reasoner == "JFact":
from uk.ac.manchester.cs.jfact import JFactFactory
owlapi_reasoner = JFactFactory().createReasoner(owlapi_ontology)
elif reasoner == "Pellet":
from openllet.owlapi import PelletReasonerFactory
owlapi_reasoner = PelletReasonerFactory().createReasoner(owlapi_ontology)
elif reasoner == "Openllet":
from openllet.owlapi import OpenlletReasonerFactory
owlapi_reasoner = OpenlletReasonerFactory().getInstance().createReasoner(owlapi_ontology)
elif reasoner == "Structural":
from org.semanticweb.owlapi.reasoner.structural import StructuralReasonerFactory
owlapi_reasoner = StructuralReasonerFactory().createReasoner(owlapi_ontology)
else:
raise NotImplementedError("Not implemented")
return owlapi_reasoner
def import_and_include_axioms_generators():
from org.semanticweb.owlapi.util import (InferredClassAssertionAxiomGenerator, InferredSubClassAxiomGenerator,
InferredEquivalentClassAxiomGenerator,
InferredDisjointClassesAxiomGenerator,
InferredEquivalentDataPropertiesAxiomGenerator,
InferredEquivalentObjectPropertyAxiomGenerator,
InferredInverseObjectPropertiesAxiomGenerator,
InferredSubDataPropertyAxiomGenerator,
InferredSubObjectPropertyAxiomGenerator,
InferredDataPropertyCharacteristicAxiomGenerator,
InferredObjectPropertyCharacteristicAxiomGenerator)

return {"InferredClassAssertionAxiomGenerator": InferredClassAssertionAxiomGenerator(),
"InferredSubClassAxiomGenerator": InferredSubClassAxiomGenerator(),
"InferredDisjointClassesAxiomGenerator": InferredDisjointClassesAxiomGenerator(),
"InferredEquivalentClassAxiomGenerator": InferredEquivalentClassAxiomGenerator(),
"InferredInverseObjectPropertiesAxiomGenerator": InferredInverseObjectPropertiesAxiomGenerator(),
"InferredEquivalentDataPropertiesAxiomGenerator": InferredEquivalentDataPropertiesAxiomGenerator(),
"InferredEquivalentObjectPropertyAxiomGenerator": InferredEquivalentObjectPropertyAxiomGenerator(),
"InferredSubDataPropertyAxiomGenerator": InferredSubDataPropertyAxiomGenerator(),
"InferredSubObjectPropertyAxiomGenerator": InferredSubObjectPropertyAxiomGenerator(),
"InferredDataPropertyCharacteristicAxiomGenerator": InferredDataPropertyCharacteristicAxiomGenerator(),
"InferredObjectPropertyCharacteristicAxiomGenerator": InferredObjectPropertyCharacteristicAxiomGenerator()}
7 changes: 7 additions & 0 deletions tests/test_sync_ontology.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ class TestSyncReasoner(unittest.TestCase):
manager = SyncOntologyManager()
onto = manager.load_ontology(ontology_path)

def test_interface_father_dataset(self):
ontology_path = "KGs/Family/father.owl"
onto = SyncOntologyManager().load_ontology(ontology_path)
assert {owl_class.reminder for owl_class in onto.classes_in_signature()}=={'male', 'female', 'Thing', 'person'}
assert {individual.reminder for individual in onto.individuals_in_signature()}=={'markus', 'anna', 'martin', 'stefan', 'heinz', 'michelle'}
assert {object_property.reminder for object_property in onto.object_properties_in_signature()}=={'hasChild'}

# NOTE AB: The name of "assertCountEqual" may be misleading,but it's essentially an order-insensitive "assertEqual".

def test_classes_in_signature(self):
Expand Down
Loading
Loading