From 70328ca5d7d3bea163da04036bfa40c93a6a3e21 Mon Sep 17 00:00:00 2001 From: SHANMUKH SAI <50857103+shanmukhkalasamudram@users.noreply.github.com> Date: Wed, 25 Mar 2026 12:06:30 -0400 Subject: [PATCH] fix: repair no_multiple_inverse_properties.sparql (#490) (#817) --- .../no_multiple_inverse_properties.sparql | 22 +-- .../test_no_multiple_inverse_properties.ttl | 146 ++++++++++++++++++ 2 files changed, 158 insertions(+), 10 deletions(-) create mode 100644 .github/deployment/sparql/tests/test_no_multiple_inverse_properties.ttl diff --git a/.github/deployment/sparql/no_multiple_inverse_properties.sparql b/.github/deployment/sparql/no_multiple_inverse_properties.sparql index 347fef0..13243e5 100644 --- a/.github/deployment/sparql/no_multiple_inverse_properties.sparql +++ b/.github/deployment/sparql/no_multiple_inverse_properties.sparql @@ -5,21 +5,23 @@ # Severity: # Error -PREFIX owl: +PREFIX owl: -SELECT ?property1 ?property2 ?error +SELECT DISTINCT ?property ?inverse1 ?inverse2 ?error WHERE { { - ?property owl:inverseOf ?property1. - ?property owl:inverseOf ?property2. - FILTER (?property1 != ?property2) + { ?property owl:inverseOf ?inverse1 } + UNION + { ?inverse1 owl:inverseOf ?property } } - UNION { - ?property1 owl:inverseOf ?property. - ?property2 owl:inverseOf ?property. - FILTER (?property1 != ?property2) + { ?property owl:inverseOf ?inverse2 } + UNION + { ?inverse2 owl:inverseOf ?property } } + FILTER (?inverse1 != ?inverse2) + FILTER (STR(?inverse1) < STR(?inverse2)) BIND (concat("ERROR: Object property ", str(?property), " has more than one inverse.") AS ?error) -} \ No newline at end of file +} +ORDER BY ?property \ No newline at end of file diff --git a/.github/deployment/sparql/tests/test_no_multiple_inverse_properties.ttl b/.github/deployment/sparql/tests/test_no_multiple_inverse_properties.ttl new file mode 100644 index 0000000..2330992 --- /dev/null +++ b/.github/deployment/sparql/tests/test_no_multiple_inverse_properties.ttl @@ -0,0 +1,146 @@ +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix test: . + + + rdf:type owl:Ontology ; + rdfs:label "Toy ontology for no_multiple_inverse_properties.sparql" . + +# ----------------------------------------------------------------------- +# SHOULD TRIGGER — property declared as inverseOf two distinct properties + +test:parentOf + rdf:type owl:ObjectProperty ; + owl:inverseOf test:childOf ; + owl:inverseOf test:hasParent ; + rdfs:label "parent of" . + +test:childOf + rdf:type owl:ObjectProperty ; + rdfs:label "child of" . + +test:hasParent + rdf:type owl:ObjectProperty ; + rdfs:label "has parent" . + +# ----------------------------------------------------------------------- +# SHOULD TRIGGER — mixed direction: one inverse forward, one backward +# test:teaches owl:inverseOf test:learnedBy (forward) +# test:taughtBy owl:inverseOf test:teaches (backward, so teaches also has taughtBy as an inverse) + +test:teaches + rdf:type owl:ObjectProperty ; + owl:inverseOf test:learnedBy ; + rdfs:label "teaches" . + +test:taughtBy + rdf:type owl:ObjectProperty ; + owl:inverseOf test:teaches ; + rdfs:label "taught by" . + +test:learnedBy + rdf:type owl:ObjectProperty ; + rdfs:label "learned by" . + +# ----------------------------------------------------------------------- +# SHOULD TRIGGER — both inverses declared backward +# test:wasBuiltBy owl:inverseOf test:builds (backward) +# test:wasCreatedBy owl:inverseOf test:builds (backward) +# => test:builds has two inverses: wasBuiltBy and wasCreatedBy + +test:builds + rdf:type owl:ObjectProperty ; + rdfs:label "builds" . + +test:wasBuiltBy + rdf:type owl:ObjectProperty ; + owl:inverseOf test:builds ; + rdfs:label "was built by" . + +test:wasCreatedBy + rdf:type owl:ObjectProperty ; + owl:inverseOf test:builds ; + rdfs:label "was created by" . + +# ----------------------------------------------------------------------- +# SHOULD TRIGGER — three inverses declared forward (produces 3 violation pairs) + +test:contains + rdf:type owl:ObjectProperty ; + owl:inverseOf test:isIn ; + owl:inverseOf test:isInsideOf ; + owl:inverseOf test:isEncompassedBy ; + rdfs:label "contains" . + +test:isIn + rdf:type owl:ObjectProperty ; + rdfs:label "is in" . + +test:isInsideOf + rdf:type owl:ObjectProperty ; + rdfs:label "is inside of" . + +test:isEncompassedBy + rdf:type owl:ObjectProperty ; + rdfs:label "is encompassed by" . + +# ----------------------------------------------------------------------- +# SHOULD NOT TRIGGER — property with exactly one inverse (forward only) + +test:employs + rdf:type owl:ObjectProperty ; + owl:inverseOf test:employedBy ; + rdfs:label "employs" . + +test:employedBy + rdf:type owl:ObjectProperty ; + rdfs:label "employed by" . + +# ----------------------------------------------------------------------- +# SHOULD NOT TRIGGER — property with no declared inverse + +test:likes + rdf:type owl:ObjectProperty ; + rdfs:label "likes" . + +# ----------------------------------------------------------------------- +# SHOULD NOT TRIGGER — single inverse declared backward only +# test:isOwnedBy declares itself as owl:inverseOf test:owns, so +# test:owns has exactly one inverse (test:isOwnedBy) + +test:owns + rdf:type owl:ObjectProperty ; + rdfs:label "owns" . + +test:isOwnedBy + rdf:type owl:ObjectProperty ; + owl:inverseOf test:owns ; + rdfs:label "is owned by" . + +# ----------------------------------------------------------------------- +# SHOULD NOT TRIGGER — self-inverse (symmetric property) +# isSiblingOf owl:inverseOf isSiblingOf: both ?inv1 and ?inv2 resolve to +# isSiblingOf, so FILTER(?inv1 != ?inv2) eliminates the row + +test:isSiblingOf + rdf:type owl:ObjectProperty ; + owl:inverseOf test:isSiblingOf ; + rdfs:label "is sibling of" . + +# ----------------------------------------------------------------------- +# SHOULD NOT TRIGGER — inverse declared redundantly in both directions +# isRelatedTo owl:inverseOf isAssociatedWith +# isAssociatedWith owl:inverseOf isRelatedTo +# These are the same single inverse pair stated twice; each property has +# exactly one inverse + +test:isRelatedTo + rdf:type owl:ObjectProperty ; + owl:inverseOf test:isAssociatedWith ; + rdfs:label "is related to" . + +test:isAssociatedWith + rdf:type owl:ObjectProperty ; + owl:inverseOf test:isRelatedTo ; + rdfs:label "is associated with" .