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 and Readme Update #59

Merged
merged 4 commits into from
Aug 22, 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
44 changes: 36 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ pytest -p no:warnings -x # Running 103 tests takes ~ 30 mins

## Usage

In this example we start with a simple atomic class expression and move to some more complex
ones and finally render and print the last of them in description logics syntax.

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

```python
from owlapy.class_expression import OWLClass, OWLObjectIntersectionOf, OWLObjectSomeValuesFrom
Expand All @@ -40,17 +41,13 @@ from owlapy import owl_expression_to_sparql, owl_expression_to_dl

# Create the male class
male = OWLClass("http://example.com/society#male")

# Create an object property using the iri as a string for 'hasChild' property.
hasChild = OWLObjectProperty("http://example.com/society#hasChild")

# Create an existential restrictions
hasChild_male = OWLObjectSomeValuesFrom(hasChild, male)

# Let's make it more complex by intersecting with another class
teacher = OWLClass("http://example.com/society#teacher")
teacher_that_hasChild_male = OWLObjectIntersectionOf([hasChild_male, teacher])

# You can render and print owl class expressions in description logics syntax (and vice-versa)
print(owl_expression_to_dl(teacher_that_hasChild_male))
# (∃ hasChild.male) ⊓ teacher
Expand All @@ -68,7 +65,35 @@ class. In the above examples we have introduced 3 types of class expressions:
Like we showed in this example, you can create all kinds of class expressions using the
OWL objects in [owlapy api](https://dice-group.github.io/owlapy/autoapi/owlapy/index.html).

Many axioms can automatically inferred with a selected reasoner
</details>

### Logical Inference

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

```python
from owlapy.owl_ontology_manager import OntologyManager
from owlapy.owlapi_adaptor import OWLAPIAdaptor

ontology_path = "KGs/Family/family-benchmark_rich_background.owl"
# Available OWL Reasoners: 'HermiT', 'Pellet', 'JFact', 'Openllet'
owlapi_adaptor = OWLAPIAdaptor(path=ontology_path, name_reasoner="Pellet")
onto = OntologyManager().load_ontology(ontology_path)
# Iterate over defined owl Classes in the signature
for i in onto.classes_in_signature():
# Performing type inference with Pellet
instances=owlapi_adaptor.instances(i,direct=False)
print(f"Class:{i}\t Num instances:{len(instances)}")
owlapi_adaptor.stopJVM()
```

</details>

### Ontology Enrichment

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

An Ontology can be enriched by inferring many different axioms.
```python
from owlapy.owlapi_adaptor import OWLAPIAdaptor

