Skip to content
Snippets Groups Projects
Commit 02292710 authored by Aurélien Lamercerie's avatar Aurélien Lamercerie
Browse files

Update module Ontology to extract all elements

parent 1b39f623
Branches
No related tags found
No related merge requests found
*.pyc
__pycache__
*.todo
env/*
No preview for this file type
No preview for this file type
No preview for this file type
......@@ -8,6 +8,7 @@
#==============================================================================
from sklearn.metrics import precision_score, recall_score, f1_score
from ontoScorer.ontology import Ontology
class Metrics:
def __init__(self):
......@@ -15,7 +16,10 @@ class Metrics:
self.recall = 0
self.f1 = 0
def calculate(self, reference_classes, generated_classes):
def calculate(self, reference_ontology, generated_ontology):
reference_classes = set([cls.name() for cls in reference_ontology.get_classes()])
generated_classes = set([cls.name() for cls in generated_ontology.get_classes()])
all_classes = reference_classes.union(generated_classes)
y_true = [1 if cls in reference_classes else 0 for cls in all_classes]
y_pred = [1 if cls in generated_classes else 0 for cls in all_classes]
......@@ -23,4 +27,3 @@ class Metrics:
self.precision = precision_score(y_true, y_pred)
self.recall = recall_score(y_true, y_pred)
self.f1 = f1_score(y_true, y_pred)
\ No newline at end of file
......@@ -2,34 +2,149 @@
# -*-coding:Utf-8 -*
#==============================================================================
# ontoScorer: [brief description of the module]
# Ontology Analyzer
#------------------------------------------------------------------------------
# Detailed module description, if needed
# Extracts various elements (Classes, Object Properties, Data Properties,
# Individuals, Annotations) from RDF/OWL ontologies. Enables foundational
# comparisons between different ontologies.
#==============================================================================
from rdflib import Graph, OWL
from rdflib import Graph, RDF, RDFS, OWL
from rdflib import URIRef, BNode
from rdflib.namespace import split_uri
#==============================================================================
# Classes: Element, NamedElement and BlankElement
#==============================================================================
class Element:
def __init__(self, reference, graph):
self.reference = reference
self.graph = graph
def properties(self):
"""Retrieve properties associated with the element."""
return list(self.graph.predicate_objects(subject=self.reference))
def name(self):
raise NotImplementedError("The method name() must be implemented by subclasses.")
class NamedElement(Element):
def __init__(self, uri, graph):
super().__init__(uri, graph)
self.uri = uri
def __str__(self):
return str(self.uri)
def name(self):
_, element_name = split_uri(self.uri)
return element_name
class BlankElement(Element):
def __init__(self, bnode, graph):
super().__init__(bnode, graph)
self.id = str(bnode)
def __str__(self):
return f"BNode: {self.id}"
def name(self):
return self.id
#==============================================================================
# Class: Ontology
#==============================================================================
class Ontology:
#--------------------------------------------------------------------------
# Constructor(s)
#--------------------------------------------------------------------------
def __init__(self, ontology_path):
"""Initialize the Ontology object."""
self.path = ontology_path
self.graph = self.load_ontology(ontology_path)
self.classes = self.get_classes()
#--------------------------------------------------------------------------
# Base Method(s)
#--------------------------------------------------------------------------
def load_ontology(self, path):
"""Load the ontology from the given path into an RDF graph."""
g = Graph()
g.parse(path, format="ttl")
return g
def _get_elements_of_type(self, rdf_type):
"""Extract all elements of a specific RDF type from the ontology."""
elements = []
for s, _, o in self.graph.triples((None, RDF.type, rdf_type)):
if isinstance(s, BNode):
elements.append(BlankElement(s, self.graph))
elif isinstance(s, URIRef):
elements.append(NamedElement(s, self.graph))
return elements
#--------------------------------------------------------------------------
# Extracting Method(s)
#--------------------------------------------------------------------------
def get_classes(self):
classes = set()
triplets_count = 0
for s, p, o in self.graph.triples((None, None, None)):
triplets_count += 1
if o == OWL.Class:
_, class_name = split_uri(s)
classes.add(class_name)
return classes
def compare_to(self, other_ontology):
return self.classes, other_ontology.classes
\ No newline at end of file
"""Extract all classes from the ontology."""
return self._get_elements_of_type(OWL.Class)
def get_object_properties(self):
"""Extract all object properties from the ontology."""
return self._get_elements_of_type(OWL.ObjectProperty)
def get_data_properties(self):
"""Extract all data properties from the ontology."""
return self._get_elements_of_type(OWL.DatatypeProperty)
def get_restrictions(self):
"""Extract all restrictons from the ontology."""
return self._get_elements_of_type(OWL.Restriction)
def get_individuals(self) -> list:
"""Extract all individuals from the ontology."""
all_types = set(self.graph.subjects(RDF.type))
non_individuals = {element.reference for element in
self.get_classes() +
self.get_object_properties() +
self.get_data_properties()}
individuals = all_types - non_individuals
return [NamedElement(i, self.graph) if isinstance(i, URIRef) else BlankElement(i, self.graph)
for i in individuals]
def get_annotations(self):
"""Extract all annotation comments from the ontology."""
annotations = set()
for _, _, o in self.graph.triples((None, RDFS.label, None)):
annotations.add(str(o))
return annotations
#--------------------------------------------------------------------------
# Comparison Method(s)
#--------------------------------------------------------------------------
def compare_to(self, other_ontology) -> tuple:
"""Compare classes of the current ontology with another."""
self_classes = {c.name() for c in self.classes}
other_classes = {c.name() for c in other_ontology.classes}
# Pour des comparaisons plus avancées, ajustez ce code
unique_to_self = self_classes - other_classes
unique_to_other = other_classes - self_classes
return unique_to_self, unique_to_other
......@@ -19,7 +19,7 @@ class OntoScorer:
def compare(self):
self.comparison_result = self.reference_ontology.compare_to(self.generated_ontology)
self.metrics.calculate(*self.comparison_result)
self.metrics.calculate(self.reference_ontology, self.generated_ontology)
def generate_report(self):
report = Report(self.reference_ontology,
......
import os
import sys
CURRENT_DIRPATH = os.path.dirname(os.path.abspath(__file__))
LIB_PATH = os.path.dirname(f'{CURRENT_DIRPATH}/../..')
print(f'Test Context: {LIB_PATH}')
sys.path.insert(0, os.path.abspath(LIB_PATH))
import ontoScorer
@prefix ns1: <https://tenet.tetras-libre.fr/base-ontology#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<https://tenet.tetras-libre.fr/extract-result#SolarSystem> a owl:Individual,
<https://tenet.tetras-libre.fr/extract-result#system>,
<https://tenet.tetras-libre.fr/extract-result#system-hasPart-object>,
<https://tenet.tetras-libre.fr/extract-result#system-hasPart-sun> ;
rdfs:label "SolarSystem" ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#direct> a owl:ObjectProperty ;
rdfs:label "direct" ;
rdfs:subPropertyOf ns1:Out_ObjectProperty ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#gravitation-bind-system> a owl:Class ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onProperty <https://tenet.tetras-libre.fr/extract-result#bind> ;
owl:someValuesFrom <https://tenet.tetras-libre.fr/extract-result#system> ],
<https://tenet.tetras-libre.fr/extract-result#gravitation> ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#hasManner> a owl:ObjectProperty ;
rdfs:label "hasManner" ;
rdfs:subPropertyOf ns1:Out_ObjectProperty ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#not-direct> a owl:ObjectProperty ;
rdfs:subPropertyOf ns1:Out_ObjectProperty ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#object-orbit-hasManner-direct-sun> a owl:Class ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onProperty <https://tenet.tetras-libre.fr/extract-result#orbit-hasManner-direct> ;
owl:someValuesFrom <https://tenet.tetras-libre.fr/extract-result#sun> ],
<https://tenet.tetras-libre.fr/extract-result#object> ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#object-orbit-hasManner-not-direct-sun> a owl:Class ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onProperty <https://tenet.tetras-libre.fr/extract-result#orbit-hasManner-not-direct> ;
owl:someValuesFrom <https://tenet.tetras-libre.fr/extract-result#sun> ],
<https://tenet.tetras-libre.fr/extract-result#object> ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#bind> a owl:ObjectProperty ;
rdfs:label "bind" ;
rdfs:subPropertyOf ns1:Out_ObjectProperty ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#gravitation> a owl:Class ;
rdfs:label "gravitation" ;
rdfs:subClassOf ns1:Entity ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#orbit-hasManner-direct> a owl:ObjectProperty ;
rdfs:subPropertyOf <https://tenet.tetras-libre.fr/extract-result#orbit> ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#orbit-hasManner-not-direct> a owl:ObjectProperty ;
rdfs:subPropertyOf <https://tenet.tetras-libre.fr/extract-result#orbit> ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#system-hasPart-object> a owl:Class ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onProperty <https://tenet.tetras-libre.fr/extract-result#hasPart> ;
owl:someValuesFrom <https://tenet.tetras-libre.fr/extract-result#object> ],
<https://tenet.tetras-libre.fr/extract-result#system> ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#system-hasPart-sun> a owl:Class ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onProperty <https://tenet.tetras-libre.fr/extract-result#hasPart> ;
owl:someValuesFrom <https://tenet.tetras-libre.fr/extract-result#sun> ],
<https://tenet.tetras-libre.fr/extract-result#system> ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#hasPart> a owl:ObjectProperty ;
rdfs:label "hasPart" ;
rdfs:subPropertyOf ns1:Out_ObjectProperty ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#orbit> a owl:ObjectProperty ;
rdfs:label "orbit" ;
rdfs:subPropertyOf ns1:Out_ObjectProperty ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#object> a owl:Class ;
rdfs:label "object" ;
rdfs:subClassOf ns1:Entity ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#sun> a owl:Class ;
rdfs:label "sun" ;
rdfs:subClassOf ns1:Entity ;
ns1:fromStructure "unknown" .
<https://tenet.tetras-libre.fr/extract-result#system> a owl:Class ;
rdfs:label "system" ;
rdfs:subClassOf ns1:Entity,
ns1:Undetermined_Thing ;
ns1:fromStructure "unknown" .
@prefix base: <https://reference.tetras-libre.fr/base-ontology#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix result: <https://reference.tetras-libre.fr/expected-result#> .
result:SolarSystem a owl:Individual,
result:system,
result:system-isBindBy-gravitation,
result:system-hasPart-object-orbit-sun,
result:system-hasPart-sun ;
rdfs:label "SolarSystem" .
result:direct a owl:ObjectProperty ;
rdfs:label "direct" ;
rdfs:subPropertyOf base:Out_ObjectProperty .
result:gravitation-bind-system a owl:Class ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onProperty result:bind ;
owl:someValuesFrom result:system ],
result:gravitation .
result:hasManner a owl:ObjectProperty ;
rdfs:label "hasManner" ;
rdfs:subPropertyOf base:Out_ObjectProperty .
result:not-direct a owl:ObjectProperty ;
rdfs:subPropertyOf base:Out_ObjectProperty .
result:object-orbit-sun a owl:Class ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onProperty result:orbit ;
owl:someValuesFrom result:sun ],
result:object .
result:object-orbit-hasManner-direct-sun a owl:Class ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onProperty result:orbit-hasManner-direct ;
owl:someValuesFrom result:sun ],
result:object-orbit-sun .
result:object-orbit-hasManner-not-direct-sun a owl:Class ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onProperty result:orbit-hasManner-not-direct ;
owl:someValuesFrom result:sun ],
result:object-orbit-sun .
result:gravitation a owl:Class ;
rdfs:label "gravitation" ;
rdfs:subClassOf base:Entity .
result:system-isBindBy-gravitation a owl:Class ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onProperty result:isBindBy ;
owl:someValuesFrom result:gravitation ],
result:system .
result:system-hasPart-object a owl:Class ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onProperty result:hasPart ;
owl:someValuesFrom result:object ],
result:system .
result:system-hasPart-object-orbit-sun a owl:Class ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onProperty result:hasPart ;
owl:someValuesFrom result:object-orbit-sun ],
result:system-hasPart-object .
result:system-hasPart-sun a owl:Class ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onProperty result:hasPart ;
owl:someValuesFrom result:sun ],
result:system .
result:bind a owl:ObjectProperty ;
rdfs:label "bind" ;
rdfs:subPropertyOf base:Out_ObjectProperty .
result:isBindBy owl:inverseOf result:bind ;
rdfs:label "isBindBy" ;
rdfs:subPropertyOf base:Out_ObjectProperty .
result:orbit a owl:ObjectProperty ;
rdfs:label "orbit" ;
rdfs:subPropertyOf base:Out_ObjectProperty .
result:orbit-hasManner-direct a owl:ObjectProperty ;
rdfs:subPropertyOf result:orbit .
result:orbit-hasManner-not-direct a owl:ObjectProperty ;
rdfs:subPropertyOf result:orbit .
result:hasPart a owl:ObjectProperty ;
rdfs:label "hasPart" ;
rdfs:subPropertyOf base:Out_ObjectProperty .
result:object a owl:Class ;
rdfs:label "object" ;
rdfs:subClassOf base:Entity .
result:system a owl:Class ;
rdfs:label "system" ;
rdfs:subClassOf base:Entity.
result:sun a owl:Class ;
rdfs:label "sun" ;
rdfs:subClassOf base:Entity .
......@@ -2,9 +2,89 @@
# -*-coding:Utf-8 -*
#==============================================================================
# ontoScorer: [brief description of the module]
# test_ontology: Ontology Testing Module
#------------------------------------------------------------------------------
# Detailed module description, if needed
# Contains tests for verifying functionality of the Ontology class.
#==============================================================================
# TODO
import unittest
import os
from context import ontoScorer
from ontoScorer.ontology import Ontology
from rdflib import URIRef
class TestOntology(unittest.TestCase):
def setUp(self):
# Test ontology paths
DATA_FOLDER_PATH = f'{os.path.dirname(os.path.abspath(__file__))}/test_data'
self.ontology1_path = f"{DATA_FOLDER_PATH}/ontology_a.ttl"
self.ontology2_path = f"{DATA_FOLDER_PATH}/ontology_b.ttl"
self.onto1 = Ontology(self.ontology1_path)
self.onto2 = Ontology(self.ontology2_path)
def test_load_ontology(self):
self.assertIsNotNone(self.onto1.graph)
self.assertIsNotNone(self.onto2.graph)
def test_get_classes(self):
classes1_names = {c.name() for c in self.onto1.get_classes()}
classes2_names = {c.name() for c in self.onto2.get_classes()}
self.assertIn("gravitation-bind-system", classes1_names)
self.assertIn("gravitation-bind-system", classes1_names)
self.assertIn("object-orbit-hasManner-direct-sun", classes1_names)
self.assertIn("object-orbit-hasManner-not-direct-sun", classes1_names)
self.assertIn("gravitation", classes1_names)
self.assertIn("system-hasPart-object", classes1_names)
self.assertIn("system-hasPart-sun", classes1_names)
self.assertIn("object", classes1_names)
self.assertIn("sun", classes1_names)
self.assertIn("system", classes1_names)
self.assertNotIn("system-isBindBy-gravitation", classes1_names)
self.assertIn("system-isBindBy-gravitation", classes2_names)
def test_get_object_properties(self):
object_properties_names = {op.name() for op in self.onto1.get_object_properties()}
self.assertIn("direct", object_properties_names)
self.assertIn("hasManner", object_properties_names)
self.assertIn("not-direct", object_properties_names)
self.assertIn("bind", object_properties_names)
self.assertIn("orbit-hasManner-direct", object_properties_names)
self.assertIn("orbit-hasManner-not-direct", object_properties_names)
self.assertIn("hasPart", object_properties_names)
self.assertIn("orbit", object_properties_names)
def test_get_data_properties(self):
data_properties_names = {dp.name() for dp in self.onto1.get_data_properties()}
self.assertEqual(len(data_properties_names), 0)
def test_get_restrictions(self):
restrictions = self.onto1.get_restrictions()
expected_restrictions_count = 5
self.assertEqual(len(restrictions), expected_restrictions_count)
def test_get_individuals(self):
individuals_names = {ind.name() for ind in self.onto1.get_individuals()}
self.assertIn("SolarSystem", individuals_names)
self.assertNotIn("gravitation", individuals_names)
def test_get_annotations(self):
annotations = self.onto1.get_annotations()
self.assertIn("SolarSystem", annotations)
self.assertIn("direct", annotations)
self.assertIn("gravitation", annotations)
self.assertIn("orbit", annotations)
self.assertIn("object", annotations)
self.assertIn("sun", annotations)
self.assertIn("system", annotations)
def test_compare_to(self):
comparison_result = self.onto1.compare_to(self.onto2)
self.assertIsInstance(comparison_result, tuple)
if __name__ == "__main__":
unittest.main()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment