Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple sh:xones on one sh:NodeShape grouping member shapes causing unexpected validation results #220

Open
ajnelson-nist opened this issue Jan 17, 2024 · 0 comments

Comments

@ajnelson-nist
Copy link
Contributor

I came across this when trying to write shapes for an OWL ontology that defines some classes as disjoint unions (covering sets) of multiple sets of classes. For example, here is an analagous, distilled set of classes:

@prefix ex: <http://example.org/ontology/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

ex:OneXorThing
	a owl:Class ;
	owl:disjointUnionOf (
		ex:ThingA
		ex:ThingB
	) ;
	.

ex:ThingA
	a owl:Class ;
	rdfs:subClassOf ex:OneXorThing ;
	owl:disjointWith ex:ThingB ;
	.

ex:ThingB
	a owl:Class ;
	rdfs:subClassOf ex:OneXorThing ;
	owl:disjointWith ex:ThingA ;
	.

ex:ThingC
	a owl:Class ;
	rdfs:subClassOf ex:TwoXorThing ;
	owl:disjointWith ex:ThingD ;
	.

ex:ThingD
	a owl:Class ;
	rdfs:subClassOf ex:TwoXorThing ;
	owl:disjointWith ex:ThingC ;
	.

ex:ThingE
	a owl:Class ;
	rdfs:subClassOf ex:TwoXorThing ;
	owl:disjointWith ex:ThingF ;
	.

ex:ThingF
	a owl:Class ;
	rdfs:subClassOf ex:TwoXorThing ;
	owl:disjointWith ex:ThingE ;
	.

ex:TwoXorThing
	a owl:Class ;
	owl:disjointUnionOf
		(
			ex:ThingC
			ex:ThingD
		) ,
		(
			ex:ThingE
			ex:ThingF
		)
		;
	.

ex:OneXorThing is a covering set of two subclasses. A member of ex:OneXorThing must be a member of exactly one of ex:ThingA or ex:ThingB. ex:TwoXorThing functions similarly, but requires each of its members to members of two of two pairs of subclasses.

An aside: I found in a deeper dive through the OWL documentation that disjoint unions entail every assertion in that example OWL graph on the ThingA...ThingF classes, aside from ex:ThingX a owl:Class.. The definition here describes the disjoint union class's member-classes as subclasses of the disjoint union class, albeit in English rather than demonstrated syntax: "Thus, each instance of C is an instance of exactly one CEi, and each instance of CEi is an instance of C." This section is linked as the "Normative syntax" from the OWL 2 New Features, Section 2.1.1 F1. I came across this when trying to determine if having more than one owl:disjointWith assertion on a class was disallowed somehow, and I believe I've exhausted the documentation and found nothing to disallow it.

Back to the distilled example: It seems to me that sh:xone lines up well as a reviewing mechanism for owl:disjointUnion, so I defined the following shapes graph, referenced further on as sh-REPRODUCTION-2.ttl:

@prefix ex: <http://example.org/ontology/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix sh-ex: <http://example.org/shapes/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

sh-ex:OneXorThing-shape
	a sh:NodeShape ;
	sh:targetClass ex:TwoXorThing ;
	sh:xone (
		[
			a sh:NodeShape ;
			sh:class ex:ThingA ;
		]
		[
			a sh:NodeShape ;
			sh:class ex:ThingB ;
		]
	) ;
	.

sh-ex:TwoXorThing-shape
	a sh:NodeShape ;
	sh:targetClass ex:TwoXorThing ;
	sh:xone
		(
			[
				a sh:NodeShape ;
				sh:class ex:ThingC ;
			]
			[
				a sh:NodeShape ;
				sh:class ex:ThingD ;
			]
		) ,
		(
			[
				a sh:NodeShape ;
				sh:class ex:ThingE ;
			]
			[
				a sh:NodeShape ;
				sh:class ex:ThingF ;
			]
		)
		;
	.

