|
39 | 39 | OWLDisjointDataPropertiesAxiom, OWLDisjointObjectPropertiesAxiom, OWLEquivalentDataPropertiesAxiom, \ |
40 | 40 | OWLEquivalentObjectPropertiesAxiom, OWLInverseObjectPropertiesAxiom, OWLNaryPropertyAxiom, OWLNaryIndividualAxiom, \ |
41 | 41 | OWLDifferentIndividualsAxiom, OWLDisjointClassesAxiom, OWLSameIndividualAxiom, OWLClassAxiom, \ |
42 | | - OWLDataPropertyDomainAxiom, OWLDataPropertyRangeAxiom, OWLObjectPropertyDomainAxiom |
| 42 | + OWLDataPropertyDomainAxiom, OWLDataPropertyRangeAxiom, OWLObjectPropertyDomainAxiom, OWLSubPropertyChainAxiom |
43 | 43 | from owlapy.static_funcs import startJVM |
44 | 44 | from owlapy.vocab import OWLFacet |
45 | 45 | import os |
@@ -510,6 +510,27 @@ def _(axiom: OWLObjectPropertyCharacteristicAxiom, ontology: AbstractOWLOntology |
510 | 510 | raise ValueError(f'ObjectPropertyCharacteristicAxiom ({axiom}) is not defined.') |
511 | 511 |
|
512 | 512 |
|
| 513 | +@_add_axiom.register |
| 514 | +def _(axiom: OWLSubPropertyChainAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): |
| 515 | + conv = ToOwlready2(world) |
| 516 | + ont_x: owlready2.Ontology = conv.map_object(ontology) |
| 517 | + |
| 518 | + super_property = axiom.get_super_property() |
| 519 | + property_chain = list(axiom.get_property_chain()) |
| 520 | + |
| 521 | + # Ensure all properties in the chain and the super property are declared |
| 522 | + _add_axiom(OWLDeclarationAxiom(super_property), ontology, world) |
| 523 | + for prop in property_chain: |
| 524 | + if isinstance(prop, OWLObjectInverseOf): |
| 525 | + _add_axiom(OWLDeclarationAxiom(prop.get_named_property()), ontology, world) |
| 526 | + else: |
| 527 | + _add_axiom(OWLDeclarationAxiom(prop), ontology, world) |
| 528 | + |
| 529 | + with ont_x: |
| 530 | + super_property_x = conv._to_owlready2_property(super_property) |
| 531 | + property_chain_x = [conv._to_owlready2_property(prop) for prop in property_chain] |
| 532 | + super_property_x.property_chain.append(owlready2.PropertyChain(property_chain_x)) |
| 533 | + |
513 | 534 | @_add_axiom.register |
514 | 535 | def _(axiom: OWLDataPropertyCharacteristicAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): |
515 | 536 | conv = ToOwlready2(world) |
@@ -820,6 +841,28 @@ def _(axiom: OWLDataPropertyCharacteristicAxiom, ontology: AbstractOWLOntology, |
820 | 841 | and owlready2.FunctionalProperty in property_x.is_a: |
821 | 842 | property_x.is_a.remove(owlready2.FunctionalProperty) |
822 | 843 |
|
| 844 | +@_remove_axiom.register |
| 845 | +def _(axiom: OWLSubPropertyChainAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): |
| 846 | + conv = ToOwlready2(world) |
| 847 | + ont_x: owlready2.Ontology = conv.map_object(ontology) |
| 848 | + |
| 849 | + super_property = axiom.get_super_property() |
| 850 | + property_chain = list(axiom.get_property_chain()) |
| 851 | + |
| 852 | + with ont_x: |
| 853 | + super_property_x = conv._to_owlready2_property(super_property) |
| 854 | + if super_property_x is None: |
| 855 | + return |
| 856 | + |
| 857 | + property_chain_x = [conv._to_owlready2_property(prop) for prop in property_chain] |
| 858 | + if not all(property_chain_x): |
| 859 | + return |
| 860 | + |
| 861 | + # Find and remove the matching property chain |
| 862 | + for pc in super_property_x.property_chain: |
| 863 | + if list(pc.properties) == property_chain_x: |
| 864 | + super_property_x.property_chain.remove(pc) |
| 865 | + break |
823 | 866 |
|
824 | 867 | class Ontology(AbstractOWLOntology): |
825 | 868 | __slots__ = '_iri', '_world', '_onto', 'is_modified' |
@@ -2137,6 +2180,36 @@ def predict(self, h: List[str] = None, r: List[str] = None, t: List[str] = None) |
2137 | 2180 | else: |
2138 | 2181 | topk = len(self.model.entity_to_idx) |
2139 | 2182 |
|
| 2183 | + # Filter out unknown relations; return empty list (0 scores) if none remain |
| 2184 | + if r is not None: |
| 2185 | + if isinstance(r, str): |
| 2186 | + if r not in self.model.relation_to_idx: |
| 2187 | + return [] |
| 2188 | + else: |
| 2189 | + r = [ri for ri in r if ri in self.model.relation_to_idx] |
| 2190 | + if not r: |
| 2191 | + return [] |
| 2192 | + |
| 2193 | + # Filter out unknown head entities; return empty list (0 scores) if none remain |
| 2194 | + if h is not None: |
| 2195 | + if isinstance(h, str): |
| 2196 | + if h not in self.model.entity_to_idx: |
| 2197 | + return [] |
| 2198 | + else: |
| 2199 | + h = [hi for hi in h if hi in self.model.entity_to_idx] |
| 2200 | + if not h: |
| 2201 | + return [] |
| 2202 | + |
| 2203 | + # Filter out unknown tail entities; return empty list (0 scores) if none remain |
| 2204 | + if t is not None: |
| 2205 | + if isinstance(t, str): |
| 2206 | + if t not in self.model.entity_to_idx: |
| 2207 | + return [] |
| 2208 | + else: |
| 2209 | + t = [ti for ti in t if ti in self.model.entity_to_idx] |
| 2210 | + if not t: |
| 2211 | + return [] |
| 2212 | + |
2140 | 2213 | return [(top_entity, score) for row in |
2141 | 2214 | self.model.predict_topk(h=h, r=r, t=t, topk=topk, batch_size=self.batch_size) for top_entity, score in |
2142 | 2215 | row if score >= self.gamma and is_valid_entity(top_entity)] |
|
0 commit comments