Skip to content

Commit

Permalink
Merge pull request #105 from dice-group/refactoring_SyncReasoner
Browse files Browse the repository at this point in the history
Refactoring sync reasoner
  • Loading branch information
Demirrr authored Nov 9, 2024
2 parents 0dbc2de + 1aaf53c commit 12183d2
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 60 deletions.
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

0 comments on commit 12183d2

Please sign in to comment.