I then used it to review the following data graph, referenced further on as kb-REPRODUCTION-2.ttl:

@prefix ex: <http://example.org/ontology/> .
@prefix kb: <http://example.org/kb/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

kb:thing-PASS-1
	a ex:ThingA ;
	rdfs:comment "This should raise no validation results."@en ;
	.

kb:thing-PASS-2
	a
		ex:ThingC ,
		ex:ThingE
		;
	rdfs:comment "This should raise no validation results."@en ;
	.

kb:thing-XFAIL-1
	a ex:OneXorThing ;
	rdfs:comment "This should raise a validation result, due to not being more specifically a ThingA or ThingB as the SHACL requires when reviewing the OWL disjoint union definition of OneXorThing."@en ;
	.

kb:thing-XFAIL-2
	a ex:ThingC ;
	rdfs:comment "This should raise a validation result, due to not being a ThingE or ThingF as the SHACL requires when reviewing the entailed superclass TwoXorThing."@en ;
	.

I get the following shell transcript using pySHACL 0.25.0:

$ pyshacl \
  --metashacl \
  --ont-graph owl-REPRODUCTION.ttl \
  --shacl sh-REPRODUCTION-2.ttl \
  kb-REPRODUCTION-2.ttl
Validation Report
Conforms: False
Results (3):
Constraint Violation in XoneConstraintComponent (http://www.w3.org/ns/shacl#XoneConstraintComponent):
	Severity: sh:Violation
	Source Shape: sh-ex:TwoXorThing-shape
	Focus Node: kb:thing-XFAIL-2
	Value Node: kb:thing-XFAIL-2
	Message: Node kb:thing-XFAIL-2 does not conform to exactly one shape in [ rdf:type sh:NodeShape ; sh:class ex:ThingC ] , [ rdf:type sh:NodeShape ; sh:class ex:ThingD ] , [ rdf:type sh:NodeShape ; sh:class ex:ThingE ] , [ rdf:type sh:NodeShape ; sh:class ex:ThingF ]
Constraint Violation in XoneConstraintComponent (http://www.w3.org/ns/shacl#XoneConstraintComponent):
	Severity: sh:Violation
	Source Shape: sh-ex:OneXorThing-shape
	Focus Node: kb:thing-PASS-2
	Value Node: kb:thing-PASS-2
	Message: Node kb:thing-PASS-2 does not conform to exactly one shape in [ rdf:type sh:NodeShape ; sh:class ex:ThingA ] , [ rdf:type sh:NodeShape ; sh:class ex:ThingB ]
Constraint Violation in XoneConstraintComponent (http://www.w3.org/ns/shacl#XoneConstraintComponent):
	Severity: sh:Violation
	Source Shape: sh-ex:OneXorThing-shape
	Focus Node: kb:thing-XFAIL-2
	Value Node: kb:thing-XFAIL-2
	Message: Node kb:thing-XFAIL-2 does not conform to exactly one shape in [ rdf:type sh:NodeShape ; sh:class ex:ThingA ] , [ rdf:type sh:NodeShape ; sh:class ex:ThingB ]

The two "XFAIL" individuals show in the validation results, which is what I want; but, one of the PASS individuals also shows up. Further, it shows up in response to the wrong shape. And the XFAIL error that I was trying to trigger with kb:thing-XFAIL-2 reports an exactly-one-of list that looks flat, rather than like two pairs.

(Once I wrote that last sentence, I realized a problem with the data I'm reviewing is that my example individual is only a member of one of my disjoint unions, not both. I got distracted looking at the apparent list-flattening. But it is still an issue that kb:thing-PASS-2 is triggering a test failure.)

If I reduce the shapes graph to only sh-ex:TwoXorThing-shape, and the data graph to only kb:thing-PASS-2, validation works. But other combinations of removing shapes or individuals cause unexpected validation errors. I've left a Makefile and the reductions I tried in this Gist - it should run as documented in a fresh git clone in macOS or Linux.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant