Repository: dice-group/owlapy (language: python)

Issue:
Refactoring and some changes to the base structure
## Refactoring
- Created package `owlapy.abstracts` with 3 modules: 
  - `abstract_owl_ontology_manager.py`
  - `abstract_owl_ontology.py`
  - `abstract_owl_reasoner.py`

- Abstract classes `OWLOntologyManager` and `OWLOntologyChange` moved from `owlapy.owl_ontology_manager` to `owlapy.abstracts.abstract_owl_ontology_manager`
- Abstract class `OWLOntology` moved from `owlapy.owl_ontology` to `owlapy.abstracts.abstract_owl_ontology`.
- Abstract classes `OWLReasoner` and `OWLReasonerEx` modev from `owlapy.owl_reasoner` to `owlapy.abstracts.abstract_owl_reasoner`

## Changes

- Signature changes on methods of `OWLReasoner`:
  - The argument `only_named` is no longer a required argument of the abstract methods
  - The argument `direct` is no longer required on the following methods: `data_property_values`, `object_property_values` and `all_data_property_values`. 

- The current reasoners have not changed. Reasoners such as _FastInstanceCheckerReasoner_ still uses the above mentioned arguments, where they have a default value, but _SyncReasoner_ for example does not.

- Class `SyncReasoner` now inherit from OWLReasoner.

- Added _Structural_ reasoner as an option to _SyncReasoner_.






Discussion / hints:

Fix patch:
diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml
new file mode 100644
index 00000000..b6690e05
--- /dev/null
+++ b/.github/workflows/ruff.yml
@@ -0,0 +1,8 @@
+name: Ruff
+on: [push, pull_request]
+jobs:
+  ruff:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: chartboost/ruff-action@v1
\ No newline at end of file
diff --git a/README.md b/README.md
index 56c1d08d..a7ca34b0 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 # OWLAPY
 [![Coverage](https://img.shields.io/badge/coverage-78%25-green)](https://dice-group.github.io/owlapy/usage/further_resources.html#coverage-report)
-[![Pypi](https://img.shields.io/badge/pypi-1.2.0-blue)](https://pypi.org/project/owlapy/1.2.0/)
-[![Docs](https://img.shields.io/badge/documentation-1.2.0-yellow)](https://dice-group.github.io/owlapy/usage/main.html)
+[![Pypi](https://img.shields.io/badge/pypi-1.3.0-blue)](https://pypi.org/project/owlapy/1.3.0/)
+[![Docs](https://img.shields.io/badge/documentation-1.3.0-yellow)](https://dice-group.github.io/owlapy/usage/main.html)
 
 ![OWLAPY](docs/_static/images/owlapy_logo.png)
 
@@ -38,21 +38,34 @@ pytest -p no:warnings -x # Running  102 tests takes ~ 1 min
 from owlapy.class_expression import OWLClass, OWLObjectIntersectionOf, OWLObjectSomeValuesFrom
 from owlapy.owl_property import OWLObjectProperty
 from owlapy import owl_expression_to_sparql, owl_expression_to_dl
+from owlapy.owl_ontology_manager import OntologyManager
+from owlapy.owl_axiom import OWLDeclarationAxiom, OWLClassAssertionAxiom
+from owlapy.owl_individual import OWLNamedIndividual, IRI
 
-# Create the male class
+# Using owl classes to create a complex class expression
 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
-print(owl_expression_to_sparql(teacher_that_hasChild_male))
-#  SELECT DISTINCT ?x WHERE {  ?x <http://example.com/society#hasChild> ?s_1 . ?s_1 a <http://example.com/society#male> . ?x a <http://example.com/society#teacher> .  } }
+
+# You can render and print owl class expressions in Description Logics syntax or convert it to SPARQL for example. 
+print(owl_expression_to_dl(teacher_that_hasChild_male)) # (∃ hasChild.male) ⊓ teacher
+print(owl_expression_to_sparql(teacher_that_hasChild_male)) #  SELECT DISTINCT ?x WHERE {  ?x <http://example.com/society#hasChild> ?s_1 . ?s_1 a <http://example.com/society#male> . ?x a <http://example.com/society#teacher> .  } }
+
+# Create an Ontology, add the axioms and save the Ontology.
+manager = OntologyManager()
+new_iri = IRI.create("file:/example_ontology.owl")
+ontology = manager.create_ontology(new_iri)
+
+john = OWLNamedIndividual("http://example.com/society#john")
+male_declaration_axiom = OWLDeclarationAxiom(male)
+hasChild_declaration_axiom = OWLDeclarationAxiom(hasChild)
+john_declaration_axiom = OWLDeclarationAxiom(john)
+john_a_male_assertion_axiom = OWLClassAssertionAxiom(john, male)
+ontology.add_axiom([male_declaration_axiom, hasChild_declaration_axiom, john_declaration_axiom, john_a_male_assertion_axiom])
+ontology.save()
+
 ```
 
 Every OWL object that can be used to classify individuals, is considered a class expression and 
@@ -73,18 +86,19 @@ OWL objects in [owlapy api](https://dice-group.github.io/owlapy/autoapi/owlapy/i
 
 ```python
 from owlapy.owl_ontology_manager import OntologyManager
-from owlapy.owlapi_adaptor import OWLAPIAdaptor
+from owlapy.owl_reasoner import SyncReasoner
+from owlapy.static_funcs import stopJVM
 
 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")
+reasoner = SyncReasoner(ontology = ontology_path, 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)
+    instances=sync_reasoner.instances(i,direct=False)
     print(f"Class:{i}\t Num instances:{len(instances)}")
-owlapi_adaptor.stopJVM()
+stopJVM()
 ```
 
 </details>
@@ -95,11 +109,12 @@ owlapi_adaptor.stopJVM()
 
 An Ontology can be enriched by inferring many different axioms.
 ```python
-from owlapy.owlapi_adaptor import OWLAPIAdaptor
+from owlapy.owl_reasoner import SyncReasoner
+from owlapy.static_funcs import stopJVM
 
-adaptor = OWLAPIAdaptor(path="KGs/Family/family-benchmark_rich_background.owl", name_reasoner="Pellet")
+sync_reasoner = SyncReasoner(ontology="KGs/Family/family-benchmark_rich_background.owl", reasoner="Pellet")
 # Infer missing class assertions
-adaptor.infer_axioms_and_save(output_path="KGs/Family/inferred_family-benchmark_rich_background.ttl",
+sync_reasoner.infer_axioms_and_save(output_path="KGs/Family/inferred_family-benchmark_rich_background.ttl",
                        output_format="ttl",
                        inference_types=[
                            "InferredClassAssertionAxiomGenerator",
@@ -108,7 +123,7 @@ adaptor.infer_axioms_and_save(output_path="KGs/Family/inferred_family-benchmark_
                                         "InferredSubClassAxiomGenerator",
                                         "InferredInverseObjectPropertiesAxiomGenerator",
                                         "InferredEquivalentClassAxiomGenerator"])
-adaptor.stopJVM()
+stopJVM()
 ```
 
 </details>
diff --git a/docs/conf.py b/docs/conf.py
index 55a57422..dedc20f6 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -13,7 +13,7 @@
 
 project = 'OWLAPY'
 author = 'Ontolearn Team'
-release = '1.2.0'
+release = '1.3.0'
 
 # -- General configuration ---------------------------------------------------
 # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
diff --git a/docs/usage/main.md b/docs/usage/main.md
index fa94d25d..7692a88f 100644
--- a/docs/usage/main.md
+++ b/docs/usage/main.md
@@ -1,6 +1,6 @@
 # About owlapy
 
-**Version:** owlapy 1.2.0
+**Version:** owlapy 1.3.0
 
 **GitHub repository:** [https://github.com/dice-group/owlapy](https://github.com/dice-group/owlapy)
 
diff --git a/docs/usage/ontologies.md b/docs/usage/ontologies.md
index 098eaa2f..73d2477d 100644
--- a/docs/usage/ontologies.md
+++ b/docs/usage/ontologies.md
@@ -78,7 +78,7 @@ iri = IRI('http://example.com/father#', 'child')
 child_class = OWLClass(iri)
 child_class_declaration_axiom = OWLDeclarationAxiom(child_class)
 
-manager.add_axiom(onto, child_class_declaration_axiom)
+onto.add_axiom(child_class_declaration_axiom)
 ```
 In this example, we added the class 'child' to the _father.owl_ ontology.
 Firstly we create an instance of [OWLClass](owlapy.class_expression.owl_class.OWLClass) to represent the concept 
@@ -86,9 +86,8 @@ of 'child' by using an [IRI](owlapy.iri.IRI).
 On the other side, an instance of `IRI` is created by passing two arguments which are
 the namespace of the ontology and the remainder 'child'. To declare this new class we need
 an axiom of type `OWLDeclarationAxiom`. We simply pass the `child_class` to create an 
-instance of this axiom. The final step is to add this axiom to the ontology using the 
-[OWLOntologyManager](owlapy.owl_ontology_manager.OWLOntologyManager). We use the `add_axiom` method
-of the `manager` to add into the ontology
+instance of this axiom. The final step is to add this axiom to the ontology
+We use the `add_axiom` method to add into the ontology
 `onto` the axiom `child_class_declaration_axiom`.
 
 #### Add a new Object Property / Data Property
@@ -105,12 +104,12 @@ from owlapy.owl_property import OWLObjectProperty, OWLDataProperty
 # adding the object property 'hasParent'
 hasParent_op = OWLObjectProperty(IRI('http://example.com/father#', 'hasParent'))
 hasParent_op_declaration_axiom = OWLDeclarationAxiom(hasParent_op)
-manager.add_axiom(onto, hasParent_op_declaration_axiom)
+onto.add_axiom(hasParent_op_declaration_axiom)
 
 # adding the data property 'hasAge' 
 hasAge_dp = OWLDataProperty(IRI('http://example.com/father#', 'hasAge'))
 hasAge_dp_declaration_axiom = OWLDeclarationAxiom(hasAge_dp)
-manager.add_axiom(onto, hasAge_dp_declaration_axiom)
+onto.add_axiom(hasAge_dp_declaration_axiom)
 ```
 
 See the [owlapy](owlapy) for more OWL entities that you can add as a declaration axiom.
@@ -129,7 +128,7 @@ heinz = individuals[1]  # get the 2nd individual in the list which is 'heinz'
 
 class_assertion_axiom = OWLClassAssertionAxiom(heinz, child_class)
 
-manager.add_axiom(onto, class_assertion_axiom)
+onto.add_axiom(class_assertion_axiom)
 ```
 We have used the previous method `individuals_in_signature()` to get all the individuals 
 and converted them to a list, so we can access them by using indexes. In this example, we
@@ -137,7 +136,7 @@ want to assert a class axiom for the individual `heinz`.
 We have used the class `OWLClassAssertionAxiom`
 where the first argument is the 'individual' `heinz` and the second argument is 
 the 'class_expression'. As the class expression, we used the previously defined class 
-`child_Class`. Finally, add the axiom by using `add_axiom` method of the [OWLOntologyManager](owlapy.owl_ontology_manager.OWLOntologyManager).
+`child_Class`. Finally, add the axiom by using `add_axiom` method of the [OWLOntology](owlapy.owl_ontology.OWLOntology).
 
 Let's show one more example using a `OWLDataPropertyAssertionAxiom` to assign the age of 17 to
 heinz. 
@@ -151,7 +150,7 @@ from owlapy.owl_axiom import OWLDataPropertyAssertionAxiom
 literal_17 = OWLLiteral(17)
 dp_assertion_axiom = OWLDataPropertyAssertionAxiom(heinz, hasAge_dp, literal_17)
 
-manager.add_axiom(onto, dp_assertion_axiom)
+onto.add_axiom(dp_assertion_axiom)
 ```
 
 [OWLLiteral](owlapy.owl_literal.OWLLiteral) is a class that represents the literal values in
@@ -167,26 +166,24 @@ assertion axioms that you can use.
 
 #### Remove an Axiom
 
-To remove an axiom you can use the `remove_axiom` method of the ontology manager as follows:
+To remove an axiom you can use the `remove_axiom` method as follows:
 
 <!--pytest-codeblocks:cont-->
 ```python
-manager.remove_axiom(onto,dp_assertion_axiom)
+onto.remove_axiom(dp_assertion_axiom)
 ```
-The first argument is the ontology you want to remove the axiom from and the second 
-argument is the axiom you want to remove.
+The required argument is the axiom/axioms you want to remove.
 
 
 ## Save an Ontology
 
 If you modified an ontology, you may want to save it as a new file. To do this
-you can use the `save_ontology` method of the [OWLOntologyManager](owlapy.owl_ontology_manager.OWLOntologyManager).
-It requires two arguments, the first is the ontology you want to save and The second
-is the IRI of the new ontology.
+you can use the `save` method of the [OWLOntology](owlapy.owl_ontology.OWLOntology).
+It requires one argument, the IRI of the new ontology.
 
 <!--pytest-codeblocks:cont-->
 ```python
-manager.save_ontology(onto, IRI.create('file:/' + 'test' + '.owl'))
+onto.save(IRI.create('file:/' + 'test' + '.owl'))
 ```
  The above line of code will save the ontology `onto` in the file *test.owl* which will be
 created in the same directory as the file you are running this code.
diff --git a/docs/usage/owlapi_adaptor.md b/docs/usage/owlapi_adaptor.md
index 3cfb288a..ded4b81e 100644
--- a/docs/usage/owlapi_adaptor.md
+++ b/docs/usage/owlapi_adaptor.md
@@ -1,62 +1,101 @@
-# Owlapi Adaptor
+# Owlapi Synchronization
 
-As mentioned earlier, owlapy is loosely based in [owlapi](https://github.com/owlcs/owlapi),
+As mentioned earlier, _owlapy_ is loosely based in [_owlapi_](https://github.com/owlcs/owlapi),
 a library for ontology modification in java.
 
-We have created [OWLAPIAdaptor](owlapy.owlapi_adaptor.OWLAPIAdaptor), 
-an adaptor class that facilitates the conversion of
-owl class expressions from owlapy to owlapi and vice-versa. 
-This adaptor is still considered experimental, and it's in the 
-initial phase of development.
+We have created [OWLAPIMapper](owlapy.owlapi_mapper.OWLAPIMapper), 
+a mapping class that makes possible the conversion of the most
+important classes from _owlapy_ to _owlapi_ and vice-versa. 
+
 
 We are able to use owlapi via [Jpype](https://jpype.readthedocs.io/en/latest/),
-a python module that provides access to Java via python. To start executing 
-Java code via jpype, one needs to start the java virtual machine (JVM).
-This is automatically done when initializing a `OWLAPIAdaptor` object.
+a python module that provides access to Java in python. To start executing 
+Java code via Jpype, one needs to start the java virtual machine (JVM).
+You don't have to worry about it, because if a class is going to use
+`OWLAPIMapper` the JVM will start automatically. However, there is the 
+function `startJVM` of the `static_functions.py` module if you ever need
+to start it manually.
+
+## "Sync" Classes
+
+With the addition of the `OWLAPIMapper`, we introduce three new classes:
+- [SyncOntologyManager](owlapy.owl_ontology_manager.SyncOntologyManager)
+- [SyncOntology](owlapy.owl_ontology.SyncOntology)
+- [SyncReasoner](owlapy.owl_reasoner.SyncReasoner)
+
+All the logic of these three classes is handled by _owlapi_ through the
+mapper. They inherit from abstract classes already present in owlapy 
+(`OWLOntologyManager`, `OWLOntology` and `OWLReasoner` respectively) so
+the usage is the same as other implementors of these abstract classes.
+However, there are also some extra methods, like `infer_axioms` of SyncReasoner
+which infers the missing axioms from the given ontology and returns them as `Iterable[OWLAxiom]`.
+Make sure to check the API docs to see them all.
+
+To make this guide self-contained, we will go through a simple example
+showing how to use this above-mentioned classes:
 
-## Initialization
+```python
+from owlapy.owl_ontology_manager import SyncOntologyManager
+from owlapy.owl_axiom import OWLDeclarationAxiom
+from owlapy.class_expression import OWLClass
+from owlapy.owl_reasoner import SyncReasoner
+from owlapy.static_funcs import stopJVM
 
-To use the adaptor you have to start the JVM via jpype, which is done automatically 
-when you create an _OWLAPIAdaptor_ object. After you are finished you can stop
-the JVM by either using `jpype.shutdownJVM()` or the static method from the 
-adaptor `stopJVM()`. This will free the resources used by JPype and the java 
-packages.
+# (.) Creat a manager and load the 'father' ontology
+manager = SyncOntologyManager()
+ontology = manager.load_ontology("KGs/Family/father.owl")
 
-```python
-from owlapy.owlapi_adaptor import OWLAPIAdaptor
+# (.) Use your ontology as you usually do
+# (..) Add a new class
+ontology.add_axiom(OWLDeclarationAxiom(OWLClass("http://example.com/father#some_new_class")))
+# (..) Print classes in signature
+[print(cls) for cls in ontology.classes_in_signature()]
+
+# (.) Create a reasoner and perform some reasoning 
+reasoner = SyncReasoner(ontology)
+
+# (..) Check ontology consistency
+print(f"Is the ontology consistent? Answer: {reasoner.has_consistent_ontology()}")
+
+# (..) Print all male individuals
+[print(ind) for ind in reasoner.instances(OWLClass("http://example.com/father#male"))]
+
+# (.) Stop the JVM if you no longer intend to use "Sync" classes
+stopJVM()
 
-adaptor = OWLAPIAdaptor("KGs/Family/father.owl")
-#  Use the adaptor
-print(f"Is the ontology consistent? {adaptor.has_consistent_ontology()}")
 
-#  Stop the JVM
-adaptor.stopJVM()
 ```
+This was a simple example using the '_father_' ontology to show
+just a small part of what you can do with "Sync" classes. 
 
-In the above code snipped, we created an adaptor for the father ontology 
-by passing the local path of that ontology. Then we print whether 
-the ontology is consistent or not.
+Notice that after we are done using them we can stop 
+the JVM by either using `jpype.shutdownJVM()` or the static function from the 
+`static_functions.py` module `stopJVM()`. This will free the resources used by JPype and the java 
+packages. Once you stop the JVM it cannot be restarted so make sure you do that
+when you are done with the owlapi related classes. Stopping the JVM is not
+strictly necessary. The resources will be freed once the execution is over, but
+in case your code is somehow longer and the "Sync" classes only make up a part of your execution
+then you can stop the JVM after it not being needed anymore.
 
-## Notes
 
-An important note is that when initialising the adaptor you are basically
-starting a JVM in the background, and therefore you are able to import and 
-use java classes as you would do in python. That means that you can 
-play around with owlapi code in python as long as your JVM is started.
-Isn't that awesome!
+## Notes
 
-`OWLAPIAdaptor` uses HermiT reasoner by default. You can choose between:
-"HermiT", "Pellet", "JFact" and "Openllet".
+An important thing to keep in mind is that when starting the JVM
+you are able to import and use java classes as you would do in python (thanks to Jpype). 
+That means that you can play around with owlapi code in python as long 
+as your JVM is started. Isn't that awesome! 
 
-You can use the reasoning method directly from the adaptor but 
-for classes that require an [OWLReasoner](owlapi.owl_reasoner.OWLReasoner)
-you can use [SyncReasoner](https://dice-group.github.io/owlapy/autoapi/owlapy/owl_reasoner/index.html#owlapy.owl_reasoner.SyncReasoner).
+`SyncReasoner` uses HermiT reasoner by default. You can choose between:
+"HermiT", "Pellet", "JFact" and "Openllet". Although no significant 
+difference is noticed between these reasoners, they surely differentiate 
+in specific scenarios. You can check owlapi [Wiki](https://github.com/owlcs/owlapi/wiki) for more references.
 
 _**owlapi version**: 5.1.9_
 
 ## Examples
 
-You can check a usage example in the [_examples_](https://github.com/dice-group/owlapy/tree/develop/examples) folder.
+You can see usage examples in the [_examples_](https://github.com/dice-group/owlapy/tree/develop/examples) folder.
 
-[Test cases](https://github.com/dice-group/owlapy/tree/develop/tests) for the adaptor can also serve as an example, so you can
-check that out as well.
+[Test cases](https://github.com/dice-group/owlapy/tree/develop/tests) 
+can also serve as an example, so you can
+check them out as well.
diff --git a/examples/comparing_adaptor_reasoners.py b/examples/comparing_adaptor_reasoners.py
index d0c1c50a..25222601 100644
--- a/examples/comparing_adaptor_reasoners.py
+++ b/examples/comparing_adaptor_reasoners.py
@@ -1,8 +1,7 @@
 from owlapy.owl_property import OWLObjectProperty
-from owlapy.owlapi_adaptor import OWLAPIAdaptor
+from owlapy.owl_reasoner import SyncReasoner
 from owlapy.iri import IRI
-from owlapy.class_expression import OWLClass, OWLObjectIntersectionOf, OWLObjectAllValuesFrom, OWLObjectComplementOf
-from owlapy.providers import owl_datatype_min_exclusive_restriction
+from owlapy.class_expression import OWLClass, OWLObjectAllValuesFrom, OWLObjectComplementOf
 import time
 ontology_location = "../KGs/Carcinogenesis/carcinogenesis.owl"
 
@@ -11,21 +10,21 @@
 i3 = set()
 i4 = set()
 
-for reasoner in ["HermiT", "Pellet", "JFact", "Openllet"]:
-    adaptor = OWLAPIAdaptor(ontology_location, reasoner)
-
-    ce = OWLObjectAllValuesFrom(property=OWLObjectProperty(IRI('http://dl-learner.org/carcinogenesis#','hasAtom')),
+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 reasoner == "HermiT":
-        i1 = set(adaptor.instances(ce))
-    elif reasoner == "Pellet":
-        i2 = set(adaptor.instances(ce))
-    elif reasoner == "JFact":
-        i3 = set(adaptor.instances(ce))
-    elif reasoner == "Openllet":
-        i4 = set(adaptor.instances(ce))
+    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]
diff --git a/examples/ontology_modification.py b/examples/ontology_modification.py
index 87d6e1ce..577e2c1d 100644
--- a/examples/ontology_modification.py
+++ b/examples/ontology_modification.py
@@ -1,5 +1,5 @@
 from owlapy.class_expression import OWLClass
-from owlapy.owl_axiom import OWLDeclarationAxiom, OWLClassAxiom, OWLClassAssertionAxiom
+from owlapy.owl_axiom import OWLDeclarationAxiom, OWLClassAssertionAxiom
 from owlapy.owl_individual import OWLNamedIndividual
 from owlapy.owl_ontology_manager import OntologyManager
 from owlapy.iri import IRI
@@ -10,7 +10,7 @@
 
 # Load the 'father' ontology using a new ontology manager.
 manager = OntologyManager()
-onto = manager.load_ontology(IRI.create(f'file://../KGs/Family/father.owl'))
+onto = manager.load_ontology(IRI.create('file://../KGs/Family/father.owl'))
 
 # Let's see what classes does this ontology has
 [print(_) for _ in onto.classes_in_signature()]
@@ -18,8 +18,8 @@
 # Create a new class
 new_class = OWLClass(IRI.create('http://example.com/father#child'))
 
-# Add a declaration axiom for this class using ontology manager
-manager.add_axiom(ontology=onto, axiom=OWLDeclarationAxiom(new_class))
+# Add a declaration axiom for this class
+onto.add_axiom(axiom=OWLDeclarationAxiom(new_class))
 
 # Check whether the new class is added in the signature of the ontology
 print("------------------------")
@@ -27,7 +27,7 @@
 
 # Add an individual of type child in the ontology
 new_ind = OWLNamedIndividual('http://example.com/father#lulu')
-manager.add_axiom(onto, OWLClassAssertionAxiom(new_ind, new_class))
+onto.add_axiom(OWLClassAssertionAxiom(new_ind, new_class))
 
 # Check if Lulu is added
 
@@ -35,7 +35,7 @@
 [print(_) for _ in onto.individuals_in_signature()]
 
 # Save the modified ontology locally (otherwise the changes will be lost)
-manager.save_ontology(ontology=onto, document_iri=IRI.create("file:/../KGs/Family/father_modified.owl"))
+onto.save(document_iri=IRI.create("file:/../KGs/Family/father_modified.owl"))
 # NOTE: using the same name will overwrite the current file with the new one.
 
 
diff --git a/examples/ontology_reasoning.py b/examples/ontology_reasoning.py
index c48f655b..dd12db7f 100644
--- a/examples/ontology_reasoning.py
+++ b/examples/ontology_reasoning.py
@@ -4,7 +4,7 @@
 from owlapy.owl_individual import OWLNamedIndividual
 from owlapy.owl_ontology_manager import OntologyManager
 from owlapy.owl_property import OWLDataProperty, OWLObjectProperty
-from owlapy.owl_reasoner import OntologyReasoner
+from owlapy.owl_reasoner import OntologyReasoner, FastInstanceCheckerReasoner
 
 data_file = '../KGs/Test/test_ontology.owl'
 NS = 'http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#'
@@ -61,7 +61,7 @@
 e = OWLNamedIndividual(IRI(NS, "e"))
 g = OWLNamedIndividual(IRI(NS, "g"))
 m = OWLNamedIndividual(IRI(NS, "m"))
-l = OWLNamedIndividual(IRI(NS, "l"))
+l = OWLNamedIndividual(IRI(NS, "l"))  # noqa: E741
 n = OWLNamedIndividual(IRI(NS, "n"))
 o = OWLNamedIndividual(IRI(NS, "o"))
 p = OWLNamedIndividual(IRI(NS, "p"))
@@ -93,11 +93,11 @@
 J = OWLClass(IRI(NS, 'J'))
 K = OWLClass(IRI(NS, 'K'))
 H = OWLClass(IRI(NS, 'H'))
-I = OWLClass(IRI(NS, 'I'))
+I = OWLClass(IRI(NS, 'I'))  # noqa: E741
 L = OWLClass(IRI(NS, 'L'))
 M = OWLClass(IRI(NS, 'M'))
 N = OWLClass(IRI(NS, 'N'))
-O = OWLClass(IRI(NS, 'O'))
+O = OWLClass(IRI(NS, 'O'))  # noqa: E741
 P = OWLClass(IRI(NS, 'P'))
 Q = OWLClass(IRI(NS, 'Q'))
 R = OWLClass(IRI(NS, 'R'))
@@ -117,20 +117,20 @@
 r1T = OWLObjectSomeValuesFrom(property=r1, filler=OWLClass(IRI('http://www.w3.org/2002/07/owl#', 'Thing')))
 
 manager = OntologyManager()
-onto = manager.load_ontology(IRI.create(f'file://' + data_file))
+onto = manager.load_ontology(IRI.create('file://' + data_file))
 
-manager.add_axiom(onto, OWLEquivalentObjectPropertiesAxiom([r6, r5]))
-manager.add_axiom(onto, OWLEquivalentObjectPropertiesAxiom([r5, r6]))
-manager.add_axiom(onto, OWLObjectPropertyDomainAxiom(r1, ST))
+onto.add_axiom(OWLEquivalentObjectPropertiesAxiom([r6, r5]))
+onto.add_axiom(OWLEquivalentObjectPropertiesAxiom([r5, r6]))
+onto.add_axiom(OWLObjectPropertyDomainAxiom(r1, ST))
 
-manager.add_axiom(onto, OWLSubClassOfAxiom(R, r5Q))
-manager.add_axiom(onto, OWLSubClassOfAxiom(ST, U))
+onto.add_axiom(OWLSubClassOfAxiom(R, r5Q))
+onto.add_axiom(OWLSubClassOfAxiom(ST, U))
 
 base_reasoner = OntologyReasoner(onto)
 
 # ---------------------------------------- Reasoning ----------------------------------------
 
-reasoner = FastInstanceCheckerReasoner(onto)
+reasoner = FastInstanceCheckerReasoner(onto, base_reasoner)
 
 # Instances
 t1 = list(reasoner.instances(N))
diff --git a/examples/owl_reasoners.py b/examples/owl_reasoners.py
new file mode 100644
index 00000000..90584e24
--- /dev/null
+++ b/examples/owl_reasoners.py
@@ -0,0 +1,124 @@
+""" A script to show that OWL Reasoners return the same retrieval results in different runtimes """
+import time
+
+from owlapy.class_expression import OWLClass, OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom
+from owlapy.owl_ontology_manager import OntologyManager
+from owlapy.owl_reasoner import SyncReasoner
+from owlapy.utils import concept_reducer_properties
+
+import matplotlib.pyplot as plt
+import seaborn as sns
+import numpy as np
+
+ontology_path = "../KGs/Family/family-benchmark_rich_background.owl"
+
+owl_reasoners = dict()
+owl_reasoners["HermiT"] = SyncReasoner(ontology=ontology_path, reasoner="HermiT")
+owl_reasoners["Pellet"] = SyncReasoner(ontology=ontology_path, reasoner="Pellet")
+owl_reasoners["JFact"] = SyncReasoner(ontology=ontology_path, reasoner="JFact")
+owl_reasoners["Openllet"] = SyncReasoner(ontology=ontology_path, reasoner="Openllet")
+onto = OntologyManager().load_ontology(ontology_path)
+c: OWLClass
+###################################################################
+# GENERATE ALCQ CONCEPTS TO EVALUATE RETRIEVAL PERFORMANCES
+# (3) R: Extract object properties.
+object_properties = {i for i in onto.object_properties_in_signature()}
+# (4) R⁻: Inverse of object properties.
+object_properties_inverse = {i.get_inverse_property() for i in object_properties}
+# (5) R*: R UNION R⁻.
+object_properties_and_inverse = object_properties.union(object_properties_inverse)
+# (6) NC: Named owl concepts.
+nc = {i for i in onto.classes_in_signature()}
+# (7) NC⁻: Complement of NC.
+nnc = {i.get_object_complement_of() for i in nc}
+# (8) \exist r. C s.t. C \in NC and r \in R* .
+exist_nc = concept_reducer_properties(
+    concepts=nc,
+    properties=object_properties_and_inverse,
+    cls=OWLObjectSomeValuesFrom)
+# (9) \forall r. C s.t. C \in NC and r \in R* .
+forall_nc = concept_reducer_properties(
+    concepts=nc,
+    properties=object_properties_and_inverse,
+    cls=OWLObjectAllValuesFrom,
+)
+
+
+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 name_i, reasoner_i in mapping.items():
+            start_time_i = time.time()
+            result_reasoner_i = {i.str for i in reasoner_i.instances(c)}
+            runtime_results.setdefault(name_i, []).append(time.time() - start_time_i)
+            for name_j, reasoner_j in mapping.items():
+                if name_i == name_j:
+                    continue  # Skip self-comparison
+                start_time_j = time.time()
+                result_reasoner_j = {i.str for i in reasoner_j.instances(c)}
+                runtime_results.setdefault(name_i, []).append(time.time() - start_time_j)
+                # Compute intersection and union
+                size_intersection = len(result_reasoner_i.intersection(result_reasoner_j))
+                size_of_union = len(result_reasoner_i.union(result_reasoner_j))
+
+                # Compute Jaccard similarity
+                sim = 1.0 if size_of_union == 0 else size_intersection / size_of_union
+                results.setdefault(name_i, {}).setdefault(name_j, []).append(sim)
+    # Calculate average runtime for each reasoner
+    average_runtime = {name: sum(times) / len(times) for name, times in runtime_results.items()}
+    return results, average_runtime
+
+
+def plot_runtimes(average_runtime, title='Average Runtime of OWL Reasoners'):
+    # Plotting the bar plot
+    plt.bar(average_runtime.keys(), average_runtime.values(), color='skyblue')
+    plt.title(title)
+    plt.ylabel('Average Runtime (seconds)')
+    plt.xticks(rotation=45)
+    max_rt = max(average_runtime.values())
+    plt.ylim(0, max_rt * 1.1)
+    plt.tight_layout()
+    # Display the plot
+    plt.show()
+
+
+def plot_similarity_btw_reasoners(results):
+    # Compute average Jaccard similarity for each pair of reasoners
+    average_jaccard = {name_i: {name_j: sum(sim_list) / len(sim_list) for name_j, sim_list in comparisons.items()} for
+                       name_i, comparisons in results.items()}
+
+    # Convert the dictionary into a matrix for heatmap plotting
+    reasoners = list(owl_reasoners.keys())
+    matrix = np.zeros((len(reasoners), len(reasoners)))
+
+    for i, name_i in enumerate(reasoners):
+        for j, name_j in enumerate(reasoners):
+            if name_i == name_j:
+                matrix[i][j] = 1.0
+            else:
+                matrix[i][j] = average_jaccard.get(name_i, {}).get(name_j, 0.0)
+
+    # Plotting the heatmap
+    sns.heatmap(matrix, xticklabels=reasoners, yticklabels=reasoners, annot=True, cmap="coolwarm", cbar=True, vmin=0,
+                vmax=1)
+    plt.title('Jaccard Similarity Between OWL Reasoners')
+    plt.xlabel('Reasoner')
+    plt.ylabel('Reasoner')
+    plt.show()
+
+
+# EVAL 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
+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
+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")
diff --git a/examples/using_owlapi_adaptor.py b/examples/using_owlapi_adaptor.py
index 44d82039..88a6b405 100644
--- a/examples/using_owlapi_adaptor.py
+++ b/examples/using_owlapi_adaptor.py
@@ -1,13 +1,14 @@
-from owlapy.owlapi_adaptor import OWLAPIAdaptor
+from owlapy.owl_reasoner import SyncReasoner
 from owlapy.iri import IRI
 from owlapy.class_expression import OWLClass, OWLObjectIntersectionOf
+from owlapy.static_funcs import stopJVM
 
 ontology_location = "../KGs/Family/family-benchmark_rich_background.owl"
 
-# Start an adaptor session and perform your operations.
-adaptor = OWLAPIAdaptor(ontology_location, "HermiT")
+# Create an SyncReasoner
+reasoner = SyncReasoner(ontology_location, "HermiT")
 # Check ontology consistency
-print(f"Is the given ontology consistent? --> {adaptor.has_consistent_ontology()}")
+print(f"Is the given ontology consistent? --> {reasoner.has_consistent_ontology()}")
 
 # Construct an owlapy class expression
 brother = OWLClass(IRI.create("http://www.benchmark.org/family#Brother"))
@@ -15,19 +16,19 @@
 brother_and_father = OWLObjectIntersectionOf([brother, father])
 
 # Find individual belonging to that class expression
-instances = adaptor.instances(brother_and_father)
+instances = reasoner.instances(brother_and_father)
 print("----------------------")
 print("Individuals that are brother and father at the same time:")
 [print(_) for _ in instances]
 
 # Map the class expression from owlapy to owlapi
-py_to_pi = adaptor.mapper.map_(brother_and_father)
+py_to_pi = reasoner.mapper.map_(brother_and_father)
 
 # Map the class expression from owlapi to owlapy
-pi_to_py = adaptor.mapper.map_(py_to_pi)
+pi_to_py = reasoner.mapper.map_(py_to_pi)
 print("----------------------")
 print(f"Owlapy ce: {pi_to_py}")
 
 # Stop the JVM to free the associated resources.
-adaptor.stopJVM()  # or jpype.shutdownJVM()
+stopJVM()  # or jpype.shutdownJVM()
 
diff --git a/owlapy/__init__.py b/owlapy/__init__.py
index f408d9d5..4f6b6692 100644
--- a/owlapy/__init__.py
+++ b/owlapy/__init__.py
@@ -1,4 +1,6 @@
-from .render import owl_expression_to_dl, owl_expression_to_manchester
-from .parser import dl_to_owl_expression, manchester_to_owl_expression
-from .converter import owl_expression_to_sparql
-__version__ = '1.2.1'
+from .render import (owl_expression_to_dl as owl_expression_to_dl,
+                     owl_expression_to_manchester as owl_expression_to_manchester)
+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'
diff --git a/owlapy/abstracts/__init__.py b/owlapy/abstracts/__init__.py
new file mode 100644
index 00000000..473f64d3
--- /dev/null
+++ b/owlapy/abstracts/__init__.py
@@ -0,0 +1,4 @@
+from .abstract_owl_ontology_manager import OWLOntologyManager, OWLOntologyChange, OWLOntology
+from .abstract_owl_reasoner import OWLReasoner, OWLReasonerEx
+
+__all__ = ['OWLOntologyManager', 'OWLOntologyChange', 'OWLOntology', 'OWLReasoner', 'OWLReasonerEx']
diff --git a/owlapy/abstracts/abstract_owl_ontology.py b/owlapy/abstracts/abstract_owl_ontology.py
new file mode 100644
index 00000000..2b8b5172
--- /dev/null
+++ b/owlapy/abstracts/abstract_owl_ontology.py
@@ -0,0 +1,185 @@
+from abc import ABCMeta, abstractmethod
+from typing import Final, Iterable, Union, Optional, TypeVar
+
+from owlapy.class_expression import OWLClass
+from owlapy.iri import IRI
+from owlapy.owl_axiom import OWLEquivalentClassesAxiom, OWLClassAxiom, OWLDataPropertyDomainAxiom, \
+    OWLDataPropertyRangeAxiom, OWLObjectPropertyDomainAxiom, OWLObjectPropertyRangeAxiom, OWLAxiom
+from owlapy.owl_individual import OWLNamedIndividual
+from owlapy.owl_object import OWLObject
+from owlapy.owl_property import OWLDataProperty, OWLObjectProperty
+
+_M = TypeVar('_M', bound='OWLOntologyManager')  # noqa: F821
+_OI = TypeVar('_OI', bound='OWLOntologyID')  # noqa: F821
+
+
+class OWLOntology(OWLObject, metaclass=ABCMeta):
+    """Represents an OWL 2 Ontology  in the OWL 2 specification.
+
+    An OWLOntology consists of a possibly empty set of OWLAxioms and a possibly empty set of OWLAnnotations.
+    An ontology can have an ontology IRI which can be used to identify the ontology. If it has an ontology IRI then
+    it may also have an ontology version IRI. Since OWL 2, an ontology need not have an ontology IRI. (See the OWL 2
+    Structural Specification).
+
+    An ontology cannot be modified directly. Changes must be applied via its OWLOntologyManager.
+    """
+    __slots__ = ()
+    type_index: Final = 1
+
+    @abstractmethod
+    def classes_in_signature(self) -> Iterable[OWLClass]:
+        """Gets the classes in the signature of this object.
+
+        Returns:
+            Classes in the signature of this object.
+        """
+        pass
+
+    @abstractmethod
+    def data_properties_in_signature(self) -> Iterable[OWLDataProperty]:
+        """Get the data properties that are in the signature of this object.
+
+        Returns:
+            Data properties that are in the signature of this object.
+        """
+        pass
+
+    @abstractmethod
+    def object_properties_in_signature(self) -> Iterable[OWLObjectProperty]:
+        """A convenience method that obtains the object properties that are in the signature of this object.
+
+        Returns:
+            Object properties that are in the signature of this object.
+        """
+        pass
+
+    @abstractmethod
+    def individuals_in_signature(self) -> Iterable[OWLNamedIndividual]:
+        """A convenience method that obtains the individuals that are in the signature of this object.
+
+        Returns:
+            Individuals that are in the signature of this object.
+        """
+        pass
+
+    @abstractmethod
+    def equivalent_classes_axioms(self, c: OWLClass) -> Iterable[OWLEquivalentClassesAxiom]:
+        """ Gets all of the equivalent axioms in this ontology that contain the specified class as an operand.
+
+        Args:
+            c: The class for which the EquivalentClasses axioms should be retrieved.
+
+        Returns:
+            EquivalentClasses axioms contained in this ontology.
+        """
+        pass
+
+    @abstractmethod
+    def general_class_axioms(self) -> Iterable[OWLClassAxiom]:
+        """Get the general class axioms of this ontology. This includes SubClass axioms with a complex class expression
+           as the sub class and EquivalentClass axioms and DisjointClass axioms with only complex class expressions.
+
+        Returns:
+            General class axioms contained in this ontology.
+        """
+        pass
+
+    @abstractmethod
+    def data_property_domain_axioms(self, property: OWLDataProperty) -> Iterable[OWLDataPropertyDomainAxiom]:
+        """Gets the OWLDataPropertyDomainAxiom objects where the property is equal to the specified property.
+
+        Args:
+            property: The property which is equal to the property of the retrieved axioms.
+
+        Returns:
+            The axioms matching the search.
+        """
+        pass
+
+    @abstractmethod
+    def data_property_range_axioms(self, property: OWLDataProperty) -> Iterable[OWLDataPropertyRangeAxiom]:
+        """Gets the OWLDataPropertyRangeAxiom objects where the property is equal to the specified property.
+
+        Args:
+            property: The property which is equal to the property of the retrieved axioms.
+
+        Returns:
+            The axioms matching the search.
+        """
+        pass
+
+    @abstractmethod
+    def object_property_domain_axioms(self, property: OWLObjectProperty) -> Iterable[OWLObjectPropertyDomainAxiom]:
+        """Gets the OWLObjectPropertyDomainAxiom objects where the property is equal to the specified property.
+
+        Args:
+            property: The property which is equal to the property of the retrieved axioms.
+
+        Returns:
+            The axioms matching the search.
+        """
+        pass
+
+    @abstractmethod
+    def object_property_range_axioms(self, property: OWLObjectProperty) -> Iterable[OWLObjectPropertyRangeAxiom]:
+        """Gets the OWLObjectPropertyRangeAxiom objects where the property is equal to the specified property.
+
+        Args:
+            property: The property which is equal to the property of the retrieved axioms.
+
+        Returns:
+            The axioms matching the search.
+        """
+        pass
+
+    @abstractmethod
+    def get_owl_ontology_manager(self) -> _M:
+        """Gets the manager that manages this ontology."""
+        pass
+
+    @abstractmethod
+    def get_ontology_id(self) -> _OI:
+        """Gets the OWLOntologyID belonging to this object.
+
+        Returns:
+            The OWLOntologyID.
+        """
+        pass
+
+    def is_anonymous(self) -> bool:
+        """Check whether this ontology does contain an IRI or not."""
+        return self.get_ontology_id().is_anonymous()
+
+    @abstractmethod
+    def add_axiom(self, axiom: Union[OWLAxiom, Iterable[OWLAxiom]]):
+        """Add the specified axiom/axioms to the ontology.
+
+        Args:
+            axiom: Can be a single axiom or a collection of axioms.
+
+        Returns:
+            Nothing.
+        """
+        pass
+
+    @abstractmethod
+    def remove_axiom(self, axiom: Union[OWLAxiom, Iterable[OWLAxiom]]):
+        """Removes the specified axiom/axioms to the ontology.
+
+        Args:
+            axiom: Can be a single axiom or a collection of axioms.
+
+        Returns:
+            Nothing.
+        """
+        pass
+
+    def save(self, document_iri: Optional[IRI] = None):
+        """Saves this ontology, using its IRI to determine where/how the ontology should be
+         saved.
+
+         Args:
+             document_iri: Whether you want to save in a different location.
+
+        """
+        pass
diff --git a/owlapy/abstracts/abstract_owl_ontology_manager.py b/owlapy/abstracts/abstract_owl_ontology_manager.py
new file mode 100644
index 00000000..891b29a8
--- /dev/null
+++ b/owlapy/abstracts/abstract_owl_ontology_manager.py
@@ -0,0 +1,70 @@
+from abc import ABCMeta, abstractmethod
+from typing import Union
+
+from owlapy.abstracts.abstract_owl_ontology import OWLOntology
+from owlapy.iri import IRI
+
+
+class OWLOntologyChange(metaclass=ABCMeta):
+    """Represents an ontology change."""
+    __slots__ = ()
+
+    _ont: OWLOntology
+
+    @abstractmethod
+    def __init__(self, ontology: OWLOntology):
+        self._ont = ontology
+
+    def get_ontology(self) -> OWLOntology:
+        """Gets the ontology that the change is/was applied to.
+
+        Returns:
+            The ontology that the change is applicable to.
+        """
+        return self._ont
+
+
+class OWLOntologyManager(metaclass=ABCMeta):
+    """An OWLOntologyManager manages a set of ontologies. It is the main point for creating, loading and accessing
+    ontologies."""
+
+    @abstractmethod
+    def create_ontology(self, iri: Union[str, IRI]) -> OWLOntology:
+        """Creates a new (empty) ontology that that has the specified ontology IRI (and no version IRI).
+
+        Args:
+            iri: The IRI of the ontology to be created, can also be a string.
+
+        Returns:
+            The newly created ontology.
+        """
+        pass
+
+    @abstractmethod
+    def load_ontology(self, iri: Union[IRI, str]) -> OWLOntology:
+        """Loads an ontology that is assumed to have the specified ontology IRI as its IRI or version IRI. The ontology
+        IRI will be mapped to an ontology document IRI.
+
+        Args:
+            iri: The IRI that identifies the ontology, can also be a string.
+                 It is expected that the ontology will also have this IRI
+                (although the OWL API should tolerate situations where this is not the case).
+
+        Returns:
+            The OWLOntology representation of the ontology that was loaded.
+        """
+        pass
+
+    @abstractmethod
+    def apply_change(self, change: OWLOntologyChange):
+        """A convenience method that applies just one change to an ontology. When this method is used through an
+        OWLOntologyManager implementation, the instance used should be the one that the ontology returns through the
+        get_owl_ontology_manager() call.
+
+        Args:
+            change: The change to be applied.
+
+        Raises:
+            ChangeApplied.UNSUCCESSFULLY: if the change was not applied successfully.
+        """
+        pass
diff --git a/owlapy/abstracts/abstract_owl_reasoner.py b/owlapy/abstracts/abstract_owl_reasoner.py
new file mode 100644
index 00000000..1ed1e01a
--- /dev/null
+++ b/owlapy/abstracts/abstract_owl_reasoner.py
@@ -0,0 +1,471 @@
+"""OWL Reasoner"""
+from abc import ABCMeta, abstractmethod
+from inspect import signature
+from typing import Iterable
+import logging
+
+from owlapy.class_expression import OWLClassExpression
+from owlapy.class_expression import OWLClass
+from owlapy.owl_data_ranges import OWLDataRange
+from owlapy.owl_object import OWLEntity
+from owlapy.abstracts.abstract_owl_ontology import OWLOntology
+from owlapy.owl_property import OWLObjectPropertyExpression, OWLDataProperty, OWLObjectProperty
+from owlapy.owl_individual import OWLNamedIndividual
+from owlapy.owl_literal import OWLLiteral
+
+logger = logging.getLogger(__name__)
+
+
+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."""
+    __slots__ = ()
+
+    @abstractmethod
+    def __init__(self, ontology: OWLOntology):
+        pass
+
+    @abstractmethod
+    def data_property_domains(self, pe: OWLDataProperty, direct: bool = False) -> Iterable[OWLClassExpression]:
+        """Gets the class expressions that are the direct or indirect domains of this property with respect to the
+           imports closure of the root ontology.
+
+        Args:
+            pe: The property expression whose domains are to be retrieved.
+            direct: Specifies if the direct domains should be retrieved (True), or if all domains should be retrieved
+                (False).
+
+        Returns:
+            :Let N = equivalent_classes(DataSomeValuesFrom(pe rdfs:Literal)). If direct is True: then if N is not
+            empty then the return value is N, else the return value is the result of
+            super_classes(DataSomeValuesFrom(pe rdfs:Literal), true). If direct is False: then the result of
+            super_classes(DataSomeValuesFrom(pe rdfs:Literal), false) together with N if N is non-empty.
+            (Note, rdfs:Literal is the top datatype).
+        """
+        pass
+
+    @abstractmethod
+    def object_property_domains(self, pe: OWLObjectProperty, direct: bool = False) -> Iterable[OWLClassExpression]:
+        """Gets the class expressions that are the direct or indirect domains of this property with respect to the
+           imports closure of the root ontology.
+
+        Args:
+            pe: The property expression whose domains are to be retrieved.
+            direct: Specifies if the direct domains should be retrieved (True), or if all domains should be retrieved
+                (False).
+
+        Returns:
+            :Let N = equivalent_classes(ObjectSomeValuesFrom(pe owl:Thing)). If direct is True: then if N is not empty
+            then the return value is N, else the return value is the result of
+            super_classes(ObjectSomeValuesFrom(pe owl:Thing), true). If direct is False: then the result of
+            super_classes(ObjectSomeValuesFrom(pe owl:Thing), false) together with N if N is non-empty.
+        """
+        pass
+
+    @abstractmethod
+    def object_property_ranges(self, pe: OWLObjectProperty, direct: bool = False) -> Iterable[OWLClassExpression]:
+        """Gets the class expressions that are the direct or indirect ranges of this property with respect to the
+           imports closure of the root ontology.
+
+        Args:
+            pe: The property expression whose ranges are to be retrieved.
+            direct: Specifies if the direct ranges should be retrieved (True), or if all ranges should be retrieved
+                (False).
+
+        Returns:
+            :Let N = equivalent_classes(ObjectSomeValuesFrom(ObjectInverseOf(pe) owl:Thing)). If direct is True: then
+            if N is not empty then the return value is N, else the return value is the result of
+            super_classes(ObjectSomeValuesFrom(ObjectInverseOf(pe) owl:Thing), true). If direct is False: then
+            the result of super_classes(ObjectSomeValuesFrom(ObjectInverseOf(pe) owl:Thing), false) together with N
+            if N is non-empty.
+        """
+        pass
+
+    @abstractmethod
+    def equivalent_classes(self, ce: OWLClassExpression) -> Iterable[OWLClassExpression]:
+        """Gets the class expressions that are equivalent to the specified class expression with respect to the set of
+        reasoner axioms.
+
+        Args:
+            ce: The class expression whose equivalent classes are to be retrieved.
+
+        Returns:
+            All class expressions C where the root ontology imports closure entails EquivalentClasses(ce C). If ce is
+            not a class name (i.e. it is an anonymous class expression) and there are no such classes C then there will
+            be no result. If ce is unsatisfiable with respect to the set of reasoner axioms then  owl:Nothing, i.e. the
+            bottom node, will be returned.
+        """
+        pass
+
+    @abstractmethod
+    def disjoint_classes(self, ce: OWLClassExpression) -> Iterable[OWLClassExpression]:
+        """Gets the class expressions that are disjoint with specified class expression with respect to the set of
+        reasoner axioms.
+
+        Args:
+            ce: The class expression whose disjoint classes are to be retrieved.
+
+        Returns:
+            All class expressions D where the set of reasoner axioms entails EquivalentClasses(D ObjectComplementOf(ce))
+            or StrictSubClassOf(D ObjectComplementOf(ce)).
+        """
+        pass
+
+    @abstractmethod
+    def different_individuals(self, ind: OWLNamedIndividual) -> Iterable[OWLNamedIndividual]:
+        """Gets the individuals that are different from the specified individual with respect to the set of
+        reasoner axioms.
+
+        Args:
+            ind: The individual whose different individuals are to be retrieved.
+
+        Returns:
+            All individuals x where the set of reasoner axioms entails DifferentIndividuals(ind x).
+        """
+        pass
+
+    @abstractmethod
+    def same_individuals(self, ind: OWLNamedIndividual) -> Iterable[OWLNamedIndividual]:
+        """Gets the individuals that are the same as the specified individual with respect to the set of
+        reasoner axioms.
+
+        Args:
+            ind: The individual whose same individuals are to be retrieved.
+
+        Returns:
+            All individuals x where the root ontology imports closure entails SameIndividual(ind x).
+        """
+        pass
+
+    @abstractmethod
+    def equivalent_object_properties(self, op: OWLObjectPropertyExpression) -> Iterable[OWLObjectPropertyExpression]:
+        """Gets the simplified object properties that are equivalent to the specified object property with respect
+        to the set of reasoner axioms.
+
+        Args:
+            op: The object property whose equivalent object properties are to be retrieved.
+
+        Returns:
+            All simplified object properties e where the root ontology imports closure entails
+            EquivalentObjectProperties(op e). If op is unsatisfiable with respect to the set of reasoner axioms
+            then owl:bottomDataProperty will be returned.
+        """
+        pass
+
+    @abstractmethod
+    def equivalent_data_properties(self, dp: OWLDataProperty) -> Iterable[OWLDataProperty]:
+        """Gets the data properties that are equivalent to the specified data property with respect to the set of
+        reasoner axioms.
+
+        Args:
+            dp: The data property whose equivalent data properties are to be retrieved.
+
+        Returns:
+            All data properties e where the root ontology imports closure entails EquivalentDataProperties(dp e).
+            If dp is unsatisfiable with respect to the set of reasoner axioms then owl:bottomDataProperty will
+            be returned.
+        """
+        pass
+
+    @abstractmethod
+    def data_property_values(self, e: OWLEntity, pe: OWLDataProperty) \
+            -> Iterable['OWLLiteral']:
+        """Gets the data property values for the specified entity and data property expression.
+
+        Args:
+            e: The owl entity (usually an individual) that is the subject of the data property values.
+            pe: The data property expression whose values are to be retrieved for the specified entity.
+
+        Note: Can be used to get values, for example, of 'label' property of owl entities such as classes and properties
+        too (not only individuals).
+
+        Returns:
+            A set of OWLLiterals containing literals such that for each literal l in the set, the set of reasoner
+            axioms entails DataPropertyAssertion(pe ind l).
+        """
+        pass
+
+    @abstractmethod
+    def object_property_values(self, ind: OWLNamedIndividual, pe: OWLObjectPropertyExpression) \
+            -> Iterable[OWLNamedIndividual]:
+        """Gets the object property values for the specified individual and object property expression.
+
+        Args:
+            ind: The individual that is the subject of the object property values.
+            pe: The object property expression whose values are to be retrieved for the specified individual.
+
+        Returns:
+            The named individuals such that for each individual j, the set of reasoner axioms entails
+            ObjectPropertyAssertion(pe ind j).
+        """
+        pass
+
+    @abstractmethod
+    def instances(self, ce: OWLClassExpression, direct: bool = False) -> Iterable[OWLNamedIndividual]:
+        """Gets the individuals which are instances of the specified class expression.
+
+        Args:
+            ce: The class expression whose instances are to be retrieved.
+            direct: Specifies if the direct instances should be retrieved (True), or if all instances should be
+                retrieved (False).
+
+        Returns:
+            If direct is True, each named individual j where the set of reasoner axioms entails
+            DirectClassAssertion(ce, j). If direct is False, each named individual j where the set of reasoner axioms
+            entails ClassAssertion(ce, j). If ce is unsatisfiable with respect to the set of reasoner axioms then
+            nothing returned.
+        """
+        pass
+
+    @abstractmethod
+    def sub_classes(self, ce: OWLClassExpression, direct: bool = False) \
+            -> Iterable[OWLClassExpression]:
+        """Gets the set of named classes that are the strict (potentially direct) subclasses of the specified class
+        expression with respect to the reasoner axioms.
+
+        Args:
+            ce: The class expression whose strict (direct) subclasses are to be retrieved.
+            direct: Specifies if the direct subclasses should be retrieved (True) or if the all subclasses
+                (descendant) classes should be retrieved (False).
+
+        Returns:
+            If direct is True, each class C where reasoner axioms entails DirectSubClassOf(C, ce). If direct is False,
+            each class C where reasoner axioms entails StrictSubClassOf(C, ce). If ce is equivalent to owl:Nothing then
+            nothing will be returned.
+        """
+        pass
+
+    @abstractmethod
+    def disjoint_object_properties(self, op: OWLObjectPropertyExpression) -> Iterable[OWLObjectPropertyExpression]:
+        """Gets the simplified object properties that are disjoint with the specified object property with respect
+        to the set of reasoner axioms.
+
+        Args:
+            op: The object property whose disjoint object properties are to be retrieved.
+
+        Returns:
+            All simplified object properties e where the root ontology imports closure entails
+            EquivalentObjectProperties(e ObjectPropertyComplementOf(op)) or
+            StrictSubObjectPropertyOf(e ObjectPropertyComplementOf(op)).
+        """
+        pass
+
+    @abstractmethod
+    def disjoint_data_properties(self, dp: OWLDataProperty) -> Iterable[OWLDataProperty]:
+        """Gets the data properties that are disjoint with the specified data property with respect
+        to the set of reasoner axioms.
+
+        Args:
+            dp: The data property whose disjoint data properties are to be retrieved.
+
+        Returns:
+            All data properties e where the root ontology imports closure entails
+            EquivalentDataProperties(e DataPropertyComplementOf(dp)) or
+            StrictSubDataPropertyOf(e DataPropertyComplementOf(dp)).
+        """
+        pass
+
+    @abstractmethod
+    def sub_data_properties(self, dp: OWLDataProperty, direct: bool = False) -> Iterable[OWLDataProperty]:
+        """Gets the set of named data properties that are the strict (potentially direct) subproperties of the
+        specified data property expression with respect to the imports closure of the root ontology.
+
+        Args:
+            dp: The data property whose strict (direct) subproperties are to be retrieved.
+            direct: Specifies if the direct subproperties should be retrieved (True) or if the all subproperties
+                (descendants) should be retrieved (False).
+
+        Returns:
+            If direct is True, each property P where the set of reasoner axioms entails DirectSubDataPropertyOf(P, pe).
+            If direct is False, each property P where the set of reasoner axioms entails
+            StrictSubDataPropertyOf(P, pe). If pe is equivalent to owl:bottomDataProperty then nothing will be
+            returned.
+        """
+        pass
+
+    @abstractmethod
+    def super_data_properties(self, dp: OWLDataProperty, direct: bool = False) -> Iterable[OWLDataProperty]:
+        """Gets the stream of data properties that are the strict (potentially direct) super properties of the
+         specified data property with respect to the imports closure of the root ontology.
+
+         Args:
+             dp (OWLDataProperty): The data property whose super properties are to be retrieved.
+             direct (bool): Specifies if the direct super properties should be retrieved (True) or if the all
+                            super properties (ancestors) should be retrieved (False).
+
+         Returns:
+             Iterable of super properties.
+         """
+        pass
+
+    @abstractmethod
+    def sub_object_properties(self, op: OWLObjectPropertyExpression, direct: bool = False) \
+            -> Iterable[OWLObjectPropertyExpression]:
+        """Gets the stream of simplified object property expressions that are the strict (potentially direct)
+        subproperties of the specified object property expression with respect to the imports closure of the root
+        ontology.
+
+        Args:
+            op: The object property expression whose strict (direct) subproperties are to be retrieved.
+            direct: Specifies if the direct subproperties should be retrieved (True) or if the all subproperties
+                (descendants) should be retrieved (False).
+
+        Returns:
+            If direct is True, simplified object property expressions, such that for each simplified object property
+            expression, P, the set of reasoner axioms entails DirectSubObjectPropertyOf(P, pe).
+            If direct is False, simplified object property expressions, such that for each simplified object property
+            expression, P, the set of reasoner axioms entails StrictSubObjectPropertyOf(P, pe).
+            If pe is equivalent to owl:bottomObjectProperty then nothing will be returned.
+        """
+        pass
+
+    @abstractmethod
+    def super_object_properties(self, op: OWLObjectPropertyExpression, direct: bool = False) \
+            -> Iterable[OWLObjectPropertyExpression]:
+        """Gets the stream of object properties that are the strict (potentially direct) super properties of the
+         specified object property with respect to the imports closure of the root ontology.
+
+         Args:
+             op (OWLObjectPropertyExpression): The object property expression whose super properties are to be
+                                                retrieved.
+             direct (bool): Specifies if the direct super properties should be retrieved (True) or if the all
+                            super properties (ancestors) should be retrieved (False).
+
+         Returns:
+             Iterable of super properties.
+         """
+        pass
+
+    @abstractmethod
+    def types(self, ind: OWLNamedIndividual, direct: bool = False) -> Iterable[OWLClass]:
+        """Gets the named classes which are (potentially direct) types of the specified named individual.
+
+        Args:
+            ind: 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).
+
+        Returns:
+            If direct is True, each named class C where the set of reasoner axioms entails
+            DirectClassAssertion(C, ind). If direct is False, each named class C where the set of reasoner axioms
+            entails ClassAssertion(C, ind).
+        """
+        pass
+
+    @abstractmethod
+    def get_root_ontology(self) -> OWLOntology:
+        """Gets the "root" ontology that is loaded into this reasoner. The reasoner takes into account the axioms in
+        this ontology and its import's closure."""
+        pass
+
+    @abstractmethod
+    def super_classes(self, ce: OWLClassExpression, direct: bool = False) \
+            -> Iterable[OWLClassExpression]:
+        """Gets the stream of named classes that are the strict (potentially direct) super classes of the specified
+        class expression with respect to the imports closure of the root ontology.
+
+        Args:
+            ce: The class expression whose strict (direct) super classes are to be retrieved.
+            direct: Specifies if the direct super classes should be retrieved (True) or if the all super classes
+                (ancestors) classes should be retrieved (False).
+
+        Returns:
+            If direct is True, each class C where the set of reasoner axioms entails DirectSubClassOf(ce, C).
+            If direct is False, each class C where  set of reasoner axioms entails StrictSubClassOf(ce, C).
+            If ce is equivalent to owl:Thing then nothing will be returned.
+        """
+        pass
+
+
+class OWLReasonerEx(OWLReasoner, metaclass=ABCMeta):
+    """Extra convenience methods for OWL Reasoners"""
+
+    # default
+    def data_property_ranges(self, pe: OWLDataProperty, direct: bool = False) -> Iterable[OWLDataRange]:
+        """Gets the data ranges that are the direct or indirect ranges of this property with respect to the imports
+        closure of the root ontology.
+
+        Args:
+            pe: The property expression whose ranges are to be retrieved.
+            direct: Specifies if the direct ranges should be retrieved (True), or if all ranges should be retrieved
+                (False).
+
+        Returns:
+        """
+        for ax in self.get_root_ontology().data_property_range_axioms(pe):
+            yield ax.get_range()
+            if not direct:
+                logger.warning("indirect not implemented")
+
+    # default
+    def all_data_property_values(self, pe: OWLDataProperty, direct: bool = True) -> Iterable[OWLLiteral]:
+        """Gets all values for the given data property expression that appear in the knowledge base.
+
+        Args:
+            pe: The data property expression whose values are to be retrieved
+            direct: Specifies if only the direct values of the data property pe should be retrieved (True), or if
+                    the values of sub properties of pe should be taken into account (False).
+
+        Returns:
+            A set of OWLLiterals containing literals such that for each literal l in the set, the set of reasoner
+            axioms entails DataPropertyAssertion(pe ind l) for any ind.
+        """
+        onto = self.get_root_ontology()
+        has_direct = "direct" in str(signature(self.data_property_values))
+        for ind in onto.individuals_in_signature():
+            if has_direct:
+                dpv = self.data_property_values(ind, pe, direct)
+            else:
+                dpv = self.data_property_values(ind, pe)
+            for lit in dpv:
+                yield lit
+
+    # default
+    def ind_data_properties(self, ind: OWLNamedIndividual, direct: bool = True) -> Iterable[OWLDataProperty]:
+        """Gets all data properties for the given individual that appear in the knowledge base.
+
+        Args:
+            ind: The named individual whose data properties are to be retrieved
+            direct: Specifies if the direct data properties should be retrieved (True), or if all
+                data properties should be retrieved (False), so that sub properties are taken into account.
+
+        Returns:
+            All data properties pe where the set of reasoner axioms entails DataPropertyAssertion(pe ind l)
+            for atleast one l.
+        """
+        onto = self.get_root_ontology()
+        has_direct = "direct" in str(signature(self.data_property_values))
+        for dp in onto.data_properties_in_signature():
+            try:
+                if has_direct:
+                    next(iter(self.data_property_values(ind, dp, direct)))
+                else:
+                    next(iter(self.data_property_values(ind, dp)))
+                yield dp
+            except StopIteration:
+                pass
+
+    # default
+    def ind_object_properties(self, ind: OWLNamedIndividual, direct: bool = True) -> Iterable[OWLObjectProperty]:
+        """Gets all object properties for the given individual that appear in the knowledge base.
+
+        Args:
+            ind: The named individual whose object properties are to be retrieved
+            direct: Specifies if the direct object properties should be retrieved (True), or if all
+                object properties should be retrieved (False), so that sub properties are taken into account.
+
+        Returns:
+            All data properties pe where the set of reasoner axioms entails ObjectPropertyAssertion(pe ind ind2)
+            for atleast one ind2.
+        """
+        onto = self.get_root_ontology()
+        has_direct = "direct" in str(signature(self.object_property_values))
+        for op in onto.object_properties_in_signature():
+            try:
+                if has_direct:
+                    next(iter(self.object_property_values(ind, op, direct)))
+                else:
+                    next(iter(self.object_property_values(ind, op)))
+                yield op
+            except StopIteration:
+                pass
diff --git a/owlapy/class_expression/__init__.py b/owlapy/class_expression/__init__.py
index f4e8d56c..5ea67ee2 100644
--- a/owlapy/class_expression/__init__.py
+++ b/owlapy/class_expression/__init__.py
@@ -34,8 +34,20 @@
                           OWLDataExactCardinality,
                           OWLObjectOneOf
                           )
+
+__all__ = ['OWLClassExpression', 'OWLAnonymousClassExpression', 'OWLBooleanClassExpression', 'OWLObjectComplementOf',
+           'OWLNaryBooleanClassExpression', 'OWLObjectUnionOf', 'OWLObjectIntersectionOf', 'OWLRestriction',
+           'OWLQuantifiedRestriction', 'OWLObjectCardinalityRestriction', 'OWLObjectHasSelf', 'OWLObjectHasValue',
+           'OWLQuantifiedDataRestriction', 'OWLObjectSomeValuesFrom', 'OWLObjectAllValuesFrom',
+           'OWLDatatypeRestriction', 'OWLFacet', 'OWLQuantifiedObjectRestriction', 'OWLObjectRestriction',
+           'OWLHasValueRestriction', 'OWLDataRestriction', 'OWLCardinalityRestriction', 'OWLFacetRestriction',
+           'OWLObjectMinCardinality', 'OWLObjectMaxCardinality', 'OWLObjectExactCardinality', 'OWLDataSomeValuesFrom',
+           'OWLDataAllValuesFrom', 'OWLDataHasValue', 'OWLClass', 'OWLDataMinCardinality', 'OWLDataMaxCardinality',
+           'OWLDataExactCardinality', 'OWLObjectOneOf', 'OWLDataOneOf', 'OWLDataCardinalityRestriction']
+
 from typing import Final
 from ..vocab import OWLRDFVocabulary
 
 OWLThing: Final = OWLClass(OWLRDFVocabulary.OWL_THING.iri)  #: : :The OWL Class corresponding to owl:Thing
 OWLNothing: Final = OWLClass(OWLRDFVocabulary.OWL_NOTHING.iri)  #: : :The OWL Class corresponding to owl:Nothing
+
diff --git a/owlapy/class_expression/nary_boolean_expression.py b/owlapy/class_expression/nary_boolean_expression.py
index 1a417341..0cd2a683 100644
--- a/owlapy/class_expression/nary_boolean_expression.py
+++ b/owlapy/class_expression/nary_boolean_expression.py
@@ -25,7 +25,7 @@ def __repr__(self):
         return f'{type(self).__name__}({repr(self._operands)})'
 
     def __eq__(self, other):
-        if type(other) == type(self):
+        if type(other) is type(self):
             return self._operands == other._operands
         return NotImplemented
 
diff --git a/owlapy/class_expression/owl_class.py b/owlapy/class_expression/owl_class.py
index c006e481..fd821f45 100644
--- a/owlapy/class_expression/owl_class.py
+++ b/owlapy/class_expression/owl_class.py
@@ -52,6 +52,9 @@ def is_owl_nothing(self) -> bool:
         return self._is_nothing
 
     def get_object_complement_of(self) -> OWLObjectComplementOf:
+        # TODO: CD: get_object_complement_of is not correct term.
+        # TODO: CD : we might want to use get_complement_of instead
+
         # documented in parent
         return OWLObjectComplementOf(self)
 
diff --git a/owlapy/class_expression/restriction.py b/owlapy/class_expression/restriction.py
index 04e7a4bc..2ccc7248 100644
--- a/owlapy/class_expression/restriction.py
+++ b/owlapy/class_expression/restriction.py
@@ -163,7 +163,7 @@ def __repr__(self):
                f"property={repr(self.get_property())},{self.get_cardinality()},filler={repr(self.get_filler())})"
 
     def __eq__(self, other):
-        if type(other) == type(self):
+        if type(other) is type(self):
             return self._property == other._property \
                 and self._cardinality == other._cardinality \
                 and self._filler == other._filler
@@ -335,7 +335,7 @@ def get_property(self) -> OWLObjectPropertyExpression:
         return self._property
 
     def __eq__(self, other):
-        if type(other) == type(self):
+        if type(other) is type(self):
             return self._property == other._property
         return NotImplemented
 
@@ -429,7 +429,7 @@ def __hash__(self):
         return hash(self._values)
 
     def __eq__(self, other):
-        if type(other) == type(self):
+        if type(other) is type(self):
             return self._values == other._values
         return NotImplemented
 
@@ -492,7 +492,7 @@ def __repr__(self):
                f"property={repr(self.get_property())},{self.get_cardinality()},filler={repr(self.get_filler())})"
 
     def __eq__(self, other):
-        if type(other) == type(self):
+        if type(other) is type(self):
             return self._property == other._property \
                 and self._cardinality == other._cardinality \
                 and self._filler == other._filler
@@ -746,7 +746,7 @@ def __hash__(self):
         return hash(self._values)
 
     def __eq__(self, other):
-        if type(other) == type(self):
+        if type(other) is type(self):
             return self._values == other._values
         return NotImplemented
 
diff --git a/owlapy/converter.py b/owlapy/converter.py
index fb7ee3f4..8a8a2f8f 100644
--- a/owlapy/converter.py
+++ b/owlapy/converter.py
@@ -508,7 +508,7 @@ def _(self, ce: OWLObjectOneOf):
                 self.append(",")
             assert isinstance(ind, OWLNamedIndividual)
             self.append(f"<{ind.to_string_id()}>")
-        self.append(f" ) )")
+        self.append(" ) )")
 
     @process.register
     def _(self, ce: OWLDataSomeValuesFrom):
@@ -573,7 +573,7 @@ def _(self, node: OWLDataOneOf):
                 self.append(",")
             if value:
                 self.append(self.render(value))
-        self.append(f" ) ) ")
+        self.append(" ) ) ")
 
     @process.register
     def _(self, node: OWLDatatypeRestriction):
@@ -624,10 +624,10 @@ def as_query(self,
             q = [f"VALUES {root_variable} {{ "]
             for x in values:
                 q.append(f"<{x.to_string_id()}>")
-            q.append(f"}} . ")
+            q.append("} . ")
             qs.extend(q)
         qs.extend(tp)
-        qs.append(f" }}")
+        qs.append(" }")
 
 
         query = "\n".join(qs)
diff --git a/owlapy/jar_dependencies/jgrapht-core-1.2.0.jar b/owlapy/jar_dependencies/jgrapht-core-1.2.0.jar
new file mode 100644
index 00000000..9f943dd1
Binary files /dev/null and b/owlapy/jar_dependencies/jgrapht-core-1.2.0.jar differ
diff --git a/owlapy/meta_classes.py b/owlapy/meta_classes.py
index b4874863..6186a4c8 100644
--- a/owlapy/meta_classes.py
+++ b/owlapy/meta_classes.py
@@ -13,7 +13,7 @@ class HasIRI(metaclass=ABCMeta):
 
     @property
     @abstractmethod
-    def iri(self) -> 'IRI':
+    def iri(self):
         """Gets the IRI of this object.
 
         Returns:
diff --git a/owlapy/owl_annotation.py b/owlapy/owl_annotation.py
index 7c9ea565..9d4a14c9 100644
--- a/owlapy/owl_annotation.py
+++ b/owlapy/owl_annotation.py
@@ -1,7 +1,6 @@
 """OWL Annotations"""
 from abc import ABCMeta
 from .owl_object import OWLObject
-from typing import Optional
 
 
 class OWLAnnotationObject(OWLObject, metaclass=ABCMeta):
@@ -9,10 +8,10 @@ class OWLAnnotationObject(OWLObject, metaclass=ABCMeta):
     __slots__ = ()
 
     # noinspection PyMethodMayBeStatic
-    def as_iri(self) -> Optional['IRI']:
+    def as_iri(self):
         """
         Returns:
-            if the value is an IRI, return it. Return Mone otherwise.
+            if the value is an IRI, return it. Return None otherwise.
         """
         return None
 
@@ -43,7 +42,7 @@ def is_literal(self) -> bool:
         return False
 
     # noinspection PyMethodMayBeStatic
-    def as_literal(self) -> Optional['OWLLiteral']:
+    def as_literal(self):
         """
         Returns:
             if the value is a literal, returns it. Return None otherwise
diff --git a/owlapy/owl_axiom.py b/owlapy/owl_axiom.py
index 2792738c..b1c46c2f 100644
--- a/owlapy/owl_axiom.py
+++ b/owlapy/owl_axiom.py
@@ -2,7 +2,7 @@
 from abc import ABCMeta, abstractmethod
 from itertools import combinations
 
-from typing import TypeVar, List, Optional, Iterable, Generic, Final, Union
+from typing import TypeVar, List, Optional, Iterable, Generic, Union
 from .owl_property import OWLDataPropertyExpression, OWLObjectPropertyExpression
 from .owl_object import OWLObject, OWLEntity
 from .owl_datatype import OWLDatatype, OWLDataRange
@@ -14,9 +14,9 @@
 from owlapy.owl_annotation import OWLAnnotationSubject, OWLAnnotationValue
 from .owl_literal import OWLLiteral
 
-_C = TypeVar('_C', bound='OWLObject')  #:
-_P = TypeVar('_P', bound='OWLPropertyExpression')  #:
-_R = TypeVar('_R', bound='OWLPropertyRange')  #:
+_C = TypeVar('_C', bound='OWLObject')  # noqa: F821
+_P = TypeVar('_P', bound='OWLPropertyExpression')  # noqa: F821
+_R = TypeVar('_R', bound='OWLPropertyRange')  # noqa: F821
 
 
 class OWLAxiom(OWLObject, metaclass=ABCMeta):
diff --git a/owlapy/owl_data_ranges.py b/owlapy/owl_data_ranges.py
index 3ad248f5..bcead840 100644
--- a/owlapy/owl_data_ranges.py
+++ b/owlapy/owl_data_ranges.py
@@ -41,7 +41,7 @@ def __repr__(self):
         return f'{type(self).__name__}({repr(self._operands)})'
 
     def __eq__(self, other):
-        if type(other) == type(self):
+        if type(other) is type(self):
             return self._operands == other._operands
         return NotImplemented
 
diff --git a/owlapy/owl_hierarchy.py b/owlapy/owl_hierarchy.py
index 108e35db..3cc2b8be 100644
--- a/owlapy/owl_hierarchy.py
+++ b/owlapy/owl_hierarchy.py
@@ -9,7 +9,7 @@
 from owlapy.meta_classes import HasIRI
 from owlapy.owl_literal import OWLTopObjectProperty, OWLBottomObjectProperty, OWLTopDataProperty, OWLBottomDataProperty
 from owlapy.owl_property import OWLObjectProperty, OWLDataProperty
-from owlapy.owl_reasoner import OWLReasoner
+from owlapy.abstracts.abstract_owl_reasoner import OWLReasoner
 
 _S = TypeVar('_S', bound=HasIRI)  #:
 _U = TypeVar('_U', bound='AbstractHierarchy')  #:
diff --git a/owlapy/owl_object.py b/owlapy/owl_object.py
index c2ccbc80..b90e9888 100644
--- a/owlapy/owl_object.py
+++ b/owlapy/owl_object.py
@@ -1,7 +1,9 @@
 """OWL Base classes"""
 from abc import abstractmethod, ABCMeta
 from .meta_classes import HasIRI
+from typing import TypeVar
 
+_I = TypeVar('_I', bound='IRI')  # noqa: F821
 
 class OWLObject(metaclass=ABCMeta):
     """Base interface for OWL objects"""
@@ -68,7 +70,7 @@ class OWLNamedObject(OWLObject, HasIRI, metaclass=ABCMeta):
      IRI as its name."""
     __slots__ = ()
 
-    _iri: 'IRI'
+    _iri: _I
 
     def __eq__(self, other):
         if type(other) is type(self):
diff --git a/owlapy/owl_ontology.py b/owlapy/owl_ontology.py
index 9e9d2f6f..fdf7acbf 100644
--- a/owlapy/owl_ontology.py
+++ b/owlapy/owl_ontology.py
@@ -1,16 +1,14 @@
 """OWL Ontology"""
-from abc import ABCMeta, abstractmethod
-from functools import singledispatchmethod
-from itertools import chain
+from functools import singledispatchmethod, singledispatch
+from itertools import chain, islice, combinations
+import types
 from types import MappingProxyType
-from typing import Iterable, TypeVar, Final, Optional, Union
+from typing import Iterable, TypeVar, Final, Optional, Union, cast
 import logging
 import owlready2
 from pandas import Timedelta
 from owlapy import namespaces
-from owlapy.owl_axiom import OWLEquivalentClassesAxiom, OWLClassAxiom, OWLDataPropertyDomainAxiom, \
-    OWLDataPropertyRangeAxiom, OWLObjectPropertyDomainAxiom, OWLObjectPropertyRangeAxiom, OWLSubClassOfAxiom, \
-    OWLAnnotationProperty
+from owlapy.abstracts.abstract_owl_ontology import OWLOntology
 from owlapy.owl_data_ranges import OWLDataRange, OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf
 from owlapy.owl_datatype import OWLDatatype
 from owlapy.owl_individual import OWLNamedIndividual, OWLIndividual
@@ -22,11 +20,23 @@
     OWLObjectIntersectionOf, OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom, OWLObjectOneOf, OWLObjectExactCardinality, \
     OWLObjectMaxCardinality, OWLObjectMinCardinality, OWLObjectHasValue, OWLDataSomeValuesFrom, OWLDataAllValuesFrom, \
     OWLDataExactCardinality, OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataHasValue, OWLDataOneOf, \
-    OWLDatatypeRestriction, OWLRestriction, OWLObjectRestriction, OWLDataRestriction, OWLFacetRestriction
+    OWLDatatypeRestriction, OWLRestriction, OWLObjectRestriction, OWLDataRestriction, OWLFacetRestriction, \
+    OWLNaryBooleanClassExpression, OWLQuantifiedObjectRestriction, OWLQuantifiedDataRestriction
 from owlapy.owl_property import OWLDataProperty, OWLObjectProperty, OWLPropertyExpression, OWLObjectInverseOf, \
-    OWLObjectPropertyExpression, OWLDataPropertyExpression
+    OWLObjectPropertyExpression, OWLDataPropertyExpression, OWLProperty
 from datetime import date, datetime
-
+from owlready2 import destroy_entity, AllDisjoint, AllDifferent, GeneralClassAxiom
+from owlapy.owl_axiom import (OWLObjectPropertyRangeAxiom, OWLAxiom, OWLSubClassOfAxiom, OWLEquivalentClassesAxiom, \
+    OWLDisjointUnionAxiom, OWLAnnotationAssertionAxiom, OWLAnnotationProperty, OWLSubPropertyAxiom, \
+    OWLPropertyRangeAxiom, OWLClassAssertionAxiom, OWLDeclarationAxiom, OWLObjectPropertyAssertionAxiom, \
+    OWLSymmetricObjectPropertyAxiom, OWLTransitiveObjectPropertyAxiom, OWLPropertyDomainAxiom, \
+    OWLAsymmetricObjectPropertyAxiom, OWLDataPropertyCharacteristicAxiom, OWLFunctionalDataPropertyAxiom, \
+    OWLReflexiveObjectPropertyAxiom, OWLDataPropertyAssertionAxiom, OWLFunctionalObjectPropertyAxiom, \
+    OWLObjectPropertyCharacteristicAxiom, OWLIrreflexiveObjectPropertyAxiom, OWLInverseFunctionalObjectPropertyAxiom, \
+    OWLDisjointDataPropertiesAxiom, OWLDisjointObjectPropertiesAxiom, OWLEquivalentDataPropertiesAxiom, \
+    OWLEquivalentObjectPropertiesAxiom, OWLInverseObjectPropertiesAxiom, OWLNaryPropertyAxiom, OWLNaryIndividualAxiom, \
+    OWLDifferentIndividualsAxiom, OWLDisjointClassesAxiom, OWLSameIndividualAxiom, OWLClassAxiom,
+                              OWLDataPropertyDomainAxiom, OWLDataPropertyRangeAxiom, OWLObjectPropertyDomainAxiom)
 from owlapy.vocab import OWLFacet
 
 logger = logging.getLogger(__name__)
@@ -45,7 +55,9 @@
 
 _VERSION_IRI: Final = IRI.create(namespaces.OWL, "versionIRI")
 
-_M = TypeVar('_M', bound='OWLOntologyManager')
+_M = TypeVar('_M', bound='OWLOntologyManager')  # noqa: F821
+_OM = TypeVar('_OM', bound='OntologyManager')  # noqa: F821
+_SM = TypeVar('_SM', bound='SyncOntologyManager')  # noqa: F821
 
 
 class OWLOntologyID:
@@ -111,152 +123,668 @@ def __eq__(self, other):
         return NotImplemented
 
 
-class OWLOntology(OWLObject, metaclass=ABCMeta):
-    """Represents an OWL 2 Ontology  in the OWL 2 specification.
-
-    An OWLOntology consists of a possibly empty set of OWLAxioms and a possibly empty set of OWLAnnotations.
-    An ontology can have an ontology IRI which can be used to identify the ontology. If it has an ontology IRI then
-    it may also have an ontology version IRI. Since OWL 2, an ontology need not have an ontology IRI. (See the OWL 2
-    Structural Specification).
-
-    An ontology cannot be modified directly. Changes must be applied via its OWLOntologyManager.
+def _check_expression(expr: OWLObject, ontology: OWLOntology, world: owlready2.namespace.World):
     """
-    __slots__ = ()
-    type_index: Final = 1
-
-    @abstractmethod
-    def classes_in_signature(self) -> Iterable[OWLClass]:
-        """Gets the classes in the signature of this object.
-
-        Returns:
-            Classes in the signature of this object.
-        """
-        pass
-
-    @abstractmethod
-    def data_properties_in_signature(self) -> Iterable[OWLDataProperty]:
-        """Get the data properties that are in the signature of this object.
-
-        Returns:
-            Data properties that are in the signature of this object.
-        """
-        pass
-
-    @abstractmethod
-    def object_properties_in_signature(self) -> Iterable[OWLObjectProperty]:
-        """A convenience method that obtains the object properties that are in the signature of this object.
+    @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
 
-        Returns:
-            Object properties that are in the signature of this object.
-        """
-        pass
-
-    @abstractmethod
-    def individuals_in_signature(self) -> Iterable[OWLNamedIndividual]:
-        """A convenience method that obtains the individuals that are in the signature of this object.
-
-        Returns:
-            Individuals that are in the signature of this object.
-        """
-        pass
-
-    @abstractmethod
-    def equivalent_classes_axioms(self, c: OWLClass) -> Iterable[OWLEquivalentClassesAxiom]:
-        """ Gets all of the equivalent axioms in this ontology that contain the specified class as an operand.
-
-        Args:
-            c: The class for which the EquivalentClasses axioms should be retrieved.
-
-        Returns:
-            EquivalentClasses axioms contained in this ontology.
-        """
-        pass
-
-    @abstractmethod
-    def general_class_axioms(self) -> Iterable[OWLClassAxiom]:
-        """Get the general class axioms of this ontology. This includes SubClass axioms with a complex class expression
-           as the sub class and EquivalentClass axioms and DisjointClass axioms with only complex class expressions.
-
-        Returns:
-            General class axioms contained in this ontology.
-        """
-        pass
-
-    @abstractmethod
-    def data_property_domain_axioms(self, property: OWLDataProperty) -> Iterable[OWLDataPropertyDomainAxiom]:
-        """Gets the OWLDataPropertyDomainAxiom objects where the property is equal to the specified property.
-
-        Args:
-            property: The property which is equal to the property of the retrieved axioms.
-
-        Returns:
-            The axioms matching the search.
-        """
-        pass
-
-    @abstractmethod
-    def data_property_range_axioms(self, property: OWLDataProperty) -> Iterable[OWLDataPropertyRangeAxiom]:
-        """Gets the OWLDataPropertyRangeAxiom objects where the property is equal to the specified property.
-
-        Args:
-            property: The property which is equal to the property of the retrieved axioms.
-
-        Returns:
-            The axioms matching the search.
-        """
-        pass
-
-    @abstractmethod
-    def object_property_domain_axioms(self, property: OWLObjectProperty) -> Iterable[OWLObjectPropertyDomainAxiom]:
-        """Gets the OWLObjectPropertyDomainAxiom objects where the property is equal to the specified property.
+    """
+    if isinstance(expr, (OWLClass, OWLProperty, OWLNamedIndividual,)):
+        _add_axiom(OWLDeclarationAxiom(expr), ontology, world)
+    elif isinstance(expr, (OWLNaryBooleanClassExpression, OWLObjectComplementOf, OWLObjectOneOf,)):
+        for op in expr.operands():
+            _check_expression(op, ontology, world)
+    elif isinstance(expr, (OWLQuantifiedObjectRestriction, OWLObjectHasValue,)):
+        _check_expression(expr.get_property(), ontology, world)
+        _check_expression(expr.get_filler(), ontology, world)
+    elif isinstance(expr, OWLObjectInverseOf):
+        _check_expression(expr.get_named_property(), ontology, world)
+        _check_expression(expr.get_inverse_property(), ontology, world)
+    elif isinstance(expr, (OWLQuantifiedDataRestriction, OWLDataHasValue,)):
+        _check_expression(expr.get_property(), ontology, world)
+    elif not isinstance(expr, OWLObject):
+        raise ValueError(f'({expr}) is not an OWLObject.')
+
+
+@singledispatch
+def _add_axiom(axiom: OWLAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    raise NotImplementedError(f'Axiom type {axiom} is not implemented yet.')
+
+
+@_add_axiom.register
+def _(axiom: OWLDeclarationAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
+
+    entity = axiom.get_entity()
+    with ont_x:
+        entity_x = world[entity.to_string_id()]
+        # Entity already exists
+        if entity_x is not None:
+            return
+
+        thing_x: owlready2.entity.ThingClass = conv.map_concept(OWLThing)
+        if isinstance(entity, OWLClass):
+            if entity.is_owl_thing() or entity.is_owl_nothing():
+                return
+            entity_x = types.new_class(name=entity.iri.get_remainder(), bases=(thing_x,))
+        elif isinstance(entity, OWLIndividual):
+            entity_x = thing_x(entity.iri.get_remainder())
+        elif isinstance(entity, OWLObjectProperty):
+            entity_x = types.new_class(name=entity.iri.get_remainder(), bases=(owlready2.ObjectProperty,))
+        elif isinstance(entity, OWLDataProperty):
+            entity_x = types.new_class(name=entity.iri.get_remainder(), bases=(owlready2.DatatypeProperty,))
+        elif isinstance(entity, OWLAnnotationProperty):
+            entity_x = types.new_class(name=entity.iri.get_remainder(), bases=(owlready2.AnnotationProperty,))
+        else:
+            raise ValueError(f'Cannot add ({entity}). Not an atomic class, property, or individual.')
+        entity_x.namespace = ont_x.get_namespace(entity.iri.get_namespace())
+        entity_x.namespace.world._refactor(entity_x.storid, entity_x.iri)
+
+
+@_add_axiom.register
+def _(axiom: OWLClassAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
+
+    individual = axiom.get_individual()
+    cls_ = axiom.get_class_expression()
+    _check_expression(cls_, ontology, world)
+    _add_axiom(OWLDeclarationAxiom(individual), ontology, world)
+    with ont_x:
+        cls_x = conv.map_concept(cls_)
+        ind_x = conv._to_owlready2_individual(individual)
+        thing_x = conv.map_concept(OWLThing)
+        if thing_x in ind_x.is_a:
+            ind_x.is_a.remove(thing_x)
+        ind_x.is_a.append(cls_x)
+
+
+@_add_axiom.register
+def _(axiom: OWLObjectPropertyAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
+
+    subject = axiom.get_subject()
+    property_ = axiom.get_property()
+    object_ = axiom.get_object()
+    _add_axiom(OWLDeclarationAxiom(subject), ontology, world)
+    _add_axiom(OWLDeclarationAxiom(property_), ontology, world)
+    _add_axiom(OWLDeclarationAxiom(object_), ontology, world)
+    with ont_x:
+        subject_x = conv._to_owlready2_individual(subject)
+        property_x = conv._to_owlready2_property(property_)
+        object_x = conv._to_owlready2_individual(object_)
+        property_x[subject_x].append(object_x)
+
+
+@_add_axiom.register
+def _(axiom: OWLDataPropertyAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
+
+    subject = axiom.get_subject()
+    property_ = axiom.get_property()
+    _add_axiom(OWLDeclarationAxiom(subject), ontology, world)
+    _add_axiom(OWLDeclarationAxiom(property_), ontology, world)
+    with ont_x:
+        subject_x = conv._to_owlready2_individual(subject)
+        property_x = conv._to_owlready2_property(property_)
+        property_x[subject_x].append(axiom.get_object().to_python())
+
+
+@_add_axiom.register
+def _(axiom: OWLSubClassOfAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
+
+    sub_class = axiom.get_sub_class()
+    super_class = axiom.get_super_class()
+
+    _check_expression(sub_class, ontology, world)
+    _check_expression(super_class, ontology, world)
+    with ont_x:
+        thing_x = conv.map_concept(OWLThing)
+        sub_class_x = conv.map_concept(sub_class)
+        super_class_x = conv.map_concept(super_class)
+        if isinstance(sub_class, OWLClass):
+            if thing_x in sub_class_x.is_a:
+                sub_class_x.is_a.remove(thing_x)
+        else:
+            # Currently owlready2 seems to expect that we make a new GeneralClassAxiom object each time.
+            # Another option would be to check whether a GeneralClassAxiom with the sub_class_x already exists and just
+            # add the super_class_x to its is_a attribute
+            sub_class_x = GeneralClassAxiom(sub_class_x)
+        sub_class_x.is_a.append(super_class_x)
+
+
+# TODO: Update as soon as owlready2 adds support for EquivalentClasses general class axioms
+@_add_axiom.register
+def _(axiom: OWLEquivalentClassesAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x = conv.map_object(ontology)
+
+    assert axiom.contains_named_equivalent_class(), 'Owlready2 does not support general' \
+                                                    'class axioms for equivalent classes.'
+    for ce in axiom.class_expressions():
+        _check_expression(ce, ontology, world)
+    with ont_x:
+        for ce_1, ce_2 in combinations(axiom.class_expressions(), 2):
+            assert ce_1 is not None, f"ce_1 cannot be None: {ce_1}, {type(ce_1)}"
+            assert ce_2 is not None, f"ce_2_x cannot be None: {ce_2}, {type(ce_2)}"
+
+            ce_1_x = conv.map_concept(ce_1)
+            ce_2_x = conv.map_concept(ce_2)
+            try:
+                assert ce_1_x is not None, f"ce_1_x cannot be None: {ce_1_x}, {type(ce_1_x)}"
+                assert ce_2_x is not None, f"ce_2_x cannot be None: {ce_2_x}, {type(ce_2_x)}"
+            except AssertionError:
+                print("function of ToOwlready2.map_concept() returns None")
+                print(ce_1, ce_1_x)
+                print(ce_2, ce_2_x)
+                print("Axiom:", axiom)
+                print("Temporary solution is reinitializing ce_1_x=ce_2_x\n\n")
+                ce_1_x=ce_2_x
+
+            if isinstance(ce_1_x, owlready2.ThingClass):
+                ce_1_x.equivalent_to.append(ce_2_x)
+            if isinstance(ce_2_x, owlready2.ThingClass):
+                ce_2_x.equivalent_to.append(ce_1_x)
+
+
+@_add_axiom.register
+def _(axiom: OWLDisjointClassesAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    for cls_ in axiom.class_expressions():
+        _check_expression(cls_, ontology, world)
+    with ont_x:
+        # TODO: If the first element in the list is a complex class expression owlready2 is bugged
+        # and creates an AllDifferent axiom
+        AllDisjoint(list(map(conv.map_concept, axiom.class_expressions())))
+
+
+@_add_axiom.register
+def _(axiom: OWLDisjointUnionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    assert isinstance(axiom.get_owl_class(), OWLClass), f'({axiom.get_owl_class()}) is not a named class.'
+    _add_axiom(OWLDeclarationAxiom(axiom.get_owl_class()), ontology, world)
+    for cls_ in axiom.get_class_expressions():
+        _check_expression(cls_, ontology, world)
+    with ont_x:
+        cls_x = conv.map_concept(axiom.get_owl_class())
+        cls_x.disjoint_unions.append(list(map(conv.map_concept, axiom.get_class_expressions())))
+
+
+@_add_axiom.register
+def _(axiom: OWLAnnotationAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    prop_x = conv.map_object(axiom.get_property())
+    if prop_x is None:
+        with ont_x:
+            prop_x: owlready2.annotation.AnnotationPropertyClass = cast(
+                owlready2.AnnotationProperty,
+                types.new_class(
+                    name=axiom.get_property().iri.get_remainder(),
+                    bases=(owlready2.AnnotationProperty,)))
+            prop_x.namespace = ont_x.get_namespace(axiom.get_property().iri.get_namespace())
+    sub_x = world[axiom.get_subject().as_iri().as_str()]
+    assert sub_x is not None, f'{axiom.get_subject} not found in {ontology}'
+    with ont_x:
+        if axiom.get_value().is_literal():
+            literal = axiom.get_value().as_literal()
+            setattr(sub_x, prop_x.python_name, literal.to_python())
+        else:
+            o_x = world[axiom.get_value().as_iri().as_str()]
+            assert o_x is not None, f'{axiom.get_value()} not found in {ontology}'
+            setattr(sub_x, prop_x.python_name, o_x)
+
+
+@_add_axiom.register
+def _(axiom: OWLNaryIndividualAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    for ind in axiom.individuals():
+        _add_axiom(OWLDeclarationAxiom(ind), ontology, world)
+    with ont_x:
+        if isinstance(axiom, OWLSameIndividualAxiom):
+            for idx, ind in enumerate(axiom.individuals()):
+                ind_x = conv._to_owlready2_individual(ind)
+                for ind_2 in islice(axiom.individuals(), idx + 1, None):
+                    ind_2_x = conv._to_owlready2_individual(ind_2)
+                    ind_x.equivalent_to.append(ind_2_x)
+        elif isinstance(axiom, OWLDifferentIndividualsAxiom):
+            AllDifferent(list(map(conv._to_owlready2_individual, axiom.individuals())))
+        else:
+            raise ValueError(f'OWLNaryIndividualAxiom ({axiom}) is not defined.')
+
+
+@_add_axiom.register
+def _(axiom: OWLSubPropertyAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    sub_property = axiom.get_sub_property()
+    super_property = axiom.get_super_property()
+    _add_axiom(OWLDeclarationAxiom(sub_property), ontology, world)
+    _add_axiom(OWLDeclarationAxiom(super_property), ontology, world)
+    with ont_x:
+        sub_property_x = conv._to_owlready2_property(sub_property)
+        super_property_x = conv._to_owlready2_property(super_property)
+        sub_property_x.is_a.append(super_property_x)
+
+
+@_add_axiom.register
+def _(axiom: OWLPropertyDomainAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    property_ = axiom.get_property()
+    domain = axiom.get_domain()
+    _add_axiom(OWLDeclarationAxiom(property_), ontology, world)
+    _check_expression(domain, ontology, world)
+    with ont_x:
+        property_x = conv._to_owlready2_property(property_)
+        domain_x = conv.map_concept(domain)
+        property_x.domain.append(domain_x)
+
+
+@_add_axiom.register
+def _(axiom: OWLPropertyRangeAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    property_ = axiom.get_property()
+    range_ = axiom.get_range()
+    _add_axiom(OWLDeclarationAxiom(property_), ontology, world)
+    if isinstance(axiom, OWLObjectPropertyRangeAxiom):
+        _check_expression(range_, ontology, world)
+    with ont_x:
+        property_x = conv._to_owlready2_property(property_)
+        range_x = conv.map_concept(range_) if isinstance(axiom, OWLObjectPropertyRangeAxiom) \
+            else conv.map_datarange(range_)
+        property_x.range.append(range_x)
+
+
+@_add_axiom.register
+def _(axiom: OWLNaryPropertyAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    for property_ in axiom.properties():
+        _add_axiom(OWLDeclarationAxiom(property_), ontology, world)
+    with ont_x:
+        if isinstance(axiom, (OWLEquivalentObjectPropertiesAxiom, OWLEquivalentDataPropertiesAxiom,)):
+            for idx, property_ in enumerate(axiom.properties()):
+                property_x = conv._to_owlready2_property(property_)
+                for property_2 in islice(axiom.properties(), idx + 1, None):
+                    property_2_x = conv._to_owlready2_property(property_2)
+                    property_x.equivalent_to.append(property_2_x)
+        elif isinstance(axiom, (OWLDisjointObjectPropertiesAxiom, OWLDisjointDataPropertiesAxiom,)):
+            AllDisjoint(list(map(conv._to_owlready2_property, axiom.properties())))
+        elif isinstance(axiom, OWLInverseObjectPropertiesAxiom):
+            property_first_x = conv._to_owlready2_property(axiom.get_first_property())
+            property_second_x = conv._to_owlready2_property(axiom.get_second_property())
+            if property_second_x.inverse_property is not None:
+                property_second_x.inverse_property = None
+            property_first_x.inverse_property = property_second_x
+        else:
+            raise ValueError(f'OWLNaryPropertyAxiom ({axiom}) is not defined.')
+
+
+@_add_axiom.register
+def _(axiom: OWLObjectPropertyCharacteristicAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    property_ = axiom.get_property()
+    _add_axiom(OWLDeclarationAxiom(property_), ontology, world)
+    with ont_x:
+        property_x = conv._to_owlready2_property(property_)
+        if isinstance(axiom, OWLFunctionalObjectPropertyAxiom):
+            property_x.is_a.append(owlready2.FunctionalProperty)
+        elif isinstance(axiom, OWLAsymmetricObjectPropertyAxiom):
+            property_x.is_a.append(owlready2.AsymmetricProperty)
+        elif isinstance(axiom, OWLInverseFunctionalObjectPropertyAxiom):
+            property_x.is_a.append(owlready2.InverseFunctionalProperty)
+        elif isinstance(axiom, OWLIrreflexiveObjectPropertyAxiom):
+            property_x.is_a.append(owlready2.IrreflexiveProperty)
+        elif isinstance(axiom, OWLReflexiveObjectPropertyAxiom):
+            property_x.is_a.append(owlready2.ReflexiveProperty)
+        elif isinstance(axiom, OWLSymmetricObjectPropertyAxiom):
+            property_x.is_a.append(owlready2.SymmetricProperty)
+        elif isinstance(axiom, OWLTransitiveObjectPropertyAxiom):
+            property_x.is_a.append(owlready2.TransitiveProperty)
+        else:
+            raise ValueError(f'ObjectPropertyCharacteristicAxiom ({axiom}) is not defined.')
 
-        Args:
-            property: The property which is equal to the property of the retrieved axioms.
 
-        Returns:
-            The axioms matching the search.
-        """
-        pass
+@_add_axiom.register
+def _(axiom: OWLDataPropertyCharacteristicAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
 
-    @abstractmethod
-    def object_property_range_axioms(self, property: OWLObjectProperty) -> Iterable[OWLObjectPropertyRangeAxiom]:
-        """Gets the OWLObjectPropertyRangeAxiom objects where the property is equal to the specified property.
+    property_ = axiom.get_property()
+    _add_axiom(OWLDeclarationAxiom(property_), ontology, world)
+    with ont_x:
+        property_x = conv._to_owlready2_property(property_)
+        if isinstance(axiom, OWLFunctionalDataPropertyAxiom):
+            property_x.is_a.append(owlready2.FunctionalProperty)
+        else:
+            raise ValueError(f'DataPropertyCharacteristicAxiom ({axiom}) is not defined.')
+
+
+@singledispatch
+def _remove_axiom(axiom: OWLAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    raise NotImplementedError(f'Axiom type {axiom} is not implemented yet.')
+
+
+@_remove_axiom.register
+def _(axiom: OWLDeclarationAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
+    with ont_x:
+        entity_x = world[axiom.get_entity().to_string_id()]
+        if entity_x is not None:
+            # TODO: owlready2 seems to be bugged for properties here
+            destroy_entity(entity_x)
+
+
+@_remove_axiom.register
+def _(axiom: OWLClassAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
+
+    with ont_x:
+        cls_x = conv.map_concept(axiom.get_class_expression())
+        ind_x = conv._to_owlready2_individual(axiom.get_individual())
+        if cls_x is None or ind_x is None:
+            return
+        if cls_x in ind_x.is_a:
+            ind_x.is_a.remove(cls_x)
+        elif isinstance(axiom.get_class_expression(), OWLClass):
+            ont_x._del_obj_triple_spo(ind_x.storid, owlready2.rdf_type, cls_x.storid)
+
+
+@_remove_axiom.register
+def _(axiom: OWLObjectPropertyAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
+
+    with ont_x:
+        subject_x = conv._to_owlready2_individual(axiom.get_subject())
+        property_x = conv._to_owlready2_property(axiom.get_property())
+        object_x = conv._to_owlready2_individual(axiom.get_object())
+        if all([subject_x, property_x, object_x]) and object_x in property_x[subject_x]:
+            property_x[subject_x].remove(object_x)
+
+
+@_remove_axiom.register
+def _(axiom: OWLDataPropertyAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
+
+    with ont_x:
+        subject_x = conv._to_owlready2_individual(axiom.get_subject())
+        property_x = conv._to_owlready2_property(axiom.get_property())
+        object_ = axiom.get_object().to_python()
+        if subject_x is not None and property_x is not None and object_ in property_x[subject_x]:
+            property_x[subject_x].remove(object_)
+
+
+@_remove_axiom.register
+def _(axiom: OWLSubClassOfAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
+    sub_class = axiom.get_sub_class()
+    super_class = axiom.get_super_class()
+
+    with ont_x:
+        sub_class_x = conv.map_concept(sub_class)
+        super_class_x = conv.map_concept(super_class)
+        if sub_class_x is None or super_class_x is None:
+            return
+
+        if isinstance(sub_class, OWLClass):
+            if super_class_x in sub_class_x.is_a:
+                sub_class_x.is_a.remove(super_class_x)
+            elif isinstance(axiom.get_sub_class(), OWLClass) and isinstance(axiom.get_super_class(), OWLClass):
+                ont_x._del_obj_triple_spo(sub_class_x.storid, owlready2.rdfs_subclassof, super_class_x.storid)
+        else:
+            for ca in ont_x.general_class_axioms():
+                if ca.left_side == sub_class_x and super_class_x in ca.is_a:
+                    ca.is_a.remove(super_class_x)
+
+
+# TODO: Update as soons as owlready2 adds support for EquivalentClasses general class axioms
+@_remove_axiom.register
+def _(axiom: OWLEquivalentClassesAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x = conv.map_object(ontology)
+
+    if not axiom.contains_named_equivalent_class():
+        return
+
+    with ont_x:
+        ces_x = list(map(conv.map_concept, axiom.class_expressions()))
+        if len(ces_x) < 2 or not all(ces_x):
+            return
+
+        for ce_1_x, ce_2_x in combinations(ces_x, 2):
+            if isinstance(ce_2_x, owlready2.ThingClass) and ce_1_x in ce_2_x.equivalent_to:
+                ce_2_x.equivalent_to.remove(ce_1_x)
+            if isinstance(ce_1_x, owlready2.ThingClass) and ce_2_x in ce_1_x.equivalent_to:
+                ce_1_x.equivalent_to.remove(ce_2_x)
+
+
+@_remove_axiom.register
+def _(axiom: OWLDisjointClassesAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    with ont_x:
+        class_expressions_x = set(map(conv.map_concept, axiom.class_expressions()))
+        if len(class_expressions_x) < 2 or not all(class_expressions_x):
+            return
+        for disjoints_x in ont_x.disjoint_classes():
+            if set(disjoints_x.entities) == class_expressions_x:
+                del disjoints_x.entities[:-1]
+                break
+
+
+@_remove_axiom.register
+def _(axiom: OWLDisjointUnionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+    assert isinstance(axiom.get_owl_class(), OWLClass), f'({axiom.get_owl_class()}) is not a named class.'
+
+    with ont_x:
+        cls_x = conv.map_concept(axiom.get_owl_class())
+        union_expressions_x = set(map(conv.map_concept, axiom.get_class_expressions()))
+        if cls_x is not None and all(union_expressions_x):
+            for union_x in cls_x.disjoint_unions:
+                if union_expressions_x == set(union_x):
+                    cls_x.disjoint_unions.remove(union_x)
+                    break
+
+
+@_remove_axiom.register
+def _(axiom: OWLAnnotationAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    sub_x = world[axiom.get_subject().as_iri().as_str()]
+    if sub_x is None:
+        return
+    name = axiom.get_property().iri.get_remainder()
+    with ont_x:
+        if axiom.get_value().is_literal():
+            o_x = axiom.get_value().as_literal().to_python()
+        else:
+            o_x = world[axiom.get_value().as_iri().as_str()]
+
+        value = getattr(sub_x, name, None)
+        if value is not None and o_x in value:
+            value.remove(o_x)
+
+
+@_remove_axiom.register
+def _(axiom: OWLNaryIndividualAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    with ont_x:
+        individuals_x = list(map(conv._to_owlready2_individual, axiom.individuals()))
+        if len(individuals_x) < 2 or not all(individuals_x):
+            return
+        if isinstance(axiom, OWLSameIndividualAxiom):
+            if set(individuals_x[1:-1]) <= set(individuals_x[0].INDIRECT_equivalent_to):
+                for individual_1_x, individual_2_x in combinations(individuals_x, 2):
+                    if individual_1_x in individual_2_x.equivalent_to:
+                        individual_2_x.equivalent_to.remove(individual_1_x)
+                    if individual_2_x in individual_1_x.equivalent_to:
+                        individual_1_x.equivalent_to.remove(individual_2_x)
+        elif isinstance(axiom, OWLDifferentIndividualsAxiom):
+            individuals_x = set(individuals_x)
+            for different_x in ont_x.different_individuals():
+                if set(different_x.entities) == individuals_x:
+                    del different_x.entities[:-1]
+                    break
+        else:
+            raise ValueError(f'OWLNaryIndividualAxiom ({axiom}) is not defined.')
 
-        Args:
-            property: The property which is equal to the property of the retrieved axioms.
 
-        Returns:
-            The axioms matching the search.
-        """
-        pass
+@_remove_axiom.register
+def _(axiom: OWLSubPropertyAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
 
-    @abstractmethod
-    def get_owl_ontology_manager(self) -> _M:
-        """Gets the manager that manages this ontology."""
-        pass
+    with ont_x:
+        sub_property_x = conv._to_owlready2_property(axiom.get_sub_property())
+        super_property_x = conv._to_owlready2_property(axiom.get_super_property())
+        if sub_property_x is None or super_property_x is None:
+            return
+        if super_property_x in sub_property_x.is_a:
+            sub_property_x.is_a.remove(super_property_x)
+        else:
+            ont_x._del_obj_triple_spo(sub_property_x.storid, owlready2.rdfs_subpropertyof, super_property_x.storid)
+
+
+@_remove_axiom.register
+def _(axiom: OWLPropertyDomainAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    with ont_x:
+        property_x = conv._to_owlready2_property(axiom.get_property())
+        domain_x = conv.map_concept(axiom.get_domain())
+        if domain_x is not None and property_x is not None and domain_x in property_x.domain:
+            property_x.domain.remove(domain_x)
+
+
+@_remove_axiom.register
+def _(axiom: OWLPropertyRangeAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    with ont_x:
+        property_x = conv._to_owlready2_property(axiom.get_property())
+        range_x = conv.map_concept(axiom.get_range()) \
+            if isinstance(axiom, OWLObjectPropertyRangeAxiom) else conv.map_datarange(axiom.get_range())
+        if range_x is not None and property_x is not None and range_x in property_x.range:
+            property_x.range.remove(range_x)
+
+
+@_remove_axiom.register
+def _(axiom: OWLNaryPropertyAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    with ont_x:
+        properties_x = list(map(conv._to_owlready2_property, axiom.properties()))
+        if len(properties_x) < 2 or not all(properties_x):
+            return
+        if isinstance(axiom, (OWLEquivalentObjectPropertiesAxiom, OWLEquivalentDataPropertiesAxiom,)):
+            # Check if all equivalent properties are defined in the ontology
+            if set(properties_x[1:-1]) <= set(properties_x[0].INDIRECT_equivalent_to):
+                for property_1_x, property_2_x in combinations(properties_x, 2):
+                    if property_1_x in property_2_x.equivalent_to:
+                        property_2_x.equivalent_to.remove(property_1_x)
+                    if property_2_x in property_1_x.equivalent_to:
+                        property_1_x.equivalent_to.remove(property_2_x)
+        elif isinstance(axiom, (OWLDisjointObjectPropertiesAxiom, OWLDisjointDataPropertiesAxiom,)):
+            properties_x = set(properties_x)
+            for disjoints_x in ont_x.disjoint_properties():
+                if set(disjoints_x.entities) == properties_x:
+                    del disjoints_x.entities[:-1]
+                    break
+        elif isinstance(axiom, OWLInverseObjectPropertiesAxiom):
+            if len(properties_x) != 2:
+                return
+            first = properties_x[0]
+            second = properties_x[1]
+            if first.inverse_property == second and second.inverse_property == first:
+                first.inverse_property = None
+        else:
+            raise ValueError(f'OWLNaryPropertyAxiom ({axiom}) is not defined.')
+
+
+@_remove_axiom.register
+def _(axiom: OWLObjectPropertyCharacteristicAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
+
+    with ont_x:
+        property_x = conv._to_owlready2_property(axiom.get_property())
+        if property_x is None:
+            return
+
+        if isinstance(axiom, OWLFunctionalObjectPropertyAxiom) and owlready2.FunctionalProperty in property_x.is_a:
+            property_x.is_a.remove(owlready2.FunctionalProperty)
+        elif isinstance(axiom, OWLAsymmetricObjectPropertyAxiom) and owlready2.AsymmetricProperty in property_x.is_a:
+            property_x.is_a.remove(owlready2.AsymmetricProperty)
+        elif isinstance(axiom, OWLInverseFunctionalObjectPropertyAxiom) \
+                and owlready2.InverseFunctionalProperty in property_x.is_a:
+            property_x.is_a.remove(owlready2.InverseFunctionalProperty)
+        elif isinstance(axiom, OWLIrreflexiveObjectPropertyAxiom) and owlready2.IrreflexiveProperty in property_x.is_a:
+            property_x.is_a.remove(owlready2.IrreflexiveProperty)
+        elif isinstance(axiom, OWLReflexiveObjectPropertyAxiom) and owlready2.ReflexiveProperty in property_x.is_a:
+            property_x.is_a.remove(owlready2.ReflexiveProperty)
+        elif isinstance(axiom, OWLSymmetricObjectPropertyAxiom) and owlready2.SymmetricProperty in property_x.is_a:
+            property_x.is_a.remove(owlready2.SymmetricProperty)
+        elif isinstance(axiom, OWLTransitiveObjectPropertyAxiom) and owlready2.TransitiveProperty in property_x.is_a:
+            property_x.is_a.remove(owlready2.TransitiveProperty)
+        else:
+            raise ValueError(f'OWLObjectPropertyCharacteristicAxiom ({axiom}) is not defined.')
 
-    @abstractmethod
-    def get_ontology_id(self) -> OWLOntologyID:
-        """Gets the OWLOntologyID belonging to this object.
 
-        Returns:
-            The OWLOntologyID.
-        """
-        pass
+@_remove_axiom.register
+def _(axiom: OWLDataPropertyCharacteristicAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
+    conv = ToOwlready2(world)
+    ont_x: owlready2.Ontology = conv.map_object(ontology)
 
-    def is_anonymous(self) -> bool:
-        """Check whether this ontology does contain an IRI or not."""
-        return self.get_ontology_id().is_anonymous()
+    with ont_x:
+        property_x = conv._to_owlready2_property(axiom.get_property())
+        if property_x is not None and isinstance(axiom, OWLFunctionalDataPropertyAxiom) \
+                and owlready2.FunctionalProperty in property_x.is_a:
+            property_x.is_a.remove(owlready2.FunctionalProperty)
 
 
 class Ontology(OWLOntology):
     __slots__ = '_manager', '_iri', '_world', '_onto'
 
-    _manager: 'OntologyManager'
+    _manager: _OM
     _onto: owlready2.Ontology
     _world: owlready2.World
 
-    def __init__(self, manager: 'OntologyManager', ontology_iri: IRI, load: bool):
+    def __init__(self, manager: _OM, ontology_iri: IRI, load: bool):
         """Represents an Ontology in Ontolearn.
 
         Args:
@@ -300,7 +828,7 @@ def general_class_axioms(self) -> Iterable[OWLClassAxiom]:
             yield from (OWLSubClassOfAxiom(_parse_concept_to_owlapy(ca.left_side), _parse_concept_to_owlapy(c))
                         for c in ca.is_a)
 
-    def get_owl_ontology_manager(self) -> 'OntologyManager':
+    def get_owl_ontology_manager(self) -> _OM:
         return self._manager
 
     def get_ontology_id(self) -> OWLOntologyID:
@@ -371,12 +899,38 @@ def object_property_range_axioms(self, pe: OWLObjectProperty) -> Iterable[OWLObj
                     logger.warning("Construct %s not implemented at %s", rng, pe)
                     pass  # XXX TODO
 
+    def add_axiom(self, axiom: Union[OWLAxiom, Iterable[OWLAxiom]]):
+        if isinstance(axiom, OWLAxiom):
+            _add_axiom(axiom, self, self._world)
+        else:
+            for ax in axiom:
+                _add_axiom(ax, self, self._world)
+
+    def remove_axiom(self, axiom: Union[OWLAxiom, Iterable[OWLAxiom]]):
+        if isinstance(axiom, OWLAxiom):
+            _remove_axiom(axiom, self, self._world)
+        else:
+            for ax in axiom:
+                _remove_axiom(ax, self, self._world)
+
+    def save(self, document_iri: Optional[IRI] = None):
+        ont_x: owlready2.namespace.Ontology = self._world.get_ontology(
+            self.get_ontology_id().get_ontology_iri().as_str()
+        )
+        if document_iri is None:
+            document_iri = self._iri
+        if document_iri.get_namespace().startswith('file:/'):
+            filename = document_iri.as_str()[len('file:/'):]
+            ont_x.save(file=filename)
+        else:
+            raise NotImplementedError("Couldn't save because the namespace of current ontology's IRI does not start with **file:/**")
+
     def get_original_iri(self):
         """Get the IRI argument that was used to create this ontology."""
         return self._iri
 
     def __eq__(self, other):
-        if type(other) == type(self):
+        if type(other) is type(self):
             return self._onto.loaded == other._onto.loaded and self._onto.base_iri == other._onto.base_iri
         return NotImplemented
 
@@ -387,6 +941,93 @@ def __repr__(self):
         return f'Ontology({IRI.create(self._onto.base_iri)}, {self._onto.loaded})'
 
 
+class SyncOntology(OWLOntology):
+
+    def __init__(self, manager: _SM, path: Union[IRI, str], new: bool = False):
+        from owlapy.owlapi_mapper import OWLAPIMapper
+        from java.io import File
+        from java.util.stream import Stream
+        from org.semanticweb.owlapi.model import IRI as owlapi_IRI
+        self.manager = manager
+        self.path = path
+        self.new = new
+        if isinstance(path, IRI):
+            file_path = path.str
+        else:
+            file_path = path
+        if new:  # create new ontology
+            if isinstance(path, IRI):
+                self.owlapi_ontology = manager.get_owlapi_manager().createOntology(Stream.empty(),
+                                                                                   owlapi_IRI.create(path.str))
+            else:
+                raise NotImplementedError("Cant initialize a new ontology using path. Use IRI instead")
+        else:  # means we are loading an existing ontology
+            self.owlapi_ontology = manager.get_owlapi_manager().loadOntologyFromOntologyDocument(File(file_path))
+        self.mapper = OWLAPIMapper(self)
+
+    def classes_in_signature(self) -> Iterable[OWLClass]:
+        return self.mapper.map_(self.owlapi_ontology.getClassesInSignature())
+
+    def data_properties_in_signature(self) -> Iterable[OWLDataProperty]:
+        return self.mapper.map_(self.owlapi_ontology.getDataPropertiesInSignature())
+
+    def object_properties_in_signature(self) -> Iterable[OWLObjectProperty]:
+        return self.mapper.map_(self.owlapi_ontology.getObjectPropertiesInSignature())
+
+    def individuals_in_signature(self) -> Iterable[OWLNamedIndividual]:
+        return self.mapper.map_(self.owlapi_ontology.getIndividualsInSignature())
+
+    def equivalent_classes_axioms(self, c: OWLClass) -> Iterable[OWLEquivalentClassesAxiom]:
+        return self.mapper.map_(self.owlapi_ontology.getEquivalentClassesAxioms(self.mapper.map_(c)))
+
+    def general_class_axioms(self) -> Iterable[OWLClassAxiom]:
+        return self.mapper.map_(self.owlapi_ontology.getGeneralClassAxioms())
+
+    def data_property_domain_axioms(self, property: OWLDataProperty) -> Iterable[OWLDataPropertyDomainAxiom]:
+        return self.mapper.map_(self.owlapi_ontology.getDataPropertyDomainAxioms(self.mapper.map_(property)))
+
+    def data_property_range_axioms(self, property: OWLDataProperty) -> Iterable[OWLDataPropertyRangeAxiom]:
+        return self.mapper.map_(self.owlapi_ontology.getDataPropertyRangeAxioms(self.mapper.map_(property)))
+
+    def object_property_domain_axioms(self, property: OWLObjectProperty) -> Iterable[OWLObjectPropertyDomainAxiom]:
+        return self.mapper.map_(self.owlapi_ontology.getObjectPropertyDomainAxioms(self.mapper.map_(property)))
+
+    def object_property_range_axioms(self, property: OWLObjectProperty) -> Iterable[OWLObjectPropertyRangeAxiom]:
+        return self.mapper.map_(self.owlapi_ontology.getObjectPropertyRangeAxioms(self.mapper.map_(property)))
+
+    def get_owl_ontology_manager(self) -> _M:
+        return self.manager
+
+    def get_owlapi_ontology(self):
+        return self.owlapi_ontology
+
+    def get_ontology_id(self) -> OWLOntologyID:
+        return self.mapper.map_(self.owlapi_ontology.getOntologyID())
+
+    def add_axiom(self, axiom: Union[OWLAxiom, Iterable[OWLAxiom]]):
+        if isinstance(axiom, OWLAxiom):
+            self.owlapi_ontology.addAxiom(self.mapper.map_(axiom))
+        else:
+            self.owlapi_ontology.addAxioms(self.mapper.map_(axiom))
+
+    def remove_axiom(self, axiom: Union[OWLAxiom, Iterable[OWLAxiom]]):
+        if isinstance(axiom, OWLAxiom):
+            self.owlapi_ontology.removeAxiom(self.mapper.map_(axiom))
+        else:
+            self.owlapi_ontology.removeAxioms(self.mapper.map_(axiom))
+
+    def __eq__(self, other):
+        if isinstance(other, SyncOntology):
+            return other.owlapi_ontology.getOntologyID().equals(other.owlapi_ontology.getOntologyID())
+        return False
+
+    def __hash__(self):
+        return int(self.owlapi_ontology.getOntologyID().hashCode())
+
+    def __repr__(self):
+        return f'SyncOntology({self.manager}, {self.path}, {self.new})'
+
+
 OWLREADY2_FACET_KEYS = MappingProxyType({
     OWLFacet.MIN_INCLUSIVE: "min_inclusive",
     OWLFacet.MIN_EXCLUSIVE: "min_exclusive",
@@ -400,6 +1041,7 @@ def __repr__(self):
     OWLFacet.FRACTION_DIGITS: "fraction_digits"
 })
 
+
 class ToOwlready2:
     __slots__ = '_world'
 
@@ -732,19 +1374,19 @@ def _(self, p: owlready2.ConstrainedDatatype) -> OWLDatatypeRestriction:
 
     @map_datarange.register
     def _(self, type_: type) -> OWLDatatype:
-        if type_ == bool:
+        if type_ is bool:
             return BooleanOWLDatatype
-        elif type_ == float:
+        elif type_ is float:
             return DoubleOWLDatatype
-        elif type_ == int:
+        elif type_ is int:
             return IntegerOWLDatatype
-        elif type_ == str:
+        elif type_ is str:
             return StringOWLDatatype
-        elif type_ == date:
+        elif type_ is date:
             return DateOWLDatatype
-        elif type_ == datetime:
+        elif type_ is datetime:
             return DateTimeOWLDatatype
-        elif type_ == Timedelta:
+        elif type_ is Timedelta:
             return DurationOWLDatatype
         else:
             raise ValueError(type_)
diff --git a/owlapy/owl_ontology_manager.py b/owlapy/owl_ontology_manager.py
index 587ddb5d..0f384f05 100644
--- a/owlapy/owl_ontology_manager.py
+++ b/owlapy/owl_ontology_manager.py
@@ -1,128 +1,14 @@
-from abc import ABCMeta, abstractmethod
-from functools import singledispatch
-from itertools import islice, combinations
-import types
-from typing import cast
+from typing import Union
 
+import jpype
 import owlready2
 
+from owlapy.abstracts.abstract_owl_ontology_manager import OWLOntologyChange, OWLOntologyManager
 from owlapy.iri import IRI
 from owlapy.meta_classes import HasIRI
-from owlapy.owl_object import OWLObject
-from owlready2 import destroy_entity, AllDisjoint, AllDifferent, GeneralClassAxiom
-from owlapy.class_expression import OWLThing, OWLClass, \
-    OWLQuantifiedDataRestriction, OWLDataHasValue, OWLNaryBooleanClassExpression, OWLObjectOneOf, OWLObjectComplementOf, \
-    OWLObjectHasValue, OWLQuantifiedObjectRestriction
-from owlapy.owl_axiom import OWLObjectPropertyRangeAxiom, OWLAxiom, OWLSubClassOfAxiom, OWLEquivalentClassesAxiom, \
-    OWLDisjointUnionAxiom, OWLAnnotationAssertionAxiom, OWLAnnotationProperty, OWLSubPropertyAxiom, \
-    OWLPropertyRangeAxiom, OWLClassAssertionAxiom, OWLDeclarationAxiom, OWLObjectPropertyAssertionAxiom, \
-    OWLSymmetricObjectPropertyAxiom, OWLTransitiveObjectPropertyAxiom, OWLPropertyDomainAxiom, \
-    OWLAsymmetricObjectPropertyAxiom, OWLDataPropertyCharacteristicAxiom, OWLFunctionalDataPropertyAxiom, \
-    OWLReflexiveObjectPropertyAxiom, OWLDataPropertyAssertionAxiom, OWLFunctionalObjectPropertyAxiom, \
-    OWLObjectPropertyCharacteristicAxiom, OWLIrreflexiveObjectPropertyAxiom, OWLInverseFunctionalObjectPropertyAxiom, \
-    OWLDisjointDataPropertiesAxiom, OWLDisjointObjectPropertiesAxiom, OWLEquivalentDataPropertiesAxiom, \
-    OWLEquivalentObjectPropertiesAxiom, OWLInverseObjectPropertiesAxiom, OWLNaryPropertyAxiom, OWLNaryIndividualAxiom, \
-    OWLDifferentIndividualsAxiom, OWLDisjointClassesAxiom, OWLSameIndividualAxiom
-from owlapy.owl_individual import OWLNamedIndividual, OWLIndividual
-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."""
-    __slots__ = ()
-
-    _ont: OWLOntology
-
-    @abstractmethod
-    def __init__(self, ontology: OWLOntology):
-        self._ont = ontology
-
-    def get_ontology(self) -> OWLOntology:
-        """Gets the ontology that the change is/was applied to.
-
-        Returns:
-            The ontology that the change is applicable to.
-        """
-        return self._ont
-
-
-class OWLOntologyManager(metaclass=ABCMeta):
-    """An OWLOntologyManager manages a set of ontologies. It is the main point for creating, loading and accessing
-    ontologies."""
-
-    @abstractmethod
-    def create_ontology(self, iri: IRI) -> OWLOntology:
-        """Creates a new (empty) ontology that that has the specified ontology IRI (and no version IRI).
-
-        Args:
-            iri: The IRI of the ontology to be created.
-
-        Returns:
-            The newly created ontology, or if an ontology with the specified IRI already exists then this existing
-            ontology will be returned.
-        """
-        pass
-
-    @abstractmethod
-    def load_ontology(self, iri: IRI) -> OWLOntology:
-        """Loads an ontology that is assumed to have the specified ontology IRI as its IRI or version IRI. The ontology
-        IRI will be mapped to an ontology document IRI.
-
-        Args:
-            iri: The IRI that identifies the ontology. It is expected that the ontology will also have this IRI
-                (although the OWL API should tolerate situations where this is not the case).
-
-        Returns:
-            The OWLOntology representation of the ontology that was loaded.
-        """
-        pass
-
-    @abstractmethod
-    def apply_change(self, change: OWLOntologyChange):
-        """A convenience method that applies just one change to an ontology. When this method is used through an
-        OWLOntologyManager implementation, the instance used should be the one that the ontology returns through the
-        get_owl_ontology_manager() call.
-
-        Args:
-            change: The change to be applied.
-
-        Raises:
-            ChangeApplied.UNSUCCESSFULLY: if the change was not applied successfully.
-        """
-        pass
-
-    @abstractmethod
-    def add_axiom(self, ontology: OWLOntology, axiom: OWLAxiom):
-        """A convenience method that adds a single axiom to an ontology.
-
-        Args:
-            ontology: The ontology to add the axiom to.
-            axiom: The axiom to be added.
-        """
-        pass
-
-    @abstractmethod
-    def remove_axiom(self, ontology: OWLOntology, axiom: OWLAxiom):
-        """A convenience method that removes a single axiom from an ontology.
-
-        Args:
-            ontology: The ontology to remove the axiom from.
-            axiom: The axiom to be removed.
-        """
-        pass
-
-    @abstractmethod
-    def save_ontology(self, ontology: OWLOntology, document_iri: IRI):
-        """Saves the specified ontology, using the specified document IRI to determine where/how the ontology should be
-        saved.
-
-        Args:
-            ontology: The ontology to be saved.
-            document_iri: The document IRI where the ontology should be saved to.
-        """
-        pass
+from owlapy.owl_ontology import Ontology, SyncOntology
+from owlapy.abstracts.abstract_owl_ontology import OWLOntology
+from owlapy.static_funcs import startJVM
 
 
 class OWLImportsDeclaration(HasIRI):
@@ -177,660 +63,6 @@ def get_import_declaration(self) -> OWLImportsDeclaration:
         return self._declaration
 
 
-@singledispatch
-def _add_axiom(axiom: OWLAxiom):
-    raise NotImplementedError(f'Axiom type {axiom} is not implemented yet.')
-
-
-@_add_axiom.register
-def _(axiom: OWLDeclarationAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
-
-    entity = axiom.get_entity()
-    with ont_x:
-        entity_x = world[entity.to_string_id()]
-        # Entity already exists
-        if entity_x is not None:
-            return
-
-        thing_x: owlready2.entity.ThingClass = conv.map_concept(OWLThing)
-        if isinstance(entity, OWLClass):
-            if entity.is_owl_thing() or entity.is_owl_nothing():
-                return
-            entity_x = types.new_class(name=entity.iri.get_remainder(), bases=(thing_x,))
-        elif isinstance(entity, OWLIndividual):
-            entity_x = thing_x(entity.iri.get_remainder())
-        elif isinstance(entity, OWLObjectProperty):
-            entity_x = types.new_class(name=entity.iri.get_remainder(), bases=(owlready2.ObjectProperty,))
-        elif isinstance(entity, OWLDataProperty):
-            entity_x = types.new_class(name=entity.iri.get_remainder(), bases=(owlready2.DatatypeProperty,))
-        elif isinstance(entity, OWLAnnotationProperty):
-            entity_x = types.new_class(name=entity.iri.get_remainder(), bases=(owlready2.AnnotationProperty,))
-        else:
-            raise ValueError(f'Cannot add ({entity}). Not an atomic class, property, or individual.')
-        entity_x.namespace = ont_x.get_namespace(entity.iri.get_namespace())
-        entity_x.namespace.world._refactor(entity_x.storid, entity_x.iri)
-
-
-@_add_axiom.register
-def _(axiom: OWLClassAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
-
-    individual = axiom.get_individual()
-    cls_ = axiom.get_class_expression()
-    _check_expression(cls_, ontology, world)
-    _add_axiom(OWLDeclarationAxiom(individual), ontology, world)
-    with ont_x:
-        cls_x = conv.map_concept(cls_)
-        ind_x = conv._to_owlready2_individual(individual)
-        thing_x = conv.map_concept(OWLThing)
-        if thing_x in ind_x.is_a:
-            ind_x.is_a.remove(thing_x)
-        ind_x.is_a.append(cls_x)
-
-
-@_add_axiom.register
-def _(axiom: OWLObjectPropertyAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
-
-    subject = axiom.get_subject()
-    property_ = axiom.get_property()
-    object_ = axiom.get_object()
-    _add_axiom(OWLDeclarationAxiom(subject), ontology, world)
-    _add_axiom(OWLDeclarationAxiom(property_), ontology, world)
-    _add_axiom(OWLDeclarationAxiom(object_), ontology, world)
-    with ont_x:
-        subject_x = conv._to_owlready2_individual(subject)
-        property_x = conv._to_owlready2_property(property_)
-        object_x = conv._to_owlready2_individual(object_)
-        property_x[subject_x].append(object_x)
-
-
-@_add_axiom.register
-def _(axiom: OWLDataPropertyAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
-
-    subject = axiom.get_subject()
-    property_ = axiom.get_property()
-    _add_axiom(OWLDeclarationAxiom(subject), ontology, world)
-    _add_axiom(OWLDeclarationAxiom(property_), ontology, world)
-    with ont_x:
-        subject_x = conv._to_owlready2_individual(subject)
-        property_x = conv._to_owlready2_property(property_)
-        property_x[subject_x].append(axiom.get_object().to_python())
-
-
-@_add_axiom.register
-def _(axiom: OWLSubClassOfAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
-
-    sub_class = axiom.get_sub_class()
-    super_class = axiom.get_super_class()
-
-    _check_expression(sub_class, ontology, world)
-    _check_expression(super_class, ontology, world)
-    with ont_x:
-        thing_x = conv.map_concept(OWLThing)
-        sub_class_x = conv.map_concept(sub_class)
-        super_class_x = conv.map_concept(super_class)
-        if isinstance(sub_class, OWLClass):
-            if thing_x in sub_class_x.is_a:
-                sub_class_x.is_a.remove(thing_x)
-        else:
-            # Currently owlready2 seems to expect that we make a new GeneralClassAxiom object each time.
-            # Another option would be to check whether a GeneralClassAxiom with the sub_class_x already exists and just
-            # add the super_class_x to its is_a attribute
-            sub_class_x = GeneralClassAxiom(sub_class_x)
-        sub_class_x.is_a.append(super_class_x)
-
-
-# TODO: Update as soon as owlready2 adds support for EquivalentClasses general class axioms
-@_add_axiom.register
-def _(axiom: OWLEquivalentClassesAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x = conv.map_object(ontology)
-
-    assert axiom.contains_named_equivalent_class(), 'Owlready2 does not support general' \
-                                                    'class axioms for equivalent classes.'
-    for ce in axiom.class_expressions():
-        _check_expression(ce, ontology, world)
-    with ont_x:
-        for ce_1, ce_2 in combinations(axiom.class_expressions(), 2):
-            assert ce_1 is not None, f"ce_1 cannot be None: {ce_1}, {type(ce_1)}"
-            assert ce_2 is not None, f"ce_2_x cannot be None: {ce_2}, {type(ce_2)}"
-
-            ce_1_x = conv.map_concept(ce_1)
-            ce_2_x = conv.map_concept(ce_2)
-            try:
-                assert ce_1_x is not None, f"ce_1_x cannot be None: {ce_1_x}, {type(ce_1_x)}"
-                assert ce_2_x is not None, f"ce_2_x cannot be None: {ce_2_x}, {type(ce_2_x)}"
-            except AssertionError:
-                print("function of ToOwlready2.map_concept() returns None")
-                print(ce_1, ce_1_x)
-                print(ce_2, ce_2_x)
-                print("Axiom:", axiom)
-                print("Temporary solution is reinitializing ce_1_x=ce_2_x\n\n")
-                ce_1_x=ce_2_x
-
-            if isinstance(ce_1_x, owlready2.ThingClass):
-                ce_1_x.equivalent_to.append(ce_2_x)
-            if isinstance(ce_2_x, owlready2.ThingClass):
-                ce_2_x.equivalent_to.append(ce_1_x)
-
-
-@_add_axiom.register
-def _(axiom: OWLDisjointClassesAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    for cls_ in axiom.class_expressions():
-        _check_expression(cls_, ontology, world)
-    with ont_x:
-        # TODO: If the first element in the list is a complex class expression owlready2 is bugged
-        # and creates an AllDifferent axiom
-        AllDisjoint(list(map(conv.map_concept, axiom.class_expressions())))
-
-
-@_add_axiom.register
-def _(axiom: OWLDisjointUnionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    assert isinstance(axiom.get_owl_class(), OWLClass), f'({axiom.get_owl_class()}) is not a named class.'
-    _add_axiom(OWLDeclarationAxiom(axiom.get_owl_class()), ontology, world)
-    for cls_ in axiom.get_class_expressions():
-        _check_expression(cls_, ontology, world)
-    with ont_x:
-        cls_x = conv.map_concept(axiom.get_owl_class())
-        cls_x.disjoint_unions.append(list(map(conv.map_concept, axiom.get_class_expressions())))
-
-
-@_add_axiom.register
-def _(axiom: OWLAnnotationAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    prop_x = conv.map_object(axiom.get_property())
-    if prop_x is None:
-        with ont_x:
-            prop_x: owlready2.annotation.AnnotationPropertyClass = cast(
-                owlready2.AnnotationProperty,
-                types.new_class(
-                    name=axiom.get_property().iri.get_remainder(),
-                    bases=(owlready2.AnnotationProperty,)))
-            prop_x.namespace = ont_x.get_namespace(axiom.get_property().iri.get_namespace())
-    sub_x = world[axiom.get_subject().as_iri().as_str()]
-    assert sub_x is not None, f'{axiom.get_subject} not found in {ontology}'
-    with ont_x:
-        if axiom.get_value().is_literal():
-            literal = axiom.get_value().as_literal()
-            setattr(sub_x, prop_x.python_name, literal.to_python())
-        else:
-            o_x = world[axiom.get_value().as_iri().as_str()]
-            assert o_x is not None, f'{axiom.get_value()} not found in {ontology}'
-            setattr(sub_x, prop_x.python_name, o_x)
-
-
-@_add_axiom.register
-def _(axiom: OWLNaryIndividualAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    for ind in axiom.individuals():
-        _add_axiom(OWLDeclarationAxiom(ind), ontology, world)
-    with ont_x:
-        if isinstance(axiom, OWLSameIndividualAxiom):
-            for idx, ind in enumerate(axiom.individuals()):
-                ind_x = conv._to_owlready2_individual(ind)
-                for ind_2 in islice(axiom.individuals(), idx + 1, None):
-                    ind_2_x = conv._to_owlready2_individual(ind_2)
-                    ind_x.equivalent_to.append(ind_2_x)
-        elif isinstance(axiom, OWLDifferentIndividualsAxiom):
-            AllDifferent(list(map(conv._to_owlready2_individual, axiom.individuals())))
-        else:
-            raise ValueError(f'OWLNaryIndividualAxiom ({axiom}) is not defined.')
-
-
-@_add_axiom.register
-def _(axiom: OWLSubPropertyAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    sub_property = axiom.get_sub_property()
-    super_property = axiom.get_super_property()
-    _add_axiom(OWLDeclarationAxiom(sub_property), ontology, world)
-    _add_axiom(OWLDeclarationAxiom(super_property), ontology, world)
-    with ont_x:
-        sub_property_x = conv._to_owlready2_property(sub_property)
-        super_property_x = conv._to_owlready2_property(super_property)
-        sub_property_x.is_a.append(super_property_x)
-
-
-@_add_axiom.register
-def _(axiom: OWLPropertyDomainAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    property_ = axiom.get_property()
-    domain = axiom.get_domain()
-    _add_axiom(OWLDeclarationAxiom(property_), ontology, world)
-    _check_expression(domain, ontology, world)
-    with ont_x:
-        property_x = conv._to_owlready2_property(property_)
-        domain_x = conv.map_concept(domain)
-        property_x.domain.append(domain_x)
-
-
-@_add_axiom.register
-def _(axiom: OWLPropertyRangeAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    property_ = axiom.get_property()
-    range_ = axiom.get_range()
-    _add_axiom(OWLDeclarationAxiom(property_), ontology, world)
-    if isinstance(axiom, OWLObjectPropertyRangeAxiom):
-        _check_expression(range_, ontology, world)
-    with ont_x:
-        property_x = conv._to_owlready2_property(property_)
-        range_x = conv.map_concept(range_) if isinstance(axiom, OWLObjectPropertyRangeAxiom) \
-            else conv.map_datarange(range_)
-        property_x.range.append(range_x)
-
-
-@_add_axiom.register
-def _(axiom: OWLNaryPropertyAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    for property_ in axiom.properties():
-        _add_axiom(OWLDeclarationAxiom(property_), ontology, world)
-    with ont_x:
-        if isinstance(axiom, (OWLEquivalentObjectPropertiesAxiom, OWLEquivalentDataPropertiesAxiom,)):
-            for idx, property_ in enumerate(axiom.properties()):
-                property_x = conv._to_owlready2_property(property_)
-                for property_2 in islice(axiom.properties(), idx + 1, None):
-                    property_2_x = conv._to_owlready2_property(property_2)
-                    property_x.equivalent_to.append(property_2_x)
-        elif isinstance(axiom, (OWLDisjointObjectPropertiesAxiom, OWLDisjointDataPropertiesAxiom,)):
-            AllDisjoint(list(map(conv._to_owlready2_property, axiom.properties())))
-        elif isinstance(axiom, OWLInverseObjectPropertiesAxiom):
-            property_first_x = conv._to_owlready2_property(axiom.get_first_property())
-            property_second_x = conv._to_owlready2_property(axiom.get_second_property())
-            if property_second_x.inverse_property is not None:
-                property_second_x.inverse_property = None
-            property_first_x.inverse_property = property_second_x
-        else:
-            raise ValueError(f'OWLNaryPropertyAxiom ({axiom}) is not defined.')
-
-
-@_add_axiom.register
-def _(axiom: OWLObjectPropertyCharacteristicAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    property_ = axiom.get_property()
-    _add_axiom(OWLDeclarationAxiom(property_), ontology, world)
-    with ont_x:
-        property_x = conv._to_owlready2_property(property_)
-        if isinstance(axiom, OWLFunctionalObjectPropertyAxiom):
-            property_x.is_a.append(owlready2.FunctionalProperty)
-        elif isinstance(axiom, OWLAsymmetricObjectPropertyAxiom):
-            property_x.is_a.append(owlready2.AsymmetricProperty)
-        elif isinstance(axiom, OWLInverseFunctionalObjectPropertyAxiom):
-            property_x.is_a.append(owlready2.InverseFunctionalProperty)
-        elif isinstance(axiom, OWLIrreflexiveObjectPropertyAxiom):
-            property_x.is_a.append(owlready2.IrreflexiveProperty)
-        elif isinstance(axiom, OWLReflexiveObjectPropertyAxiom):
-            property_x.is_a.append(owlready2.ReflexiveProperty)
-        elif isinstance(axiom, OWLSymmetricObjectPropertyAxiom):
-            property_x.is_a.append(owlready2.SymmetricProperty)
-        elif isinstance(axiom, OWLTransitiveObjectPropertyAxiom):
-            property_x.is_a.append(owlready2.TransitiveProperty)
-        else:
-            raise ValueError(f'ObjectPropertyCharacteristicAxiom ({axiom}) is not defined.')
-
-
-@_add_axiom.register
-def _(axiom: OWLDataPropertyCharacteristicAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    property_ = axiom.get_property()
-    _add_axiom(OWLDeclarationAxiom(property_), ontology, world)
-    with ont_x:
-        property_x = conv._to_owlready2_property(property_)
-        if isinstance(axiom, OWLFunctionalDataPropertyAxiom):
-            property_x.is_a.append(owlready2.FunctionalProperty)
-        else:
-            raise ValueError(f'DataPropertyCharacteristicAxiom ({axiom}) is not defined.')
-
-
-@singledispatch
-def _remove_axiom(axiom: OWLAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    raise NotImplementedError(f'Axiom type {axiom} is not implemented yet.')
-
-
-@_remove_axiom.register
-def _(axiom: OWLDeclarationAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
-    with ont_x:
-        entity_x = world[axiom.get_entity().to_string_id()]
-        if entity_x is not None:
-            # TODO: owlready2 seems to be bugged for properties here
-            destroy_entity(entity_x)
-
-
-@_remove_axiom.register
-def _(axiom: OWLClassAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
-
-    with ont_x:
-        cls_x = conv.map_concept(axiom.get_class_expression())
-        ind_x = conv._to_owlready2_individual(axiom.get_individual())
-        if cls_x is None or ind_x is None:
-            return
-        if cls_x in ind_x.is_a:
-            ind_x.is_a.remove(cls_x)
-        elif isinstance(axiom.get_class_expression(), OWLClass):
-            ont_x._del_obj_triple_spo(ind_x.storid, owlready2.rdf_type, cls_x.storid)
-
-
-@_remove_axiom.register
-def _(axiom: OWLObjectPropertyAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
-
-    with ont_x:
-        subject_x = conv._to_owlready2_individual(axiom.get_subject())
-        property_x = conv._to_owlready2_property(axiom.get_property())
-        object_x = conv._to_owlready2_individual(axiom.get_object())
-        if all([subject_x, property_x, object_x]) and object_x in property_x[subject_x]:
-            property_x[subject_x].remove(object_x)
-
-
-@_remove_axiom.register
-def _(axiom: OWLDataPropertyAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
-
-    with ont_x:
-        subject_x = conv._to_owlready2_individual(axiom.get_subject())
-        property_x = conv._to_owlready2_property(axiom.get_property())
-        object_ = axiom.get_object().to_python()
-        if subject_x is not None and property_x is not None and object_ in property_x[subject_x]:
-            property_x[subject_x].remove(object_)
-
-
-@_remove_axiom.register
-def _(axiom: OWLSubClassOfAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
-    sub_class = axiom.get_sub_class()
-    super_class = axiom.get_super_class()
-
-    with ont_x:
-        sub_class_x = conv.map_concept(sub_class)
-        super_class_x = conv.map_concept(super_class)
-        if sub_class_x is None or super_class_x is None:
-            return
-
-        if isinstance(sub_class, OWLClass):
-            if super_class_x in sub_class_x.is_a:
-                sub_class_x.is_a.remove(super_class_x)
-            elif isinstance(axiom.get_sub_class(), OWLClass) and isinstance(axiom.get_super_class(), OWLClass):
-                ont_x._del_obj_triple_spo(sub_class_x.storid, owlready2.rdfs_subclassof, super_class_x.storid)
-        else:
-            for ca in ont_x.general_class_axioms():
-                if ca.left_side == sub_class_x and super_class_x in ca.is_a:
-                    ca.is_a.remove(super_class_x)
-
-
-# TODO: Update as soons as owlready2 adds support for EquivalentClasses general class axioms
-@_remove_axiom.register
-def _(axiom: OWLEquivalentClassesAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x = conv.map_object(ontology)
-
-    if not axiom.contains_named_equivalent_class():
-        return
-
-    with ont_x:
-        ces_x = list(map(conv.map_concept, axiom.class_expressions()))
-        if len(ces_x) < 2 or not all(ces_x):
-            return
-
-        for ce_1_x, ce_2_x in combinations(ces_x, 2):
-            if isinstance(ce_2_x, owlready2.ThingClass) and ce_1_x in ce_2_x.equivalent_to:
-                ce_2_x.equivalent_to.remove(ce_1_x)
-            if isinstance(ce_1_x, owlready2.ThingClass) and ce_2_x in ce_1_x.equivalent_to:
-                ce_1_x.equivalent_to.remove(ce_2_x)
-
-
-@_remove_axiom.register
-def _(axiom: OWLDisjointClassesAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    with ont_x:
-        class_expressions_x = set(map(conv.map_concept, axiom.class_expressions()))
-        if len(class_expressions_x) < 2 or not all(class_expressions_x):
-            return
-        for disjoints_x in ont_x.disjoint_classes():
-            if set(disjoints_x.entities) == class_expressions_x:
-                del disjoints_x.entities[:-1]
-                break
-
-
-@_remove_axiom.register
-def _(axiom: OWLDisjointUnionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-    assert isinstance(axiom.get_owl_class(), OWLClass), f'({axiom.get_owl_class()}) is not a named class.'
-
-    with ont_x:
-        cls_x = conv.map_concept(axiom.get_owl_class())
-        union_expressions_x = set(map(conv.map_concept, axiom.get_class_expressions()))
-        if cls_x is not None and all(union_expressions_x):
-            for union_x in cls_x.disjoint_unions:
-                if union_expressions_x == set(union_x):
-                    cls_x.disjoint_unions.remove(union_x)
-                    break
-
-
-@_remove_axiom.register
-def _(axiom: OWLAnnotationAssertionAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    sub_x = world[axiom.get_subject().as_iri().as_str()]
-    if sub_x is None:
-        return
-    name = axiom.get_property().iri.get_remainder()
-    with ont_x:
-        if axiom.get_value().is_literal():
-            o_x = axiom.get_value().as_literal().to_python()
-        else:
-            o_x = world[axiom.get_value().as_iri().as_str()]
-
-        value = getattr(sub_x, name, None)
-        if value is not None and o_x in value:
-            value.remove(o_x)
-
-
-@_remove_axiom.register
-def _(axiom: OWLNaryIndividualAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    with ont_x:
-        individuals_x = list(map(conv._to_owlready2_individual, axiom.individuals()))
-        if len(individuals_x) < 2 or not all(individuals_x):
-            return
-        if isinstance(axiom, OWLSameIndividualAxiom):
-            if set(individuals_x[1:-1]) <= set(individuals_x[0].INDIRECT_equivalent_to):
-                for individual_1_x, individual_2_x in combinations(individuals_x, 2):
-                    if individual_1_x in individual_2_x.equivalent_to:
-                        individual_2_x.equivalent_to.remove(individual_1_x)
-                    if individual_2_x in individual_1_x.equivalent_to:
-                        individual_1_x.equivalent_to.remove(individual_2_x)
-        elif isinstance(axiom, OWLDifferentIndividualsAxiom):
-            individuals_x = set(individuals_x)
-            for different_x in ont_x.different_individuals():
-                if set(different_x.entities) == individuals_x:
-                    del different_x.entities[:-1]
-                    break
-        else:
-            raise ValueError(f'OWLNaryIndividualAxiom ({axiom}) is not defined.')
-
-
-@_remove_axiom.register
-def _(axiom: OWLSubPropertyAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.namespace.Ontology = conv.map_object(ontology)
-
-    with ont_x:
-        sub_property_x = conv._to_owlready2_property(axiom.get_sub_property())
-        super_property_x = conv._to_owlready2_property(axiom.get_super_property())
-        if sub_property_x is None or super_property_x is None:
-            return
-        if super_property_x in sub_property_x.is_a:
-            sub_property_x.is_a.remove(super_property_x)
-        else:
-            ont_x._del_obj_triple_spo(sub_property_x.storid, owlready2.rdfs_subpropertyof, super_property_x.storid)
-
-
-@_remove_axiom.register
-def _(axiom: OWLPropertyDomainAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    with ont_x:
-        property_x = conv._to_owlready2_property(axiom.get_property())
-        domain_x = conv.map_concept(axiom.get_domain())
-        if domain_x is not None and property_x is not None and domain_x in property_x.domain:
-            property_x.domain.remove(domain_x)
-
-
-@_remove_axiom.register
-def _(axiom: OWLPropertyRangeAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    with ont_x:
-        property_x = conv._to_owlready2_property(axiom.get_property())
-        range_x = conv.map_concept(axiom.get_range()) \
-            if isinstance(axiom, OWLObjectPropertyRangeAxiom) else conv.map_datarange(axiom.get_range())
-        if range_x is not None and property_x is not None and range_x in property_x.range:
-            property_x.range.remove(range_x)
-
-
-@_remove_axiom.register
-def _(axiom: OWLNaryPropertyAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    with ont_x:
-        properties_x = list(map(conv._to_owlready2_property, axiom.properties()))
-        if len(properties_x) < 2 or not all(properties_x):
-            return
-        if isinstance(axiom, (OWLEquivalentObjectPropertiesAxiom, OWLEquivalentDataPropertiesAxiom,)):
-            # Check if all equivalent properties are defined in the ontology
-            if set(properties_x[1:-1]) <= set(properties_x[0].INDIRECT_equivalent_to):
-                for property_1_x, property_2_x in combinations(properties_x, 2):
-                    if property_1_x in property_2_x.equivalent_to:
-                        property_2_x.equivalent_to.remove(property_1_x)
-                    if property_2_x in property_1_x.equivalent_to:
-                        property_1_x.equivalent_to.remove(property_2_x)
-        elif isinstance(axiom, (OWLDisjointObjectPropertiesAxiom, OWLDisjointDataPropertiesAxiom,)):
-            properties_x = set(properties_x)
-            for disjoints_x in ont_x.disjoint_properties():
-                if set(disjoints_x.entities) == properties_x:
-                    del disjoints_x.entities[:-1]
-                    break
-        elif isinstance(axiom, OWLInverseObjectPropertiesAxiom):
-            if len(properties_x) != 2:
-                return
-            first = properties_x[0]
-            second = properties_x[1]
-            if first.inverse_property == second and second.inverse_property == first:
-                first.inverse_property = None
-        else:
-            raise ValueError(f'OWLNaryPropertyAxiom ({axiom}) is not defined.')
-
-
-@_remove_axiom.register
-def _(axiom: OWLObjectPropertyCharacteristicAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    with ont_x:
-        property_x = conv._to_owlready2_property(axiom.get_property())
-        if property_x is None:
-            return
-
-        if isinstance(axiom, OWLFunctionalObjectPropertyAxiom) and owlready2.FunctionalProperty in property_x.is_a:
-            property_x.is_a.remove(owlready2.FunctionalProperty)
-        elif isinstance(axiom, OWLAsymmetricObjectPropertyAxiom) and owlready2.AsymmetricProperty in property_x.is_a:
-            property_x.is_a.remove(owlready2.AsymmetricProperty)
-        elif isinstance(axiom, OWLInverseFunctionalObjectPropertyAxiom) \
-                and owlready2.InverseFunctionalProperty in property_x.is_a:
-            property_x.is_a.remove(owlready2.InverseFunctionalProperty)
-        elif isinstance(axiom, OWLIrreflexiveObjectPropertyAxiom) and owlready2.IrreflexiveProperty in property_x.is_a:
-            property_x.is_a.remove(owlready2.IrreflexiveProperty)
-        elif isinstance(axiom, OWLReflexiveObjectPropertyAxiom) and owlready2.ReflexiveProperty in property_x.is_a:
-            property_x.is_a.remove(owlready2.ReflexiveProperty)
-        elif isinstance(axiom, OWLSymmetricObjectPropertyAxiom) and owlready2.SymmetricProperty in property_x.is_a:
-            property_x.is_a.remove(owlready2.SymmetricProperty)
-        elif isinstance(axiom, OWLTransitiveObjectPropertyAxiom) and owlready2.TransitiveProperty in property_x.is_a:
-            property_x.is_a.remove(owlready2.TransitiveProperty)
-        else:
-            raise ValueError(f'OWLObjectPropertyCharacteristicAxiom ({axiom}) is not defined.')
-
-
-@_remove_axiom.register
-def _(axiom: OWLDataPropertyCharacteristicAxiom, ontology: OWLOntology, world: owlready2.namespace.World):
-    conv = ToOwlready2(world)
-    ont_x: owlready2.Ontology = conv.map_object(ontology)
-
-    with ont_x:
-        property_x = conv._to_owlready2_property(axiom.get_property())
-        if property_x is not None and isinstance(axiom, OWLFunctionalDataPropertyAxiom) \
-                and owlready2.FunctionalProperty in property_x.is_a:
-            property_x.is_a.remove(owlready2.FunctionalProperty)
-
-
-def _check_expression(expr: OWLObject, ontology: OWLOntology, 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
-
-    """
-    if isinstance(expr, (OWLClass, OWLProperty, OWLNamedIndividual,)):
-        _add_axiom(OWLDeclarationAxiom(expr), ontology, world)
-    elif isinstance(expr, (OWLNaryBooleanClassExpression, OWLObjectComplementOf, OWLObjectOneOf,)):
-        for op in expr.operands():
-            _check_expression(op, ontology, world)
-    elif isinstance(expr, (OWLQuantifiedObjectRestriction, OWLObjectHasValue,)):
-        _check_expression(expr.get_property(), ontology, world)
-        _check_expression(expr.get_filler(), ontology, world)
-    elif isinstance(expr, OWLObjectInverseOf):
-        _check_expression(expr.get_named_property(), ontology, world)
-        _check_expression(expr.get_inverse_property(), ontology, world)
-    elif isinstance(expr, (OWLQuantifiedDataRestriction, OWLDataHasValue,)):
-        _check_expression(expr.get_property(), ontology, world)
-    elif not isinstance(expr, OWLObject):
-        raise ValueError(f'({expr}) is not an OWLObject.')
-
-
 class OntologyManager(OWLOntologyManager):
     __slots__ = '_world'
 
@@ -849,16 +81,16 @@ def __init__(self, world_store=None):
         else:
             self._world = owlready2.World(filename=world_store)
 
-    def create_ontology(self, iri:Union[str,IRI]=None) -> 'Ontology':
+    def create_ontology(self, iri: Union[str, IRI] = None) -> Ontology:
         if isinstance(iri, str):
-            iri=IRI.create(iri)
+            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: Union[str,IRI]=None) -> 'Ontology':
+    def load_ontology(self, iri: Union[IRI, str] = None) -> Ontology:
         if isinstance(iri, str):
-            iri=IRI.create(iri)
+            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)
@@ -873,24 +105,33 @@ def apply_change(self, change: OWLOntologyChange):
             # TODO XXX
             raise NotImplementedError
 
-    def add_axiom(self, ontology: OWLOntology, axiom: OWLAxiom):
-        _add_axiom(axiom, ontology, self._world)
-
-    def remove_axiom(self, ontology: OWLOntology, axiom: OWLAxiom):
-        _remove_axiom(axiom, ontology, self._world)
-
-    def save_ontology(self, ontology: OWLOntology, document_iri: IRI):
-        ont_x: owlready2.namespace.Ontology = self._world.get_ontology(
-            ontology.get_ontology_id().get_ontology_iri().as_str()
-        )
-        if document_iri.get_namespace().startswith('file:/'):
-            filename = document_iri.as_str()[len('file:/'):]
-            ont_x.save(file=filename)
-        else:
-            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.
         """
         self._world.save()
 
+
+class SyncOntologyManager(OWLOntologyManager):
+
+    # WARN: Do not move local imports to top of the module
+    def __init__(self):
+        if not jpype.isJVMStarted():
+            startJVM()
+        from org.semanticweb.owlapi.apibinding import OWLManager
+        self.owlapi_manager = OWLManager.createOWLOntologyManager()
+
+    def create_ontology(self, iri: Union[IRI, str]) -> SyncOntology:
+        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 SyncOntology(self, iri, new=True)
+
+    def load_ontology(self, iri: Union[IRI, str]) -> SyncOntology:
+        return SyncOntology(self, iri, new=False)
+
+    def get_owlapi_manager(self):
+        return self.owlapi_manager
+
+    def apply_change(self, change: OWLOntologyChange):
+        raise NotImplementedError()
diff --git a/owlapy/owl_reasoner.py b/owlapy/owl_reasoner.py
index 318ad2c9..45d02bca 100644
--- a/owlapy/owl_reasoner.py
+++ b/owlapy/owl_reasoner.py
@@ -1,490 +1,39 @@
 """OWL Reasoner"""
 import operator
-from abc import ABCMeta, abstractmethod
+import logging
+import owlready2
+
 from collections import defaultdict
 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
-import logging
-
-import owlready2
+from typing import DefaultDict, Iterable, Dict, Mapping, Set, Type, TypeVar, Optional, FrozenSet, List, Union
 
 from owlapy.class_expression import OWLClassExpression, OWLObjectSomeValuesFrom, OWLObjectUnionOf, \
     OWLObjectIntersectionOf, OWLObjectComplementOf, OWLObjectAllValuesFrom, OWLObjectOneOf, OWLObjectHasValue, \
     OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLObjectExactCardinality, OWLObjectCardinalityRestriction, \
     OWLDataSomeValuesFrom, OWLDataOneOf, OWLDatatypeRestriction, OWLFacetRestriction, OWLDataHasValue, \
     OWLDataAllValuesFrom
-from owlapy.class_expression import OWLClass
-from owlapy.iri import IRI
-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
-from owlapy.owl_ontology_manager import OntologyManager
-from owlapy.owl_property import OWLObjectPropertyExpression, OWLDataProperty, OWLObjectProperty, OWLObjectInverseOf, \
-    OWLPropertyExpression, OWLDataPropertyExpression
-from owlapy.owl_individual import OWLNamedIndividual
-from owlapy.owl_literal import OWLLiteral
-from owlapy.owlapi_adaptor import OWLAPIAdaptor
-from owlapy.utils import LRUCache
-
-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."""
-    __slots__ = ()
-
-    @abstractmethod
-    def __init__(self, ontology: OWLOntology):
-        pass
-
-    @abstractmethod
-    def data_property_domains(self, pe: OWLDataProperty, direct: bool = False) -> Iterable[OWLClassExpression]:
-        """Gets the class expressions that are the direct or indirect domains of this property with respect to the
-           imports closure of the root ontology.
-
-        Args:
-            pe: The property expression whose domains are to be retrieved.
-            direct: Specifies if the direct domains should be retrieved (True), or if all domains should be retrieved
-                (False).
-
-        Returns:
-            :Let N = equivalent_classes(DataSomeValuesFrom(pe rdfs:Literal)). If direct is True: then if N is not
-            empty then the return value is N, else the return value is the result of
-            super_classes(DataSomeValuesFrom(pe rdfs:Literal), true). If direct is False: then the result of
-            super_classes(DataSomeValuesFrom(pe rdfs:Literal), false) together with N if N is non-empty.
-            (Note, rdfs:Literal is the top datatype).
-        """
-        pass
-
-    @abstractmethod
-    def object_property_domains(self, pe: OWLObjectProperty, direct: bool = False) -> Iterable[OWLClassExpression]:
-        """Gets the class expressions that are the direct or indirect domains of this property with respect to the
-           imports closure of the root ontology.
-
-        Args:
-            pe: The property expression whose domains are to be retrieved.
-            direct: Specifies if the direct domains should be retrieved (True), or if all domains should be retrieved
-                (False).
-
-        Returns:
-            :Let N = equivalent_classes(ObjectSomeValuesFrom(pe owl:Thing)). If direct is True: then if N is not empty
-            then the return value is N, else the return value is the result of
-            super_classes(ObjectSomeValuesFrom(pe owl:Thing), true). If direct is False: then the result of
-            super_classes(ObjectSomeValuesFrom(pe owl:Thing), false) together with N if N is non-empty.
-        """
-        pass
-
-    @abstractmethod
-    def object_property_ranges(self, pe: OWLObjectProperty, direct: bool = False) -> Iterable[OWLClassExpression]:
-        """Gets the class expressions that are the direct or indirect ranges of this property with respect to the
-           imports closure of the root ontology.
-
-        Args:
-            pe: The property expression whose ranges are to be retrieved.
-            direct: Specifies if the direct ranges should be retrieved (True), or if all ranges should be retrieved
-                (False).
-
-        Returns:
-            :Let N = equivalent_classes(ObjectSomeValuesFrom(ObjectInverseOf(pe) owl:Thing)). If direct is True: then
-            if N is not empty then the return value is N, else the return value is the result of
-            super_classes(ObjectSomeValuesFrom(ObjectInverseOf(pe) owl:Thing), true). If direct is False: then
-            the result of super_classes(ObjectSomeValuesFrom(ObjectInverseOf(pe) owl:Thing), false) together with N
-            if N is non-empty.
-        """
-        pass
-
-    @abstractmethod
-    def equivalent_classes(self, ce: OWLClassExpression, only_named: bool = True) -> Iterable[OWLClassExpression]:
-        """Gets the class expressions that are equivalent to the specified class expression with respect to the set of
-        reasoner axioms.
-
-        Args:
-            ce: The class expression whose equivalent classes are to be retrieved.
-            only_named: Whether to only retrieve named equivalent classes or also complex class expressions.
-
-        Returns:
-            All class expressions C where the root ontology imports closure entails EquivalentClasses(ce C). If ce is
-            not a class name (i.e. it is an anonymous class expression) and there are no such classes C then there will
-            be no result. If ce is unsatisfiable with respect to the set of reasoner axioms then  owl:Nothing, i.e. the
-            bottom node, will be returned.
-        """
-        pass
-
-    @abstractmethod
-    def disjoint_classes(self, ce: OWLClassExpression, only_named: bool = True) -> Iterable[OWLClassExpression]:
-        """Gets the class expressions that are disjoint with specified class expression with respect to the set of
-        reasoner axioms.
-
-        Args:
-            ce: The class expression whose disjoint classes are to be retrieved.
-            only_named: Whether to only retrieve named disjoint classes or also complex class expressions.
-
-        Returns:
-            All class expressions D where the set of reasoner axioms entails EquivalentClasses(D ObjectComplementOf(ce))
-            or StrictSubClassOf(D ObjectComplementOf(ce)).
-        """
-        pass
-
-    @abstractmethod
-    def different_individuals(self, ind: OWLNamedIndividual) -> Iterable[OWLNamedIndividual]:
-        """Gets the individuals that are different from the specified individual with respect to the set of
-        reasoner axioms.
-
-        Args:
-            ind: The individual whose different individuals are to be retrieved.
-
-        Returns:
-            All individuals x where the set of reasoner axioms entails DifferentIndividuals(ind x).
-        """
-        pass
-
-    @abstractmethod
-    def same_individuals(self, ind: OWLNamedIndividual) -> Iterable[OWLNamedIndividual]:
-        """Gets the individuals that are the same as the specified individual with respect to the set of
-        reasoner axioms.
-
-        Args:
-            ind: The individual whose same individuals are to be retrieved.
-
-        Returns:
-            All individuals x where the root ontology imports closure entails SameIndividual(ind x).
-        """
-        pass
-
-    @abstractmethod
-    def equivalent_object_properties(self, op: OWLObjectPropertyExpression) -> Iterable[OWLObjectPropertyExpression]:
-        """Gets the simplified object properties that are equivalent to the specified object property with respect
-        to the set of reasoner axioms.
-
-        Args:
-            op: The object property whose equivalent object properties are to be retrieved.
-
-        Returns:
-            All simplified object properties e where the root ontology imports closure entails
-            EquivalentObjectProperties(op e). If op is unsatisfiable with respect to the set of reasoner axioms
-            then owl:bottomDataProperty will be returned.
-        """
-        pass
-
-    @abstractmethod
-    def equivalent_data_properties(self, dp: OWLDataProperty) -> Iterable[OWLDataProperty]:
-        """Gets the data properties that are equivalent to the specified data property with respect to the set of
-        reasoner axioms.
-
-        Args:
-            dp: The data property whose equivalent data properties are to be retrieved.
-
-        Returns:
-            All data properties e where the root ontology imports closure entails EquivalentDataProperties(dp e).
-            If dp is unsatisfiable with respect to the set of reasoner axioms then owl:bottomDataProperty will
-            be returned.
-        """
-        pass
-
-    @abstractmethod
-    def data_property_values(self, e: OWLEntity, pe: OWLDataProperty, direct: bool = True) \
-            -> Iterable['OWLLiteral']:
-        """Gets the data property values for the specified entity and data property expression.
-
-        Args:
-            e: The owl entity (usually an individual) that is the subject of the data property values.
-            pe: The data property expression whose values are to be retrieved for the specified entity.
-            direct: Specifies if the direct values should be retrieved (True), or if all values should be retrieved
-                (False), so that sub properties are taken into account.
-
-        Note: Can be used to get values, for example, of 'label' property of owl entities such as classes and properties
-        too (not only individuals).
-
-        Returns:
-            A set of OWLLiterals containing literals such that for each literal l in the set, the set of reasoner
-            axioms entails DataPropertyAssertion(pe ind l).
-        """
-        pass
-
-    @abstractmethod
-    def object_property_values(self, ind: OWLNamedIndividual, pe: OWLObjectPropertyExpression, direct: bool = True) \
-            -> Iterable[OWLNamedIndividual]:
-        """Gets the object property values for the specified individual and object property expression.
-
-        Args:
-            ind: The individual that is the subject of the object property values.
-            pe: The object property expression whose values are to be retrieved for the specified individual.
-            direct: Specifies if the direct values should be retrieved (True), or if all values should be retrieved
-                (False), so that sub properties are taken into account.
-
-        Returns:
-            The named individuals such that for each individual j, the set of reasoner axioms entails
-            ObjectPropertyAssertion(pe ind j).
-        """
-        pass
-
-    @abstractmethod
-    def instances(self, ce: OWLClassExpression, direct: bool = False) -> Iterable[OWLNamedIndividual]:
-        """Gets the individuals which are instances of the specified class expression.
-
-        Args:
-            ce: The class expression whose instances are to be retrieved.
-            direct: Specifies if the direct instances should be retrieved (True), or if all instances should be
-                retrieved (False).
-
-        Returns:
-            If direct is True, each named individual j where the set of reasoner axioms entails
-            DirectClassAssertion(ce, j). If direct is False, each named individual j where the set of reasoner axioms
-            entails ClassAssertion(ce, j). If ce is unsatisfiable with respect to the set of reasoner axioms then
-            nothing returned.
-        """
-        pass
-
-    @abstractmethod
-    def sub_classes(self, ce: OWLClassExpression, direct: bool = False, only_named: bool = True) \
-            -> Iterable[OWLClassExpression]:
-        """Gets the set of named classes that are the strict (potentially direct) subclasses of the specified class
-        expression with respect to the reasoner axioms.
-
-        Args:
-            ce: The class expression whose strict (direct) subclasses are to be retrieved.
-            direct: Specifies if the direct subclasses should be retrieved (True) or if the all subclasses
-                (descendant) classes should be retrieved (False).
-            only_named: Whether to only retrieve named sub-classes or also complex class expressions.
-
-        Returns:
-            If direct is True, each class C where reasoner axioms entails DirectSubClassOf(C, ce). If direct is False,
-            each class C where reasoner axioms entails StrictSubClassOf(C, ce). If ce is equivalent to owl:Nothing then
-            nothing will be returned.
-        """
-        pass
-
-    @abstractmethod
-    def disjoint_object_properties(self, op: OWLObjectPropertyExpression) -> Iterable[OWLObjectPropertyExpression]:
-        """Gets the simplified object properties that are disjoint with the specified object property with respect
-        to the set of reasoner axioms.
-
-        Args:
-            op: The object property whose disjoint object properties are to be retrieved.
-
-        Returns:
-            All simplified object properties e where the root ontology imports closure entails
-            EquivalentObjectProperties(e ObjectPropertyComplementOf(op)) or
-            StrictSubObjectPropertyOf(e ObjectPropertyComplementOf(op)).
-        """
-        pass
-
-    @abstractmethod
-    def disjoint_data_properties(self, dp: OWLDataProperty) -> Iterable[OWLDataProperty]:
-        """Gets the data properties that are disjoint with the specified data property with respect
-        to the set of reasoner axioms.
-
-        Args:
-            dp: The data property whose disjoint data properties are to be retrieved.
-
-        Returns:
-            All data properties e where the root ontology imports closure entails
-            EquivalentDataProperties(e DataPropertyComplementOf(dp)) or
-            StrictSubDataPropertyOf(e DataPropertyComplementOf(dp)).
-        """
-        pass
-
-    @abstractmethod
-    def sub_data_properties(self, dp: OWLDataProperty, direct: bool = False) -> Iterable[OWLDataProperty]:
-        """Gets the set of named data properties that are the strict (potentially direct) subproperties of the
-        specified data property expression with respect to the imports closure of the root ontology.
-
-        Args:
-            dp: The data property whose strict (direct) subproperties are to be retrieved.
-            direct: Specifies if the direct subproperties should be retrieved (True) or if the all subproperties
-                (descendants) should be retrieved (False).
-
-        Returns:
-            If direct is True, each property P where the set of reasoner axioms entails DirectSubDataPropertyOf(P, pe).
-            If direct is False, each property P where the set of reasoner axioms entails
-            StrictSubDataPropertyOf(P, pe). If pe is equivalent to owl:bottomDataProperty then nothing will be
-            returned.
-        """
-        pass
-
-    @abstractmethod
-    def super_data_properties(self, dp: OWLDataProperty, direct: bool = False) -> Iterable[OWLDataProperty]:
-        """Gets the stream of data properties that are the strict (potentially direct) super properties of the
-         specified data property with respect to the imports closure of the root ontology.
-
-         Args:
-             dp (OWLDataProperty): The data property whose super properties are to be retrieved.
-             direct (bool): Specifies if the direct super properties should be retrieved (True) or if the all
-                            super properties (ancestors) should be retrieved (False).
-
-         Returns:
-             Iterable of super properties.
-         """
-        pass
-
-    @abstractmethod
-    def sub_object_properties(self, op: OWLObjectPropertyExpression, direct: bool = False) \
-            -> Iterable[OWLObjectPropertyExpression]:
-        """Gets the stream of simplified object property expressions that are the strict (potentially direct)
-        subproperties of the specified object property expression with respect to the imports closure of the root
-        ontology.
-
-        Args:
-            op: The object property expression whose strict (direct) subproperties are to be retrieved.
-            direct: Specifies if the direct subproperties should be retrieved (True) or if the all subproperties
-                (descendants) should be retrieved (False).
-
-        Returns:
-            If direct is True, simplified object property expressions, such that for each simplified object property
-            expression, P, the set of reasoner axioms entails DirectSubObjectPropertyOf(P, pe).
-            If direct is False, simplified object property expressions, such that for each simplified object property
-            expression, P, the set of reasoner axioms entails StrictSubObjectPropertyOf(P, pe).
-            If pe is equivalent to owl:bottomObjectProperty then nothing will be returned.
-        """
-        pass
-
-    @abstractmethod
-    def super_object_properties(self, op: OWLObjectPropertyExpression, direct: bool = False) \
-            -> Iterable[OWLObjectPropertyExpression]:
-        """Gets the stream of object properties that are the strict (potentially direct) super properties of the
-         specified object property with respect to the imports closure of the root ontology.
-
-         Args:
-             op (OWLObjectPropertyExpression): The object property expression whose super properties are to be
-                                                retrieved.
-             direct (bool): Specifies if the direct super properties should be retrieved (True) or if the all
-                            super properties (ancestors) should be retrieved (False).
-
-         Returns:
-             Iterable of super properties.
-         """
-        pass
-
-    @abstractmethod
-    def types(self, ind: OWLNamedIndividual, direct: bool = False) -> Iterable[OWLClass]:
-        """Gets the named classes which are (potentially direct) types of the specified named individual.
-
-        Args:
-            ind: 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).
-
-        Returns:
-            If direct is True, each named class C where the set of reasoner axioms entails
-            DirectClassAssertion(C, ind). If direct is False, each named class C where the set of reasoner axioms
-            entails ClassAssertion(C, ind).
-        """
-        pass
-
-    @abstractmethod
-    def get_root_ontology(self) -> OWLOntology:
-        """Gets the "root" ontology that is loaded into this reasoner. The reasoner takes into account the axioms in
-        this ontology and its import's closure."""
-        pass
-
-    @abstractmethod
-    def super_classes(self, ce: OWLClassExpression, direct: bool = False, only_named: bool = True) \
-            -> Iterable[OWLClassExpression]:
-        """Gets the stream of named classes that are the strict (potentially direct) super classes of the specified
-        class expression with respect to the imports closure of the root ontology.
-
-        Args:
-            ce: The class expression whose strict (direct) super classes are to be retrieved.
-            direct: Specifies if the direct super classes should be retrieved (True) or if the all super classes
-                (ancestors) classes should be retrieved (False).
-            only_named: Whether to only retrieve named super classes or also complex class expressions.
-
-        Returns:
-            If direct is True, each class C where the set of reasoner axioms entails DirectSubClassOf(ce, C).
-            If direct is False, each class C where  set of reasoner axioms entails StrictSubClassOf(ce, C).
-            If ce is equivalent to owl:Thing then nothing will be returned.
-        """
-        pass
-class OWLReasonerEx(OWLReasoner, metaclass=ABCMeta):
-    """Extra convenience methods for OWL Reasoners"""
-
-    # default
-    def data_property_ranges(self, pe: OWLDataProperty, direct: bool = False) -> Iterable[OWLDataRange]:
-        """Gets the data ranges that are the direct or indirect ranges of this property with respect to the imports
-        closure of the root ontology.
-
-        Args:
-            pe: The property expression whose ranges are to be retrieved.
-            direct: Specifies if the direct ranges should be retrieved (True), or if all ranges should be retrieved
-                (False).
-
-        Returns:
-        """
-        for ax in self.get_root_ontology().data_property_range_axioms(pe):
-            yield ax.get_range()
-            if not direct:
-                logger.warning("indirect not implemented")
-                # TODO:
-
-    # default
-    def all_data_property_values(self, pe: OWLDataProperty, direct: bool = True) -> Iterable[OWLLiteral]:
-        """Gets all values for the given data property expression that appear in the knowledge base.
-
-        Args:
-            pe: The data property expression whose values are to be retrieved
-            direct: Specifies if only the direct values of the data property pe should be retrieved (True), or if
-                    the values of sub properties of pe should be taken into account (False).
-
-        Returns:
-            A set of OWLLiterals containing literals such that for each literal l in the set, the set of reasoner
-            axioms entails DataPropertyAssertion(pe ind l) for any ind.
-        """
-        onto = self.get_root_ontology()
-        for ind in onto.individuals_in_signature():
-            for lit in self.data_property_values(ind, pe, direct):
-                yield lit
-
-    # default
-    def ind_data_properties(self, ind: OWLNamedIndividual, direct: bool = True) -> Iterable[OWLDataProperty]:
-        """Gets all data properties for the given individual that appear in the knowledge base.
-
-        Args:
-            ind: The named individual whose data properties are to be retrieved
-            direct: Specifies if the direct data properties should be retrieved (True), or if all
-                data properties should be retrieved (False), so that sub properties are taken into account.
+from owlapy.class_expression import OWLClass
+from owlapy.iri import IRI
+from owlapy.owl_axiom import OWLAxiom, 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 Ontology, _parse_concept_to_owlapy, SyncOntology
+from owlapy.abstracts.abstract_owl_ontology import OWLOntology
+from owlapy.owl_ontology_manager import SyncOntologyManager
+from owlapy.owl_property import OWLObjectPropertyExpression, OWLDataProperty, OWLObjectProperty, OWLObjectInverseOf, \
+    OWLPropertyExpression, OWLDataPropertyExpression
+from owlapy.owl_individual import OWLNamedIndividual
+from owlapy.owl_literal import OWLLiteral
+from owlapy.utils import LRUCache
+from owlapy.abstracts.abstract_owl_reasoner import OWLReasoner, OWLReasonerEx
 
-        Returns:
-            All data properties pe where the set of reasoner axioms entails DataPropertyAssertion(pe ind l)
-            for atleast one l.
-        """
-        onto = self.get_root_ontology()
-        for dp in onto.data_properties_in_signature():
-            try:
-                next(iter(self.data_property_values(ind, dp, direct)))
-                yield dp
-            except StopIteration:
-                pass
-
-    # default
-    def ind_object_properties(self, ind: OWLNamedIndividual, direct: bool = True) -> Iterable[OWLObjectProperty]:
-        """Gets all object properties for the given individual that appear in the knowledge base.
+logger = logging.getLogger(__name__)
 
-        Args:
-            ind: The named individual whose object properties are to be retrieved
-            direct: Specifies if the direct object properties should be retrieved (True), or if all
-                object properties should be retrieved (False), so that sub properties are taken into account.
+_P = TypeVar('_P', bound=OWLPropertyExpression)
 
-        Returns:
-            All data properties pe where the set of reasoner axioms entails ObjectPropertyAssertion(pe ind ind2)
-            for atleast one ind2.
-        """
-        onto = self.get_root_ontology()
-        for op in onto.object_properties_in_signature():
-            try:
-                next(iter(self.object_property_values(ind, op, direct)))
-                yield op
-            except StopIteration:
-                pass
 
 class OntologyReasoner(OWLReasonerEx):
     __slots__ = '_ontology', '_world'
@@ -1598,86 +1147,519 @@ def _retrieve_triples(self, pe: OWLPropertyExpression) -> Iterable:
 
 class SyncReasoner(OWLReasonerEx):
 
-    def __init__(self, ontology_path: str, reasoner="HermiT"):
+    def __init__(self, ontology: Union[SyncOntology, str], reasoner="HermiT"):
         """
         OWL reasoner that syncs to other reasoners like HermiT,Pellet,etc.
 
         Args:
-            ontology_path: Path of ontology that should be used by the reasoner.
-            reasoner: Choose from (case-sensitive): ["HermiT", "Pellet", "JFact", "Openllet"]. Default: "HermiT".
+            ontology(SyncOntology): Ontology that will be used by this reasoner.
+            reasoner: Name of the reasoner. Possible values (case-sensitive): ["HermiT", "Pellet", "JFact", "Openllet",
+             "Structural"].
+                Default: "HermiT".
         """
-        self.manager = OntologyManager()
-        self.ontology = self.manager.load_ontology(IRI.create("file://" + ontology_path))
-        super().__init__(self.ontology)
-        self.adaptor = OWLAPIAdaptor(ontology_path, reasoner)
+        assert reasoner in ["HermiT", "Pellet", "JFact", "Openllet", "Structural"], \
+            (f"'{reasoner}' is not implemented. Available reasoners: ['HermiT', 'Pellet', 'JFact', 'Openllet', "
+             f"'Structural']. "
+             f"This field is case sensitive.")
+        if isinstance(ontology, SyncOntology):
+            self.manager = ontology.manager
+            self.ontology = ontology
+        elif isinstance(ontology, str):
+            self.manager = SyncOntologyManager()
+            self.ontology = self.manager.load_ontology(ontology)
+
+        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")
 
-    def instances(self, ce: OWLClassExpression, direct: bool = False) -> Iterable[OWLNamedIndividual]:
-        yield from self.adaptor.instances(ce, direct)
+    def instances(self, ce: OWLClassExpression, direct=False) -> List[OWLNamedIndividual]:
+        """
+        Get the instances for a given class expression using HermiT.
 
-    def data_property_domains(self, pe: OWLDataProperty, direct: bool = False) -> Iterable[OWLClassExpression]:
-        yield from self.adaptor.data_property_domains(pe, direct)
+        Args:
+            ce (OWLClassExpression): The class expression in OWLAPY format.
+            direct (bool): Whether to get direct instances or not. Defaults to False.
 
-    def object_property_domains(self, pe: OWLObjectProperty, direct: bool = False) -> Iterable[OWLClassExpression]:
-        yield from self.adaptor.object_property_domains(pe, direct)
+        Returns:
+            list: A list of individuals classified by the given class expression.
+        """
+        inds = self._owlapi_reasoner.getInstances(self.mapper.map_(ce), direct).getFlattened()
+        return [self.mapper.map_(ind) for ind in inds]
 
-    def object_property_ranges(self, pe: OWLObjectProperty, direct: bool = False) -> Iterable[OWLClassExpression]:
-        yield from self.adaptor.object_property_ranges(pe, direct)
+    def equivalent_classes(self, ce: OWLClassExpression) -> List[OWLClassExpression]:
+        """
+        Gets the set of named classes that are equivalent to the specified class expression with
+        respect to the set of reasoner axioms.
 
-    def equivalent_classes(self, ce: OWLClassExpression, only_named: bool = True) -> Iterable[OWLClassExpression]:
-        yield from self.adaptor.equivalent_classes(ce)
+        Args:
+            ce (OWLClassExpression): The class expression whose equivalent classes are to be retrieved.
 
-    def disjoint_classes(self, ce: OWLClassExpression, only_named: bool = True) -> Iterable[OWLClassExpression]:
-        yield from self.adaptor.disjoint_classes(ce)
+        Returns:
+            Equivalent classes of the given class expression.
+        """
+        classes = self._owlapi_reasoner.getEquivalentClasses(self.mapper.map_(ce)).getEntities()
+        yield from [self.mapper.map_(cls) for cls in classes]
 
-    def different_individuals(self, ind: OWLNamedIndividual) -> Iterable[OWLNamedIndividual]:
-        yield from self.adaptor.different_individuals(ind)
+    def disjoint_classes(self, ce: OWLClassExpression) -> List[OWLClassExpression]:
+        """
+        Gets the classes that are disjoint with the specified class expression.
 
-    def same_individuals(self, ind: OWLNamedIndividual) -> Iterable[OWLNamedIndividual]:
-        yield from self.adaptor.same_individuals(ind)
+        Args:
+            ce (OWLClassExpression): The class expression whose disjoint classes are to be retrieved.
 
-    def data_property_values(self, e: OWLEntity, pe: OWLDataProperty, direct: bool = True) -> Iterable[OWLLiteral]:
-        yield from self.adaptor.data_property_values(e, pe)
+        Returns:
+            Disjoint classes of the given class expression.
+        """
+        classes = self._owlapi_reasoner.getDisjointClasses(self.mapper.map_(ce)).getFlattened()
+        yield from [self.mapper.map_(cls) for cls in classes]
 
-    def object_property_values(self, ind: OWLNamedIndividual, pe: OWLObjectPropertyExpression, direct: bool = False) -> \
-            Iterable[OWLNamedIndividual]:
-        yield from self.adaptor.object_property_values(ind, pe)
+    def sub_classes(self, ce: OWLClassExpression, direct=False) -> List[OWLClassExpression]:
+        """
+         Gets the set of named classes that are the strict (potentially direct) subclasses of the
+         specified class expression with respect to the reasoner axioms.
 
-    def sub_classes(self, ce: OWLClassExpression, direct: bool = False, only_named: bool = True) -> Iterable[
-        OWLClassExpression]:
-        yield from self.adaptor.sub_classes(ce, direct)
+         Args:
+             ce (OWLClassExpression): The class expression whose strict (direct) subclasses are to be retrieved.
+             direct (bool, optional): Specifies if the direct subclasses should be retrieved (True) or if
+                all subclasses (descendant) classes should be retrieved (False). Defaults to False.
+        Returns:
+            The subclasses of the given class expression depending on `direct` field.
+        """
+        classes = self._owlapi_reasoner.getSubClasses(self.mapper.map_(ce), direct).getFlattened()
+        yield from [self.mapper.map_(cls) for cls in classes]
 
-    def super_classes(self, ce: OWLClassExpression, direct: bool = False, only_named: bool = True) -> Iterable[
-        OWLClassExpression]:
-        yield from self.adaptor.super_classes(ce, direct)
+    def super_classes(self, ce: OWLClassExpression, direct=False) -> List[OWLClassExpression]:
+        """
+        Gets the stream of named classes that are the strict (potentially direct) super classes of
+        the specified class expression with respect to the imports closure of the root ontology.
 
-    def equivalent_object_properties(self, op: OWLObjectPropertyExpression) -> Iterable[OWLObjectPropertyExpression]:
-        yield from self.adaptor.equivalent_object_properties(op)
+        Args:
+             ce (OWLClassExpression): The class expression whose strict (direct) subclasses are to be retrieved.
+             direct (bool, optional): Specifies if the direct superclasses should be retrieved (True) or if
+                all superclasses (descendant) classes should be retrieved (False). Defaults to False.
 
-    def equivalent_data_properties(self, dp: OWLDataProperty) -> Iterable[OWLDataProperty]:
-        yield from self.adaptor.equivalent_data_properties(dp)
+        Returns:
+            The subclasses of the given class expression depending on `direct` field.
+        """
+        classes = self._owlapi_reasoner.getSuperClasses(self.mapper.map_(ce), direct).getFlattened()
+        yield from [self.mapper.map_(cls) for cls in classes]
 
-    def disjoint_object_properties(self, op: OWLObjectPropertyExpression) -> Iterable[OWLObjectPropertyExpression]:
-        yield from self.adaptor.disjoint_object_properties(op)
+    def data_property_domains(self, p: OWLDataProperty, direct: bool = False):
+        """Gets the class expressions that are the direct or indirect domains of this property with respect to the
+           imports closure of the root ontology.
 
-    def disjoint_data_properties(self, dp: OWLDataProperty) -> Iterable[OWLDataProperty]:
-        yield from self.adaptor.disjoint_data_properties(dp)
+        Args:
+            p: The property expression whose domains are to be retrieved.
+            direct: Specifies if the direct domains should be retrieved (True), or if all domains should be retrieved
+                (False).
 
-    def super_data_properties(self, dp: OWLDataProperty, direct: bool = False) -> Iterable[OWLDataProperty]:
-        yield from self.adaptor.super_data_properties(dp, direct)
+        Returns:
+            :Let N = equivalent_classes(DataSomeValuesFrom(pe rdfs:Literal)). If direct is True: then if N is not
+            empty then the return value is N, else the return value is the result of
+            super_classes(DataSomeValuesFrom(pe rdfs:Literal), true). If direct is False: then the result of
+            super_classes(DataSomeValuesFrom(pe rdfs:Literal), false) together with N if N is non-empty.
+            (Note, rdfs:Literal is the top datatype).
+        """
+        yield from [self.mapper.map_(ce) for ce in
+                    self._owlapi_reasoner.getDataPropertyDomains(self.mapper.map_(p), direct).getFlattened()]
 
-    def sub_data_properties(self, dp: OWLDataProperty, direct: bool = False) -> Iterable[OWLDataProperty]:
-        yield from self.adaptor.sub_data_properties(dp, direct)
+    def object_property_domains(self, p: OWLObjectProperty, direct: bool = False):
+        """Gets the class expressions that are the direct or indirect domains of this property with respect to the
+           imports closure of the root ontology.
+
+        Args:
+            p: The property expression whose domains are to be retrieved.
+            direct: Specifies if the direct domains should be retrieved (True), or if all domains should be retrieved
+                (False).
 
-    def super_object_properties(self, op: OWLObjectPropertyExpression, direct: bool = False) -> Iterable[
-        OWLObjectPropertyExpression]:
-        yield from self.adaptor.super_object_properties(op, direct)
+        Returns:
+            :Let N = equivalent_classes(ObjectSomeValuesFrom(pe owl:Thing)). If direct is True: then if N is not empty
+            then the return value is N, else the return value is the result of
+            super_classes(ObjectSomeValuesFrom(pe owl:Thing), true). If direct is False: then the result of
+            super_classes(ObjectSomeValuesFrom(pe owl:Thing), false) together with N if N is non-empty.
+        """
+        yield from [self.mapper.map_(ce) for ce in
+                    self._owlapi_reasoner.getObjectPropertyDomains(self.mapper.map_(p), direct).getFlattened()]
 
-    def sub_object_properties(self, op: OWLObjectPropertyExpression, direct: bool = False) -> Iterable[
-        OWLObjectPropertyExpression]:
-        yield from self.adaptor.sub_object_properties(op, direct)
+    def object_property_ranges(self, p: OWLObjectProperty, direct: bool = False):
+        """Gets the class expressions that are the direct or indirect ranges of this property with respect to the
+           imports closure of the root ontology.
 
-    def types(self, ind: OWLNamedIndividual, direct: bool = False) -> Iterable[OWLClass]:
-        yield from self.adaptor.types(ind, direct)
+        Args:
+            p: The property expression whose ranges are to be retrieved.
+            direct: Specifies if the direct ranges should be retrieved (True), or if all ranges should be retrieved
+                (False).
+
+        Returns:
+            :Let N = equivalent_classes(ObjectSomeValuesFrom(ObjectInverseOf(pe) owl:Thing)). If direct is True: then
+            if N is not empty then the return value is N, else the return value is the result of
+            super_classes(ObjectSomeValuesFrom(ObjectInverseOf(pe) owl:Thing), true). If direct is False: then
+            the result of super_classes(ObjectSomeValuesFrom(ObjectInverseOf(pe) owl:Thing), false) together with N
+            if N is non-empty.
+        """
+        yield from [self.mapper.map_(ce) for ce in
+                    self._owlapi_reasoner.getObjectPropertyRanges(self.mapper.map_(p), direct).getFlattened()]
+
+    def sub_object_properties(self, p: OWLObjectProperty, direct: bool = False):
+        """Gets the stream of simplified object property expressions that are the strict (potentially direct)
+        subproperties of the specified object property expression with respect to the imports closure of the root
+        ontology.
+
+        Args:
+            p: The object property expression whose strict (direct) subproperties are to be retrieved.
+            direct: Specifies if the direct subproperties should be retrieved (True) or if the all subproperties
+                (descendants) should be retrieved (False).
+
+        Returns:
+            If direct is True, simplified object property expressions, such that for each simplified object property
+            expression, P, the set of reasoner axioms entails DirectSubObjectPropertyOf(P, pe).
+            If direct is False, simplified object property expressions, such that for each simplified object property
+            expression, P, the set of reasoner axioms entails StrictSubObjectPropertyOf(P, pe).
+            If pe is equivalent to owl:bottomObjectProperty then nothing will be returned.
+        """
+        yield from [self.mapper.map_(pe) for pe in
+                    self._owlapi_reasoner.getSubObjectProperties(self.mapper.map_(p), direct).getFlattened()]
+
+    def super_object_properties(self, p: OWLObjectProperty, direct: bool = False):
+        """Gets the stream of object properties that are the strict (potentially direct) super properties of the
+         specified object property with respect to the imports closure of the root ontology.
+
+         Args:
+             p (OWLObjectPropertyExpression): The object property expression whose super properties are to be
+                                                retrieved.
+             direct (bool): Specifies if the direct super properties should be retrieved (True) or if the all
+                            super properties (ancestors) should be retrieved (False).
+
+         Returns:
+             Iterable of super properties.
+         """
+        yield from [self.mapper.map_(pe) for pe in
+                    self._owlapi_reasoner.getSuperObjectProperties(self.mapper.map_(p), direct).getFlattened()]
+
+    def sub_data_properties(self, p: OWLDataProperty, direct: bool = False):
+        """Gets the set of named data properties that are the strict (potentially direct) subproperties of the
+        specified data property expression with respect to the imports closure of the root ontology.
+
+        Args:
+            p: The data property whose strict (direct) subproperties are to be retrieved.
+            direct: Specifies if the direct subproperties should be retrieved (True) or if the all subproperties
+                (descendants) should be retrieved (False).
+
+        Returns:
+            If direct is True, each property P where the set of reasoner axioms entails DirectSubDataPropertyOf(P, pe).
+            If direct is False, each property P where the set of reasoner axioms entails
+            StrictSubDataPropertyOf(P, pe). If pe is equivalent to owl:bottomDataProperty then nothing will be
+            returned.
+        """
+        yield from [self.mapper.map_(pe) for pe in
+                    self._owlapi_reasoner.getSubDataProperties(self.mapper.map_(p), direct).getFlattened()]
+
+    def super_data_properties(self, p: OWLDataProperty, direct: bool = False):
+        """Gets the stream of data properties that are the strict (potentially direct) super properties of the
+         specified data property with respect to the imports closure of the root ontology.
+
+         Args:
+             p (OWLDataProperty): The data property whose super properties are to be retrieved.
+             direct (bool): Specifies if the direct super properties should be retrieved (True) or if the all
+                            super properties (ancestors) should be retrieved (False).
+
+         Returns:
+             Iterable of super properties.
+         """
+        yield from [self.mapper.map_(pe) for pe in
+                    self._owlapi_reasoner.getSuperDataProperties(self.mapper.map_(p), direct).getFlattened()]
+
+    def different_individuals(self, i: OWLNamedIndividual):
+        """Gets the individuals that are different from the specified individual with respect to the set of
+        reasoner axioms.
+
+        Args:
+            i: The individual whose different individuals are to be retrieved.
+
+        Returns:
+            All individuals x where the set of reasoner axioms entails DifferentIndividuals(ind x).
+        """
+        yield from [self.mapper.map_(ind) for ind in
+                    self._owlapi_reasoner.getDifferentIndividuals(self.mapper.map_(i)).getFlattened()]
+
+    def same_individuals(self, i: OWLNamedIndividual):
+        """Gets the individuals that are the same as the specified individual with respect to the set of
+        reasoner axioms.
+
+        Args:
+            i: The individual whose same individuals are to be retrieved.
+
+        Returns:
+            All individuals x where the root ontology imports closure entails SameIndividual(ind x).
+        """
+        yield from [self.mapper.map_(ind) for ind in
+                    self.mapper.to_list(self._owlapi_reasoner.sameIndividuals(self.mapper.map_(i)))]
+
+    def equivalent_object_properties(self, p: OWLObjectProperty):
+        """Gets the simplified object properties that are equivalent to the specified object property with respect
+        to the set of reasoner axioms.
+
+        Args:
+            p: The object property whose equivalent object properties are to be retrieved.
+
+        Returns:
+            All simplified object properties e where the root ontology imports closure entails
+            EquivalentObjectProperties(op e). If op is unsatisfiable with respect to the set of reasoner axioms
+            then owl:bottomDataProperty will be returned.
+        """
+        yield from [self.mapper.map_(pe) for pe in
+                    self.mapper.to_list(self._owlapi_reasoner.equivalentObjectProperties(self.mapper.map_(p)))]
+
+    def equivalent_data_properties(self, p: OWLDataProperty):
+        """Gets the data properties that are equivalent to the specified data property with respect to the set of
+        reasoner axioms.
+
+        Args:
+            p: The data property whose equivalent data properties are to be retrieved.
+
+        Returns:
+            All data properties e where the root ontology imports closure entails EquivalentDataProperties(dp e).
+            If dp is unsatisfiable with respect to the set of reasoner axioms then owl:bottomDataProperty will
+            be returned.
+        """
+        yield from [self.mapper.map_(pe) for pe in
+                    self.mapper.to_list(self._owlapi_reasoner.getEquivalentDataProperties(self.mapper.map_(p)))]
+
+    def object_property_values(self, i: OWLNamedIndividual, p: OWLObjectProperty):
+        """Gets the object property values for the specified individual and object property expression.
+
+        Args:
+            i: The individual that is the subject of the object property values.
+            p: The object property expression whose values are to be retrieved for the specified individual.
+
+        Returns:
+            The named individuals such that for each individual j, the set of reasoner axioms entails
+            ObjectPropertyAssertion(pe ind j).
+        """
+        yield from [self.mapper.map_(ind) for ind in
+                    self._owlapi_reasoner.getObjectPropertyValues(self.mapper.map_(i), self.mapper.map_(p)).getFlattened()]
+
+    def data_property_values(self, e: OWLEntity, p: OWLDataProperty):
+        """Gets the data property values for the specified entity and data property expression.
+
+        Args:
+            e: The entity (usually an individual) that is the subject of the data property values.
+            p: The data property expression whose values are to be retrieved for the specified individual.
+
+        Returns:
+            A set of OWLLiterals containing literals such that for each literal l in the set, the set of reasoner
+            axioms entails DataPropertyAssertion(pe ind l).
+        """
+        yield from [self.mapper.map_(literal) for literal in
+                    self.mapper.to_list(self._owlapi_reasoner.dataPropertyValues(self.mapper.map_(e), self.mapper.map_(p)))]
+
+    def disjoint_object_properties(self, p: OWLObjectProperty):
+        """Gets the simplified object properties that are disjoint with the specified object property with respect
+        to the set of reasoner axioms.
+
+        Args:
+            p: The object property whose disjoint object properties are to be retrieved.
+
+        Returns:
+            All simplified object properties e where the root ontology imports closure entails
+            EquivalentObjectProperties(e ObjectPropertyComplementOf(op)) or
+            StrictSubObjectPropertyOf(e ObjectPropertyComplementOf(op)).
+        """
+        yield from [self.mapper.map_(pe) for pe in
+                    self._owlapi_reasoner.getDisjointObjectProperties(self.mapper.map_(p)).getFlattened()]
+
+    def disjoint_data_properties(self, p: OWLDataProperty):
+        """Gets the data properties that are disjoint with the specified data property with respect
+        to the set of reasoner axioms.
+
+        Args:
+            p: The data property whose disjoint data properties are to be retrieved.
+
+        Returns:
+            All data properties e where the root ontology imports closure entails
+            EquivalentDataProperties(e DataPropertyComplementOf(dp)) or
+            StrictSubDataPropertyOf(e DataPropertyComplementOf(dp)).
+        """
+        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):
+        """Gets the named classes which are (potentially direct) types of the specified named individual.
+
+        Args:
+            i: 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).
+
+        Returns:
+            If direct is True, each named class C where the set of reasoner axioms entails
+            DirectClassAssertion(C, ind). If direct is False, each named class C where the set of reasoner axioms
+            entails ClassAssertion(C, ind).
+        """
+        yield from [self.mapper.map_(ind) for ind in
+                    self._owlapi_reasoner.getTypes(self.mapper.map_(i), direct).getFlattened()]
+
+    def has_consistent_ontology(self) -> bool:
+        """
+        Check if the used ontology is consistent.
+
+        Returns:
+            bool: True if the ontology used by this reasoner is consistent, False otherwise.
+        """
+        return self._owlapi_reasoner.isConsistent()
+
+    def infer_axioms(self, inference_types: list[str]) -> Iterable[OWLAxiom]:
+        """
+        Infer the specified inference type of axioms for the ontology managed by this instance's reasoner and
+        return them.
+
+        Args:
+            inference_types: Axiom inference types: Avaliable options (can set more than 1):
+             ["InferredClassAssertionAxiomGenerator", "InferredSubClassAxiomGenerator",
+             "InferredDisjointClassesAxiomGenerator", "InferredEquivalentClassAxiomGenerator",
+             "InferredEquivalentDataPropertiesAxiomGenerator","InferredEquivalentObjectPropertyAxiomGenerator",
+             "InferredInverseObjectPropertiesAxiomGenerator","InferredSubDataPropertyAxiomGenerator",
+             "InferredSubObjectPropertyAxiomGenerator","InferredDataPropertyCharacteristicAxiomGenerator",
+             "InferredObjectPropertyCharacteristicAxiomGenerator"
+             ]
+
+        Returns:
+            Iterable of inferred axioms.
+        """
+        from java.util import ArrayList
+        from org.semanticweb.owlapi.util import InferredOntologyGenerator
+
+        generators = ArrayList()
+        for i in inference_types:
+            if java_object := self.inference_types_mapping.get(i, None):
+                generators.add(java_object)
+        iog = InferredOntologyGenerator(self._owlapi_reasoner, generators)
+        inferred_axioms = list(iog.getAxiomGenerators())
+        for ia in inferred_axioms:
+            for axiom in ia.createAxioms(self._owlapi_manager.getOWLDataFactory(), self._owlapi_reasoner):
+                yield self.mapper.map_(axiom)
+
+    def infer_axioms_and_save(self, output_path: str = None, output_format: str = None, inference_types: list[str] = None):
+        """
+        Generates inferred axioms for the ontology managed by this instance's reasoner and saves them to a file.
+        This function uses the OWL API to generate inferred class assertion axioms based on the ontology and reasoner
+        associated with this instance. The inferred axioms are saved to the specified output file in the desired format.
+
+        Args:
+            output_path : The name of the file where the inferred axioms will be saved.
+            output_format : The format in which to save the inferred axioms. Supported formats are:
+                - "ttl" or "turtle" for Turtle format
+                - "rdf/xml" for RDF/XML format
+                - "owl/xml" for OWL/XML format
+                If not specified, the format of the original ontology is used.
+            inference_types: Axiom inference types: Avaliable options (can set more than 1):
+             ["InferredClassAssertionAxiomGenerator", "InferredSubClassAxiomGenerator",
+             "InferredDisjointClassesAxiomGenerator", "InferredEquivalentClassAxiomGenerator",
+             "InferredEquivalentDataPropertiesAxiomGenerator","InferredEquivalentObjectPropertyAxiomGenerator",
+             "InferredInverseObjectPropertiesAxiomGenerator","InferredSubDataPropertyAxiomGenerator",
+             "InferredSubObjectPropertyAxiomGenerator","InferredDataPropertyCharacteristicAxiomGenerator",
+             "InferredObjectPropertyCharacteristicAxiomGenerator"
+             ]
+
+        Returns:
+            None (the file is saved to the specified directory)
+        """
+        from java.io import File, FileOutputStream
+        from java.util import ArrayList
+        from org.semanticweb.owlapi.util import InferredOntologyGenerator
+        from org.semanticweb.owlapi.formats import TurtleDocumentFormat, RDFXMLDocumentFormat, OWLXMLDocumentFormat
+        if output_format == "ttl" or output_format == "turtle":
+            document_format = TurtleDocumentFormat()
+        elif output_format == "rdf/xml":
+            document_format = RDFXMLDocumentFormat()
+        elif output_format == "owl/xml":
+            document_format = OWLXMLDocumentFormat()
+        else:
+            document_format = self._owlapi_manager.getOntologyFormat(self._owlapi_ontology)
+        generators = ArrayList()
+
+        for i in inference_types:
+            if java_object := self.inference_types_mapping.get(i, None):
+                generators.add(java_object)
+        iog = InferredOntologyGenerator(self._owlapi_reasoner, generators)
+        inferred_axioms_ontology = self._owlapi_manager.createOntology()
+        iog.fillOntology(self._owlapi_manager.getOWLDataFactory(), inferred_axioms_ontology)
+        inferred_ontology_file = File(output_path).getAbsoluteFile()
+        output_stream = FileOutputStream(inferred_ontology_file)
+        self._owlapi_manager.saveOntology(inferred_axioms_ontology, document_format, output_stream)
+
+    def generate_and_save_inferred_class_assertion_axioms(self, output="temp.ttl", output_format: str = None):
+        """
+        Generates inferred class assertion axioms for the ontology managed by this instance's reasoner and saves them
+        to a file. This function uses the OWL API to generate inferred class assertion axioms based on the ontology
+        and reasoner associated with this instance. The inferred axioms are saved to the specified output file in
+        the desired format.
+        Parameters:
+        -----------
+        output : str, optional
+            The name of the file where the inferred axioms will be saved. Default is "temp.ttl".
+        output_format : str, optional
+            The format in which to save the inferred axioms. Supported formats are:
+            - "ttl" or "turtle" for Turtle format
+            - "rdf/xml" for RDF/XML format
+            - "owl/xml" for OWL/XML format
+            If not specified, the format of the original ontology is used.
+        Notes:
+        ------
+        - The function supports saving in multiple formats: Turtle, RDF/XML, and OWL/XML.
+        - The inferred axioms are generated using the reasoner associated with this instance and the OWL API's
+          InferredClassAssertionAxiomGenerator.
+        - The inferred axioms are added to a new ontology which is then saved in the specified format.
+        Example:
+        --------
+        >>> instance.generate_and_save_inferred_class_assertion_axioms(output="inferred_axioms.ttl", format="ttl")
+        This will save the inferred class assertion axioms to the file "inferred_axioms.ttl" in Turtle format.
+        """
+        self.infer_axioms_and_save(output, output_format, ["InferredClassAssertionAxiomGenerator"])
 
     def get_root_ontology(self) -> OWLOntology:
-        return self.ontology
\ No newline at end of file
+        return self.ontology
diff --git a/owlapy/owlapi_adaptor.py b/owlapy/owlapi_adaptor.py
deleted file mode 100644
index 856cef2b..00000000
--- a/owlapy/owlapi_adaptor.py
+++ /dev/null
@@ -1,584 +0,0 @@
-"""Owlapi Adaptor
-
-Part of the docstrings are taken directly from owlapi
-"""
-import jpype.imports
-import os
-import pkg_resources
-
-from owlapy.class_expression import OWLClassExpression
-from owlapy.owl_axiom import OWLAxiom
-from owlapy.owl_individual import OWLNamedIndividual
-from owlapy.owl_object import OWLEntity
-from owlapy.owl_property import OWLDataProperty, OWLObjectProperty
-from typing import List, Iterable
-
-
-def to_list(stream_obj):
-    """Converts Java Stream object to Python list"""
-    return stream_obj.collect(jpype.JClass("java.util.stream.Collectors").toList())
-
-
-class OWLAPIAdaptor:
-    """
-    A class to interface with the OWL API using the HermiT reasoner, enabling ontology management,
-    reasoning, and parsing class expressions in Manchester OWL Syntax.
-
-    Attributes:
-        path (str): The file path to the ontology.
-        name_reasoner (str): The reasoner to be used, default is "HermiT".
-        manager: The OWL ontology manager.
-        ontology: The loaded OWL ontology.
-        reasoner: Choose from (case-sensitive): ["HermiT", "Pellet", "JFact", "Openllet"]. Default: "HermiT".
-    """
-
-    def __init__(self, path: str, name_reasoner: str = "HermiT"):
-        """
-        Initialize the OWLAPIAdaptor with a path to an ontology and a reasoner name.
-
-        Args:
-            path (str): The file path to the ontology.
-            name_reasoner (str, optional): The reasoner to be used.
-                    Available options are: ['HermiT' (default), 'Pellet', 'JFact', 'Openllet'].
-
-        Raises:
-            AssertionError: If the provided reasoner name is not implemented.
-        """
-        self.path = path
-        assert name_reasoner in ["HermiT", "Pellet", "JFact", "Openllet"], \
-            (f"'{name_reasoner}' is not implemented. Available reasoners: ['HermiT', 'Pellet', 'JFact', 'Openllet']. "
-             f"This field is case sensitive.")
-        self.name_reasoner = name_reasoner
-        # Attributes are initialized as JVM is started
-        # () Manager is needed to load an ontology
-        self.manager = None
-        # () Load a local ontology using the manager
-        self.ontology = None
-        # () Create a reasoner for the loaded ontology
-        self.reasoner = None
-        # () For mapping entities/expressions from/to owlapi
-        self.mapper = None
-        # () Set up the necessary attributes by making use of the java packages
-        self._setup()
-
-    def _startJVM(self):
-        """Start the JVM with jar dependencies. This method is called automatically on object initialization, if the
-        JVM is not started yet."""
-        # Start a java virtual machine using the dependencies in the respective folder:
-        jar_folder = pkg_resources.resource_filename('owlapy', 'jar_dependencies')
-        jar_files = [os.path.join(jar_folder, f) for f in os.listdir(jar_folder) if f.endswith('.jar')]
-        # Starting JVM.
-        jpype.startJVM(classpath=jar_files)
-
-    def stopJVM(self, *args, **kwargs) -> None:
-        """Detaches the thread from Java packages and shuts down the java virtual machine hosted by jpype."""
-        if jpype.isJVMStarted():
-            jpype.detachThreadFromJVM()
-            jpype.shutdownJVM()
-
-    def _setup(self):
-        """
-        Start the JVM if not already, import necessary OWL API dependencies, and initialize attributes.
-        """
-        if not jpype.isJVMStarted():
-            self._startJVM()
-
-        # Imports
-        from owlapy.owlapi_mapper import OWLAPIMapper
-        from org.semanticweb.owlapi.apibinding import OWLManager
-        from java.io import File
-        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(),
-                                        }
-
-        if self.name_reasoner == "HermiT":
-            from org.semanticweb.HermiT import ReasonerFactory
-        elif self.name_reasoner == "Pellet":
-            from openllet.owlapi import PelletReasonerFactory
-        elif self.name_reasoner == "JFact":
-            from uk.ac.manchester.cs.jfact import JFactFactory
-        elif self.name_reasoner == "Openllet":
-            from openllet.owlapi import OpenlletReasonerFactory
-        else:
-            raise NotImplementedError("Not implemented")
-
-        # () Manager is needed to load an ontology
-        self.manager = OWLManager.createOWLOntologyManager()
-        # () Load a local ontology using the manager
-        self.ontology = self.manager.loadOntologyFromOntologyDocument(File(self.path))
-        self.mapper = OWLAPIMapper(self.ontology)
-
-        # () Create a reasoner for the loaded ontology
-        if self.name_reasoner == "HermiT":
-            self.reasoner = ReasonerFactory().createReasoner(self.ontology)
-            assert self.reasoner.getReasonerName() == "HermiT"
-        elif self.name_reasoner == "JFact":
-            self.reasoner = JFactFactory().createReasoner(self.ontology)
-        elif self.name_reasoner == "Pellet":
-            self.reasoner = PelletReasonerFactory().createReasoner(self.ontology)
-        elif self.name_reasoner == "Openllet":
-            self.reasoner = OpenlletReasonerFactory().getInstance().createReasoner(self.ontology)
-
-    def has_consistent_ontology(self) -> bool:
-        """
-        Check if the used ontology is consistent.
-
-        Returns:
-            bool: True if the ontology is consistent, False otherwise.
-        """
-        return self.reasoner.isConsistent()
-
-    def instances(self, ce: OWLClassExpression, direct=False) -> List[OWLNamedIndividual]:
-        """
-        Get the instances for a given class expression using HermiT.
-
-        Args:
-            ce (OWLClassExpression): The class expression in OWLAPY format.
-            direct (bool): Whether to get direct instances or not. Defaults to False.
-
-        Returns:
-            list: A list of individuals classified by the given class expression.
-        """
-        inds = self.reasoner.getInstances(self.mapper.map_(ce), direct).getFlattened()
-        return [self.mapper.map_(ind) for ind in inds]
-
-    def equivalent_classes(self, ce: OWLClassExpression) -> List[OWLClassExpression]:
-        """
-        Gets the set of named classes that are equivalent to the specified class expression with
-        respect to the set of reasoner axioms.
-
-        Args:
-            ce (OWLClassExpression): The class expression whose equivalent classes are to be retrieved.
-
-        Returns:
-            Equivalent classes of the given class expression.
-        """
-        classes = self.reasoner.getEquivalentClasses(self.mapper.map_(ce)).getEntities()
-        yield from [self.mapper.map_(cls) for cls in classes]
-
-    def disjoint_classes(self, ce: OWLClassExpression) -> List[OWLClassExpression]:
-        """
-        Gets the classes that are disjoint with the specified class expression.
-
-        Args:
-            ce (OWLClassExpression): The class expression whose disjoint classes are to be retrieved.
-
-        Returns:
-            Disjoint classes of the given class expression.
-        """
-        classes = self.reasoner.getDisjointClasses(self.mapper.map_(ce)).getFlattened()
-        yield from [self.mapper.map_(cls) for cls in classes]
-
-    def sub_classes(self, ce: OWLClassExpression, direct=False) -> List[OWLClassExpression]:
-        """
-         Gets the set of named classes that are the strict (potentially direct) subclasses of the
-         specified class expression with respect to the reasoner axioms.
-
-         Args:
-             ce (OWLClassExpression): The class expression whose strict (direct) subclasses are to be retrieved.
-             direct (bool, optional): Specifies if the direct subclasses should be retrieved (True) or if
-                all subclasses (descendant) classes should be retrieved (False). Defaults to False.
-        Returns:
-            The subclasses of the given class expression depending on `direct` field.
-        """
-        classes = self.reasoner.getSubClasses(self.mapper.map_(ce), direct).getFlattened()
-        yield from [self.mapper.map_(cls) for cls in classes]
-
-    def super_classes(self, ce: OWLClassExpression, direct=False) -> List[OWLClassExpression]:
-        """
-        Gets the stream of named classes that are the strict (potentially direct) super classes of
-        the specified class expression with respect to the imports closure of the root ontology.
-
-        Args:
-             ce (OWLClassExpression): The class expression whose strict (direct) subclasses are to be retrieved.
-             direct (bool, optional): Specifies if the direct superclasses should be retrieved (True) or if
-                all superclasses (descendant) classes should be retrieved (False). Defaults to False.
-
-        Returns:
-            The subclasses of the given class expression depending on `direct` field.
-        """
-        classes = self.reasoner.getSuperClasses(self.mapper.map_(ce), direct).getFlattened()
-        yield from [self.mapper.map_(cls) for cls in classes]
-
-    def data_property_domains(self, p: OWLDataProperty, direct: bool = False):
-        """Gets the class expressions that are the direct or indirect domains of this property with respect to the
-           imports closure of the root ontology.
-
-        Args:
-            p: The property expression whose domains are to be retrieved.
-            direct: Specifies if the direct domains should be retrieved (True), or if all domains should be retrieved
-                (False).
-
-        Returns:
-            :Let N = equivalent_classes(DataSomeValuesFrom(pe rdfs:Literal)). If direct is True: then if N is not
-            empty then the return value is N, else the return value is the result of
-            super_classes(DataSomeValuesFrom(pe rdfs:Literal), true). If direct is False: then the result of
-            super_classes(DataSomeValuesFrom(pe rdfs:Literal), false) together with N if N is non-empty.
-            (Note, rdfs:Literal is the top datatype).
-        """
-        yield from [self.mapper.map_(ce) for ce in
-                    self.reasoner.getDataPropertyDomains(self.mapper.map_(p), direct).getFlattened()]
-
-    def object_property_domains(self, p: OWLObjectProperty, direct: bool = False):
-        """Gets the class expressions that are the direct or indirect domains of this property with respect to the
-           imports closure of the root ontology.
-
-        Args:
-            p: The property expression whose domains are to be retrieved.
-            direct: Specifies if the direct domains should be retrieved (True), or if all domains should be retrieved
-                (False).
-
-        Returns:
-            :Let N = equivalent_classes(ObjectSomeValuesFrom(pe owl:Thing)). If direct is True: then if N is not empty
-            then the return value is N, else the return value is the result of
-            super_classes(ObjectSomeValuesFrom(pe owl:Thing), true). If direct is False: then the result of
-            super_classes(ObjectSomeValuesFrom(pe owl:Thing), false) together with N if N is non-empty.
-        """
-        yield from [self.mapper.map_(ce) for ce in
-                    self.reasoner.getObjectPropertyDomains(self.mapper.map_(p), direct).getFlattened()]
-
-    def object_property_ranges(self, p: OWLObjectProperty, direct: bool = False):
-        """Gets the class expressions that are the direct or indirect ranges of this property with respect to the
-           imports closure of the root ontology.
-
-        Args:
-            p: The property expression whose ranges are to be retrieved.
-            direct: Specifies if the direct ranges should be retrieved (True), or if all ranges should be retrieved
-                (False).
-
-        Returns:
-            :Let N = equivalent_classes(ObjectSomeValuesFrom(ObjectInverseOf(pe) owl:Thing)). If direct is True: then
-            if N is not empty then the return value is N, else the return value is the result of
-            super_classes(ObjectSomeValuesFrom(ObjectInverseOf(pe) owl:Thing), true). If direct is False: then
-            the result of super_classes(ObjectSomeValuesFrom(ObjectInverseOf(pe) owl:Thing), false) together with N
-            if N is non-empty.
-        """
-        yield from [self.mapper.map_(ce) for ce in
-                    self.reasoner.getObjectPropertyRanges(self.mapper.map_(p), direct).getFlattened()]
-
-    def sub_object_properties(self, p: OWLObjectProperty, direct: bool = False):
-        """Gets the stream of simplified object property expressions that are the strict (potentially direct)
-        subproperties of the specified object property expression with respect to the imports closure of the root
-        ontology.
-
-        Args:
-            p: The object property expression whose strict (direct) subproperties are to be retrieved.
-            direct: Specifies if the direct subproperties should be retrieved (True) or if the all subproperties
-                (descendants) should be retrieved (False).
-
-        Returns:
-            If direct is True, simplified object property expressions, such that for each simplified object property
-            expression, P, the set of reasoner axioms entails DirectSubObjectPropertyOf(P, pe).
-            If direct is False, simplified object property expressions, such that for each simplified object property
-            expression, P, the set of reasoner axioms entails StrictSubObjectPropertyOf(P, pe).
-            If pe is equivalent to owl:bottomObjectProperty then nothing will be returned.
-        """
-        yield from [self.mapper.map_(pe) for pe in
-                    self.reasoner.getSubObjectProperties(self.mapper.map_(p), direct).getFlattened()]
-
-    def super_object_properties(self, p: OWLObjectProperty, direct: bool = False):
-        """Gets the stream of object properties that are the strict (potentially direct) super properties of the
-         specified object property with respect to the imports closure of the root ontology.
-
-         Args:
-             p (OWLObjectPropertyExpression): The object property expression whose super properties are to be
-                                                retrieved.
-             direct (bool): Specifies if the direct super properties should be retrieved (True) or if the all
-                            super properties (ancestors) should be retrieved (False).
-
-         Returns:
-             Iterable of super properties.
-         """
-        yield from [self.mapper.map_(pe) for pe in
-                    self.reasoner.getSuperObjectProperties(self.mapper.map_(p), direct).getFlattened()]
-
-    def sub_data_properties(self, p: OWLDataProperty, direct: bool = False):
-        """Gets the set of named data properties that are the strict (potentially direct) subproperties of the
-        specified data property expression with respect to the imports closure of the root ontology.
-
-        Args:
-            p: The data property whose strict (direct) subproperties are to be retrieved.
-            direct: Specifies if the direct subproperties should be retrieved (True) or if the all subproperties
-                (descendants) should be retrieved (False).
-
-        Returns:
-            If direct is True, each property P where the set of reasoner axioms entails DirectSubDataPropertyOf(P, pe).
-            If direct is False, each property P where the set of reasoner axioms entails
-            StrictSubDataPropertyOf(P, pe). If pe is equivalent to owl:bottomDataProperty then nothing will be
-            returned.
-        """
-        yield from [self.mapper.map_(pe) for pe in
-                    self.reasoner.getSubDataProperties(self.mapper.map_(p), direct).getFlattened()]
-
-    def super_data_properties(self, p: OWLDataProperty, direct: bool = False):
-        """Gets the stream of data properties that are the strict (potentially direct) super properties of the
-         specified data property with respect to the imports closure of the root ontology.
-
-         Args:
-             p (OWLDataProperty): The data property whose super properties are to be retrieved.
-             direct (bool): Specifies if the direct super properties should be retrieved (True) or if the all
-                            super properties (ancestors) should be retrieved (False).
-
-         Returns:
-             Iterable of super properties.
-         """
-        yield from [self.mapper.map_(pe) for pe in
-                    self.reasoner.getSuperDataProperties(self.mapper.map_(p), direct).getFlattened()]
-
-    def different_individuals(self, i: OWLNamedIndividual):
-        """Gets the individuals that are different from the specified individual with respect to the set of
-        reasoner axioms.
-
-        Args:
-            i: The individual whose different individuals are to be retrieved.
-
-        Returns:
-            All individuals x where the set of reasoner axioms entails DifferentIndividuals(ind x).
-        """
-        yield from [self.mapper.map_(ind) for ind in
-                    self.reasoner.getDifferentIndividuals(self.mapper.map_(i)).getFlattened()]
-
-    def same_individuals(self, i: OWLNamedIndividual):
-        """Gets the individuals that are the same as the specified individual with respect to the set of
-        reasoner axioms.
-
-        Args:
-            i: The individual whose same individuals are to be retrieved.
-
-        Returns:
-            All individuals x where the root ontology imports closure entails SameIndividual(ind x).
-        """
-        yield from [self.mapper.map_(ind) for ind in
-                    to_list(self.reasoner.sameIndividuals(self.mapper.map_(i)))]
-
-    def equivalent_object_properties(self, p: OWLObjectProperty):
-        """Gets the simplified object properties that are equivalent to the specified object property with respect
-        to the set of reasoner axioms.
-
-        Args:
-            p: The object property whose equivalent object properties are to be retrieved.
-
-        Returns:
-            All simplified object properties e where the root ontology imports closure entails
-            EquivalentObjectProperties(op e). If op is unsatisfiable with respect to the set of reasoner axioms
-            then owl:bottomDataProperty will be returned.
-        """
-        yield from [self.mapper.map_(pe) for pe in
-                    to_list(self.reasoner.equivalentObjectProperties(self.mapper.map_(p)))]
-
-    def equivalent_data_properties(self, p: OWLDataProperty):
-        """Gets the data properties that are equivalent to the specified data property with respect to the set of
-        reasoner axioms.
-
-        Args:
-            p: The data property whose equivalent data properties are to be retrieved.
-
-        Returns:
-            All data properties e where the root ontology imports closure entails EquivalentDataProperties(dp e).
-            If dp is unsatisfiable with respect to the set of reasoner axioms then owl:bottomDataProperty will
-            be returned.
-        """
-        yield from [self.mapper.map_(pe) for pe in
-                    to_list(self.reasoner.getEquivalentDataProperties(self.mapper.map_(p)))]
-
-    def object_property_values(self, i: OWLNamedIndividual, p: OWLObjectProperty):
-        """Gets the object property values for the specified individual and object property expression.
-
-        Args:
-            i: The individual that is the subject of the object property values.
-            p: The object property expression whose values are to be retrieved for the specified individual.
-
-        Returns:
-            The named individuals such that for each individual j, the set of reasoner axioms entails
-            ObjectPropertyAssertion(pe ind j).
-        """
-        yield from [self.mapper.map_(ind) for ind in
-                    self.reasoner.getObjectPropertyValues(self.mapper.map_(i), self.mapper.map_(p)).getFlattened()]
-
-    def data_property_values(self, e: OWLEntity, p: OWLDataProperty):
-        """Gets the data property values for the specified entity and data property expression.
-
-        Args:
-            e: The entity (usually an individual) that is the subject of the data property values.
-            p: The data property expression whose values are to be retrieved for the specified individual.
-
-        Returns:
-            A set of OWLLiterals containing literals such that for each literal l in the set, the set of reasoner
-            axioms entails DataPropertyAssertion(pe ind l).
-        """
-        yield from [self.mapper.map_(literal) for literal in
-                    to_list(self.reasoner.dataPropertyValues(self.mapper.map_(e), self.mapper.map_(p)))]
-
-    def disjoint_object_properties(self, p: OWLObjectProperty):
-        """Gets the simplified object properties that are disjoint with the specified object property with respect
-        to the set of reasoner axioms.
-
-        Args:
-            p: The object property whose disjoint object properties are to be retrieved.
-
-        Returns:
-            All simplified object properties e where the root ontology imports closure entails
-            EquivalentObjectProperties(e ObjectPropertyComplementOf(op)) or
-            StrictSubObjectPropertyOf(e ObjectPropertyComplementOf(op)).
-        """
-        yield from [self.mapper.map_(pe) for pe in
-                    self.reasoner.getDisjointObjectProperties(self.mapper.map_(p)).getFlattened()]
-
-    def disjoint_data_properties(self, p: OWLDataProperty):
-        """Gets the data properties that are disjoint with the specified data property with respect
-        to the set of reasoner axioms.
-
-        Args:
-            p: The data property whose disjoint data properties are to be retrieved.
-
-        Returns:
-            All data properties e where the root ontology imports closure entails
-            EquivalentDataProperties(e DataPropertyComplementOf(dp)) or
-            StrictSubDataPropertyOf(e DataPropertyComplementOf(dp)).
-        """
-        yield from [self.mapper.map_(pe) for pe in
-                    self.reasoner.getDisjointDataProperties(self.mapper.map_(p)).getFlattened()]
-
-    def types(self, i: 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.
-            direct: Specifies if the direct types should be retrieved (True), or if all types should be retrieved
-                (False).
-
-        Returns:
-            If direct is True, each named class C where the set of reasoner axioms entails
-            DirectClassAssertion(C, ind). If direct is False, each named class C where the set of reasoner axioms
-            entails ClassAssertion(C, ind).
-        """
-        yield from [self.mapper.map_(ind) for ind in
-                    self.reasoner.getTypes(self.mapper.map_(i), direct).getFlattened()]
-
-    def infer_axioms(self, inference_types: list[str]) -> Iterable[OWLAxiom]:
-        """
-        Infer the specified inference type of axioms for the ontology managed by this instance's reasoner and
-        return them.
-
-        Args:
-            inference_types: Axiom inference types: Avaliable options (can set more than 1):
-             ["InferredClassAssertionAxiomGenerator", "InferredSubClassAxiomGenerator",
-             "InferredDisjointClassesAxiomGenerator", "InferredEquivalentClassAxiomGenerator",
-             "InferredEquivalentDataPropertiesAxiomGenerator","InferredEquivalentObjectPropertyAxiomGenerator",
-             "InferredInverseObjectPropertiesAxiomGenerator","InferredSubDataPropertyAxiomGenerator",
-             "InferredSubObjectPropertyAxiomGenerator","InferredDataPropertyCharacteristicAxiomGenerator",
-             "InferredObjectPropertyCharacteristicAxiomGenerator"
-             ]
-
-        Returns:
-            Iterable of inferred axioms.
-        """
-        from java.util import ArrayList
-        from org.semanticweb.owlapi.util import InferredOntologyGenerator
-
-        generators = ArrayList()
-        for i in inference_types:
-            if java_object := self.inference_types_mapping.get(i, None):
-                generators.add(java_object)
-        iog = InferredOntologyGenerator(self.reasoner, generators)
-        inferred_axioms = list(iog.getAxiomGenerators())
-        for ia in inferred_axioms:
-            for axiom in ia.createAxioms(self.manager.getOWLDataFactory(), self.reasoner):
-                yield self.mapper.map_(axiom)
-
-    def infer_axioms_and_save(self, output_path: str = None, output_format: str = None, inference_types: list[str] = None):
-        """
-        Generates inferred axioms for the ontology managed by this instance's reasoner and saves them to a file.
-        This function uses the OWL API to generate inferred class assertion axioms based on the ontology and reasoner
-        associated with this instance. The inferred axioms are saved to the specified output file in the desired format.
-
-        Args:
-            output_path : The name of the file where the inferred axioms will be saved.
-            output_format : The format in which to save the inferred axioms. Supported formats are:
-                - "ttl" or "turtle" for Turtle format
-                - "rdf/xml" for RDF/XML format
-                - "owl/xml" for OWL/XML format
-                If not specified, the format of the original ontology is used.
-            inference_types: Axiom inference types: Avaliable options (can set more than 1):
-             ["InferredClassAssertionAxiomGenerator", "InferredSubClassAxiomGenerator",
-             "InferredDisjointClassesAxiomGenerator", "InferredEquivalentClassAxiomGenerator",
-             "InferredEquivalentDataPropertiesAxiomGenerator","InferredEquivalentObjectPropertyAxiomGenerator",
-             "InferredInverseObjectPropertiesAxiomGenerator","InferredSubDataPropertyAxiomGenerator",
-             "InferredSubObjectPropertyAxiomGenerator","InferredDataPropertyCharacteristicAxiomGenerator",
-             "InferredObjectPropertyCharacteristicAxiomGenerator"
-             ]
-
-        Returns:
-            None (the file is saved to the specified directory)
-        """
-        from java.io import File, FileOutputStream
-        from java.util import ArrayList
-        from org.semanticweb.owlapi.util import InferredOntologyGenerator
-        from org.semanticweb.owlapi.formats import TurtleDocumentFormat, RDFXMLDocumentFormat, OWLXMLDocumentFormat
-        if output_format == "ttl" or output_format == "turtle":
-            document_format = TurtleDocumentFormat()
-        elif output_format == "rdf/xml":
-            document_format = RDFXMLDocumentFormat()
-        elif output_format == "owl/xml":
-            document_format = OWLXMLDocumentFormat()
-        else:
-            document_format = self.manager.getOntologyFormat(self.ontology)
-        generators = ArrayList()
-
-        for i in inference_types:
-            if java_object := self.inference_types_mapping.get(i, None):
-                generators.add(java_object)
-        iog = InferredOntologyGenerator(self.reasoner, generators)
-        inferred_axioms_ontology = self.manager.createOntology()
-        iog.fillOntology(self.manager.getOWLDataFactory(), inferred_axioms_ontology)
-        inferred_ontology_file = File(output_path).getAbsoluteFile()
-        output_stream = FileOutputStream(inferred_ontology_file)
-        self.manager.saveOntology(inferred_axioms_ontology, document_format, output_stream)
-
-    def generate_and_save_inferred_class_assertion_axioms(self, output="temp.ttl", output_format: str = None):
-        """
-        Generates inferred class assertion axioms for the ontology managed by this instance's reasoner and saves them to a file.
-        This function uses the OWL API to generate inferred class assertion axioms based on the ontology and reasoner
-        associated with this instance. The inferred axioms are saved to the specified output file in the desired format.
-        Parameters:
-        -----------
-        output : str, optional
-            The name of the file where the inferred axioms will be saved. Default is "temp.ttl".
-        output_format : str, optional
-            The format in which to save the inferred axioms. Supported formats are:
-            - "ttl" or "turtle" for Turtle format
-            - "rdf/xml" for RDF/XML format
-            - "owl/xml" for OWL/XML format
-            If not specified, the format of the original ontology is used.
-        Notes:
-        ------
-        - The function supports saving in multiple formats: Turtle, RDF/XML, and OWL/XML.
-        - The inferred axioms are generated using the reasoner associated with this instance and the OWL API's
-          InferredClassAssertionAxiomGenerator.
-        - The inferred axioms are added to a new ontology which is then saved in the specified format.
-        Example:
-        --------
-        >>> instance.generate_inferred_class_assertion_axioms(output="inferred_axioms.ttl", format="ttl")
-        This will save the inferred class assertion axioms to the file "inferred_axioms.ttl" in Turtle format.
-        """
-        self.infer_axioms_and_save(output, output_format, ["InferredClassAssertionAxiomGenerator"])
diff --git a/owlapy/owlapi_mapper.py b/owlapy/owlapi_mapper.py
index 9e2ec046..efbd9ac8 100644
--- a/owlapy/owlapi_mapper.py
+++ b/owlapy/owlapi_mapper.py
@@ -1,9 +1,7 @@
 from functools import singledispatchmethod
-from typing import Iterable
-
+from typing import Iterable, TypeVar
 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
@@ -23,62 +21,62 @@
 from owlapy.owl_datatype import OWLDatatype
 from owlapy.owl_individual import OWLNamedIndividual
 from owlapy.owl_literal import OWLLiteral
+from owlapy.owl_ontology import OWLOntologyID
 from owlapy.owl_property import OWLObjectProperty, OWLDataProperty
+from owlapy.static_funcs import startJVM
 from owlapy.vocab import OWLFacet
 
-if jpype.isJVMStarted():
-    from org.semanticweb.owlapi.model import IRI as owlapi_IRI
-    from org.semanticweb.owlapi.vocab import OWLFacet as owlapi_OWLFacet
-    from org.semanticweb.owlapi.manchestersyntax.parser import ManchesterOWLSyntaxClassExpressionParser
-    from org.semanticweb.owlapi.manchestersyntax.renderer import ManchesterOWLSyntaxOWLObjectRendererImpl
-    from org.semanticweb.owlapi.util import BidirectionalShortFormProviderAdapter, SimpleShortFormProvider
-    from org.semanticweb.owlapi.expression import ShortFormEntityChecker
-    from java.util import HashSet, ArrayList, List, Set
-    from java.util.stream import Stream
-    from uk.ac.manchester.cs.owl.owlapi import (OWLAnonymousClassExpressionImpl, OWLCardinalityRestrictionImpl,
-                                                OWLClassExpressionImpl, OWLClassImpl, OWLDataAllValuesFromImpl,
-                                                OWLDataCardinalityRestrictionImpl, OWLDataExactCardinalityImpl,
-                                                OWLDataHasValueImpl, OWLDataMaxCardinalityImpl, OWLDataUnionOfImpl,
-                                                OWLDataMinCardinalityImpl, OWLDataSomeValuesFromImpl,
-                                                OWLNaryBooleanClassExpressionImpl, OWLObjectAllValuesFromImpl,
-                                                OWLObjectCardinalityRestrictionImpl, OWLObjectComplementOfImpl,
-                                                OWLObjectExactCardinalityImpl, OWLObjectHasSelfImpl,
-                                                OWLObjectHasValueImpl, OWLObjectIntersectionOfImpl,
-                                                OWLObjectMaxCardinalityImpl, OWLObjectMinCardinalityImpl,
-                                                OWLObjectOneOfImpl, OWLObjectSomeValuesFromImpl, OWLNaryDataRangeImpl,
-                                                OWLObjectUnionOfImpl, OWLQuantifiedDataRestrictionImpl,
-                                                OWLQuantifiedObjectRestrictionImpl, OWLQuantifiedRestrictionImpl,
-                                                OWLValueRestrictionImpl, OWLLiteralImplBoolean, OWLLiteralImplString,
-                                                OWLLiteralImplDouble, OWLLiteralImplFloat, OWLLiteralImplInteger,
-                                                OWLDisjointClassesAxiomImpl, OWLDeclarationAxiomImpl, OWLAnnotationImpl,
-                                                OWLAnnotationPropertyImpl, OWLClassAssertionAxiomImpl,
-                                                OWLDataPropertyAssertionAxiomImpl, OWLDataPropertyDomainAxiomImpl,
-                                                OWLDataPropertyRangeAxiomImpl, OWLEquivalentClassesAxiomImpl,
-                                                OWLEquivalentDataPropertiesAxiomImpl, OWLDataIntersectionOfImpl,
-                                                OWLEquivalentObjectPropertiesAxiomImpl, OWLDataOneOfImpl,
-                                                OWLObjectPropertyDomainAxiomImpl, OWLObjectPropertyRangeAxiomImpl,
-                                                OWLObjectPropertyAssertionAxiomImpl, OWLDisjointDataPropertiesAxiomImpl,
-                                                OWLDisjointObjectPropertiesAxiomImpl, OWLHasKeyAxiomImpl,
-                                                OWLSubClassOfAxiomImpl, OWLSubDataPropertyOfAxiomImpl,
-                                                OWLSubObjectPropertyOfAxiomImpl, OWLAsymmetricObjectPropertyAxiomImpl,
-                                                OWLDatatypeDefinitionAxiomImpl, OWLDatatypeImpl, OWLObjectPropertyImpl,
-                                                OWLDataPropertyImpl, OWLNamedIndividualImpl, OWLDisjointUnionAxiomImpl,
-                                                OWLDifferentIndividualsAxiomImpl, OWLFunctionalDataPropertyAxiomImpl,
-                                                OWLFunctionalObjectPropertyAxiomImpl, OWLSameIndividualAxiomImpl,
-                                                OWLInverseFunctionalObjectPropertyAxiomImpl, OWLDataComplementOfImpl,
-                                                OWLInverseObjectPropertiesAxiomImpl,OWLReflexiveObjectPropertyAxiomImpl,
-                                                OWLIrreflexiveObjectPropertyAxiomImpl, OWLAnnotationAssertionAxiomImpl,
-                                                OWLNegativeDataPropertyAssertionAxiomImpl, OWLFacetRestrictionImpl,
-                                                OWLNegativeObjectPropertyAssertionAxiomImpl, OWLDatatypeRestrictionImpl,
-                                                OWLSymmetricObjectPropertyAxiomImpl,
-                                                OWLTransitiveObjectPropertyAxiomImpl,
-                                                OWLAnnotationPropertyDomainAxiomImpl,
-                                                OWLAnnotationPropertyRangeAxiomImpl,
-                                                OWLSubAnnotationPropertyOfAxiomImpl
-                                                )
-
-else:
-    raise ImportError("Jpype JVM is not started! Tip: Import OWLAPIMapper after JVM has started")
+if not jpype.isJVMStarted():
+    startJVM()
+from org.semanticweb.owlapi.model import IRI as owlapi_IRI, OWLOntologyID as owlapi_OWLOntologyID
+from org.semanticweb.owlapi.vocab import OWLFacet as owlapi_OWLFacet
+from org.semanticweb.owlapi.manchestersyntax.parser import ManchesterOWLSyntaxClassExpressionParser
+from org.semanticweb.owlapi.manchestersyntax.renderer import ManchesterOWLSyntaxOWLObjectRendererImpl
+from org.semanticweb.owlapi.util import BidirectionalShortFormProviderAdapter, SimpleShortFormProvider
+from org.semanticweb.owlapi.expression import ShortFormEntityChecker
+from java.util import HashSet, ArrayList, List, Set, LinkedHashSet, Optional
+from java.util.stream import Stream
+from uk.ac.manchester.cs.owl.owlapi import (OWLAnonymousClassExpressionImpl, OWLCardinalityRestrictionImpl,
+                                            OWLClassExpressionImpl, OWLClassImpl, OWLDataAllValuesFromImpl,
+                                            OWLDataCardinalityRestrictionImpl, OWLDataExactCardinalityImpl,
+                                            OWLDataHasValueImpl, OWLDataMaxCardinalityImpl, OWLDataUnionOfImpl,
+                                            OWLDataMinCardinalityImpl, OWLDataSomeValuesFromImpl,
+                                            OWLNaryBooleanClassExpressionImpl, OWLObjectAllValuesFromImpl,
+                                            OWLObjectCardinalityRestrictionImpl, OWLObjectComplementOfImpl,
+                                            OWLObjectExactCardinalityImpl, OWLObjectHasSelfImpl,
+                                            OWLObjectHasValueImpl, OWLObjectIntersectionOfImpl,
+                                            OWLObjectMaxCardinalityImpl, OWLObjectMinCardinalityImpl,
+                                            OWLObjectOneOfImpl, OWLObjectSomeValuesFromImpl, OWLNaryDataRangeImpl,
+                                            OWLObjectUnionOfImpl, OWLQuantifiedDataRestrictionImpl,
+                                            OWLQuantifiedObjectRestrictionImpl, OWLQuantifiedRestrictionImpl,
+                                            OWLValueRestrictionImpl, OWLLiteralImplBoolean, OWLLiteralImplString,
+                                            OWLLiteralImplDouble, OWLLiteralImplFloat, OWLLiteralImplInteger,
+                                            OWLDisjointClassesAxiomImpl, OWLDeclarationAxiomImpl, OWLAnnotationImpl,
+                                            OWLAnnotationPropertyImpl, OWLClassAssertionAxiomImpl,
+                                            OWLDataPropertyAssertionAxiomImpl, OWLDataPropertyDomainAxiomImpl,
+                                            OWLDataPropertyRangeAxiomImpl, OWLEquivalentClassesAxiomImpl,
+                                            OWLEquivalentDataPropertiesAxiomImpl, OWLDataIntersectionOfImpl,
+                                            OWLEquivalentObjectPropertiesAxiomImpl, OWLDataOneOfImpl,
+                                            OWLObjectPropertyDomainAxiomImpl, OWLObjectPropertyRangeAxiomImpl,
+                                            OWLObjectPropertyAssertionAxiomImpl, OWLDisjointDataPropertiesAxiomImpl,
+                                            OWLDisjointObjectPropertiesAxiomImpl, OWLHasKeyAxiomImpl,
+                                            OWLSubClassOfAxiomImpl, OWLSubDataPropertyOfAxiomImpl,
+                                            OWLSubObjectPropertyOfAxiomImpl, OWLAsymmetricObjectPropertyAxiomImpl,
+                                            OWLDatatypeDefinitionAxiomImpl, OWLDatatypeImpl, OWLObjectPropertyImpl,
+                                            OWLDataPropertyImpl, OWLNamedIndividualImpl, OWLDisjointUnionAxiomImpl,
+                                            OWLDifferentIndividualsAxiomImpl, OWLFunctionalDataPropertyAxiomImpl,
+                                            OWLFunctionalObjectPropertyAxiomImpl, OWLSameIndividualAxiomImpl,
+                                            OWLInverseFunctionalObjectPropertyAxiomImpl, OWLDataComplementOfImpl,
+                                            OWLInverseObjectPropertiesAxiomImpl,OWLReflexiveObjectPropertyAxiomImpl,
+                                            OWLIrreflexiveObjectPropertyAxiomImpl, OWLAnnotationAssertionAxiomImpl,
+                                            OWLNegativeDataPropertyAssertionAxiomImpl, OWLFacetRestrictionImpl,
+                                            OWLNegativeObjectPropertyAssertionAxiomImpl, OWLDatatypeRestrictionImpl,
+                                            OWLSymmetricObjectPropertyAxiomImpl,
+                                            OWLTransitiveObjectPropertyAxiomImpl,
+                                            OWLAnnotationPropertyDomainAxiomImpl,
+                                            OWLAnnotationPropertyRangeAxiomImpl,
+                                            OWLSubAnnotationPropertyOfAxiomImpl
+                                            )
 
 
 def init(the_class):
@@ -89,16 +87,16 @@ def init(the_class):
         return globals().get(cls_name + "Impl")
 
 
+_SO = TypeVar('_SO', bound='SyncOntology')  # noqa: F821
+
+
 class OWLAPIMapper:
 
-    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()
+    def __init__(self, ontology: _SO):
+        self.manager = ontology.manager.get_owlapi_manager()
+        self.ontology = ontology.get_owlapi_ontology()
 
-        # () Get the name space.
+        # () Get the name space. (used for rendering class expressions)
         self.namespace = self.ontology.getOntologyID().getOntologyIRI().orElse(None)
         if self.namespace is not None:
             self.namespace = str(self.namespace)
@@ -107,7 +105,7 @@ def __init__(self, ontology=None):
         else:
             self.namespace = "http://www.anonymous.org/anonymous#"
 
-        # () Create a manchester parser and a renderer.
+        # () Create a manchester parser and a renderer using the given ontology.
         ontology_set = HashSet()
         ontology_set.add(self.ontology)
         bidi_provider = BidirectionalShortFormProviderAdapter(self.manager, ontology_set, SimpleShortFormProvider())
@@ -466,8 +464,32 @@ def _(self, e):
         return OWLInverseObjectPropertiesAxiom(self.map_(e.getFirstProperty()), self.map_(e.getSecondProperty()),
                                                self.map_(e.annotationsAsList()))
 
+    @map_.register(OWLOntologyID)
+    def _(self, e):
+        if e.get_ontology_iri():
+            i1 = self.map_(e.get_ontology_iri())
+        else:
+            i1 = None
+        if e.get_version_iri():
+            i2 = self.map_(e.get_version_iri())
+        else:
+            i2 = None
+        return owlapi_OWLOntologyID(i1, i2)
+
+    @map_.register(owlapi_OWLOntologyID)
+    def _(self, e):
+        return OWLOntologyID(self.map_(e.getOntologyIRI()), self.map_(e.getVersionIRI()))
+
+    @map_.register(Optional)
+    def _(self, e):
+        if bool(e.isPresent()):
+            return self.map_(e.get())
+        else:
+            return None
+
     @map_.register(List)
     @map_.register(Set)
+    @map_.register(LinkedHashSet)
     def _(self, e):
         python_list = list()
         casted_list = list(e)
@@ -484,3 +506,8 @@ def _(self, e):
             for item in e:
                 java_list.add(self.map_(item))
         return java_list
+
+    @staticmethod
+    def to_list(stream_obj):
+        """Converts Java Stream object to Python list"""
+        return stream_obj.collect(jpype.JClass("java.util.stream.Collectors").toList())
diff --git a/owlapy/providers.py b/owlapy/providers.py
index d0d99c78..d9390089 100644
--- a/owlapy/providers.py
+++ b/owlapy/providers.py
@@ -39,7 +39,7 @@ def owl_datatype_min_max_exclusive_restriction(min_: Restriction_Literals,
         max_ = float(max_)
     if isinstance(max_, float) and isinstance(min_, int):
         min_ = float(min_)
-    assert type(min_) == type(max_)
+    assert type(min_) is type(max_)
 
     r_min = OWLFacetRestriction(OWLFacet.MIN_EXCLUSIVE, min_)
     r_max = OWLFacetRestriction(OWLFacet.MAX_EXCLUSIVE, max_)
@@ -54,7 +54,7 @@ def owl_datatype_min_max_inclusive_restriction(min_: Restriction_Literals,
         max_ = float(max_)
     if isinstance(max_, float) and isinstance(min_, int):
         min_ = float(min_)
-    assert type(min_) == type(max_)
+    assert type(min_) is type(max_)
 
     r_min = OWLFacetRestriction(OWLFacet.MIN_INCLUSIVE, min_)
     r_max = OWLFacetRestriction(OWLFacet.MAX_INCLUSIVE, max_)
diff --git a/owlapy/render.py b/owlapy/render.py
index a8bb5a8e..0e30bb6d 100644
--- a/owlapy/render.py
+++ b/owlapy/render.py
@@ -7,10 +7,10 @@
 
 from owlapy import namespaces
 from .iri import IRI
-from .owl_individual import OWLNamedIndividual, OWLIndividual
+from .owl_individual import OWLNamedIndividual
 from .owl_literal import OWLLiteral
 from .owl_object import OWLObjectRenderer, OWLEntity, OWLObject
-from .owl_property import OWLObjectInverseOf, OWLPropertyExpression, OWLDataProperty, OWLObjectProperty
+from .owl_property import OWLObjectInverseOf, OWLPropertyExpression, OWLDataProperty
 from .class_expression import OWLClassExpression, OWLBooleanClassExpression, OWLClass, OWLObjectSomeValuesFrom, \
     OWLObjectAllValuesFrom, OWLObjectUnionOf, OWLObjectIntersectionOf, OWLObjectComplementOf, OWLObjectMinCardinality, \
     OWLObjectExactCardinality, OWLObjectMaxCardinality, OWLObjectHasSelf, OWLDataSomeValuesFrom, OWLDataAllValuesFrom, \
@@ -20,8 +20,7 @@
 from .owl_data_ranges import OWLNaryDataRange, OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf
 from .class_expression import OWLObjectHasValue, OWLFacetRestriction, OWLDatatypeRestriction, OWLObjectOneOf
 from .owl_datatype import OWLDatatype
-from .owl_reasoner import OWLReasoner
-from typing import Union, Tuple
+from .abstracts.abstract_owl_reasoner import OWLReasoner
 import requests
 import warnings
 import abc
diff --git a/owlapy/static_funcs.py b/owlapy/static_funcs.py
index 4fd0a764..228aa050 100644
--- a/owlapy/static_funcs.py
+++ b/owlapy/static_funcs.py
@@ -3,6 +3,9 @@
 import subprocess
 import platform
 import shutil
+import jpype
+import jpype.imports
+import pkg_resources
 
 # NOTE: Static functions closely related with owl classes should be placed in utils.py not here
 
@@ -37,3 +40,20 @@ def download_external_files(ftp_link: str):
             subprocess.run(['unzip', file_name])
         os.remove(os.path.join(os.getcwd(), file_name))
         shutil.move(current_dir, root_dir)
+
+
+def startJVM():
+    """Start the JVM with jar dependencies. This method is called automatically on object initialization, if the
+    JVM is not started yet."""
+    # Start a java virtual machine using the dependencies in the respective folder:
+    jar_folder = pkg_resources.resource_filename('owlapy', 'jar_dependencies')
+    jar_files = [os.path.join(jar_folder, f) for f in os.listdir(jar_folder) if f.endswith('.jar')]
+    # Starting JVM
+    jpype.startJVM(classpath=jar_files)
+
+
+def stopJVM() -> None:
+    """Detaches the thread from Java packages and shuts down the java virtual machine hosted by jpype."""
+    if jpype.isJVMStarted():
+        jpype.detachThreadFromJVM()
+        jpype.shutdownJVM()
diff --git a/owlapy/utils.py b/owlapy/utils.py
index 945da589..6a81a8fc 100644
--- a/owlapy/utils.py
+++ b/owlapy/utils.py
@@ -14,12 +14,66 @@
     OWLDataAllValuesFrom, OWLDataSomeValuesFrom, OWLObjectAllValuesFrom, \
     OWLDataOneOf, OWLObjectIntersectionOf, \
     OWLDataCardinalityRestriction, OWLNaryBooleanClassExpression, OWLObjectUnionOf, \
-    OWLObjectHasValue, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectOneOf
+    OWLObjectHasValue, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectOneOf, OWLQuantifiedObjectRestriction
 from .owl_data_ranges import OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf, OWLNaryDataRange, OWLDataRange, \
     OWLPropertyRange
 from .owl_object import OWLObject
 from .owl_datatype import OWLDatatype
 
+def concept_reducer(concepts:Iterable, opt:Callable):
+    """
+    Reduces a set of concepts by applying a binary operation to each pair of concepts.
+
+    Args:
+        concepts (set): A set of concepts to be reduced.
+        opt (function): A binary function that takes a pair of concepts and returns a single concept.
+
+    Returns:
+        set: A set containing the results of applying the binary operation to each pair of concepts.
+
+    Example:
+        >>> concepts = {1, 2, 3}
+        >>> opt = lambda x: x[0] + x[1]
+        >>> concept_reducer(concepts, opt)
+        {2, 3, 4, 5, 6}
+
+    Note:
+        The operation `opt` should be commutative and associative to ensure meaningful reduction in the context of set operations.
+    """
+    result = set()
+    for i in concepts:
+        for j in concepts:
+            result.add(opt((i, j)))
+    return result
+
+def concept_reducer_properties(
+        concepts: Iterable, properties, cls: Callable = None, cardinality: int = 2
+) -> Iterable[Union[OWLQuantifiedObjectRestriction, OWLObjectCardinalityRestriction]]:
+    """
+    Map a set of owl concepts and a set of properties into OWL Restrictions
+
+    Args:
+        concepts:
+        properties:
+        cls (Callable): An owl Restriction class
+        cardinality: A positive Integer
+
+    Returns: List of OWL Restrictions
+
+    """
+    assert isinstance(concepts, Iterable), "Concepts must be an Iterable"
+    assert isinstance(properties, Iterable), "properties must be an Iterable"
+    assert isinstance(cls, Callable), "cls must be an Callable"
+    assert cardinality > 0
+    result = set()
+    for i in concepts:
+        for j in properties:
+            if cls == OWLObjectMinCardinality or cls == OWLObjectMaxCardinality:
+                result.add(cls(cardinality=cardinality, property=j, filler=i))
+                continue
+            result.add(cls(j, i))
+    return result
+
 
 class OWLClassExpressionLengthMetric:
     """Length calculation of OWLClassExpression
diff --git a/setup.py b/setup.py
index 80b77624..b04bd1b3 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@
 setup(
     name="owlapy",
     description="OWLAPY is a Python Framework for creating and manipulating OWL Ontologies.",
-    version="1.2.1",
+    version="1.3.0",
     packages=find_packages(),
     include_package_data=True,
     package_data={


Test patch:
diff --git a/tests/test_owlapi_adaptor.py b/tests/test_owlapi_adaptor.py
index 5f6c1975..e69de29b 100644
--- a/tests/test_owlapi_adaptor.py
+++ b/tests/test_owlapi_adaptor.py
@@ -1,124 +0,0 @@
-import os
-import unittest
-
-from jpype import JDouble
-
-from owlapy.class_expression import OWLClass, OWLDataSomeValuesFrom, OWLObjectIntersectionOf
-from owlapy.iri import IRI
-from owlapy.owl_axiom import OWLDisjointClassesAxiom, OWLDeclarationAxiom, OWLClassAssertionAxiom
-from owlapy.owl_individual import OWLNamedIndividual
-from owlapy.owl_ontology_manager import OntologyManager
-from owlapy.owl_property import OWLDataProperty
-from owlapy.owlapi_adaptor import OWLAPIAdaptor
-from owlapy.providers import owl_datatype_min_inclusive_restriction
-
-from owlapy.class_expression import OWLClassExpression
-from owlapy.owl_ontology_manager import OntologyManager
-from owlapy.owlapi_adaptor import OWLAPIAdaptor
-
-
-class TestOwlapiAdaptor(unittest.TestCase):
-    ns = "http://dl-learner.org/mutagenesis#"
-    ontology_path = "KGs/Mutagenesis/mutagenesis.owl"
-    nitrogen38 = OWLClass(IRI.create(ns, "Nitrogen-38"))
-    charge = OWLDataProperty(IRI.create(ns, "charge"))
-    has_charge_more_than_0_85 = OWLDataSomeValuesFrom(charge, owl_datatype_min_inclusive_restriction(0.85))
-    ce = OWLObjectIntersectionOf([nitrogen38, has_charge_more_than_0_85])
-    adaptor = OWLAPIAdaptor(ontology_path)
-
-    def test_named_concepts(self):
-
-        ontology_path = "KGs/Family/family-benchmark_rich_background.owl"
-
-        # Available OWL Reasoners: 'HermiT', 'Pellet', 'JFact', 'Openllet'
-        owl_reasoners = dict()
-        owl_reasoners["HermiT"] = OWLAPIAdaptor(path=ontology_path, name_reasoner="HermiT")
-        owl_reasoners["Pellet"] = OWLAPIAdaptor(path=ontology_path, name_reasoner="Pellet")
-        owl_reasoners["JFact"] = OWLAPIAdaptor(path=ontology_path, name_reasoner="JFact")
-        owl_reasoners["Openllet"] = OWLAPIAdaptor(path=ontology_path, name_reasoner="Openllet")
-
-        onto = OntologyManager().load_ontology(ontology_path)
-
-        def compute_agreements(i: OWLClassExpression, verbose=False):
-            if verbose:
-                print(f"Computing agreements between Reasoners on {i}...")
-            retrieval_result = None
-            flag = False
-            for k, reasoner in owl_reasoners.items():
-                if retrieval_result:
-                    flag = retrieval_result == {_.str for _ in reasoner.instances(i)}
-                else:
-                    retrieval_result = {_.str for _ in reasoner.instances(i)}
-            return flag
-        # Agreement between instances over
-        for i in onto.classes_in_signature():
-            assert compute_agreements(i, True)
-        for k, reasoner in owl_reasoners.items():
-            reasoner.stopJVM()
-
-    def test_consistency_check(self):
-        self.assertEqual(self.adaptor.has_consistent_ontology(), True)
-
-    def test_inconsistency_check(self):
-        manager = OntologyManager()
-        onto = manager.load_ontology(IRI.create(self.ontology_path))
-
-        carbon230 = OWLClass(IRI.create(self.ns, "Carbon-230"))
-        axiom = OWLDisjointClassesAxiom([self.nitrogen38, carbon230])
-        manager.add_axiom(onto, axiom)
-        new_individual = OWLNamedIndividual(IRI.create(self.ns, "testIndividual"))
-        manager.add_axiom(onto, OWLDeclarationAxiom(new_individual))
-        manager.add_axiom(onto, OWLClassAssertionAxiom(new_individual, self.nitrogen38))
-        manager.add_axiom(onto, OWLClassAssertionAxiom(new_individual, carbon230))
-
-        manager.save_ontology(onto, IRI.create("file:/test.owl"))
-        adaptor1 = OWLAPIAdaptor("test.owl")
-        self.assertEqual(adaptor1.has_consistent_ontology(), False)
-        os.remove("test.owl")
-
-    def test_instances_retrieval(self):
-        instances = self.adaptor.instances(self.ce)
-        expected = [OWLNamedIndividual(IRI('http://dl-learner.org/mutagenesis#', 'd141_10')),
-                    OWLNamedIndividual(IRI('http://dl-learner.org/mutagenesis#', 'd195_12')),
-                    OWLNamedIndividual(IRI('http://dl-learner.org/mutagenesis#', 'd144_10')),
-                    OWLNamedIndividual(IRI('http://dl-learner.org/mutagenesis#', 'd147_11')),
-                    OWLNamedIndividual(IRI('http://dl-learner.org/mutagenesis#', 'e18_9')),
-                    OWLNamedIndividual(IRI('http://dl-learner.org/mutagenesis#', 'd175_17')),
-                    OWLNamedIndividual(IRI('http://dl-learner.org/mutagenesis#', 'e16_9'))]
-        # Assert equal without considering the order
-        for instance in instances:
-            self.assertIn(instance, expected)
-        self.assertEqual(len(list(instances)), len(expected))
-
-    def test_conversion(self):
-        # construct the class expression in owlapi
-        from org.semanticweb.owlapi.model import IRI as IRIowlapi, OWLClass, OWLObjectProperty
-        from org.semanticweb.owlapi.vocab import OWLFacet
-
-        nitrogenIRI = IRIowlapi.create(self.ns + "Nitrogen-38")
-        charge_iri = IRIowlapi.create(self.ns + "charge")
-
-        data_factory = self.adaptor.manager.getOWLDataFactory()
-        nitrogen_class = data_factory.getOWLClass(nitrogenIRI)
-
-        charge_property = data_factory.getOWLDataProperty(charge_iri)
-        double_datatype = data_factory.getDoubleOWLDatatype()
-        facet_restriction = data_factory.getOWLFacetRestriction(OWLFacet.MIN_INCLUSIVE, JDouble(0.85))
-        datatype_restriction = data_factory.getOWLDatatypeRestriction(double_datatype, facet_restriction)
-        some_values_from = data_factory.getOWLDataSomeValuesFrom(charge_property, datatype_restriction)
-
-        class_expression = data_factory.getOWLObjectIntersectionOf(nitrogen_class, some_values_from)
-
-        # compare them with the adaptor converted expression
-        ce_converted = self.adaptor.mapper.map_(self.ce)
-        print(ce_converted)
-        print(class_expression)
-        self.assertEqual(class_expression, ce_converted)
-
-        # convert back to owlapy and check for equality
-        ce_1 = self.adaptor.mapper.map_(class_expression)
-        ce_2 = self.adaptor.mapper.map_(ce_converted)
-
-        self.assertEqual(ce_1, ce_2)
-        self.assertEqual(ce_1, self.ce)
-        self.assertEqual(ce_2, self.ce)
diff --git a/tests/test_owlapy_fastinstancechecker.py b/tests/test_owlapy_fastinstancechecker.py
index 48fd6647..ea0e061b 100644
--- a/tests/test_owlapy_fastinstancechecker.py
+++ b/tests/test_owlapy_fastinstancechecker.py
@@ -9,17 +9,15 @@
 from owlapy.owl_axiom import OWLSubDataPropertyOfAxiom, OWLInverseObjectPropertiesAxiom, OWLSubObjectPropertyOfAxiom
 from owlapy.owl_data_ranges import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf
 from owlapy.owl_individual import OWLNamedIndividual
-from owlapy.owl_literal import DoubleOWLDatatype, OWLLiteral, DurationOWLDatatype
+from owlapy.owl_literal import DoubleOWLDatatype, OWLLiteral
 from owlapy.owl_ontology_manager import OntologyManager
 from owlapy.owl_property import OWLObjectInverseOf, OWLObjectProperty, OWLDataProperty
 from owlready2.prop import DataProperty
-from pandas import Timedelta
 
 from owlapy.owl_reasoner import FastInstanceCheckerReasoner, OntologyReasoner
 
-from owlapy.providers import owl_datatype_min_exclusive_restriction, \
-                            owl_datatype_min_max_inclusive_restriction, owl_datatype_min_max_exclusive_restriction, \
-                            owl_datatype_max_exclusive_restriction, owl_datatype_max_inclusive_restriction
+from owlapy.providers import owl_datatype_min_max_inclusive_restriction, owl_datatype_min_max_exclusive_restriction, \
+                             owl_datatype_max_inclusive_restriction
 
 
 class Owlapy_FastInstanceChecker_Test(unittest.TestCase):
@@ -241,78 +239,62 @@ def test_data_properties(self):
                                  OWLNamedIndividual(IRI(NS, 'd180'))})
         self.assertEqual(inst, target_inst)
 
-    # def test_data_properties_time(self):
-    #     NS = "http://example.com/father#"
-    #     mgr = OWLOntologyManager_Owlready2()
-    #     onto = mgr.load_ontology(IRI.create("file://KGs/Family/father.owl"))
-    #
-    #     with onto._onto:
-    #         class birthDate(DataProperty):
-    #             range = [date]
-    #
-    #         class birthDateTime(DataProperty):
-    #             range = [datetime]
-    #
-    #         class age(DataProperty):
-    #             range = [Timedelta]
-    #
-    #     onto._onto.markus.birthDate = [date(year=1990, month=10, day=2)]
-    #     onto._onto.markus.birthDateTime = [datetime(year=1990, month=10, day=2, hour=10, minute=20, second=5)]
-    #     onto._onto.markus.age = [Timedelta(days=11315, hours=10, minutes=2)]
-    #
-    #     onto._onto.anna.birthDate = [date(year=1995, month=6, day=10)]
-    #     onto._onto.anna.birthDateTime = [datetime(year=1995, month=6, day=10, hour=2, minute=10)]
-    #     onto._onto.anna.age = [Timedelta(days=9490, hours=4)]
-    #
-    #     onto._onto.heinz.birthDate = [date(year=1986, month=6, day=10)]
-    #     onto._onto.heinz.birthDateTime = [datetime(year=1986, month=6, day=10, hour=10, second=10)]
-    #     onto._onto.heinz.age = [Timedelta(days=12775, hours=14, seconds=40)]
-    #
-    #     onto._onto.michelle.birthDate = [date(year=2000, month=1, day=4)]
-    #     onto._onto.michelle.birthDateTime = [datetime(year=2000, month=1, day=4, minute=4, second=10)]
-    #     onto._onto.michelle.age = [Timedelta(days=7665, hours=1, milliseconds=11)]
-    #
-    #     onto._onto.martin.birthDate = [date(year=1999, month=3, day=1)]
-    #     onto._onto.martin.birthDateTime = [datetime(year=1999, month=3, day=2, hour=20, minute=2, second=30)]
-    #     onto._onto.martin.age = [Timedelta(days=8030, minutes=2)]
-    #
-    #     birth_date = OWLDataProperty(IRI(NS, 'birthDate'))
-    #     birth_date_time = OWLDataProperty(IRI(NS, 'birthDateTime'))
-    #     age_ = OWLDataProperty(IRI(NS, 'age'))
-    #     markus = OWLNamedIndividual(IRI(NS, 'markus'))
-    #     anna = OWLNamedIndividual(IRI(NS, 'anna'))
-    #     heinz = OWLNamedIndividual(IRI(NS, 'heinz'))
-    #     michelle = OWLNamedIndividual(IRI(NS, 'michelle'))
-    #     martin = OWLNamedIndividual(IRI(NS, 'martin'))
-    #
-    #     base_reasoner = OWLReasoner_Owlready2(onto)
-    #     reasoner = OWLReasoner_FastInstanceChecker(onto, base_reasoner=base_reasoner)
-    #
-    #     restriction = owl_datatype_min_max_exclusive_restriction(date(year=1995, month=6, day=12),
-    #                                                         date(year=1999, month=3, day=2))
-    #     inst = frozenset(reasoner.instances(OWLDataSomeValuesFrom(property=birth_date,
-    #                                                               filler=restriction)))
-    #     target_inst = frozenset({martin})
-    #     self.assertEqual(inst, target_inst)
-    #
-    #     inst = frozenset(reasoner.instances(OWLDataSomeValuesFrom(property=birth_date,
-    #                                                               filler=OWLDataComplementOf(restriction))))
-    #     target_inst = frozenset({michelle, anna, heinz, markus})
-    #     self.assertEqual(inst, target_inst)
-    #
-    #     restriction = owl_datatype_max_inclusive_restriction(datetime(year=1990, month=10, day=2, hour=10,
-    #                                                               minute=20, second=5))
-    #     inst = frozenset(reasoner.instances(OWLDataSomeValuesFrom(property=birth_date_time,
-    #                                                               filler=restriction)))
-    #     target_inst = frozenset({markus, heinz})
-    #     self.assertEqual(inst, target_inst)
-    #
-    #     restriction_min = owl_datatype_min_exclusive_restriction(Timedelta(days=8030, minutes=1))
-    #     restriction_max = owl_datatype_max_exclusive_restriction(Timedelta(days=9490, hours=4, nanoseconds=1))
-    #     filler = OWLDataIntersectionOf([restriction_min, restriction_max, DurationOWLDatatype])
-    #     inst = frozenset(reasoner.instances(OWLDataSomeValuesFrom(property=age_, filler=filler)))
-    #     target_inst = frozenset({anna, martin})
-    #     self.assertEqual(inst, target_inst)
+    def test_data_properties_time(self):
+        NS = "http://example.com/father#"
+        mgr = OntologyManager()
+        onto = mgr.load_ontology(IRI.create("file://KGs/Family/father.owl"))
+
+        with onto._onto:
+            class birthDate(DataProperty):
+                range = [date]
+
+            class birthDateTime(DataProperty):
+                range = [datetime]
+
+        onto._onto.markus.birthDate = [date(year=1990, month=10, day=2)]
+        onto._onto.markus.birthDateTime = [datetime(year=1990, month=10, day=2, hour=10, minute=20, second=5)]
+
+        onto._onto.anna.birthDate = [date(year=1995, month=6, day=10)]
+        onto._onto.anna.birthDateTime = [datetime(year=1995, month=6, day=10, hour=2, minute=10)]
+
+        onto._onto.heinz.birthDate = [date(year=1986, month=6, day=10)]
+        onto._onto.heinz.birthDateTime = [datetime(year=1986, month=6, day=10, hour=10, second=10)]
+
+        onto._onto.michelle.birthDate = [date(year=2000, month=1, day=4)]
+        onto._onto.michelle.birthDateTime = [datetime(year=2000, month=1, day=4, minute=4, second=10)]
+
+        onto._onto.martin.birthDate = [date(year=1999, month=3, day=1)]
+        onto._onto.martin.birthDateTime = [datetime(year=1999, month=3, day=2, hour=20, minute=2, second=30)]
+
+        birth_date = OWLDataProperty(IRI(NS, 'birthDate'))
+        birth_date_time = OWLDataProperty(IRI(NS, 'birthDateTime'))
+        markus = OWLNamedIndividual(IRI(NS, 'markus'))
+        anna = OWLNamedIndividual(IRI(NS, 'anna'))
+        heinz = OWLNamedIndividual(IRI(NS, 'heinz'))
+        michelle = OWLNamedIndividual(IRI(NS, 'michelle'))
+        martin = OWLNamedIndividual(IRI(NS, 'martin'))
+
+        base_reasoner = OntologyReasoner(onto)
+        reasoner = FastInstanceCheckerReasoner(onto, base_reasoner=base_reasoner)
+
+        restriction = owl_datatype_min_max_exclusive_restriction(date(year=1995, month=6, day=12),
+                                                            date(year=1999, month=3, day=2))
+        inst = frozenset(reasoner.instances(OWLDataSomeValuesFrom(property=birth_date,
+                                                                  filler=restriction)))
+        target_inst = frozenset({martin})
+        self.assertEqual(inst, target_inst)
+
+        inst = frozenset(reasoner.instances(OWLDataSomeValuesFrom(property=birth_date,
+                                                                  filler=OWLDataComplementOf(restriction))))
+        target_inst = frozenset({michelle, anna, heinz, markus})
+        self.assertEqual(inst, target_inst)
+
+        restriction = owl_datatype_max_inclusive_restriction(datetime(year=1990, month=10, day=2, hour=10,
+                                                                  minute=20, second=5))
+        inst = frozenset(reasoner.instances(OWLDataSomeValuesFrom(property=birth_date_time,
+                                                                  filler=restriction)))
+        target_inst = frozenset({markus, heinz})
+        self.assertEqual(inst, target_inst)
 
     def test_sub_property_inclusion(self):
         ns = "http://dl-learner.org/mutagenesis#"
@@ -326,8 +308,8 @@ def test_sub_property_inclusion(self):
         super_has_structure = OWLObjectProperty(IRI(ns, 'superHasStucture'))
         charge = OWLDataProperty(IRI(ns, 'charge'))
         super_charge = OWLDataProperty(IRI.create(ns, 'super_charge'))
-        mgr.add_axiom(onto, OWLSubObjectPropertyOfAxiom(has_structure, super_has_structure))
-        mgr.add_axiom(onto, OWLSubDataPropertyOfAxiom(charge, super_charge))
+        onto.add_axiom(OWLSubObjectPropertyOfAxiom(has_structure, super_has_structure))
+        onto.add_axiom(OWLSubDataPropertyOfAxiom(charge, super_charge))
 
         # sub_property = True
         base_reasoner = OntologyReasoner(onto)
@@ -357,8 +339,8 @@ def test_sub_property_inclusion(self):
         individuals = frozenset(reasoner.instances(ce))
         self.assertEqual(len(individuals), 0)
 
-        mgr.remove_axiom(onto, OWLSubObjectPropertyOfAxiom(has_structure, super_has_structure))
-        mgr.remove_axiom(onto, OWLSubDataPropertyOfAxiom(charge, super_charge))
+        onto.remove_axiom(OWLSubObjectPropertyOfAxiom(has_structure, super_has_structure))
+        onto.remove_axiom(OWLSubDataPropertyOfAxiom(charge, super_charge))
 
     def test_inverse(self):
         ns = "http://example.com/father#"
@@ -367,7 +349,7 @@ def test_inverse(self):
 
         has_child = OWLObjectProperty(IRI(ns, 'hasChild'))
         has_child_inverse = OWLObjectProperty(IRI.create(ns, 'hasChild_inverse'))
-        mgr.add_axiom(onto, OWLInverseObjectPropertiesAxiom(has_child, has_child_inverse))
+        onto.add_axiom(OWLInverseObjectPropertiesAxiom(has_child, has_child_inverse))
 
         parents = {OWLNamedIndividual(IRI.create(ns, 'anna')),
                    OWLNamedIndividual(IRI.create(ns, 'martin')),
@@ -384,13 +366,13 @@ def test_inverse(self):
         self.assertEqual(parents_expr, parents)
         self.assertEqual(parents_expr_inverse, parents)
         # Removal not needed, just for completeness
-        mgr.remove_axiom(onto, OWLInverseObjectPropertiesAxiom(has_child, has_child_inverse))
+        onto.remove_axiom(OWLInverseObjectPropertiesAxiom(has_child, has_child_inverse))
 
         # test sub properties
         super_has_child = OWLObjectProperty(IRI(ns, 'super_hasChild'))
-        mgr.add_axiom(onto, OWLSubObjectPropertyOfAxiom(has_child, super_has_child))
+        onto.add_axiom(OWLSubObjectPropertyOfAxiom(has_child, super_has_child))
         super_has_child_inverse = OWLObjectProperty(IRI(ns, 'super_hasChild_inverse'))
-        mgr.add_axiom(onto, OWLInverseObjectPropertiesAxiom(super_has_child, super_has_child_inverse))
+        onto.add_axiom(OWLInverseObjectPropertiesAxiom(super_has_child, super_has_child_inverse))
 
         # False (sub properties not taken into account)
         expr = OWLObjectSomeValuesFrom(super_has_child, OWLThing)
@@ -409,8 +391,8 @@ def test_inverse(self):
         self.assertEqual(parents_expr, parents)
         self.assertEqual(parents_expr_inverse, parents)
 
-        mgr.remove_axiom(onto, OWLSubObjectPropertyOfAxiom(has_child, super_has_child))
-        mgr.remove_axiom(onto, OWLInverseObjectPropertiesAxiom(super_has_child, super_has_child_inverse))
+        onto.remove_axiom(OWLSubObjectPropertyOfAxiom(has_child, super_has_child))
+        onto.remove_axiom(OWLInverseObjectPropertiesAxiom(super_has_child, super_has_child_inverse))
 
 
 if __name__ == '__main__':
diff --git a/tests/test_owlapy_ontology_management.py b/tests/test_owlapy_ontology_management.py
index fefbf0c4..96a3ed9f 100644
--- a/tests/test_owlapy_ontology_management.py
+++ b/tests/test_owlapy_ontology_management.py
@@ -45,9 +45,9 @@ def test_equivalent_classes(self):
         compound = OWLClass(IRI(ns, 'Compound'))
         has_atom = OWLObjectProperty(IRI(ns, 'hasAtom'))
 
-        mgr.add_axiom(onto, OWLEquivalentClassesAxiom([OWLObjectUnionOf([atom, bond]), compound, atom, bond]))
-        mgr.add_axiom(onto, OWLEquivalentClassesAxiom([bond, benzene]))
-        mgr.add_axiom(onto, OWLEquivalentClassesAxiom([bond, OWLObjectSomeValuesFrom(has_atom, ball3)]))
+        onto.add_axiom(OWLEquivalentClassesAxiom([OWLObjectUnionOf([atom, bond]), compound, atom, bond]))
+        onto.add_axiom(OWLEquivalentClassesAxiom([bond, benzene]))
+        onto.add_axiom(OWLEquivalentClassesAxiom([bond, OWLObjectSomeValuesFrom(has_atom, ball3)]))
 
         classes = frozenset({atom, compound, bond})
         target_classes = frozenset(reasoner.equivalent_classes(benzene, only_named=True))
@@ -87,9 +87,9 @@ def test_sub_classes(self):
         benzene = OWLClass(IRI(ns, 'Benzene'))
         has_atom = OWLObjectProperty(IRI(ns, 'hasAtom'))
 
-        mgr.add_axiom(onto, OWLSubClassOfAxiom(benzene, OWLObjectUnionOf([bond, bond])))
-        mgr.add_axiom(onto, OWLSubClassOfAxiom(OWLObjectUnionOf([bond, bond]), ball3))
-        mgr.add_axiom(onto, OWLSubClassOfAxiom(ball3, OWLObjectSomeValuesFrom(has_atom, ball3)))
+        onto.add_axiom(OWLSubClassOfAxiom(benzene, OWLObjectUnionOf([bond, bond])))
+        onto.add_axiom(OWLSubClassOfAxiom(OWLObjectUnionOf([bond, bond]), ball3))
+        onto.add_axiom(OWLSubClassOfAxiom(ball3, OWLObjectSomeValuesFrom(has_atom, ball3)))
 
         # Named class
         # Direct, only named
@@ -149,9 +149,9 @@ def test_super_classes(self):
         ring_structure = OWLClass(IRI(ns, 'RingStructure'))
         has_atom = OWLObjectProperty(IRI(ns, 'hasAtom'))
 
-        mgr.add_axiom(onto, OWLSubClassOfAxiom(OWLObjectSomeValuesFrom(has_atom, ball3), benzene))
-        mgr.add_axiom(onto, OWLSubClassOfAxiom(benzene, OWLObjectUnionOf([bond, bond])))
-        mgr.add_axiom(onto, OWLSubClassOfAxiom(OWLObjectUnionOf([bond, bond]), ball3))
+        onto.add_axiom(OWLSubClassOfAxiom(OWLObjectSomeValuesFrom(has_atom, ball3), benzene))
+        onto.add_axiom(OWLSubClassOfAxiom(benzene, OWLObjectUnionOf([bond, bond])))
+        onto.add_axiom(OWLSubClassOfAxiom(OWLObjectUnionOf([bond, bond]), ball3))
 
         # Named class
         # Direct, only named
@@ -255,7 +255,7 @@ def test_object_values(self):
         heinz = OWLNamedIndividual(IRI(ns, 'heinz'))
         has_child = OWLObjectProperty(IRI.create(ns, 'hasChild'))
         super_has_child = OWLObjectProperty(IRI.create(ns, 'super_hasChild'))
-        mgr.add_axiom(onto, OWLSubObjectPropertyOfAxiom(has_child, super_has_child))
+        onto.add_axiom(OWLSubObjectPropertyOfAxiom(has_child, super_has_child))
 
         kids = frozenset(reasoner.object_property_values(stefan, has_child))
         target_kids = frozenset({markus})
@@ -275,12 +275,12 @@ def test_object_values(self):
 
         # test inverse
         has_child_inverse = OWLObjectProperty(IRI.create(ns, 'hasChild_inverse'))
-        mgr.add_axiom(onto, OWLInverseObjectPropertiesAxiom(has_child, has_child_inverse))
+        onto.add_axiom(OWLInverseObjectPropertiesAxiom(has_child, has_child_inverse))
         parents = frozenset(reasoner.object_property_values(markus, OWLObjectInverseOf(has_child), direct=True))
         target_parents = frozenset({stefan})
         self.assertEqual(target_parents, parents)
         # Remove again for completeness, would not be necessary
-        mgr.remove_axiom(onto, OWLInverseObjectPropertiesAxiom(has_child, has_child_inverse))
+        onto.remove_axiom(OWLInverseObjectPropertiesAxiom(has_child, has_child_inverse))
 
         # test inverse with sub property
         # Setup:
@@ -288,7 +288,7 @@ def test_object_values(self):
         # hasChild inverseOf hasChild_inverse
         # super_hasChild inverseOf super_hasChild_inverse
         super_has_child_inverse = OWLObjectProperty(IRI.create(ns, 'super_hasChild_inverse'))
-        mgr.add_axiom(onto, OWLInverseObjectPropertiesAxiom(super_has_child, super_has_child_inverse))
+        onto.add_axiom(OWLInverseObjectPropertiesAxiom(super_has_child, super_has_child_inverse))
 
         parents = frozenset(reasoner.object_property_values(stefan,
                                                             OWLObjectInverseOf(super_has_child_inverse),
@@ -301,8 +301,8 @@ def test_object_values(self):
                                                             direct=False))
         target_parents = frozenset({markus})
         self.assertEqual(target_parents, parents)
-        mgr.remove_axiom(onto, OWLInverseObjectPropertiesAxiom(super_has_child, super_has_child_inverse))
-        mgr.remove_axiom(onto, OWLSubObjectPropertyOfAxiom(has_child, super_has_child))
+        onto.remove_axiom(OWLInverseObjectPropertiesAxiom(super_has_child, super_has_child_inverse))
+        onto.remove_axiom(OWLSubObjectPropertyOfAxiom(has_child, super_has_child))
 
     def test_data_values(self):
         ns = "http://dl-learner.org/mutagenesis#"
@@ -314,7 +314,7 @@ def test_data_values(self):
         d100_1 = OWLNamedIndividual(IRI.create(ns, 'd100_1'))
         charge = OWLDataProperty(IRI.create(ns, 'charge'))
         super_charge = OWLDataProperty(IRI.create(ns, 'super_charge'))
-        mgr.add_axiom(onto, OWLSubDataPropertyOfAxiom(charge, super_charge))
+        onto.add_axiom(OWLSubDataPropertyOfAxiom(charge, super_charge))
 
         values = frozenset(reasoner.data_property_values(d100_1, charge))
         targets = frozenset({OWLLiteral(-0.128)})
@@ -332,7 +332,7 @@ def test_data_values(self):
         values = frozenset(reasoner.data_property_values(d100_1, super_charge, direct=True))
         targets = frozenset()
         self.assertEqual(targets, values)
-        mgr.remove_axiom(onto, OWLSubDataPropertyOfAxiom(charge, super_charge))
+        onto.remove_axiom(OWLSubDataPropertyOfAxiom(charge, super_charge))
 
     def test_all_data_values(self):
         ns = "http://dl-learner.org/mutagenesis#"
@@ -343,7 +343,7 @@ def test_all_data_values(self):
 
         charge = OWLDataProperty(IRI.create(ns, 'charge'))
         super_charge = OWLDataProperty(IRI.create(ns, 'super_charge'))
-        mgr.add_axiom(onto, OWLSubDataPropertyOfAxiom(charge, super_charge))
+        onto.add_axiom(OWLSubDataPropertyOfAxiom(charge, super_charge))
 
         values = frozenset(reasoner.all_data_property_values(charge, direct=True))
         self.assertEqual(529, len(values))
@@ -353,7 +353,7 @@ def test_all_data_values(self):
 
         values = frozenset(reasoner.all_data_property_values(super_charge, direct=False))
         self.assertEqual(529, len(values))
-        mgr.remove_axiom(onto, OWLSubDataPropertyOfAxiom(charge, super_charge))
+        onto.remove_axiom(OWLSubDataPropertyOfAxiom(charge, super_charge))
 
     def test_ind_object_properties(self):
         ns = "http://example.com/father#"
@@ -365,7 +365,7 @@ def test_ind_object_properties(self):
         stefan = OWLNamedIndividual(IRI.create(ns, 'stefan'))
         has_child = OWLObjectProperty(IRI.create(ns, 'hasChild'))
         super_has_child = OWLObjectProperty(IRI.create(ns, 'super_hasChild'))
-        mgr.add_axiom(onto, OWLSubObjectPropertyOfAxiom(has_child, super_has_child))
+        onto.add_axiom(OWLSubObjectPropertyOfAxiom(has_child, super_has_child))
 
         properties = frozenset(reasoner.ind_object_properties(stefan, direct=True))
         target_properties = frozenset({has_child})
@@ -374,7 +374,7 @@ def test_ind_object_properties(self):
         properties = frozenset(reasoner.ind_object_properties(stefan, direct=False))
         target_properties = frozenset({has_child, super_has_child})
         self.assertEqual(target_properties, properties)
-        mgr.remove_axiom(onto, OWLSubObjectPropertyOfAxiom(has_child, super_has_child))
+        onto.remove_axiom(OWLSubObjectPropertyOfAxiom(has_child, super_has_child))
 
     def test_ind_data_properties(self):
         ns = "http://dl-learner.org/mutagenesis#"
@@ -386,7 +386,7 @@ def test_ind_data_properties(self):
         d100_1 = OWLNamedIndividual(IRI.create(ns, 'd100_1'))
         charge = OWLDataProperty(IRI.create(ns, 'charge'))
         super_charge = OWLDataProperty(IRI.create(ns, 'super_charge'))
-        mgr.add_axiom(onto, OWLSubDataPropertyOfAxiom(charge, super_charge))
+        onto.add_axiom(OWLSubDataPropertyOfAxiom(charge, super_charge))
 
         properties = frozenset(reasoner.ind_data_properties(d100_1, direct=True))
         target_properties = frozenset({charge})
@@ -395,7 +395,7 @@ def test_ind_data_properties(self):
         properties = frozenset(reasoner.ind_data_properties(d100_1, direct=False))
         target_properties = frozenset({charge, super_charge})
         self.assertEqual(target_properties, properties)
-        mgr.remove_axiom(onto, OWLSubDataPropertyOfAxiom(charge, super_charge))
+        onto.remove_axiom(OWLSubDataPropertyOfAxiom(charge, super_charge))
 
     def test_add_remove_axiom(self):
         ns = "http://example.com/father#"
@@ -423,159 +423,159 @@ def test_add_remove_axiom(self):
         aerial_animal = OWLClass(IRI(ns, 'aerialAnimal'))
 
         self.assertNotIn(sister, list(onto.classes_in_signature()))
-        mgr.add_axiom(onto, OWLClassAssertionAxiom(anna, sister))
+        onto.add_axiom(OWLClassAssertionAxiom(anna, sister))
         self.assertIn(sister, list(onto.classes_in_signature()))
         self.assertIn(anna, list(reasoner.instances(sister)))
         self.assertIn(sister, list(reasoner.types(anna)))
-        mgr.remove_axiom(onto, OWLClassAssertionAxiom(anna, sister))
+        onto.remove_axiom(OWLClassAssertionAxiom(anna, sister))
         self.assertNotIn(anna, list(reasoner.instances(sister)))
         self.assertNotIn(sister, list(reasoner.types(anna)))
 
         self.assertNotIn(michelle, list(reasoner.instances(sister)))
-        mgr.add_axiom(onto, OWLClassAssertionAxiom(michelle, sister))
+        onto.add_axiom(OWLClassAssertionAxiom(michelle, sister))
         self.assertIn(michelle, list(reasoner.instances(sister)))
         self.assertIn(sister, list(reasoner.types(michelle)))
-        mgr.remove_axiom(onto, OWLClassAssertionAxiom(michelle, sister))
+        onto.remove_axiom(OWLClassAssertionAxiom(michelle, sister))
         self.assertNotIn(michelle, list(reasoner.instances(sister)))
         self.assertNotIn(sister, list(reasoner.types(michelle)))
 
         self.assertFalse(list(reasoner.object_property_values(michelle, has_child)))
-        mgr.add_axiom(onto, OWLObjectPropertyAssertionAxiom(michelle, has_child, anna))
+        onto.add_axiom(OWLObjectPropertyAssertionAxiom(michelle, has_child, anna))
         self.assertIn(anna, list(reasoner.object_property_values(michelle, has_child)))
-        mgr.remove_axiom(onto, OWLObjectPropertyAssertionAxiom(michelle, has_child, anna))
+        onto.remove_axiom(OWLObjectPropertyAssertionAxiom(michelle, has_child, anna))
         self.assertNotIn(anna, list(reasoner.object_property_values(michelle, has_child)))
-        mgr.remove_axiom(onto, OWLObjectPropertyAssertionAxiom(michelle, has_child, anna))
+        onto.remove_axiom(OWLObjectPropertyAssertionAxiom(michelle, has_child, anna))
 
         self.assertNotIn(has_sibling, list(onto.object_properties_in_signature()))
         self.assertNotIn(marius, list(onto.individuals_in_signature()))
-        mgr.add_axiom(onto, OWLObjectPropertyAssertionAxiom(marius, has_sibling, michelle))
+        onto.add_axiom(OWLObjectPropertyAssertionAxiom(marius, has_sibling, michelle))
         self.assertIn(has_sibling, list(onto.object_properties_in_signature()))
         self.assertIn(marius, list(onto.individuals_in_signature()))
         self.assertIn(michelle, list(reasoner.object_property_values(marius, has_sibling)))
-        mgr.remove_axiom(onto, OWLObjectPropertyAssertionAxiom(marius, has_sibling, michelle))
+        onto.remove_axiom(OWLObjectPropertyAssertionAxiom(marius, has_sibling, michelle))
         self.assertNotIn(michelle, list(reasoner.object_property_values(marius, has_sibling)))
 
         self.assertNotIn(age, list(onto.data_properties_in_signature()))
-        mgr.add_axiom(onto, OWLDataPropertyAssertionAxiom(markus, age, OWLLiteral(30)))
+        onto.add_axiom(OWLDataPropertyAssertionAxiom(markus, age, OWLLiteral(30)))
         self.assertIn(age, list(onto.data_properties_in_signature()))
         self.assertIn(OWLLiteral(30), list(reasoner.data_property_values(markus, age)))
-        mgr.remove_axiom(onto, OWLDataPropertyAssertionAxiom(markus, age, OWLLiteral(30)))
+        onto.remove_axiom(OWLDataPropertyAssertionAxiom(markus, age, OWLLiteral(30)))
         self.assertNotIn(OWLLiteral(30), list(reasoner.data_property_values(markus, age)))
 
         self.assertNotIn(OWLLiteral(31), list(reasoner.data_property_values(anna, age)))
-        mgr.add_axiom(onto, OWLDataPropertyAssertionAxiom(anna, age, OWLLiteral(31)))
+        onto.add_axiom(OWLDataPropertyAssertionAxiom(anna, age, OWLLiteral(31)))
         self.assertIn(OWLLiteral(31), list(reasoner.data_property_values(anna, age)))
-        mgr.remove_axiom(onto, OWLDataPropertyAssertionAxiom(anna, age, OWLLiteral(31)))
+        onto.remove_axiom(OWLDataPropertyAssertionAxiom(anna, age, OWLLiteral(31)))
         self.assertNotIn(OWLLiteral(31), list(reasoner.data_property_values(anna, age)))
 
         self.assertNotIn(brother, list(onto.classes_in_signature()))
         self.assertNotIn(animal, list(onto.classes_in_signature()))
         self.assertNotIn(aerial_animal, list(onto.classes_in_signature()))
-        mgr.add_axiom(onto, OWLSubClassOfAxiom(brother, male))
-        mgr.add_axiom(onto, OWLSubClassOfAxiom(aerial_animal, animal))
+        onto.add_axiom(OWLSubClassOfAxiom(brother, male))
+        onto.add_axiom(OWLSubClassOfAxiom(aerial_animal, animal))
         self.assertIn(brother, list(reasoner.sub_classes(male)))
         self.assertIn(aerial_animal, list(reasoner.sub_classes(animal)))
         self.assertIn(male, list(reasoner.super_classes(brother)))
         self.assertIn(animal, list(reasoner.super_classes(aerial_animal)))
-        mgr.remove_axiom(onto, OWLSubClassOfAxiom(brother, male))
+        onto.remove_axiom(OWLSubClassOfAxiom(brother, male))
         self.assertNotIn(brother, list(reasoner.sub_classes(male)))
         self.assertNotIn(male, list(reasoner.super_classes(brother)))
 
         self.assertNotIn(has_sibling, list(reasoner.sub_object_properties(has_child)))
-        mgr.add_axiom(onto, OWLSubObjectPropertyOfAxiom(has_sibling, has_child))
+        onto.add_axiom(OWLSubObjectPropertyOfAxiom(has_sibling, has_child))
         self.assertIn(has_sibling, list(reasoner.sub_object_properties(has_child)))
-        mgr.remove_axiom(onto, OWLSubObjectPropertyOfAxiom(has_sibling, has_child))
+        onto.remove_axiom(OWLSubObjectPropertyOfAxiom(has_sibling, has_child))
         self.assertNotIn(has_sibling, list(reasoner.sub_object_properties(has_child)))
 
         self.assertNotIn(OWLObjectUnionOf([person, person_sibling]),
                          list(reasoner.object_property_domains(has_sibling)))
-        mgr.add_axiom(onto, OWLObjectPropertyDomainAxiom(has_sibling, OWLObjectUnionOf([person, person_sibling])))
+        onto.add_axiom(OWLObjectPropertyDomainAxiom(has_sibling, OWLObjectUnionOf([person, person_sibling])))
         self.assertIn(OWLObjectUnionOf([person, person_sibling]),
                       list(reasoner.object_property_domains(has_sibling, direct=True)))
-        mgr.remove_axiom(onto, OWLObjectPropertyDomainAxiom(has_sibling, OWLObjectUnionOf([person, person_sibling])))
+        onto.remove_axiom(OWLObjectPropertyDomainAxiom(has_sibling, OWLObjectUnionOf([person, person_sibling])))
         self.assertNotIn(OWLObjectUnionOf([person, person_sibling]),
                          list(reasoner.object_property_domains(has_sibling, direct=True)))
 
         self.assertNotIn(sister, list(reasoner.object_property_ranges(has_sibling)))
-        mgr.add_axiom(onto, OWLObjectPropertyRangeAxiom(has_sibling, sister))
+        onto.add_axiom(OWLObjectPropertyRangeAxiom(has_sibling, sister))
         self.assertIn(sister, list(reasoner.object_property_ranges(has_sibling)))
-        mgr.remove_axiom(onto, OWLObjectPropertyRangeAxiom(has_sibling, sister))
+        onto.remove_axiom(OWLObjectPropertyRangeAxiom(has_sibling, sister))
         self.assertNotIn(sister, list(reasoner.object_property_ranges(has_sibling)))
 
         self.assertNotIn(person, list(reasoner.data_property_domains(age)))
-        mgr.add_axiom(onto, OWLDataPropertyDomainAxiom(age, person))
+        onto.add_axiom(OWLDataPropertyDomainAxiom(age, person))
         self.assertIn(person, list(reasoner.data_property_domains(age)))
-        mgr.remove_axiom(onto, OWLDataPropertyDomainAxiom(age, person))
+        onto.remove_axiom(OWLDataPropertyDomainAxiom(age, person))
         self.assertNotIn(person, list(reasoner.data_property_domains(age)))
 
         self.assertFalse(list(reasoner.data_property_ranges(age)))
-        mgr.add_axiom(onto, OWLDataPropertyRangeAxiom(age, OWLDataUnionOf([IntegerOWLDatatype, DateOWLDatatype])))
+        onto.add_axiom(OWLDataPropertyRangeAxiom(age, OWLDataUnionOf([IntegerOWLDatatype, DateOWLDatatype])))
         self.assertIn(OWLDataUnionOf([IntegerOWLDatatype, DateOWLDatatype]), list(reasoner.data_property_ranges(age)))
-        mgr.remove_axiom(onto, OWLDataPropertyRangeAxiom(age, OWLDataUnionOf([IntegerOWLDatatype, DateOWLDatatype])))
+        onto.remove_axiom(OWLDataPropertyRangeAxiom(age, OWLDataUnionOf([IntegerOWLDatatype, DateOWLDatatype])))
         self.assertNotIn(OWLDataUnionOf([IntegerOWLDatatype, DateOWLDatatype]),
                          list(reasoner.data_property_ranges(age)))
 
         self.assertFalse(list(reasoner.equivalent_classes(brother)))
-        mgr.add_axiom(onto, OWLEquivalentClassesAxiom([brother, male]))
+        onto.add_axiom(OWLEquivalentClassesAxiom([brother, male]))
         self.assertIn(male, list(reasoner.equivalent_classes(brother)))
-        mgr.remove_axiom(onto, OWLEquivalentClassesAxiom([brother, male]))
+        onto.remove_axiom(OWLEquivalentClassesAxiom([brother, male]))
         self.assertNotIn(male, list(reasoner.equivalent_classes(brother)))
 
         self.assertFalse(list(reasoner.equivalent_object_properties(has_child)))
-        mgr.add_axiom(onto, OWLEquivalentObjectPropertiesAxiom([has_child, has_sibling]))
+        onto.add_axiom(OWLEquivalentObjectPropertiesAxiom([has_child, has_sibling]))
         self.assertIn(has_sibling, list(reasoner.equivalent_object_properties(has_child)))
-        mgr.remove_axiom(onto, OWLEquivalentObjectPropertiesAxiom([has_child, has_sibling]))
+        onto.remove_axiom(OWLEquivalentObjectPropertiesAxiom([has_child, has_sibling]))
         self.assertNotIn(has_sibling, list(reasoner.equivalent_object_properties(has_child)))
 
         self.assertFalse(list(reasoner.equivalent_data_properties(age)))
-        mgr.add_axiom(onto, OWLEquivalentDataPropertiesAxiom([age, test1]))
+        onto.add_axiom(OWLEquivalentDataPropertiesAxiom([age, test1]))
         self.assertIn(test1, list(reasoner.equivalent_data_properties(age)))
-        mgr.remove_axiom(onto, OWLEquivalentDataPropertiesAxiom([age, test1]))
+        onto.remove_axiom(OWLEquivalentDataPropertiesAxiom([age, test1]))
         self.assertNotIn(test1, list(reasoner.equivalent_data_properties(age)))
 
         self.assertFalse(list(reasoner.same_individuals(markus)))
-        mgr.add_axiom(onto, OWLSameIndividualAxiom([markus, anna, person1]))
+        onto.add_axiom(OWLSameIndividualAxiom([markus, anna, person1]))
         self.assertEqual({anna, person1}, set(reasoner.same_individuals(markus)))
-        mgr.remove_axiom(onto, OWLSameIndividualAxiom([markus, anna, person1]))
+        onto.remove_axiom(OWLSameIndividualAxiom([markus, anna, person1]))
         self.assertFalse(set(reasoner.same_individuals(markus)))
 
         self.assertFalse(list(reasoner.disjoint_classes(brother)))
         self.assertFalse(list(reasoner.disjoint_classes(person)))
-        mgr.add_axiom(onto, OWLDisjointClassesAxiom([brother, sister, aerial_animal]))
+        onto.add_axiom(OWLDisjointClassesAxiom([brother, sister, aerial_animal]))
         self.assertEqual({sister, aerial_animal}, set(reasoner.disjoint_classes(brother)))
-        mgr.remove_axiom(onto, OWLDisjointClassesAxiom([brother, sister, aerial_animal]))
+        onto.remove_axiom(OWLDisjointClassesAxiom([brother, sister, aerial_animal]))
         self.assertFalse(set(reasoner.disjoint_classes(brother)))
-        mgr.add_axiom(onto, OWLDisjointClassesAxiom([person, animal]))
+        onto.add_axiom(OWLDisjointClassesAxiom([person, animal]))
         self.assertEqual({animal, aerial_animal}, set(reasoner.disjoint_classes(person)))
-        mgr.remove_axiom(onto, OWLDisjointClassesAxiom([person, animal]))
+        onto.remove_axiom(OWLDisjointClassesAxiom([person, animal]))
         self.assertFalse(set(reasoner.disjoint_classes(person)))
 
         self.assertFalse(list(reasoner.disjoint_object_properties(has_sibling)))
         self.assertFalse(list(reasoner.disjoint_object_properties(has_child)))
-        mgr.add_axiom(onto, OWLDisjointObjectPropertiesAxiom([has_child, has_sibling]))
+        onto.add_axiom(OWLDisjointObjectPropertiesAxiom([has_child, has_sibling]))
         self.assertIn(has_sibling, set(reasoner.disjoint_object_properties(has_child)))
         self.assertIn(has_child, set(reasoner.disjoint_object_properties(has_sibling)))
-        mgr.remove_axiom(onto, OWLDisjointObjectPropertiesAxiom([has_child, has_sibling]))
+        onto.remove_axiom(OWLDisjointObjectPropertiesAxiom([has_child, has_sibling]))
         self.assertNotIn(has_sibling, set(reasoner.disjoint_object_properties(has_child)))
         self.assertNotIn(has_child, set(reasoner.disjoint_object_properties(has_sibling)))
 
         self.assertFalse(list(reasoner.disjoint_data_properties(age)))
         self.assertFalse(list(reasoner.disjoint_data_properties(test1)))
-        mgr.add_axiom(onto, OWLDisjointDataPropertiesAxiom([age, test1]))
+        onto.add_axiom(OWLDisjointDataPropertiesAxiom([age, test1]))
         self.assertIn(test1, set(reasoner.disjoint_data_properties(age)))
         self.assertIn(age, set(reasoner.disjoint_data_properties(test1)))
-        mgr.remove_axiom(onto, OWLDisjointDataPropertiesAxiom([age, test1]))
+        onto.remove_axiom(OWLDisjointDataPropertiesAxiom([age, test1]))
         self.assertNotIn(test1, set(reasoner.disjoint_data_properties(age)))
         self.assertNotIn(age, set(reasoner.disjoint_data_properties(test1)))
 
         self.assertFalse(list(reasoner.different_individuals(markus)))
         self.assertFalse(list(reasoner.different_individuals(michelle)))
-        mgr.add_axiom(onto, OWLDifferentIndividualsAxiom([markus, michelle]))
-        mgr.add_axiom(onto, OWLDifferentIndividualsAxiom([markus, anna, marius]))
+        onto.add_axiom(OWLDifferentIndividualsAxiom([markus, michelle]))
+        onto.add_axiom(OWLDifferentIndividualsAxiom([markus, anna, marius]))
         self.assertEqual({michelle, anna, marius}, set(reasoner.different_individuals(markus)))
         self.assertEqual({markus}, set(reasoner.different_individuals(michelle)))
-        mgr.remove_axiom(onto, OWLDifferentIndividualsAxiom([markus, michelle]))
-        mgr.remove_axiom(onto, OWLDifferentIndividualsAxiom([markus, anna, marius]))
+        onto.remove_axiom(OWLDifferentIndividualsAxiom([markus, michelle]))
+        onto.remove_axiom(OWLDifferentIndividualsAxiom([markus, anna, marius]))
         self.assertFalse(set(reasoner.different_individuals(markus)))
         self.assertFalse(set(reasoner.different_individuals(michelle)))
 
diff --git a/tests/test_owlapy_owl2sparql_converter.py b/tests/test_owlapy_owl2sparql_converter.py
index f943f0e0..b240cb78 100644
--- a/tests/test_owlapy_owl2sparql_converter.py
+++ b/tests/test_owlapy_owl2sparql_converter.py
@@ -11,10 +11,11 @@
 from owlapy.owl_ontology_manager import OntologyManager
 from owlapy.owl_reasoner import OntologyReasoner, FastInstanceCheckerReasoner
 from owlapy.parser import DLSyntaxParser
-from owlapy.converter import Owl2SparqlConverter
 from rdflib import Graph
+from owlapy.converter import Owl2SparqlConverter
+
 
-PATH_FAMILY = '../KGs/Family/family-benchmark_rich_background.owl'
+PATH_FAMILY = 'KGs/Family/family-benchmark_rich_background.owl'
 
 
 # checks whether all individuals returned by the reasoner are found in results generated by the sparql query
@@ -92,164 +93,164 @@ def test_as_query(self):
 #  )"""
         self.assertEqual(query, query_t)  # add assertion here
 
-    # def test_Single(self):
-    #     # rdf graph - using rdflib
-    #     family_rdf_graph = Graph()
-    #     family_rdf_graph.parse(location=PATH_FAMILY)
-    #     # knowledge base - using OWLReasoner
-    #     mgr = OntologyManager()
-    #     onto = mgr.load_ontology(IRI.create(PATH_FAMILY))
-    #     base_reasoner = Reasoner(onto)
-    #     family_kb_reasoner = FastInstanceCheckerReasoner(onto, base_reasoner=base_reasoner, negation_default=True)
-    #
-    #     ce_str = "Brother"
-    #     ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str)
-    #     actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False,
-    #                                                   values=None, named_individuals=True)
-    #     expected_query = """SELECT DISTINCT ?x
-    #                         WHERE {
-    #                             ?x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.benchmark.org/family#Brother> .
-    #                         }"""
-    #
-    #     sparql_results_actual = family_rdf_graph.query(actual_query)
-    #     sparql_results_expected = family_rdf_graph.query(expected_query)
-    #     reasoner_results = set(family_kb_reasoner.instances(ce_parsed))
-    #
-    #     self.assertEqual(len(sparql_results_actual), len(sparql_results_expected))
-    #     self.assertEqual(len(sparql_results_actual), len(reasoner_results))
-    #     self.assertTrue(check_reasoner_instances_in_sparql_results(sparql_results_actual, reasoner_results))
-    #
-    #     ce_str = "Male"
-    #     ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str)
-    #     actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False,
-    #                                                   values=None, named_individuals=True)
-    #     expected_query = """SELECT DISTINCT ?x
-    #                                 WHERE {
-    #                                     ?x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.benchmark.org/family#Male> .
-    #                                 }"""
-    #
-    #     sparql_results_actual = family_rdf_graph.query(actual_query)
-    #     sparql_results_expected = family_rdf_graph.query(expected_query)
-    #     reasoner_results = set(family_kb_reasoner.instances(ce_parsed))
-    #
-    #     self.assertEqual(len(sparql_results_actual), len(sparql_results_expected))
-    #     self.assertEqual(len(sparql_results_actual), len(reasoner_results))
-    #     self.assertTrue(check_reasoner_instances_in_sparql_results(sparql_results_actual, reasoner_results))
-    #
-    # def test_Intersection(self):
-    #     # rdf graph - using rdflib
-    #     family_rdf_graph = Graph()
-    #     family_rdf_graph.parse(location=PATH_FAMILY)
-    #     # knowledge base - using OWLReasoner
-    #     mgr = OntologyManager()
-    #     onto = mgr.load_ontology(IRI.create(PATH_FAMILY))
-    #     base_reasoner = Reasoner(onto)
-    #     family_kb_reasoner = FastInstanceCheckerReasoner(onto, base_reasoner=base_reasoner, negation_default=True)
-    #
-    #     ce_str = "Brother ⊓ Father"
-    #     ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str)
-    #     actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False,
-    #                                                   values=None, named_individuals=True)
-    #     expected_query = """SELECT DISTINCT ?x
-    #                         WHERE {
-    #                             ?x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.benchmark.org/family#Brother> .
-    #                             ?x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.benchmark.org/family#Father> .
-    #                         }"""
-    #
-    #     sparql_results_actual = family_rdf_graph.query(actual_query)
-    #     sparql_results_expected = family_rdf_graph.query(expected_query)
-    #     reasoner_results = set(family_kb_reasoner.instances(ce_parsed))
-    #
-    #     self.assertEqual(len(sparql_results_actual), len(sparql_results_expected))
-    #     self.assertEqual(len(sparql_results_actual), len(reasoner_results))
-    #     self.assertTrue(check_reasoner_instances_in_sparql_results(sparql_results_actual, reasoner_results))
-    #
-    # def test_Union(self):
-    #     # rdf graph - using rdflib
-    #     family_rdf_graph = Graph()
-    #     family_rdf_graph.parse(location=PATH_FAMILY)
-    #     # knowledge base - using OWLReasoner
-    #     mgr = OntologyManager()
-    #     onto = mgr.load_ontology(IRI.create(PATH_FAMILY))
-    #     base_reasoner = Reasoner(onto)
-    #     family_kb_reasoner = FastInstanceCheckerReasoner(onto, base_reasoner=base_reasoner, negation_default=True)
-    #
-    #     ce_str = "Sister ⊔ Mother"
-    #     ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str)
-    #     actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False,
-    #                                                   values=None, named_individuals=True)
-    #     expected_query = """SELECT DISTINCT ?x
-    #                         WHERE {
-    #                             { ?x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.benchmark.org/family#Sister> . }
-    #                             UNION
-    #                             { ?x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.benchmark.org/family#Mother> . }
-    #                         }"""
-    #
-    #     sparql_results_actual = family_rdf_graph.query(actual_query)
-    #     sparql_results_expected = family_rdf_graph.query(expected_query)
-    #     reasoner_results = set(family_kb_reasoner.instances(ce_parsed))
-    #
-    #     self.assertEqual(len(sparql_results_actual), len(sparql_results_expected))
-    #     self.assertEqual(len(sparql_results_actual), len(reasoner_results))
-    #     self.assertTrue(check_reasoner_instances_in_sparql_results(sparql_results_actual, reasoner_results))
-    #
-    # def test_Complement(self):
-    #     # rdf graph - using rdflib
-    #     family_rdf_graph = Graph()
-    #     family_rdf_graph.parse(location=PATH_FAMILY)
-    #     # knowledge base - using OWLReasoner
-    #     mgr = OntologyManager()
-    #     onto = mgr.load_ontology(IRI.create(PATH_FAMILY))
-    #     base_reasoner = Reasoner(onto)
-    #     family_kb_reasoner = FastInstanceCheckerReasoner(onto, base_reasoner=base_reasoner, negation_default=True)
-    #
-    #     ce_str = "¬Mother"
-    #     ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str)
-    #     actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False,
-    #                                                   values=None, named_individuals=True)
-    #     expected_query = """SELECT DISTINCT ?x
-    #                         WHERE {
-    #                                 ?x a <http://www.w3.org/2002/07/owl#NamedIndividual> .
-    #                                 ?x ?p ?o .
-    #                                 FILTER NOT EXISTS { ?x a <http://www.benchmark.org/family#Mother> . }
-    #                         }"""
-    #
-    #     sparql_results_actual = family_rdf_graph.query(actual_query)
-    #     sparql_results_expected = family_rdf_graph.query(expected_query)
-    #     reasoner_results = set(family_kb_reasoner.instances(ce_parsed))
-    #
-    #     self.assertEqual(len(sparql_results_actual), len(sparql_results_expected))
-    #     self.assertEqual(len(sparql_results_actual), len(reasoner_results))
-    #     self.assertTrue(check_reasoner_instances_in_sparql_results(sparql_results_actual, reasoner_results))
-    #
-    # def test_Exists(self):
-    #     # rdf graph - using rdflib
-    #     family_rdf_graph = Graph()
-    #     family_rdf_graph.parse(location=PATH_FAMILY)
-    #     # knowledge base - using OWLReasoner
-    #     mgr = OntologyManager()
-    #     onto = mgr.load_ontology(IRI.create(PATH_FAMILY))
-    #     base_reasoner = Reasoner(onto)
-    #     family_kb_reasoner = FastInstanceCheckerReasoner(onto, base_reasoner=base_reasoner, negation_default=True)
-    #
-    #     ce_str = "∃hasChild.Male"
-    #     ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str)
-    #     actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False,
-    #                                                   values=None, named_individuals=True)
-    #     expected_query = """SELECT DISTINCT ?x
-    #                         WHERE {
-    #                             ?x <http://www.benchmark.org/family#hasChild> ?s .
-    #                             ?s a <http://www.benchmark.org/family#Male> .
-    #                         }"""
-    #
-    #     sparql_results_actual = family_rdf_graph.query(actual_query)
-    #     sparql_results_expected = family_rdf_graph.query(expected_query)
-    #     reasoner_results = set(family_kb_reasoner.instances(ce_parsed))
-    #
-    #     self.assertEqual(len(sparql_results_actual), len(sparql_results_expected))
-    #     self.assertEqual(len(sparql_results_actual), len(reasoner_results))
-    #     self.assertTrue(check_reasoner_instances_in_sparql_results(sparql_results_actual, reasoner_results))
-    #
+    def test_Single(self):
+        # rdf graph - using rdflib
+        family_rdf_graph = Graph()
+        family_rdf_graph.parse(location=PATH_FAMILY)
+        # knowledge base - using OWLReasoner
+        mgr = OntologyManager()
+        onto = mgr.load_ontology(IRI.create(PATH_FAMILY))
+        base_reasoner = OntologyReasoner(onto)
+        family_kb_reasoner = FastInstanceCheckerReasoner(onto, base_reasoner=base_reasoner, negation_default=True)
+
+        ce_str = "Brother"
+        ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str)
+        actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False,
+                                                      values=None, named_individuals=True)
+        expected_query = """SELECT DISTINCT ?x
+                            WHERE {
+                                ?x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.benchmark.org/family#Brother> .
+                            }"""
+
+        sparql_results_actual = family_rdf_graph.query(actual_query)
+        sparql_results_expected = family_rdf_graph.query(expected_query)
+        reasoner_results = set(family_kb_reasoner.instances(ce_parsed))
+
+        self.assertEqual(len(sparql_results_actual), len(sparql_results_expected))
+        self.assertEqual(len(sparql_results_actual), len(reasoner_results))
+        self.assertTrue(check_reasoner_instances_in_sparql_results(sparql_results_actual, reasoner_results))
+
+        ce_str = "Male"
+        ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str)
+        actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False,
+                                                      values=None, named_individuals=True)
+        expected_query = """SELECT DISTINCT ?x
+                                    WHERE {
+                                        ?x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.benchmark.org/family#Male> .
+                                    }"""
+
+        sparql_results_actual = family_rdf_graph.query(actual_query)
+        sparql_results_expected = family_rdf_graph.query(expected_query)
+        reasoner_results = set(family_kb_reasoner.instances(ce_parsed))
+
+        self.assertEqual(len(sparql_results_actual), len(sparql_results_expected))
+        self.assertEqual(len(sparql_results_actual), len(reasoner_results))
+        self.assertTrue(check_reasoner_instances_in_sparql_results(sparql_results_actual, reasoner_results))
+
+    def test_Intersection(self):
+        # rdf graph - using rdflib
+        family_rdf_graph = Graph()
+        family_rdf_graph.parse(location=PATH_FAMILY)
+        # knowledge base - using OWLReasoner
+        mgr = OntologyManager()
+        onto = mgr.load_ontology(IRI.create(PATH_FAMILY))
+        base_reasoner = OntologyReasoner(onto)
+        family_kb_reasoner = FastInstanceCheckerReasoner(onto, base_reasoner=base_reasoner, negation_default=True)
+
+        ce_str = "Brother ⊓ Father"
+        ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str)
+        actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False,
+                                                      values=None, named_individuals=True)
+        expected_query = """SELECT DISTINCT ?x
+                            WHERE {
+                                ?x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.benchmark.org/family#Brother> .
+                                ?x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.benchmark.org/family#Father> .
+                            }"""
+
+        sparql_results_actual = family_rdf_graph.query(actual_query)
+        sparql_results_expected = family_rdf_graph.query(expected_query)
+        reasoner_results = set(family_kb_reasoner.instances(ce_parsed))
+
+        self.assertEqual(len(sparql_results_actual), len(sparql_results_expected))
+        self.assertEqual(len(sparql_results_actual), len(reasoner_results))
+        self.assertTrue(check_reasoner_instances_in_sparql_results(sparql_results_actual, reasoner_results))
+
+    def test_Union(self):
+        # rdf graph - using rdflib
+        family_rdf_graph = Graph()
+        family_rdf_graph.parse(location=PATH_FAMILY)
+        # knowledge base - using OWLReasoner
+        mgr = OntologyManager()
+        onto = mgr.load_ontology(IRI.create(PATH_FAMILY))
+        base_reasoner = OntologyReasoner(onto)
+        family_kb_reasoner = FastInstanceCheckerReasoner(onto, base_reasoner=base_reasoner, negation_default=True)
+
+        ce_str = "Sister ⊔ Mother"
+        ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str)
+        actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False,
+                                                      values=None, named_individuals=True)
+        expected_query = """SELECT DISTINCT ?x
+                            WHERE {
+                                { ?x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.benchmark.org/family#Sister> . }
+                                UNION
+                                { ?x <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.benchmark.org/family#Mother> . }
+                            }"""
+
+        sparql_results_actual = family_rdf_graph.query(actual_query)
+        sparql_results_expected = family_rdf_graph.query(expected_query)
+        reasoner_results = set(family_kb_reasoner.instances(ce_parsed))
+
+        self.assertEqual(len(sparql_results_actual), len(sparql_results_expected))
+        self.assertEqual(len(sparql_results_actual), len(reasoner_results))
+        self.assertTrue(check_reasoner_instances_in_sparql_results(sparql_results_actual, reasoner_results))
+
+    def test_Complement(self):
+        # rdf graph - using rdflib
+        family_rdf_graph = Graph()
+        family_rdf_graph.parse(location=PATH_FAMILY)
+        # knowledge base - using OWLReasoner
+        mgr = OntologyManager()
+        onto = mgr.load_ontology(IRI.create(PATH_FAMILY))
+        base_reasoner = OntologyReasoner(onto)
+        family_kb_reasoner = FastInstanceCheckerReasoner(onto, base_reasoner=base_reasoner, negation_default=True)
+
+        ce_str = "¬Mother"
+        ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str)
+        actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False,
+                                                      values=None, named_individuals=True)
+        expected_query = """SELECT DISTINCT ?x
+                            WHERE {
+                                    ?x a <http://www.w3.org/2002/07/owl#NamedIndividual> .
+                                    ?x ?p ?o .
+                                    FILTER NOT EXISTS { ?x a <http://www.benchmark.org/family#Mother> . }
+                            }"""
+
+        sparql_results_actual = family_rdf_graph.query(actual_query)
+        sparql_results_expected = family_rdf_graph.query(expected_query)
+        reasoner_results = set(family_kb_reasoner.instances(ce_parsed))
+
+        self.assertEqual(len(sparql_results_actual), len(sparql_results_expected))
+        self.assertEqual(len(sparql_results_actual), len(reasoner_results))
+        self.assertTrue(check_reasoner_instances_in_sparql_results(sparql_results_actual, reasoner_results))
+
+    def test_Exists(self):
+        # rdf graph - using rdflib
+        family_rdf_graph = Graph()
+        family_rdf_graph.parse(location=PATH_FAMILY)
+        # knowledge base - using OWLReasoner
+        mgr = OntologyManager()
+        onto = mgr.load_ontology(IRI.create(PATH_FAMILY))
+        base_reasoner = OntologyReasoner(onto)
+        family_kb_reasoner = FastInstanceCheckerReasoner(onto, base_reasoner=base_reasoner, negation_default=True)
+
+        ce_str = "∃hasChild.Male"
+        ce_parsed = DLSyntaxParser(namespace="http://www.benchmark.org/family#").parse_expression(expression_str=ce_str)
+        actual_query = Owl2SparqlConverter().as_query(root_variable=self._root_var_, ce=ce_parsed, count=False,
+                                                      values=None, named_individuals=True)
+        expected_query = """SELECT DISTINCT ?x
+                            WHERE {
+                                ?x <http://www.benchmark.org/family#hasChild> ?s .
+                                ?s a <http://www.benchmark.org/family#Male> .
+                            }"""
+
+        sparql_results_actual = family_rdf_graph.query(actual_query)
+        sparql_results_expected = family_rdf_graph.query(expected_query)
+        reasoner_results = set(family_kb_reasoner.instances(ce_parsed))
+
+        self.assertEqual(len(sparql_results_actual), len(sparql_results_expected))
+        self.assertEqual(len(sparql_results_actual), len(reasoner_results))
+        self.assertTrue(check_reasoner_instances_in_sparql_results(sparql_results_actual, reasoner_results))
+
     # def test_ForAll(self):
     #     # rdf graph - using rdflib
     #     family_rdf_graph = Graph()
@@ -257,7 +258,7 @@ def test_as_query(self):
     #     # knowledge base - using OWLReasoner
     #     mgr = OntologyManager()
     #     onto = mgr.load_ontology(IRI.create(PATH_FAMILY))
-    #     base_reasoner = Reasoner(onto)
+    #     base_reasoner = OntologyReasoner(onto)
     #     family_kb_reasoner = FastInstanceCheckerReasoner(onto, base_reasoner=base_reasoner, negation_default=True)
     #
     #     ce_str = "∀hasChild.Male"
@@ -307,7 +308,7 @@ def test_as_query(self):
     #     # knowledge base - using OWLReasoner
     #     mgr = OntologyManager()
     #     onto = mgr.load_ontology(IRI.create(PATH_FAMILY))
-    #     base_reasoner = Reasoner(onto)
+    #     base_reasoner = OntologyReasoner(onto)
     #     family_kb_reasoner = FastInstanceCheckerReasoner(onto, base_reasoner=base_reasoner, negation_default=True)
     #
     #     ce_str = "∀hasChild.Male"
@@ -342,7 +343,7 @@ def test_as_query(self):
     #     # knowledge base - using OWLReasoner
     #     mgr = OntologyManager()
     #     onto = mgr.load_ontology(IRI.create(PATH_FAMILY))
-    #     base_reasoner = Reasoner(onto)
+    #     base_reasoner = OntologyReasoner(onto)
     #     family_kb_reasoner = FastInstanceCheckerReasoner(onto, base_reasoner=base_reasoner, negation_default=True)
     #
     #     concepts = [
@@ -373,7 +374,7 @@ def test_as_query(self):
     #     # knowledge base - using OWLReasoner
     #     mgr = OntologyManager()
     #     onto = mgr.load_ontology(IRI.create(PATH_FAMILY))
-    #     base_reasoner = Reasoner(onto)
+    #     base_reasoner = OntologyReasoner(onto)
     #     family_kb_reasoner = FastInstanceCheckerReasoner(onto, base_reasoner=base_reasoner, negation_default=True)
     #
     #     concepts = [
diff --git a/tests/test_sync_ontology.py b/tests/test_sync_ontology.py
new file mode 100644
index 00000000..42c7727e
--- /dev/null
+++ b/tests/test_sync_ontology.py
@@ -0,0 +1,112 @@
+import unittest
+
+from owlapy.class_expression import OWLClass, OWLObjectIntersectionOf, OWLObjectSomeValuesFrom
+from owlapy.iri import IRI
+from owlapy.owl_axiom import OWLEquivalentClassesAxiom
+from owlapy.owl_individual import OWLNamedIndividual
+from owlapy.owl_ontology import OWLOntologyID
+from owlapy.owl_ontology_manager import SyncOntologyManager
+from owlapy.owl_property import OWLDataProperty, OWLObjectProperty
+
+NS = "http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#"
+
+# ==== Individuals ====
+a = OWLNamedIndividual(IRI(NS, "a"))
+b = OWLNamedIndividual(IRI(NS, "b"))
+c = OWLNamedIndividual(IRI(NS, "c"))
+d = OWLNamedIndividual(IRI(NS, "d"))
+e = OWLNamedIndividual(IRI(NS, "e"))
+f = OWLNamedIndividual(IRI(NS, "f"))
+g = OWLNamedIndividual(IRI(NS, "g"))
+h = OWLNamedIndividual(IRI(NS, "h"))
+m = OWLNamedIndividual(IRI(NS, "m"))
+l = OWLNamedIndividual(IRI(NS, "l"))  # noqa: E741
+n = OWLNamedIndividual(IRI(NS, "n"))
+o = OWLNamedIndividual(IRI(NS, "o"))
+p = OWLNamedIndividual(IRI(NS, "p"))
+q = OWLNamedIndividual(IRI(NS, "q"))
+r = OWLNamedIndividual(IRI(NS, "r"))
+s = OWLNamedIndividual(IRI(NS, "s"))
+ind1 = OWLNamedIndividual(IRI(NS, "ind1"))
+
+# ==== Object Properties ====
+r1 = OWLObjectProperty(IRI(NS, "r1"))
+r2 = OWLObjectProperty(IRI(NS, "r2"))
+r3 = OWLObjectProperty(IRI(NS, "r3"))
+r4 = OWLObjectProperty(IRI(NS, "r4"))
+r5 = OWLObjectProperty(IRI(NS, "r5"))
+r6 = OWLObjectProperty(IRI(NS, "r6"))
+r7 = OWLObjectProperty(IRI(NS, "r7"))
+
+# ==== Data Properties ====
+
+dp1 = OWLDataProperty(IRI(NS, "dp1"))
+dp2 = OWLDataProperty(IRI(NS, "dp2"))
+dp3 = OWLDataProperty(IRI(NS, "dp3"))
+
+# ==== Classes ====
+
+A = OWLClass(IRI(NS, 'A'))
+B = OWLClass(IRI(NS, 'B'))
+C = OWLClass(IRI(NS, 'C'))
+AB = OWLClass(IRI(NS, 'AB'))
+D = OWLClass(IRI(NS, 'D'))
+E = OWLClass(IRI(NS, 'E'))
+F = OWLClass(IRI(NS, 'F'))
+G = OWLClass(IRI(NS, 'G'))
+J = OWLClass(IRI(NS, 'J'))
+K = OWLClass(IRI(NS, 'K'))
+H = OWLClass(IRI(NS, 'H'))
+I = OWLClass(IRI(NS, 'I'))  # noqa: E741
+L = OWLClass(IRI(NS, 'L'))
+M = OWLClass(IRI(NS, 'M'))
+N = OWLClass(IRI(NS, 'N'))
+O = OWLClass(IRI(NS, 'O'))  # noqa: E741
+P = OWLClass(IRI(NS, 'P'))
+Q = OWLClass(IRI(NS, 'Q'))
+R = OWLClass(IRI(NS, 'R'))
+S = OWLClass(IRI(NS, 'S'))
+T = OWLClass(IRI(NS, 'T'))
+U = OWLClass(IRI(NS, 'U'))
+
+
+class TestSyncReasoner(unittest.TestCase):
+
+    ontology_path = "KGs/Test/test_ontology.owl"
+    manager = SyncOntologyManager()
+    onto = manager.load_ontology(ontology_path)
+
+    # NOTE AB: The name of "assertCountEqual" may be misleading,but it's essentially an order-insensitive "assertEqual".
+
+    def test_classes_in_signature(self):
+        self.assertCountEqual(list(self.onto.classes_in_signature()), [A, AB, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
+                                                                       P, Q, R, S, T, U])
+
+    def test_data_properties_in_signature(self):
+        self.assertCountEqual(list(self.onto.data_properties_in_signature()), [dp1, dp2, dp3])
+
+    def test_object_properties_in_signature(self):
+        self.assertCountEqual(list(self.onto.object_properties_in_signature()), [r1, r2, r3, r4, r5, r6, r7])
+
+    def test_individuals_in_signature(self):
+        self.assertCountEqual(list(self.onto.individuals_in_signature()), [a, b, c, d, e, f, g, h, m, l, n, o, p, q, r,
+                                                                           s, ind1])
+
+    def test_equivalent_classes_axiom(self):
+        eq1 = OWLEquivalentClassesAxiom([N, Q])
+        eq2 = OWLEquivalentClassesAxiom([F, OWLObjectSomeValuesFrom(property=r2, filler=G)])
+        eq3 = OWLEquivalentClassesAxiom([AB, OWLObjectIntersectionOf((A, B))])
+        aeq = set()
+        for cls in self.onto.classes_in_signature():
+            ea = set(self.onto.equivalent_classes_axioms(cls))
+            aeq.update(ea)
+        self.assertCountEqual(aeq, {eq1, eq2, eq3})
+
+    def test_get_ontology_id(self):
+        onto_id = OWLOntologyID(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/', 'untitled-ontology-11'),
+                                None)
+        self.assertEqual(self.onto.get_ontology_id(), onto_id)
+
+    def test__eq__(self):
+        onto2 = self.manager.load_ontology(self.ontology_path)
+        self.assertTrue(self.onto.__eq__(onto2))
diff --git a/tests/test_sync_reasoner.py b/tests/test_sync_reasoner.py
new file mode 100644
index 00000000..2e32d217
--- /dev/null
+++ b/tests/test_sync_reasoner.py
@@ -0,0 +1,353 @@
+import os
+import unittest
+
+from jpype import JDouble
+from owlapy.class_expression import OWLClass, OWLDataSomeValuesFrom, OWLObjectIntersectionOf, OWLNothing, OWLThing, \
+    OWLClassExpression
+from owlapy.iri import IRI
+from owlapy.owl_axiom import OWLDisjointClassesAxiom, OWLDeclarationAxiom, OWLClassAssertionAxiom, OWLSubClassOfAxiom, \
+    OWLEquivalentClassesAxiom, OWLSubDataPropertyOfAxiom, OWLSubObjectPropertyOfAxiom
+from owlapy.owl_individual import OWLNamedIndividual
+from owlapy.owl_literal import OWLBottomObjectProperty, OWLTopObjectProperty, OWLBottomDataProperty, OWLTopDataProperty, \
+    OWLLiteral
+from owlapy.owl_ontology_manager import OntologyManager
+from owlapy.owl_property import OWLDataProperty, OWLObjectProperty
+from owlapy.owl_reasoner import SyncReasoner
+from owlapy.providers import owl_datatype_min_inclusive_restriction
+
+NS = 'http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#'
+
+a = OWLNamedIndividual(IRI(NS, "a"))
+b = OWLNamedIndividual(IRI(NS, "b"))
+c = OWLNamedIndividual(IRI(NS, "c"))
+d = OWLNamedIndividual(IRI(NS, "d"))
+e = OWLNamedIndividual(IRI(NS, "e"))
+g = OWLNamedIndividual(IRI(NS, "g"))
+m = OWLNamedIndividual(IRI(NS, "m"))
+l = OWLNamedIndividual(IRI(NS, "l"))  # noqa: E741
+n = OWLNamedIndividual(IRI(NS, "n"))
+o = OWLNamedIndividual(IRI(NS, "o"))
+p = OWLNamedIndividual(IRI(NS, "p"))
+q = OWLNamedIndividual(IRI(NS, "q"))
+r = OWLNamedIndividual(IRI(NS, "r"))
+s = OWLNamedIndividual(IRI(NS, "s"))
+ind1 = OWLNamedIndividual(IRI(NS, "ind1"))
+
+r1 = OWLObjectProperty(IRI(NS, "r1"))
+r2 = OWLObjectProperty(IRI(NS, "r2"))
+r3 = OWLObjectProperty(IRI(NS, "r3"))
+r4 = OWLObjectProperty(IRI(NS, "r4"))
+r5 = OWLObjectProperty(IRI(NS, "r5"))
+r6 = OWLObjectProperty(IRI(NS, "r6"))
+r7 = OWLObjectProperty(IRI(NS, "r7"))
+
+dp1 = OWLDataProperty(IRI(NS, "dp1"))
+dp2 = OWLDataProperty(IRI(NS, "dp2"))
+dp3 = OWLDataProperty(IRI(NS, "dp3"))
+
+A = OWLClass(IRI(NS, 'A'))
+B = OWLClass(IRI(NS, 'B'))
+C = OWLClass(IRI(NS, 'C'))
+AB = OWLClass(IRI(NS, 'AB'))
+D = OWLClass(IRI(NS, 'D'))
+E = OWLClass(IRI(NS, 'E'))
+F = OWLClass(IRI(NS, 'F'))
+G = OWLClass(IRI(NS, 'G'))
+J = OWLClass(IRI(NS, 'J'))
+K = OWLClass(IRI(NS, 'K'))
+H = OWLClass(IRI(NS, 'H'))
+I = OWLClass(IRI(NS, 'I'))  # noqa: E741
+L = OWLClass(IRI(NS, 'L'))
+M = OWLClass(IRI(NS, 'M'))
+N = OWLClass(IRI(NS, 'N'))
+O = OWLClass(IRI(NS, 'O'))  # noqa: E741
+P = OWLClass(IRI(NS, 'P'))
+Q = OWLClass(IRI(NS, 'Q'))
+R = OWLClass(IRI(NS, 'R'))
+S = OWLClass(IRI(NS, 'S'))
+T = OWLClass(IRI(NS, 'T'))
+U = OWLClass(IRI(NS, 'U'))
+reasoner2 = SyncReasoner("KGs/Test/test_ontology.owl")
+
+class TestSyncReasoner(unittest.TestCase):
+    ns = "http://dl-learner.org/mutagenesis#"
+    ontology_path = "KGs/Mutagenesis/mutagenesis.owl"
+    nitrogen38 = OWLClass(IRI.create(ns, "Nitrogen-38"))
+    compound = OWLClass(IRI.create(ns, "Compound"))
+    atom = OWLClass(IRI.create(ns, "Atom"))
+    charge = OWLDataProperty(IRI.create(ns, "charge"))
+    hasAtom = OWLObjectProperty(IRI.create(ns, "hasAtom"))
+    d100_25 = OWLNamedIndividual(IRI.create(ns, "d100_25"))
+    has_charge_more_than_0_85 = OWLDataSomeValuesFrom(charge, owl_datatype_min_inclusive_restriction(0.85))
+    ce = OWLObjectIntersectionOf([nitrogen38, has_charge_more_than_0_85])
+    reasoner = SyncReasoner(ontology_path)
+
+    def test_consistency_check(self):
+        self.assertEqual(self.reasoner.has_consistent_ontology(), True)
+
+    def test_named_concepts(self):
+
+        ontology_path = "KGs/Family/family-benchmark_rich_background.owl"
+
+        # Available OWL Reasoners: 'HermiT', 'Pellet', 'JFact', 'Openllet'
+        owl_reasoners = dict()
+        owl_reasoners["HermiT"] = SyncReasoner(ontology=ontology_path, reasoner="HermiT")
+        owl_reasoners["Pellet"] = SyncReasoner(ontology=ontology_path, reasoner="Pellet")
+        owl_reasoners["JFact"] = SyncReasoner(ontology=ontology_path, reasoner="JFact")
+        owl_reasoners["Openllet"] = SyncReasoner(ontology=ontology_path, reasoner="Openllet")
+
+        onto = OntologyManager().load_ontology(ontology_path)
+
+        def compute_agreements(i: OWLClassExpression, verbose=False):
+            if verbose:
+                print(f"Computing agreements between Reasoners on {i}...")
+            retrieval_result = None
+            flag = False
+            for __, reasoner in owl_reasoners.items():
+                if retrieval_result:
+                    flag = retrieval_result == {_.str for _ in reasoner.instances(i)}
+                else:
+                    retrieval_result = {_.str for _ in reasoner.instances(i)}
+            return flag
+
+        # Agreement between instances over
+        for i in onto.classes_in_signature():
+            assert compute_agreements(i, True)
+
+    def test_inconsistency_check(self):
+        manager = OntologyManager()
+        onto = manager.load_ontology(IRI.create(self.ontology_path))
+
+        carbon230 = OWLClass(IRI.create(self.ns, "Carbon-230"))
+        axiom = OWLDisjointClassesAxiom([self.nitrogen38, carbon230])
+        onto.add_axiom(axiom)
+        new_individual = OWLNamedIndividual(IRI.create(self.ns, "testIndividual"))
+        onto.add_axiom(OWLDeclarationAxiom(new_individual))
+        onto.add_axiom(OWLClassAssertionAxiom(new_individual, self.nitrogen38))
+        onto.add_axiom(OWLClassAssertionAxiom(new_individual, carbon230))
+
+        onto.save(IRI.create("file:/test.owl"))
+        reasoner = SyncReasoner("test.owl")
+        self.assertEqual(reasoner.has_consistent_ontology(), False)
+        os.remove("test.owl")
+
+    def test_instances_retrieval(self):
+        instances = self.reasoner.instances(self.ce)
+        expected = [OWLNamedIndividual(IRI('http://dl-learner.org/mutagenesis#', 'd141_10')),
+                    OWLNamedIndividual(IRI('http://dl-learner.org/mutagenesis#', 'd195_12')),
+                    OWLNamedIndividual(IRI('http://dl-learner.org/mutagenesis#', 'd144_10')),
+                    OWLNamedIndividual(IRI('http://dl-learner.org/mutagenesis#', 'd147_11')),
+                    OWLNamedIndividual(IRI('http://dl-learner.org/mutagenesis#', 'e18_9')),
+                    OWLNamedIndividual(IRI('http://dl-learner.org/mutagenesis#', 'd175_17')),
+                    OWLNamedIndividual(IRI('http://dl-learner.org/mutagenesis#', 'e16_9'))]
+        # Assert equal without considering the order
+        for instance in instances:
+            self.assertIn(instance, expected)
+        self.assertEqual(len(list(instances)), len(expected))
+
+    def test_conversion(self):
+        # construct the class expression in owlapi
+        from org.semanticweb.owlapi.model import IRI as IRIowlapi
+        from org.semanticweb.owlapi.vocab import OWLFacet
+
+        nitrogenIRI = IRIowlapi.create(self.ns + "Nitrogen-38")
+        charge_iri = IRIowlapi.create(self.ns + "charge")
+
+        data_factory = self.reasoner.manager.get_owlapi_manager().getOWLDataFactory()
+        nitrogen_class = data_factory.getOWLClass(nitrogenIRI)
+
+        charge_property = data_factory.getOWLDataProperty(charge_iri)
+        double_datatype = data_factory.getDoubleOWLDatatype()
+        facet_restriction = data_factory.getOWLFacetRestriction(OWLFacet.MIN_INCLUSIVE, JDouble(0.85))
+        datatype_restriction = data_factory.getOWLDatatypeRestriction(double_datatype, facet_restriction)
+        some_values_from = data_factory.getOWLDataSomeValuesFrom(charge_property, datatype_restriction)
+
+        class_expression = data_factory.getOWLObjectIntersectionOf(nitrogen_class, some_values_from)
+
+        # compare them with the converted expression
+        ce_converted = self.reasoner.mapper.map_(self.ce)
+        print(ce_converted)
+        print(class_expression)
+        self.assertEqual(class_expression, ce_converted)
+
+        # convert back to owlapy and check for equality
+        ce_1 = self.reasoner.mapper.map_(class_expression)
+        ce_2 = self.reasoner.mapper.map_(ce_converted)
+
+        self.assertEqual(ce_1, ce_2)
+        self.assertEqual(ce_1, self.ce)
+        self.assertEqual(ce_2, self.ce)
+
+    def test_equivalent_classes(self):
+        self.assertCountEqual(list(reasoner2.equivalent_classes(N)), [N, Q])
+
+    def test_disjoint_classes(self):
+        self.assertCountEqual(list(reasoner2.disjoint_classes(L)), [M, OWLNothing])
+
+    def test_sub_classes(self):
+        self.assertCountEqual(list(reasoner2.sub_classes(P)), [O, OWLNothing])
+
+    def test_super_classes(self):
+        self.assertCountEqual(list(reasoner2.super_classes(O)), [P, OWLThing])
+
+    def test_object_property_domains(self):
+        self.assertCountEqual(list(self.reasoner.object_property_domains(self.hasAtom, False)), [self.compound, OWLThing])
+        self.assertCountEqual(list(self.reasoner.object_property_domains(self.hasAtom, True)), [self.compound])
+
+    def test_object_property_ranges(self):
+        self.assertCountEqual(list(reasoner2.object_property_ranges(r1, False)), [OWLThing, G])
+        self.assertCountEqual(list(reasoner2.object_property_ranges(r1, True)), [G])
+
+    def test_sub_object_properties(self):
+        self.assertCountEqual(list(reasoner2.sub_object_properties(r1, False)), [r2, OWLBottomObjectProperty])
+        self.assertCountEqual(list(reasoner2.sub_object_properties(r1, True)), [r2])
+
+    def test_super_object_properties(self):
+        self.assertCountEqual(list(reasoner2.super_object_properties(r2, False)), [r1, OWLTopObjectProperty])
+        self.assertCountEqual(list(reasoner2.super_object_properties(r2, True)), [r1])
+
+    def test_sub_data_properties(self):
+        self.assertCountEqual(list(reasoner2.sub_data_properties(dp1, False)), [dp2, OWLBottomDataProperty])
+        self.assertCountEqual(list(reasoner2.sub_data_properties(dp1, True)), [dp2])
+
+    def test_super_data_properties(self):
+        self.assertCountEqual(list(reasoner2.super_data_properties(dp2, False)), [dp1, OWLTopDataProperty])
+        self.assertCountEqual(list(reasoner2.super_data_properties(dp2, True)), [dp1])
+
+    def test_different_individuals(self):
+        self.assertCountEqual(list(reasoner2.different_individuals(l)), [m])
+        self.assertCountEqual(list(reasoner2.different_individuals(m)), [l])
+
+    def test_object_property_values(self):
+        self.assertCountEqual(list(reasoner2.object_property_values(n, r3)), [q])
+        self.assertCountEqual(list(reasoner2.object_property_values(n, r4)), [l, q])
+
+    def test_data_property_values(self):
+        self.assertCountEqual(list(self.reasoner.data_property_values(self.d100_25, self.charge)), [OWLLiteral(0.332)])
+
+    def test_disjoint_object_properties(self):
+        self.assertCountEqual(list(reasoner2.disjoint_object_properties(r5)), [r1, r2, OWLBottomObjectProperty])
+        self.assertCountEqual(list(reasoner2.disjoint_object_properties(r1)), [r5, OWLBottomObjectProperty])
+        self.assertCountEqual(list(reasoner2.disjoint_object_properties(r2)), [r5, OWLBottomObjectProperty])
+
+    def test_disjoint_data_properties(self):
+        self.assertCountEqual(list(reasoner2.disjoint_data_properties(dp1)), [dp3, OWLBottomDataProperty])
+        self.assertCountEqual(list(reasoner2.disjoint_data_properties(dp3)), [dp1,dp2, OWLBottomDataProperty])
+
+    def test_types(self):
+        self.assertCountEqual(list(reasoner2.types(c)), [I, J, K, OWLThing])
+
+    def test_infer_axiom(self):
+
+        self.assertCountEqual(list(reasoner2.infer_axioms(["InferredClassAssertionAxiomGenerator", "InferredSubClassAxiomGenerator",
+             "InferredDisjointClassesAxiomGenerator", "InferredEquivalentClassAxiomGenerator",
+             "InferredEquivalentDataPropertiesAxiomGenerator","InferredEquivalentObjectPropertyAxiomGenerator",
+             "InferredInverseObjectPropertiesAxiomGenerator","InferredSubDataPropertyAxiomGenerator",
+             "InferredSubObjectPropertyAxiomGenerator","InferredDataPropertyCharacteristicAxiomGenerator",
+             "InferredObjectPropertyCharacteristicAxiomGenerator"
+             ])), [ OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','f')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','l')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','L')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','m')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','M')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','a')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','e')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','C')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','s')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','n')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','p')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','P')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','a')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','AB')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','q')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','Q')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','a')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','B')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','n')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','N')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','c')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','K')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','e')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','A')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','ind1')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','d')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','o')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','O')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','c')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','I')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','r')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','R')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','q')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','l')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','s')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','S')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','f')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','E')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','g')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','b')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','n')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','Q')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','e')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','B')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','a')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','C')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','o')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','o')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','P')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','ind1')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','H')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','a')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','A')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','e')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','ind1')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','F')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','s')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','T')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','r')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','e')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','AB')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','m')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','h')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','d')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','D')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','c')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','J')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','b')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','B')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','c')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','d')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','B')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','p')),class_expression=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','q')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','N')),annotations=[]),
+                    OWLClassAssertionAxiom(individual=OWLNamedIndividual(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','g')),class_expression=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','G')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','AB')),super_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','A')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','I')),super_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','K')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','N')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','Q')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','A')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','D')),super_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','B')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','AB')),super_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','C')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','K')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','B')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','G')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','O')),super_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','P')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','L')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','S')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','F')),super_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','H')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','AB')),super_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','B')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','E')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','J')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','U')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','I')),super_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','J')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','T')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','P')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','C')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','H')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','M')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLSubClassOfAxiom(sub_class=OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','R')),super_class=OWLClass(IRI('http://www.w3.org/2002/07/owl#','Thing')),annotations=[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','D')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','Q')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','J')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','E')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','K')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','L')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','R')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','AB')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','S')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','M')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','F')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','A')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','G')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','T')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','H')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','N')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','U')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','L')), OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','M'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','I')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','B')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','O')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','P')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLDisjointClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','C')), OWLClass(IRI('http://www.w3.org/2002/07/owl#','Nothing'))],[]),
+                    OWLEquivalentClassesAxiom([OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','N')), OWLClass(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','Q'))],[]),
+                    OWLSubDataPropertyOfAxiom(sub_property=OWLDataProperty(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','dp2')),super_property=OWLDataProperty(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','dp1')),annotations=[]),
+                    OWLSubDataPropertyOfAxiom(sub_property=OWLDataProperty(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','dp3')),super_property=OWLDataProperty(IRI('http://www.w3.org/2002/07/owl#','topDataProperty')),annotations=[]),
+                    OWLSubDataPropertyOfAxiom(sub_property=OWLDataProperty(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','dp1')),super_property=OWLDataProperty(IRI('http://www.w3.org/2002/07/owl#','topDataProperty')),annotations=[]),
+                    OWLSubObjectPropertyOfAxiom(sub_property=OWLObjectProperty(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','r5')),super_property=OWLObjectProperty(IRI('http://www.w3.org/2002/07/owl#','topObjectProperty')),annotations=[]),
+                    OWLSubObjectPropertyOfAxiom(sub_property=OWLObjectProperty(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','r2')),super_property=OWLObjectProperty(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','r1')),annotations=[]),
+                    OWLSubObjectPropertyOfAxiom(sub_property=OWLObjectProperty(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','r7')),super_property=OWLObjectProperty(IRI('http://www.w3.org/2002/07/owl#','topObjectProperty')),annotations=[]),
+                    OWLSubObjectPropertyOfAxiom(sub_property=OWLObjectProperty(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','r4')),super_property=OWLObjectProperty(IRI('http://www.w3.org/2002/07/owl#','topObjectProperty')),annotations=[]),
+                    OWLSubObjectPropertyOfAxiom(sub_property=OWLObjectProperty(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','r1')),super_property=OWLObjectProperty(IRI('http://www.w3.org/2002/07/owl#','topObjectProperty')),annotations=[]),
+                    OWLSubObjectPropertyOfAxiom(sub_property=OWLObjectProperty(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','r3')),super_property=OWLObjectProperty(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','r4')),annotations=[]),
+                    OWLSubObjectPropertyOfAxiom(sub_property=OWLObjectProperty(IRI('http://www.semanticweb.org/stefan/ontologies/2023/1/untitled-ontology-11#','r6')),super_property=OWLObjectProperty(IRI('http://www.w3.org/2002/07/owl#','topObjectProperty')),annotations=[])])
\ No newline at end of file