Expand All @@ -86,7 +111,10 @@ adaptor.infer_axioms_and_save(output_path="KGs/Family/inferred_family-benchmark_
adaptor.stopJVM()
```

Check also the [examples](https://github.com/dice-group/owlapy/tree/develop/examples) folder.
</details>


Check also the [examples](https://github.com/dice-group/owlapy/tree/develop/examples) and [tests](https://github.com/dice-group/owlapy/tree/develop/tests) folders.

## How to cite
Currently, we are working on our manuscript describing our framework.
17 changes: 12 additions & 5 deletions owlapy/owl_ontology_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from owlapy.owl_ontology import OWLOntology, Ontology, ToOwlready2
from owlapy.owl_property import OWLDataProperty, OWLObjectInverseOf, OWLObjectProperty, \
OWLProperty

from typing import Union

class OWLOntologyChange(metaclass=ABCMeta):
"""Represents an ontology change."""
Expand Down Expand Up @@ -849,10 +849,18 @@ def __init__(self, world_store=None):
else:
self._world = owlready2.World(filename=world_store)

def create_ontology(self, iri: IRI) -> 'Ontology':
def create_ontology(self, iri:Union[str,IRI]=None) -> 'Ontology':
if isinstance(iri, str):
iri=IRI.create(iri)
else:
assert isinstance(iri, IRI), "iri either must be string or an instance of IRI Class"
return Ontology(self, iri, load=False)

def load_ontology(self, iri: IRI) -> 'Ontology':
def load_ontology(self, iri: Union[str,IRI]=None) -> 'Ontology':
if isinstance(iri, str):
iri=IRI.create(iri)
else:
assert isinstance(iri, IRI), "iri either must be string or an instance of IRI Class"
return Ontology(self, iri, load=True)

def apply_change(self, change: OWLOntologyChange):
Expand All @@ -879,8 +887,7 @@ def save_ontology(self, ontology: OWLOntology, document_iri: IRI):
filename = document_iri.as_str()[len('file:/'):]
ont_x.save(file=filename)
else:
# TODO XXX
raise NotImplementedError
raise NotImplementedError("Couldn't save because the namespace of document_iri does not start with **file:/**")

def save_world(self):
"""Saves the actual state of the quadstore in the SQLite3 file.
Expand Down
32 changes: 9 additions & 23 deletions owlapy/owl_reasoner.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
import operator
from abc import ABCMeta, abstractmethod
from collections import defaultdict
from enum import Enum, auto
from functools import singledispatchmethod, reduce
from itertools import chain, repeat
from types import MappingProxyType, FunctionType
from typing import DefaultDict, Iterable, Dict, Mapping, Set, Type, TypeVar, Optional, FrozenSet, List, cast
from typing import DefaultDict, Iterable, Dict, Mapping, Set, Type, TypeVar, Optional, FrozenSet
import logging

import owlready2
Expand All @@ -18,11 +17,11 @@
OWLDataAllValuesFrom
from owlapy.class_expression import OWLClass
from owlapy.iri import IRI
from owlapy.owl_axiom import OWLAxiom, OWLSubClassOfAxiom
from owlapy.owl_axiom import OWLSubClassOfAxiom
from owlapy.owl_data_ranges import OWLDataRange, OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf
from owlapy.owl_datatype import OWLDatatype
from owlapy.owl_object import OWLEntity
from owlapy.owl_ontology import OWLOntology, Ontology, _parse_concept_to_owlapy, ToOwlready2
from owlapy.owl_ontology import OWLOntology, Ontology, _parse_concept_to_owlapy
from owlapy.owl_ontology_manager import OntologyManager
from owlapy.owl_property import OWLObjectPropertyExpression, OWLDataProperty, OWLObjectProperty, OWLObjectInverseOf, \
OWLPropertyExpression, OWLDataPropertyExpression
Expand All @@ -33,7 +32,12 @@

logger = logging.getLogger(__name__)

_P = TypeVar('_P', bound=OWLPropertyExpression)

# TODO:CD:The name of the classes defined with metaclass=ABCMeta should reflect that
# TODO:CD: An instance cannot be created from those classes.
# TODO:CD: We should move those Abstract Base Classes into a respective package, e.g.
# TODO:CD: owlapy/abstract_owl_reasoner/abstract_owl_reasoner.py should contain OWLReasoner and OWLReasonerEx
class OWLReasoner(metaclass=ABCMeta):
"""An OWLReasoner reasons over a set of axioms (the set of reasoner axioms) that is based on the imports closure of
a particular ontology - the "root" ontology."""
Expand Down Expand Up @@ -401,20 +405,6 @@ class expression with respect to the imports closure of the root ontology.
If ce is equivalent to owl:Thing then nothing will be returned.
"""
pass


# Deprecated
# class BaseReasoner(Enum):
# """Enumeration class for base reasoner when calling sync_reasoner.
#
# Attributes:
# PELLET: Pellet base reasoner.
# HERMIT: HermiT base reasoner.
# """
# PELLET = auto()
# HERMIT = auto()


class OWLReasonerEx(OWLReasoner, metaclass=ABCMeta):
"""Extra convenience methods for OWL Reasoners"""

Expand Down Expand Up @@ -496,10 +486,9 @@ def ind_object_properties(self, ind: OWLNamedIndividual, direct: bool = True) ->
except StopIteration:
pass


class OntologyReasoner(OWLReasonerEx):
__slots__ = '_ontology', '_world'

# TODO: CD: We will remove owlready2 from owlapy
_ontology: Ontology
_world: owlready2.World

Expand Down Expand Up @@ -1042,9 +1031,6 @@ def get_root_ontology(self) -> OWLOntology:
return self._ontology


_P = TypeVar('_P', bound=OWLPropertyExpression)


class FastInstanceCheckerReasoner(OWLReasonerEx):
"""Tries to check instances fast (but maybe incomplete)."""
__slots__ = '_ontology', '_base_reasoner', \
Expand Down
6 changes: 5 additions & 1 deletion owlapy/owlapi_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import jpype.imports

import owlapy.owl_ontology
from owlapy import owl_expression_to_manchester, manchester_to_owl_expression
from owlapy.class_expression import OWLClassExpression, OWLDataOneOf, OWLFacetRestriction, OWLDatatypeRestriction
from owlapy.iri import IRI
Expand Down Expand Up @@ -90,7 +91,10 @@ def init(the_class):

class OWLAPIMapper:

def __init__(self, ontology):
def __init__(self, ontology=None):
# TODO: CD: Please use class type of ontology
# TODO: CD: if ontology is None, then we should throw an exception with a useful information
# assert isinstance(ontology, OWLAPIMapper)
self.ontology = ontology
self.manager = ontology.getOWLOntologyManager()

Expand Down
Loading