Skip to content

Commit

Permalink
Merge pull request #128 from dice-group/develop
Browse files Browse the repository at this point in the history
Merge with main
  • Loading branch information
alkidbaci authored Feb 4, 2025
2 parents d3cf32e + 6601ac6 commit 2c92968
Show file tree
Hide file tree
Showing 40 changed files with 2,129 additions and 551 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ on:
- main
- documentation # just for testing
pull_request:
branches:
- main

jobs:
docs:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ jobs:
run: |
wget https://files.dice-research.org/projects/Ontolearn/KGs.zip
unzip KGs.zip
pip install scikit-learn
python -m pytest -p no:warnings -x
- name: Coverage report
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,4 @@ cython_debug/
.vscode/

# Project related files
/KGs/
KGs/
76 changes: 61 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# OWLAPY
[![Downloads](https://static.pepy.tech/badge/owlapy)](https://pepy.tech/project/owlapy)
[![Downloads](https://img.shields.io/pypi/dm/owlapy)](https://pypi.org/project/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.3.3-blue)](https://pypi.org/project/owlapy/1.3.3/)
[![Docs](https://img.shields.io/badge/documentation-1.3.3-yellow)](https://dice-group.github.io/owlapy/usage/main.html)
[![Pypi](https://img.shields.io/badge/pypi-1.4.0-blue)](https://pypi.org/project/owlapy/1.4.0/)
[![Docs](https://img.shields.io/badge/documentation-1.4.0-yellow)](https://dice-group.github.io/owlapy/usage/main.html)

![OWLAPY](docs/_static/images/owlapy_logo.png)

Expand All @@ -20,16 +22,40 @@ or
```bash
pip3 install owlapy
```


```shell
# To download RDF knowledge graphs
wget https://files.dice-research.org/projects/Ontolearn/KGs.zip -O ./KGs.zip && unzip KGs.zip
pytest -p no:warnings -x # Running 142 tests ~ 30 secs
pytest -p no:warnings -x # Running 147 tests ~ 35 secs
```

## Examples

### OWL Reasoning from Command line

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

```shell
owlapy --path_ontology "KGs/Family/family-benchmark_rich_background.owl" --inference_types "all" --out_ontology "enriched_family.owl"
```

```--inference_types``` can be specified by selecting one from

```
["InferredClassAssertionAxiomGenerator",
"InferredSubClassAxiomGenerator",
"InferredDisjointClassesAxiomGenerator",
"InferredEquivalentClassAxiomGenerator",
"InferredEquivalentDataPropertiesAxiomGenerator",
"InferredEquivalentObjectPropertyAxiomGenerator",
"InferredInverseObjectPropertiesAxiomGenerator",
"InferredSubDataPropertyAxiomGenerator",
"InferredSubObjectPropertyAxiomGenerator",
"InferredDataPropertyCharacteristicAxiomGenerator",
"InferredObjectPropertyCharacteristicAxiomGenerator"]
```

</details>

### Exploring OWL Ontology

<details><summary> Click me! </summary>
Expand Down Expand Up @@ -78,7 +104,8 @@ for axiom in onto.get_abox_axioms():

</details>

### Creating OWL Class Expressions
### OWL Knowledge Engineering

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

```python
Expand All @@ -88,31 +115,27 @@ 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

from owlapy.static_funcs import create_ontology
# Using owl classes to create a complex class expression
male = OWLClass("http://example.com/society#male")
hasChild = OWLObjectProperty("http://example.com/society#hasChild")
hasChild_male = OWLObjectSomeValuesFrom(hasChild, male)
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 or convert it to SPARQL for example.
# 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)

# Create an ontology via ontology manager directly
ontology = create_ontology("file:/example_ontology.owl",with_owlapi=False)
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()

ontology.save(inplace=True)
```

Every OWL object that can be used to classify individuals, is considered a class expression and
Expand Down Expand Up @@ -178,5 +201,28 @@ stopJVM()

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

### Sklearn to OWL Ontology

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

```python
from owlapy.owl_ontology_manager import SyncOntologyManager
from owlapy.util_owl_static_funcs import csv_to_rdf_kg
import pandas as pd
from sklearn.datasets import load_iris
data = load_iris()
df = pd.DataFrame(data.data, columns=data.feature_names)
df.to_csv("iris_dataset.csv", index=False)
path_kg = "iris_kg.owl"
# Construct an RDF Knowledge Graph from a CSV file
csv_to_rdf_kg(path_csv="iris_dataset.csv", path_kg=path_kg, namespace="http://owlapy.com/iris")
onto = SyncOntologyManager().load_ontology(path_kg)
assert len(onto.get_abox_axioms()) == 750

```

</details>


## How to cite
Currently, we are working on our manuscript describing our framework.
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

project = 'OWLAPY'
author = 'Ontolearn Team'
release = '1.3.3'
release = '1.4.0'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
2 changes: 1 addition & 1 deletion docs/usage/main.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# About owlapy

**Version:** owlapy 1.3.3
**Version:** owlapy 1.4.0

**GitHub repository:** [https://github.com/dice-group/owlapy](https://github.com/dice-group/owlapy)

Expand Down
64 changes: 64 additions & 0 deletions examples/owlapy_serve.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# To start the FastAPI server with the 'family-benchmark_rich_background.owl' ontology,
# run the following command in your terminal:
# $ owlapy-serve --path_kb KGs/Family/family-benchmark_rich_background.owl --reasoner HermiT

# Optionally, you provide custom host and port for the FastAPI server:
# $ owlapy-serve --path_kb KGs/Family/family-benchmark_rich_background.owl --reasoner HermiT --host 0.0.0.0 --port 8000
import requests

# Base URL where your FastAPI server is running
BASE_URL = 'http://localhost:8000'

# 1. Get Classes in the Ontology
print("1. Get Classes:")
response = requests.get(f'{BASE_URL}/classes')
print('Classes:', response.json())

# 2. Get Object Properties in the Ontology
print("\n2. Get Object Properties:")
response = requests.get(f'{BASE_URL}/object_properties')
print('Object Properties:', response.json())

# 3. Get Data Properties in the Ontology
print("\n3. Get Data Properties:")
response = requests.get(f'{BASE_URL}/data_properties')
print('Data Properties:', response.json())

# 4. Get Individuals in the Ontology
print("\n4. Get Individuals:")
response = requests.get(f'{BASE_URL}/individuals')
print('Individuals:', response.json())

# 5. Get ABox Axioms (Assertions about individuals)
print("\n5. Get ABox Axioms:")
response = requests.get(f'{BASE_URL}/abox')
print('ABox Axioms:', response.json())

# 6. Get TBox Axioms (Class and property definitions)
print("\n6. Get TBox Axioms:")
response = requests.get(f'{BASE_URL}/tbox')
print('TBox Axioms:', response.json())

# 7. Get Instances of a Specific Class
print("\n7. Get Instances of a Class:")
class_iri_request = {
"class_iri": "http://www.example.org/family#Person"
}
response = requests.post(f'{BASE_URL}/instances', json=class_iri_request)
print('Instances of Class:', response.json())

# 8. Infer Axioms of a Specific Type
print("\n8. Infer Subclass Axioms:")
inference_request = {
"inference_type": "InferredSubClassAxiomGenerator"
}
response = requests.post(f'{BASE_URL}/infer_axioms', json=inference_request)
print('Inferred Subclass Axioms:', response.json())

# 9. Infer All Types of Axioms
print("\n9. Infer All Axioms:")
inference_request = {
"inference_type": "all"
}
response = requests.post(f'{BASE_URL}/infer_axioms', json=inference_request)
print('All Inferred Axioms:', response.json())
2 changes: 1 addition & 1 deletion owlapy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from .converter import owl_expression_to_sparql, owl_expression_to_sparql_with_confusion_matrix
from .owl_ontology_manager import OntologyManager

__version__ = '1.3.3'
__version__ = '1.4.0'

__all__ = [
'owl_expression_to_dl', 'owl_expression_to_manchester',
Expand Down
1 change: 1 addition & 0 deletions owlapy/abstracts/abstract_owl_ontology.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ def remove_axiom(self, axiom: Union[OWLAxiom, Iterable[OWLAxiom]]):
"""
pass

@abstractmethod
def save(self, document_iri: Optional[IRI] = None):
"""Saves this ontology, using its IRI to determine where/how the ontology should be
saved.
Expand Down
9 changes: 9 additions & 0 deletions owlapy/class_expression/class_expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ class OWLObjectComplementOf(OWLBooleanClassExpression, HasOperands[OWLClassExpre

_operand: OWLClassExpression

def __new__(cls, op: OWLClassExpression):
"""
Creates a new instance or returns the operand if op is already a complement.
"""
if isinstance(op, OWLObjectComplementOf):
return op.get_operand()
else:
return super(OWLObjectComplementOf, cls).__new__(cls)

def __init__(self, op: OWLClassExpression):
"""
Args:
Expand Down
6 changes: 3 additions & 3 deletions owlapy/class_expression/nary_boolean_expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ def __repr__(self):

def __eq__(self, other):
if type(other) is type(self):
return {i for i in self._operands} == { j for j in other.operands()}
else:
return False
return (set(self._operands) == set(other.operands())
and len(list(self._operands)) == len(list(other.operands())))
return False

def __hash__(self):
return hash(self._operands)
Expand Down
Loading

0 comments on commit 2c92968

Please sign in to comment.