From 7bde13284d63be25753ead161798e6ec9ea1983f Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 16 Sep 2024 13:10:04 +0200 Subject: [PATCH 01/12] __repr__ modified --- owlapy/iri.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/owlapy/iri.py b/owlapy/iri.py index c7234414..c9ec7490 100644 --- a/owlapy/iri.py +++ b/owlapy/iri.py @@ -89,7 +89,7 @@ def create(string, remainder=None) -> 'IRI': return IRI(string[0:index], string[index:]) def __repr__(self): - return f"IRI({repr(self._namespace)},{repr(self._remainder)})" + return f"IRI(namespace:{repr(self._namespace)}, reminder:{repr(self._remainder)})" def __eq__(self, other): if type(other) is type(self): From bebeb81d7ddf30f96d02c38944bebee838f9c533 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 16 Sep 2024 15:26:54 +0200 Subject: [PATCH 02/12] type info of LinkedHashSet is shown --- examples/ontology_reasoning_retrieval.py | 39 ++++++++++++++++++++++++ owlapy/owl_reasoner.py | 4 +++ 2 files changed, 43 insertions(+) create mode 100644 examples/ontology_reasoning_retrieval.py diff --git a/examples/ontology_reasoning_retrieval.py b/examples/ontology_reasoning_retrieval.py new file mode 100644 index 00000000..414de2b0 --- /dev/null +++ b/examples/ontology_reasoning_retrieval.py @@ -0,0 +1,39 @@ +""" + +KB = { (A subclass B), (B subclass C), (x type A) } + +KB = { (A subclass B), (B subclass C), (x type A), (x type B), (x type C) } + +Missing types are inferred due to subclass hierarchy. +""" +from owlapy.class_expression import OWLClass +from owlapy.owl_axiom import OWLDeclarationAxiom, OWLClassAssertionAxiom, OWLSubClassOfAxiom +from owlapy.owl_ontology_manager import OntologyManager +from owlapy.owl_individual import OWLNamedIndividual +from owlapy.iri import IRI +from owlapy.owl_reasoner import SyncReasoner +# () Define a base IRI. +base_iri = IRI(namespace="https://github.com/dice-group/owlapy#") +# () Create an empty ontology. +onto = OntologyManager().create_ontology(iri=base_iri) +# () Define classes and individuals. +A = OWLClass(iri=base_iri.get_namespace() + "A") +B = OWLClass(iri=base_iri.get_namespace() + "B") +C = OWLClass(iri=base_iri.get_namespace() + "C") +x = OWLNamedIndividual(iri=base_iri.get_namespace() + "x") +# () Add axioms. +onto.add_axiom([OWLDeclarationAxiom(A), + OWLDeclarationAxiom(B), + OWLDeclarationAxiom(C), + OWLDeclarationAxiom(x), + OWLSubClassOfAxiom(A,B), + OWLSubClassOfAxiom(B,C), + OWLClassAssertionAxiom(x,A)]) +# () Save axioms [ (A subclass B), (B subclass C), (x type A) ]. +onto.save("new_ontology.owl") +# () Initialize reasoner. +reasoner = SyncReasoner(ontology="new_ontology.owl", reasoner="Pellet") +# () Infer instances. +for i in reasoner.ontology.classes_in_signature(): + print(f"Retrieve {i}:",end=" ") + print(" ".join( [_.str for _ in reasoner.instances(i)])) \ No newline at end of file diff --git a/owlapy/owl_reasoner.py b/owlapy/owl_reasoner.py index 45d02bca..7a90403b 100644 --- a/owlapy/owl_reasoner.py +++ b/owlapy/owl_reasoner.py @@ -9,6 +9,8 @@ from types import MappingProxyType, FunctionType from typing import DefaultDict, Iterable, Dict, Mapping, Set, Type, TypeVar, Optional, FrozenSet, List, Union +from jpype import javax + from owlapy.class_expression import OWLClassExpression, OWLObjectSomeValuesFrom, OWLObjectUnionOf, \ OWLObjectIntersectionOf, OWLObjectComplementOf, OWLObjectAllValuesFrom, OWLObjectOneOf, OWLObjectHasValue, \ OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLObjectExactCardinality, OWLObjectCardinalityRestriction, \ @@ -1228,6 +1230,8 @@ def instances(self, ce: OWLClassExpression, direct=False) -> List[OWLNamedIndivi list: A list of individuals classified by the given class expression. """ inds = self._owlapi_reasoner.getInstances(self.mapper.map_(ce), direct).getFlattened() + assert str(type(inds)) == "" + return [self.mapper.map_(ind) for ind in inds] def equivalent_classes(self, ce: OWLClassExpression) -> List[OWLClassExpression]: From 73bc32a6b7cab81c532666b641b5ae4317a70948 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 16 Sep 2024 15:27:55 +0200 Subject: [PATCH 03/12] save of ontology extended --- owlapy/owl_ontology.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/owlapy/owl_ontology.py b/owlapy/owl_ontology.py index 44b064a7..0e72b3c3 100644 --- a/owlapy/owl_ontology.py +++ b/owlapy/owl_ontology.py @@ -38,6 +38,7 @@ OWLDifferentIndividualsAxiom, OWLDisjointClassesAxiom, OWLSameIndividualAxiom, OWLClassAxiom, OWLDataPropertyDomainAxiom, OWLDataPropertyRangeAxiom, OWLObjectPropertyDomainAxiom) from owlapy.vocab import OWLFacet +import os logger = logging.getLogger(__name__) @@ -800,6 +801,9 @@ def __init__(self, manager: _OM, ontology_iri: IRI, load: bool): onto = onto.load() self._onto = onto + def __len__(self) -> int: + return len([t for t in self._onto.get_triples()]) + def classes_in_signature(self) -> Iterable[OWLClass]: for c in self._onto.classes(): yield OWLClass(IRI.create(c.iri)) @@ -928,13 +932,27 @@ def remove_axiom(self, axiom: Union[OWLAxiom, Iterable[OWLAxiom]]): for ax in axiom: _remove_axiom(ax, self, self._world) - def save(self, path: Union[str,IRI] = None, rdf_format = "rdfxml"): + def save(self, path: Union[str,IRI] = None, inplace:bool=False, rdf_format = "rdfxml"): + # convert it into str. if isinstance(path, IRI): - path=path.as_str() + path = path.as_str() + # Sanity checking + if inplace is False: + assert isinstance(path,str), f"path must be string if inplace is set to False. Current path is {type(path)}" + # Get the current ontology defined in the world. ont_x:owlready2.namespace.Ontology - assert isinstance(path,str), f"path must be string. Currently it is {type(path)}" ont_x = self._world.get_ontology(self.get_ontology_id().get_ontology_iri().as_str()) - ont_x.save(file=path,format=rdf_format) + + if inplace: + if os.path.exists(self._iri.as_str()): + print(f"Saving {self} inplace...") + ont_x.save(file=self._iri.as_str(), format=rdf_format) + else: + print(f"Saving {self} inplace with name of demo.owl...") + self._world.get_ontology(self.get_ontology_id().get_ontology_iri().as_str()).save(file="demo.owl") + else: + print(f"Saving {path}..") + ont_x.save(file=path,format=rdf_format) def get_original_iri(self): """Get the IRI argument that was used to create this ontology.""" @@ -949,7 +967,7 @@ def __hash__(self): return hash(self._onto.base_iri) def __repr__(self): - return f'Ontology({IRI.create(self._onto.base_iri)}, {self._onto.loaded})' + return f'Ontology({self._onto.base_iri}, loaded:{self._onto.loaded})' class SyncOntology(OWLOntology): From f9153d2cee2de498aa4c0acf4ee0f4da36c6e61a Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 16 Sep 2024 15:29:07 +0200 Subject: [PATCH 04/12] pass keyword is removed --- owlapy/owl_object.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/owlapy/owl_object.py b/owlapy/owl_object.py index b90e9888..02894034 100644 --- a/owlapy/owl_object.py +++ b/owlapy/owl_object.py @@ -88,8 +88,6 @@ def __hash__(self): def __repr__(self): return f"{type(self).__name__}({repr(self._iri)})" - pass - class OWLEntity(OWLNamedObject, metaclass=ABCMeta): """Represents Entities in the OWL 2 Specification.""" From b5fd7f12f86964f6601b27dd9cccbb17da693952 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 16 Sep 2024 15:32:01 +0200 Subject: [PATCH 05/12] __str__ and __repr__ for owlclass are implemented --- owlapy/class_expression/owl_class.py | 6 ++++++ owlapy/owl_reasoner.py | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/owlapy/class_expression/owl_class.py b/owlapy/class_expression/owl_class.py index fd821f45..0f218a75 100644 --- a/owlapy/class_expression/owl_class.py +++ b/owlapy/class_expression/owl_class.py @@ -62,4 +62,10 @@ def get_nnf(self) -> 'OWLClass': # documented in parent return self + def __str__(self): + return f"OWLClass({self.reminder})" + + def __repr__(self): + return f"OWLClass({self._iri})" + diff --git a/owlapy/owl_reasoner.py b/owlapy/owl_reasoner.py index 7a90403b..21cea2ff 100644 --- a/owlapy/owl_reasoner.py +++ b/owlapy/owl_reasoner.py @@ -1231,7 +1231,6 @@ def instances(self, ce: OWLClassExpression, direct=False) -> List[OWLNamedIndivi """ inds = self._owlapi_reasoner.getInstances(self.mapper.map_(ce), direct).getFlattened() assert str(type(inds)) == "" - return [self.mapper.map_(ind) for ind in inds] def equivalent_classes(self, ce: OWLClassExpression) -> List[OWLClassExpression]: From d7cacf2aba814635af07434ec713400d84b9cb21 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 16 Sep 2024 15:32:57 +0200 Subject: [PATCH 06/12] __repr__ of IRI updated --- owlapy/iri.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/owlapy/iri.py b/owlapy/iri.py index c9ec7490..66166bb4 100644 --- a/owlapy/iri.py +++ b/owlapy/iri.py @@ -39,7 +39,7 @@ class IRI(OWLAnnotationSubject, OWLAnnotationValue, metaclass=_meta_IRI): _namespace: str _remainder: str - def __init__(self, namespace: Union[str, Namespaces], remainder: str): + def __init__(self, namespace: Union[str, Namespaces], remainder: str=""): if isinstance(namespace, Namespaces): namespace = namespace.ns else: @@ -89,7 +89,7 @@ def create(string, remainder=None) -> 'IRI': return IRI(string[0:index], string[index:]) def __repr__(self): - return f"IRI(namespace:{repr(self._namespace)}, reminder:{repr(self._remainder)})" + return f"IRI({repr(self._namespace)}, {repr(self._remainder)})" def __eq__(self, other): if type(other) is type(self): From a18eaf37c682466d466cfc2fecb8a01f50b3f278 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 16 Sep 2024 17:04:24 +0200 Subject: [PATCH 07/12] reformatting --- owlapy/owl_reasoner.py | 2 -- setup.py | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/owlapy/owl_reasoner.py b/owlapy/owl_reasoner.py index 21cea2ff..f909e15e 100644 --- a/owlapy/owl_reasoner.py +++ b/owlapy/owl_reasoner.py @@ -9,8 +9,6 @@ from types import MappingProxyType, FunctionType from typing import DefaultDict, Iterable, Dict, Mapping, Set, Type, TypeVar, Optional, FrozenSet, List, Union -from jpype import javax - from owlapy.class_expression import OWLClassExpression, OWLObjectSomeValuesFrom, OWLObjectUnionOf, \ OWLObjectIntersectionOf, OWLObjectComplementOf, OWLObjectAllValuesFrom, OWLObjectOneOf, OWLObjectHasValue, \ OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLObjectExactCardinality, OWLObjectCardinalityRestriction, \ diff --git a/setup.py b/setup.py index b04bd1b3..4bcd0259 100644 --- a/setup.py +++ b/setup.py @@ -8,9 +8,7 @@ version="1.3.0", packages=find_packages(), include_package_data=True, - package_data={ - 'owlapy': ['jar_dependencies/*.jar'], - }, + package_data={'owlapy': ['jar_dependencies/*.jar'],}, install_requires=[ "pandas>=1.5.0", "requests>=2.32.3", From 9cde19341739096ea92d545d9edea077fdd71dd7 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 16 Sep 2024 17:14:05 +0200 Subject: [PATCH 08/12] Reasoners are evaluated on named concepts --- examples/comparing_adaptor_reasoners.py | 45 ------------------- ...ontology_reasoning_retrieval_agreements.py | 33 ++++++++++++++ 2 files changed, 33 insertions(+), 45 deletions(-) delete mode 100644 examples/comparing_adaptor_reasoners.py create mode 100644 examples/ontology_reasoning_retrieval_agreements.py diff --git a/examples/comparing_adaptor_reasoners.py b/examples/comparing_adaptor_reasoners.py deleted file mode 100644 index 25222601..00000000 --- a/examples/comparing_adaptor_reasoners.py +++ /dev/null @@ -1,45 +0,0 @@ -from owlapy.owl_property import OWLObjectProperty -from owlapy.owl_reasoner import SyncReasoner -from owlapy.iri import IRI -from owlapy.class_expression import OWLClass, OWLObjectAllValuesFrom, OWLObjectComplementOf -import time -ontology_location = "../KGs/Carcinogenesis/carcinogenesis.owl" - -i1 = set() -i2 = set() -i3 = set() -i4 = set() - -for rsn in ["HermiT", "Pellet", "JFact", "Openllet"]: - reasoner = SyncReasoner(ontology_location, rsn) - # TODO AB: needs a more complex class expression to show the specific differences of the reasoners - ce = OWLObjectAllValuesFrom(property=OWLObjectProperty(IRI('http://dl-learner.org/carcinogenesis#', 'hasAtom')), - filler=OWLObjectComplementOf(OWLClass(IRI('http://dl-learner.org/carcinogenesis#', - 'Sulfur-75')))) - - if rsn == "HermiT": - i1 = set(reasoner.instances(ce)) - elif rsn == "Pellet": - i2 = set(reasoner.instances(ce)) - elif rsn == "JFact": - i3 = set(reasoner.instances(ce)) - elif rsn == "Openllet": - i4 = set(reasoner.instances(ce)) - -print("Hermit-Pellet:") -[print(_) for _ in i1-i2] -time.sleep(10) -print("Hermit-JFact:") -[print(_) for _ in i1-i3] -time.sleep(10) -print("Hermit-Openllet:") -[print(_) for _ in i1-i4] -time.sleep(10) -print("Pellet-JFact:") -[print(_) for _ in i2-i3] -time.sleep(10) -print("Pellet-Openllet:") -[print(_) for _ in i2-i4] -time.sleep(10) -print("JFact-Openllet:") -[print(_) for _ in i3-i4] \ No newline at end of file diff --git a/examples/ontology_reasoning_retrieval_agreements.py b/examples/ontology_reasoning_retrieval_agreements.py new file mode 100644 index 00000000..ca66d1e3 --- /dev/null +++ b/examples/ontology_reasoning_retrieval_agreements.py @@ -0,0 +1,33 @@ +from owlapy.owl_reasoner import SyncReasoner +from owlapy import OntologyManager +from owlapy.class_expression import OWLClassExpression +from typing import Dict +ontology_path = "../KGs/Family/family-benchmark_rich_background.owl" +# () Load ontology +onto = OntologyManager().load_ontology(ontology_path) + +# () Initialize Reasoners +reasoners = dict() +reasoners["HermiT"] = SyncReasoner(ontology=ontology_path, reasoner="HermiT") +reasoners["Pellet"] = SyncReasoner(ontology=ontology_path, reasoner="Pellet") +reasoners["JFact"] = SyncReasoner(ontology=ontology_path, reasoner="JFact") +reasoners["Openllet"] = SyncReasoner(ontology=ontology_path, reasoner="Openllet") + +def compute_agreements(owl_reasoners:Dict[str,SyncReasoner], expression: OWLClassExpression, verbose=False): + if verbose: + print(f"Computing agreements between Reasoners on {expression}...",end="\t") + retrieval_result = None + flag = False + for __, reasoner in owl_reasoners.items(): + if retrieval_result: + flag = retrieval_result == {_.str for _ in reasoner.instances(expression)} + else: + retrieval_result = {_.str for _ in reasoner.instances(expression)} + if verbose: + print(f"Successful:{flag}") + return flag + +# () Iterate over named classes +for c in onto.classes_in_signature(): + # reasoners must agree + assert compute_agreements(reasoners, c, True) \ No newline at end of file From 16efd2f12bd680a542200a2bff22a0824793d3ad Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 16 Sep 2024 17:14:31 +0200 Subject: [PATCH 09/12] version increased --- owlapy/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/owlapy/__init__.py b/owlapy/__init__.py index 4f6b6692..6c8bd5cf 100644 --- a/owlapy/__init__.py +++ b/owlapy/__init__.py @@ -3,4 +3,6 @@ from .parser import (dl_to_owl_expression as dl_to_owl_expression, manchester_to_owl_expression as manchester_to_owl_expression) from .converter import owl_expression_to_sparql as owl_expression_to_sparql -__version__ = '1.3.0' +from .owl_ontology_manager import OntologyManager as OntologyManager + +__version__ = '1.3.1' From c45d4a3877791776cfb6c6977b3195a3067b4d08 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 16 Sep 2024 17:24:49 +0200 Subject: [PATCH 10/12] tqdm is being used in the loop --- ...tology_reasoning_retrieval_agreements_and_runtimes.py} | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) rename examples/{owl_reasoners.py => ontology_reasoning_retrieval_agreements_and_runtimes.py} (95%) diff --git a/examples/owl_reasoners.py b/examples/ontology_reasoning_retrieval_agreements_and_runtimes.py similarity index 95% rename from examples/owl_reasoners.py rename to examples/ontology_reasoning_retrieval_agreements_and_runtimes.py index 90584e24..4c449184 100644 --- a/examples/owl_reasoners.py +++ b/examples/ontology_reasoning_retrieval_agreements_and_runtimes.py @@ -9,6 +9,7 @@ import matplotlib.pyplot as plt import seaborn as sns import numpy as np +from tqdm import tqdm ontology_path = "../KGs/Family/family-benchmark_rich_background.owl" @@ -45,10 +46,9 @@ def eval_reasoners(iter_owl_exp, mapping): - print("Number of expressions:", len(iter_owl_exp)) results = dict() runtime_results = dict() - for c in iter_owl_exp: + for c in tqdm(iter_owl_exp): for name_i, reasoner_i in mapping.items(): start_time_i = time.time() result_reasoner_i = {i.str for i in reasoner_i.instances(c)} @@ -110,15 +110,19 @@ def plot_similarity_btw_reasoners(results): # EVAL Named Concepts +print("Evaluation over named concepts...") similarity_results, average_runtime_owl_reasoners = eval_reasoners(nc, owl_reasoners) plot_similarity_btw_reasoners(similarity_results) plot_runtimes(average_runtime_owl_reasoners, title="Avg Runtime of Reasoners on Named Concepts") + # EVAL Negated Concepts +print("Evaluation over negated named concepts...") similarity_results, average_runtime_owl_reasoners = eval_reasoners(nnc, owl_reasoners) plot_similarity_btw_reasoners(similarity_results) plot_runtimes(average_runtime_owl_reasoners, title="Avg Runtime of Reasoners on Negated Named Concepts") # EVAL Exist R. NC +print("Evaluation over existential object property restrictions... takes some time") similarity_results, average_runtime_owl_reasoners = eval_reasoners(exist_nc, owl_reasoners) plot_similarity_btw_reasoners(similarity_results) plot_runtimes(average_runtime_owl_reasoners, title="Avg Runtime of Reasoners on OWLObjectSomeValuesFrom") From 27efe0706b6d075d2b14f0230a7b06b8fddc75c5 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 16 Sep 2024 17:25:02 +0200 Subject: [PATCH 11/12] tqdm is included --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4bcd0259..9170c153 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,8 @@ "pytest>=8.1.1", "sortedcontainers>=2.4.0", "owlready2>=0.40", - "JPype1>=1.5.0"], + "JPype1>=1.5.0", + "tqdm>=4.66.5"], author='Caglar Demir', author_email='caglardemir8@gmail.com', url='https://github.com/dice-group/owlapy', From 1b004528f7a5b7fd9df34f011f49cfa348a516a8 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 16 Sep 2024 17:26:05 +0200 Subject: [PATCH 12/12] renamed --- examples/{ontology_modification.py => ontology_engineering.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{ontology_modification.py => ontology_engineering.py} (100%) diff --git a/examples/ontology_modification.py b/examples/ontology_engineering.py similarity index 100% rename from examples/ontology_modification.py rename to examples/ontology_engineering.py