diff --git a/ontoScorer/metric_score.py b/ontoScorer/metric_score.py index 20027adf56aefc95c19c6c466c8abe9f3c0cbcf7..dd899bcfe9fb08982a309c9680963bd37b36d649 100644 --- a/ontoScorer/metric_score.py +++ b/ontoScorer/metric_score.py @@ -46,11 +46,12 @@ class Score: """ self.y_true = y_true self.y_pred = y_pred - self.precision = precision_score(y_true, y_pred) - self.recall = recall_score(y_true, y_pred) - self.f1 = f1_score(y_true, y_pred) - self.total_elements = len(y_true) - self.matched_elements = sum([1 for true, pred in zip(y_true, y_pred) if true == pred]) + if len(y_true) > 0: + self.precision = precision_score(y_true, y_pred) + self.recall = recall_score(y_true, y_pred) + self.f1 = f1_score(y_true, y_pred) + self.total_elements = len(y_true) + self.matched_elements = sum([1 for true, pred in zip(y_true, y_pred) if true == pred]) #-------------------------------------------------------------------------- diff --git a/ontoScorer/metrics.py b/ontoScorer/metrics.py index f712fa80a0660d5b880027ed1669112358c4d701..4a903def7e00f9306bb40be1c625b4fec6a47101 100644 --- a/ontoScorer/metrics.py +++ b/ontoScorer/metrics.py @@ -123,52 +123,52 @@ class Metrics: self.scores["taxonomic_relations"]["synthesis"].compute(y_true_overall, y_pred_overall) - # def compute_non_taxonomic_relation_scores(self, reference_ontology, generated_ontology): - # relation_methods = { - # "object_properties": ("get_object_property_relations", Ontology.compare_relations), - # "data_properties": ("get_data_property_relations", Ontology.compare_relations) - # } + def compute_non_taxonomic_relation_scores(self, reference_ontology, generated_ontology): + relation_methods = { + "object_properties": ("get_object_property_relations", Ontology.compare_relations), + "data_properties": ("get_data_property_relations", Ontology.compare_relations) + } - # y_true_overall = [] - # y_pred_overall = [] + y_true_overall = [] + y_pred_overall = [] - # for score_name, (method_name, comparison_function) in relation_methods.items(): - # reference_relations = getattr(reference_ontology, method_name)() - # generated_relations = getattr(generated_ontology, method_name)() + for score_name, (method_name, comparison_function) in relation_methods.items(): + reference_relations = getattr(reference_ontology, method_name)() + generated_relations = getattr(generated_ontology, method_name)() - # all_relations = list(set(reference_relations + generated_relations)) - # y_true = [1 if rel in reference_relations else 0 for rel in all_relations] - # y_pred = [1 if rel in generated_relations else 0 for rel in all_relations] + all_relations = list(set(reference_relations + generated_relations)) + y_true = [1 if any([comparison_function(elem, ref_elem) for ref_elem in reference_relations]) else 0 for elem in all_relations] + y_pred = [1 if any([comparison_function(elem, gen_elem) for gen_elem in generated_relations]) else 0 for elem in all_relations] - # self.scores["non_taxonomic_relations"][score_name].compute(y_true, y_pred) + self.scores["non_taxonomic_relations"][score_name].compute(y_true, y_pred) - # y_true_overall.extend(y_true) - # y_pred_overall.extend(y_pred) + y_true_overall.extend(y_true) + y_pred_overall.extend(y_pred) - # self.scores["non_taxonomic_relations"]["synthesis"].compute(y_true_overall, y_pred_overall) + self.scores["non_taxonomic_relations"]["synthesis"].compute(y_true_overall, y_pred_overall) - # def compute_axiom_scores(self, reference_ontology, generated_ontology): - # axiom_methods = { - # "restriction_axioms": ("get_restriction_axioms", Ontology.compare_axioms) - # } + def compute_axiom_scores(self, reference_ontology, generated_ontology): + axiom_methods = { + "restriction_axioms": ("get_axioms", Ontology.compare_axioms) + } - # y_true_overall = [] - # y_pred_overall = [] + y_true_overall = [] + y_pred_overall = [] - # for score_name, (method_name, comparison_function) in axiom_methods.items(): - # reference_axioms = getattr(reference_ontology, method_name)() - # generated_axioms = getattr(generated_ontology, method_name)() + for score_name, (method_name, comparison_function) in axiom_methods.items(): + reference_axioms = getattr(reference_ontology, method_name)() + generated_axioms = getattr(generated_ontology, method_name)() - # all_axioms = list(set(reference_axioms + generated_axioms)) - # y_true = [1 if ax in reference_axioms else 0 for ax in all_axioms] - # y_pred = [1 if ax in generated_axioms else 0 for ax in all_axioms] + all_relations = list(set(reference_axioms + generated_axioms)) + y_true = [1 if any([comparison_function(elem, ref_elem) for ref_elem in reference_axioms]) else 0 for elem in all_relations] + y_pred = [1 if any([comparison_function(elem, gen_elem) for gen_elem in generated_axioms]) else 0 for elem in all_relations] - # self.scores["axioms"][score_name].compute(y_true, y_pred) + self.scores["axioms"][score_name].compute(y_true, y_pred) - # y_true_overall.extend(y_true) - # y_pred_overall.extend(y_pred) + y_true_overall.extend(y_true) + y_pred_overall.extend(y_pred) - # self.scores["axioms"]["synthesis"].compute(y_true_overall, y_pred_overall) + self.scores["axioms"]["synthesis"].compute(y_true_overall, y_pred_overall) #-------------------------------------------------------------------------- @@ -192,16 +192,16 @@ class Metrics: print(score) print("----------------------------") - # nontaxonomic_relation_scores = self.scores["non_taxonomic_relations"] - # for element, score in nontaxonomic_relation_scores.items(): - # print(f"Metrics for {element.capitalize()} (Non-Taxonomic Relation axis):") - # print(score) - # print("----------------------------") + nontaxonomic_relation_scores = self.scores["non_taxonomic_relations"] + for element, score in nontaxonomic_relation_scores.items(): + print(f"Metrics for {element.capitalize()} (Non-Taxonomic Relation axis):") + print(score) + print("----------------------------") - # axiom_scores = self.scores["axioms"] - # for element, score in axiom_scores.items(): - # print(f"Metrics for {element.capitalize()} (Axiom axis):") - # print(score) - # print("----------------------------") + axiom_scores = self.scores["axioms"] + for element, score in axiom_scores.items(): + print(f"Metrics for {element.capitalize()} (Axiom axis):") + print(score) + print("----------------------------") diff --git a/ontoScorer/ontology.py b/ontoScorer/ontology.py index 8da24eacede59b70cd1bd0755ede371f7f5a778e..a9eb33a67eb1f083139e488325fe5887554e9379 100644 --- a/ontoScorer/ontology.py +++ b/ontoScorer/ontology.py @@ -13,19 +13,15 @@ from rdflib import Graph, RDF, RDFS, OWL from rdflib import URIRef, BNode from rdflib.namespace import split_uri -from ontology_metadata import Metadata - -from ontoScorer.ontology_entity import (Entity, - NamedEntity, - BlankEntity) +from ontology_utils import harmonize_prefixes, uri_to_short_form, extract_prefixes_from_graph +from ontology_metadata import Metadata +from ontoScorer.ontology_entity import (Entity, NamedEntity, BlankEntity) from ontoScorer.ontology_taxonomic_relations import (SubclassOfRelation, SubpropertyOfRelation, InstanceOfRelation) - from ontoScorer.ontology_nontaxonomic_relations import (ObjectPropertyRelation, DataPropertyRelation) - from ontoScorer.ontology_axioms import (Axiom, RestrictionAxiom, SomeValuesFromRestrictionAxiom) @@ -41,12 +37,14 @@ class Ontology: # Constructor(s) #-------------------------------------------------------------------------- - def __init__(self, ontology_path): + def __init__(self, ontology_path, equivalent_prefix=None): """Initialize the Ontology object.""" self.path = ontology_path + self.equivalent_prefix = equivalent_prefix if equivalent_prefix else [] self.graph = self.load_ontology(ontology_path) self.classes = self.get_classes() + #-------------------------------------------------------------------------- # Base Method(s) #-------------------------------------------------------------------------- @@ -55,7 +53,26 @@ class Ontology: """Load the ontology from the given path into an RDF graph.""" g = Graph() g.parse(path, format="ttl") + g = self.harmonize_ontology_prefixes(g) + return g + + def load_ontology(self, path): + """Load the ontology from the given path into an RDF graph.""" + g = Graph() + g.parse(path, format="ttl") + g = self.harmonize_ontology_prefixes(g) return g + + def harmonize_ontology_prefixes(self, graph): + if self.equivalent_prefix: + for prefix, source_uri, target_uri in self.equivalent_prefix: + graph = harmonize_prefixes(graph, source_uri, target_uri) + return graph + + def get_uri_short_form(self, uri): + graph_prefixes = extract_prefixes_from_graph(self.graph) + return uri_to_short_form(uri, self.equivalent_prefix, graph_prefixes) + def _get_elements_of_type(self, rdf_type): """Extract all entities of a specific RDF type from the ontology.""" @@ -66,6 +83,7 @@ class Ontology: elif isinstance(s, URIRef): entities.append(NamedEntity(s, self.graph)) return entities + #-------------------------------------------------------------------------- # Metadata and Annotation Extraction @@ -123,27 +141,30 @@ class Ontology: #-------------------------------------------------------------------------- # Taxonomic Relation Extraction (Hierarchical Structure) #-------------------------------------------------------------------------- - + def get_subclass_relations(self): relations = [] for s, _, o in self.graph.triples((None, RDFS.subClassOf, None)): - relations.append(SubclassOfRelation(s, o, self.graph)) + if not (isinstance(s, BNode) or isinstance(o, BNode)): + relations.append(SubclassOfRelation(s, o, self.graph)) return relations - + def get_subproperty_relations(self): relations = [] for s, _, o in self.graph.triples((None, RDFS.subPropertyOf, None)): - relations.append(SubpropertyOfRelation(s, o, self.graph)) + if not (isinstance(s, BNode) or isinstance(o, BNode)): + relations.append(SubpropertyOfRelation(s, o, self.graph)) return relations - + def get_instance_relations(self): relations = [] for s, _, o in self.graph.triples((None, RDF.type, None)): # Filter out the RDF schema and ontology types to get only the actual instances - if o not in [RDF.Property, RDFS.Class, OWL.Class, OWL.ObjectProperty, OWL.DatatypeProperty]: + if o not in [RDF.Property, RDFS.Class, OWL.Class, OWL.ObjectProperty, OWL.DatatypeProperty] and not (isinstance(s, BNode) or isinstance(o, BNode)): relations.append(InstanceOfRelation(s, o, self.graph)) return relations + def get_taxonomic_relations(self): return self.get_subclass_relations() + self.get_subproperty_relations() + self.get_instance_relations() @@ -220,4 +241,31 @@ class Ontology: @staticmethod def compare_relations(relation1, relation2): - return relation1.compare_relation(relation2) \ No newline at end of file + return relation1.compare_relation(relation2) + + @staticmethod + def compare_axioms(axiom1, axiom2): + return axiom1 == axiom2 + + @staticmethod + def compare_axiom_lists(axioms1, axioms2): + common = [] + only_in_1 = [] + only_in_2 = [] + + for axiom in axioms1: + if axiom in axioms2: + common.append(axiom) + else: + only_in_1.append(axiom) + + for axiom in axioms2: + if axiom not in axioms1: + only_in_2.append(axiom) + + return { + "common": common, + "only_in_1": only_in_1, + "only_in_2": only_in_2 + } + diff --git a/ontoScorer/ontology_axioms.py b/ontoScorer/ontology_axioms.py index e3019179545d67b280fb37e9de2730aaf14c56a9..51e6e2f4c5deda64842b8f51f1a59f63bb29db7c 100644 --- a/ontoScorer/ontology_axioms.py +++ b/ontoScorer/ontology_axioms.py @@ -10,10 +10,25 @@ from rdflib import URIRef, BNode + +#-------------------------------------------------------------------------- +# Base Class for Axioms +#-------------------------------------------------------------------------- class Axiom: + def __str__(self) -> str: """String representation of the axiom for display or debugging.""" raise NotImplementedError("Subclasses must implement this method.") + + def __eq__(self, other): + return isinstance(other, self.__class__) + + def __lt__(self, other): + return str(self) < str(other) + + def __hash__(self): + return hash(str(self)) + #-------------------------------------------------------------------------- # Restriction Axioms @@ -23,30 +38,31 @@ class RestrictionAxiom(Axiom): self.parent_class = parent_class self.restriction_node = restriction_node + def __eq__(self, other): + return super().__eq__(other) and self.parent_class == other.parent_class + def __str__(self): return f"Restriction on class: {self.parent_class} with node: {self.restriction_node}" - + def __hash__(self): + return hash((self.parent_class)) + + class SomeValuesFromRestrictionAxiom(RestrictionAxiom): def __init__(self, parent_class: (URIRef, BNode), restriction_node: (URIRef, BNode), on_property: URIRef, some_values_from: (URIRef, BNode)): super().__init__(parent_class, restriction_node) self.on_property = on_property self.some_values_from = some_values_from + def __eq__(self, other): + return super().__eq__(other) and self.on_property == other.on_property and self.some_values_from == other.some_values_from + def __str__(self): return f"Restriction on class: {self.parent_class} with node: {self.restriction_node} via property: {self.on_property} with some values from: {self.some_values_from}" + def __hash__(self): + return hash((self.parent_class, self.on_property, self.some_values_from)) -# class SomeValuesFromRestrictionAxiom(RestrictionAxiom): -# def __init__(self, restriction_node: (URIRef, BNode), on_property: URIRef, some_values_from: (URIRef, BNode)): -# super().__init__(restriction_node) -# self.on_property = on_property -# self.some_values_from = some_values_from - -# def __str__(self): -# return f"Restriction on: {self.restriction_node} via property: {self.on_property} with some values from: {self.some_values_from}" - - # There are different kinds of restriction axioms, e.g., someValueFrom, allValuesFrom, etc. # Each type can be implemented as a subclass of RestrictionAxiom if needed. @@ -57,16 +73,12 @@ class SomeValuesFromRestrictionAxiom(RestrictionAxiom): class ClassEquivalenceAxiom(Axiom): def __init__(self, classes: [URIRef]): self.classes = classes - # Further methods to handle class equivalences can be added here. + def __eq__(self, other): + return super().__eq__(other) and set(self.classes) == set(other.classes) -#-------------------------------------------------------------------------- -# Disjointness Axioms -#-------------------------------------------------------------------------- -class ClassDisjointnessAxiom(Axiom): - def __init__(self, classes: [URIRef]): - self.classes = classes - # Further methods to handle class disjointness can be added here. + def __hash__(self): + return hash(tuple(sorted(self.classes))) #-------------------------------------------------------------------------- @@ -76,6 +88,11 @@ class PropertyCharacteristicAxiom(Axiom): def __init__(self, property_ref: URIRef, characteristic_type: URIRef): self.property_ref = property_ref self.characteristic_type = characteristic_type - # Further methods to handle property characteristics can be added here. + + def __eq__(self, other): + return super().__eq__(other) and self.property_ref == other.property_ref and self.characteristic_type == other.characteristic_type + + def __hash__(self): + return hash((self.property_ref, self.characteristic_type)) # Additional axioms, such as subproperty axioms, inverse properties, etc., can be added as needed. diff --git a/ontoScorer/ontology_entity.py b/ontoScorer/ontology_entity.py index c75c78970012357b619e442375131607db54899a..2e5f843bf975c085f63e6275af99693bd7517774 100644 --- a/ontoScorer/ontology_entity.py +++ b/ontoScorer/ontology_entity.py @@ -25,6 +25,13 @@ class Entity: def name(self): raise NotImplementedError("The method name() must be implemented by subclasses.") + + def __lt__(self, other): + """Override the default < (less than) operator to compare entities by their name.""" + if isinstance(other, Entity): + return self.name() < other.name() + return NotImplemented + class NamedEntity(Entity): def __init__(self, uri, graph): @@ -38,6 +45,7 @@ class NamedEntity(Entity): _, entity_name = split_uri(self.uri) return entity_name + class BlankEntity(Entity): def __init__(self, bnode, graph): super().__init__(bnode, graph) diff --git a/ontoScorer/ontology_taxonomic_relations.py b/ontoScorer/ontology_taxonomic_relations.py index eaa35800ae259d2be6930d732e89c5f947ba3aed..4c1d7433394357a50b985d4a6161ac3d2a1194c4 100644 --- a/ontoScorer/ontology_taxonomic_relations.py +++ b/ontoScorer/ontology_taxonomic_relations.py @@ -23,6 +23,7 @@ class TaxonomicRelation: :param graph: The RDF graph from which the relation is extracted. """ self.source = source + self.relation_type = "" # Cet attribut sera défini dans chaque sous-classe self.target = target self.graph = graph @@ -48,6 +49,19 @@ class TaxonomicRelation: def __str__(self): return f"{self.source} -> {self.target}" + + def __lt__(self, other): + """Compare based on source, relation type, and target entities.""" + if isinstance(other, TaxonomicRelation): + if self.source != other.source: + return str(self.source) < str(other.source) + # If source entities are the same, compare based on relation type + if self.relation_type != other.relation_type: + return self.relation_type < other.relation_type + # If both source entities and relation types are the same, compare based on target entity + return str(self.target) < str(other.target) + return NotImplemented + #-------------------------------------------------------------------------- @@ -55,21 +69,36 @@ class TaxonomicRelation: #-------------------------------------------------------------------------- class SubclassOfRelation(TaxonomicRelation): """Represents a 'subclass of' relation.""" + def __init__(self, source, target, graph): + super().__init__(source, target, graph) + self.relation_type = "subClassOf" + def __str__(self): - return f"({self.source}, subClassOf, {self.target})" + return f"({self.source}, {self.relation_type}, {self.target})" + #-------------------------------------------------------------------------- # Subproperty Relations #-------------------------------------------------------------------------- class SubpropertyOfRelation(TaxonomicRelation): """Represents a 'subproperty of' relation.""" + def __init__(self, source, target, graph): + super().__init__(source, target, graph) + self.relation_type = "subPropertyOf" + def __str__(self): - return f"({self.source}, subPropertyOf, {self.target})" + return f"({self.source}, {self.relation_type}, {self.target})" + #-------------------------------------------------------------------------- # Instance Relations #-------------------------------------------------------------------------- class InstanceOfRelation(TaxonomicRelation): """Represents an 'instance of' relation.""" + def __init__(self, source, target, graph): + super().__init__(source, target, graph) + self.relation_type = "instanceOf" + def __str__(self): - return f"({self.source}, instanceOf, {self.target})" + return f"({self.source}, {self.relation_type}, {self.target})" + diff --git a/ontoScorer/ontology_utils.py b/ontoScorer/ontology_utils.py index e87b6659c0d828c21b20f8d4acd77df4be8dc253..d21577f1ee10ac3b65087e4f98cf33a72a7b6fcb 100644 --- a/ontoScorer/ontology_utils.py +++ b/ontoScorer/ontology_utils.py @@ -9,14 +9,42 @@ from rdflib import Graph +# def harmonize_prefixes(graph, source_uri, target_uri): +# for s, p, o in graph.triples((None, None, None)): +# s = s if not s.startswith(source_uri) else s.replace(source_uri, target_uri) +# p = p if not p.startswith(source_uri) else p.replace(source_uri, target_uri) +# o = o if not isinstance(o, str) or not o.startswith(source_uri) else o.replace(source_uri, target_uri) +# graph.add((s, p, o)) +# return graph + +from rdflib import URIRef + def harmonize_prefixes(graph, source_uri, target_uri): + triples_to_add = [] + + # Parcourir les triples et identifier ceux qui nécessitent une modification for s, p, o in graph.triples((None, None, None)): - s = s if not s.startswith(source_uri) else s.replace(source_uri, target_uri) - p = p if not p.startswith(source_uri) else p.replace(source_uri, target_uri) - o = o if not isinstance(o, str) or not o.startswith(source_uri) else o.replace(source_uri, target_uri) - graph.add((s, p, o)) + new_s = URIRef(s.replace(source_uri, target_uri)) if isinstance(s, URIRef) and s.startswith(source_uri) else s + new_p = URIRef(p.replace(source_uri, target_uri)) if isinstance(p, URIRef) and p.startswith(source_uri) else p + new_o = o + + if isinstance(o, URIRef) and o.startswith(source_uri): + new_o = URIRef(o.replace(source_uri, target_uri)) + elif isinstance(o, str) and o.startswith(source_uri): + new_o = o.replace(source_uri, target_uri) + + # Si un changement a été effectué, supprimer l'ancien triple et se préparer à ajouter le nouveau + if s != new_s or p != new_p or o != new_o: + graph.remove((s, p, o)) + triples_to_add.append((new_s, new_p, new_o)) + + # Ajouter les nouveaux triples + for triple in triples_to_add: + graph.add(triple) + return graph + def extract_prefixes_from_graph(graph): return {prefix: namespace for prefix, namespace in graph.namespaces()} diff --git a/tests/test_metrics.py b/tests/test_metrics.py index bfd909bd5804af68e4c448528bf906ad9318b270..760951ea2b66942a2b4a945ab931a1fa5ce5c256 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -22,10 +22,20 @@ class TestMetrics(unittest.TestCase): 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) + self.ontology3_path = f"{DATA_FOLDER_PATH}/ontology_c.ttl" + + self.equivalent_prefix = [ + ("base", "https://reference.tetras-libre.fr/base-ontology#", "https://tenet.tetras-libre.fr/base-ontology#"), + ("result", "https://reference.tetras-libre.fr/expected-result#", "https://tenet.tetras-libre.fr/extract-result#") + ] + + self.onto1 = Ontology(self.ontology1_path, self.equivalent_prefix) + self.onto2 = Ontology(self.ontology2_path, self.equivalent_prefix) + self.onto3 = Ontology(self.ontology3_path, self.equivalent_prefix) + self.metrics = Metrics() + def test_computes_entity_scores(self): self.metrics.compute_entity_scores(self.onto1, self.onto2) self.verify_scores(self.metrics.scores["entities"]) @@ -34,13 +44,17 @@ class TestMetrics(unittest.TestCase): self.metrics.compute_taxonomic_relation_scores(self.onto1, self.onto2) self.verify_scores(self.metrics.scores["taxonomic_relations"]) - # def test_computes_non_taxonomic_relation_scores(self): - # self.metrics.compute_non_taxonomic_relation_scores(self.onto1, self.onto2) - # self.verify_scores(self.metrics.scores["non_taxonomic_relations"]) + def test_computes_non_taxonomic_relation_scores_1(self): + self.metrics.compute_non_taxonomic_relation_scores(self.onto1, self.onto2) + self.verify_scores(self.metrics.scores["non_taxonomic_relations"]) + + def test_computes_non_taxonomic_relation_scores_2(self): + self.metrics.compute_non_taxonomic_relation_scores(self.onto3, self.onto3) + self.verify_scores(self.metrics.scores["non_taxonomic_relations"]) - # def test_computes_axiom_scores(self): - # self.metrics.compute_axiom_scores(self.onto1, self.onto2) - # self.verify_scores(self.metrics.scores["axioms"]) + def test_computes_axiom_scores(self): + self.metrics.compute_axiom_scores(self.onto1, self.onto2) + self.verify_scores(self.metrics.scores["axioms"]) def verify_scores(self, score_category): for element, score in score_category.items(): @@ -56,8 +70,8 @@ class TestMetrics(unittest.TestCase): def test_print_scores(self): self.metrics.compute_entity_scores(self.onto1, self.onto2) self.metrics.compute_taxonomic_relation_scores(self.onto1, self.onto2) - # self.metrics.compute_non_taxonomic_relation_scores(self.onto1, self.onto2) - # self.metrics.compute_axiom_scores(self.onto1, self.onto2) + self.metrics.compute_non_taxonomic_relation_scores(self.onto3, self.onto3) + self.metrics.compute_axiom_scores(self.onto1, self.onto2) print() self.metrics.print_scores() diff --git a/tests/test_ontology.py b/tests/test_ontology.py index 170200a5e88057aa3b9a5ea3d0923f1287dc70ca..02428b82297868d363dbf9f94f4dcf745bdf1588 100644 --- a/tests/test_ontology.py +++ b/tests/test_ontology.py @@ -111,8 +111,8 @@ class TestOntologyTaxonomicRelations(unittest.TestCase): def test_subclass_relation_extraction_2(self): relations = self.onto1.get_taxonomic_relations() subclasses = [rel for rel in relations if isinstance(rel, SubclassOfRelation)] - self.assertTrue(any(rel.source.endswith("#gravitation-bind-system") and rel.target.endswith("#gravitation") for rel in subclasses)) - self.assertTrue(any(rel.source.endswith("#object-orbit-hasManner-direct-sun") and rel.target.endswith("#object") for rel in subclasses)) + self.assertTrue(any(rel.source.endswith("gravitation-bind-system") and rel.target.endswith("gravitation") for rel in subclasses)) + self.assertTrue(any(rel.source.endswith("object-orbit-hasManner-direct-sun") and rel.target.endswith("object") for rel in subclasses)) def test_subproperty_relation_extraction_1(self): @@ -123,7 +123,7 @@ class TestOntologyTaxonomicRelations(unittest.TestCase): def test_subproperty_relation_extraction_2(self): relations = self.onto1.get_taxonomic_relations() subproperties = [rel for rel in relations if isinstance(rel, SubpropertyOfRelation)] - self.assertTrue(any(rel.source.endswith("#direct") and rel.target.endswith("#Out_ObjectProperty") for rel in subproperties)) + self.assertTrue(any(rel.source.endswith("#direct") and rel.target.endswith("Out_ObjectProperty") for rel in subproperties)) self.assertTrue(any(rel.source.endswith("#orbit-hasManner-direct") and rel.target.endswith("#orbit") for rel in subproperties)) @@ -135,7 +135,7 @@ class TestOntologyTaxonomicRelations(unittest.TestCase): def test_instance_relation_extraction_2(self): relations = self.onto1.get_taxonomic_relations() instances = [rel for rel in relations if isinstance(rel, InstanceOfRelation)] - self.assertTrue(any(rel.source.endswith("#SolarSystem") and rel.target.endswith("#system") for rel in instances)) + self.assertTrue(any(rel.source.endswith("#SolarSystem") and rel.target.endswith("system") for rel in instances)) def test_get_taxonomic_relations(self): @@ -165,9 +165,9 @@ class TestOntologyNonTaxonomicRelations(unittest.TestCase): def test_object_property_relations_2(self): relations = self.onto1.get_non_taxonomic_relations() instances = [rel for rel in relations if isinstance(rel, ObjectPropertyRelation)] - self.assertTrue(any(rel.source.endswith("#SolarSystem") - and rel.property.endswith("#contains") - and rel.target.endswith("#SomeSmallerObjectInstance") + self.assertTrue(any(rel.source.endswith("SolarSystem") + and rel.property.endswith("contains") + and rel.target.endswith("SomeSmallerObjectInstance") for rel in instances)) @@ -203,11 +203,11 @@ class TestOntologyAxioms(unittest.TestCase): # self.assertTrue(any(rel.on_property.endswith("#orbit-hasManner-not-direct") # and rel.some_values_from.endswith("#sun") # for rel in axioms)) - self.assertTrue(any(rel.on_property.endswith("#orbit-hasManner-direct") - and rel.some_values_from.endswith("#sun") + self.assertTrue(any(rel.on_property.endswith("orbit-hasManner-direct") + and rel.some_values_from.endswith("sun") for rel in axioms)) - self.assertTrue(any(rel.on_property.endswith("#bind") - and rel.some_values_from.endswith("#system") + self.assertTrue(any(rel.on_property.endswith("bind") + and rel.some_values_from.endswith("system") and rel.parent_class.endswith("gravitation-bind-system") for rel in axioms)) @@ -219,38 +219,53 @@ class TestOntologyAxioms(unittest.TestCase): class TestOntologyComparisonMethods(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.ontology3_path = f"{DATA_FOLDER_PATH}/ontology_c.ttl" - self.onto1 = Ontology(self.ontology1_path) - self.onto2 = Ontology(self.ontology2_path) - self.onto3 = Ontology(self.ontology3_path) + + self.equivalent_prefix = [ + ("base", "https://reference.tetras-libre.fr/base-ontology#", "https://tenet.tetras-libre.fr/base-ontology#"), + ("result", "https://reference.tetras-libre.fr/expected-result#", "https://tenet.tetras-libre.fr/extract-result#") + ] + + self.onto1 = Ontology(self.ontology1_path, self.equivalent_prefix) + self.onto2 = Ontology(self.ontology2_path, self.equivalent_prefix) + self.onto3 = Ontology(self.ontology3_path, self.equivalent_prefix) def test_compare_entity_names(self): - entity1 = self.onto1.get_classes()[0] - entity2 = self.onto2.get_classes()[0] - entity3 = self.onto2.get_classes()[1] - self.assertTrue(Ontology.compare_entity_names(entity1, entity2)) + entity1 = sorted(self.onto1.get_classes())[0] + entity2 = sorted(self.onto2.get_classes())[0] + entity3 = sorted(self.onto2.get_classes())[1] + self.assertTrue(Ontology.compare_entity_names(entity1, entity2), + f'{entity1.name()} | {entity2.name()}') self.assertFalse(Ontology.compare_entity_names(entity1, entity3)) def test_compare_relations_1(self): - relation1 = self.onto1.get_taxonomic_relations()[0] - relation2 = self.onto2.get_taxonomic_relations()[0] - relation3 = self.onto2.get_taxonomic_relations()[1] - print(relation1) - print(relation2) - self.assertTrue(Ontology.compare_relations(relation1, relation2)) + relation1 = sorted(self.onto1.get_taxonomic_relations())[0] + relation2 = sorted(self.onto2.get_taxonomic_relations())[0] + relation3 = sorted(self.onto2.get_taxonomic_relations())[1] + self.assertTrue(Ontology.compare_relations(relation1, relation2), + f'{relation1} | {relation2}') self.assertFalse(Ontology.compare_relations(relation1, relation3)) def test_compare_relations_2(self): relation1 = self.onto3.get_non_taxonomic_relations()[0] relation2 = self.onto3.get_non_taxonomic_relations()[0] # relation3 = self.onto3.get_non_taxonomic_relations()[1] - self.assertTrue(Ontology.compare_relations(relation1, relation2)) + self.assertTrue(Ontology.compare_relations(relation1, relation2), + f'{relation1} | {relation2}') # self.assertFalse(Ontology.compare_relations(relation1, relation3)) + def test_compare_axioms(self): + axiom1 = sorted(self.onto1.get_axioms())[0] + axiom2 = sorted(self.onto2.get_axioms())[0] + axiom3 = sorted(self.onto2.get_axioms())[1] + self.assertTrue(Ontology.compare_axioms(axiom1, axiom2), + f'{axiom1} | {axiom2}') + self.assertFalse(Ontology.compare_axioms(axiom1, axiom3)) + #--------------------------------------------------------------------------