We want to transform a UML diagram of an ontology with cardinalities into a SHACL shape to validate if the cardinalities in our data are correct.
Let's say we have Author 1 ---first author ---> 1.n Book, the right part is quite easy to model as:
:AuthorShape a sh:NodeShape;
sh:targetClass :Author;
sh:property [sh:path :firstAuthor; sh:minCount 1].
However now I also want to model the "other end", i.e. that a book cannot have more than 1 first authors:
:FirstAuthorCardinalityOtherEndShape a sh:NodeShape;
sh:targetObjectsOf :firstAuthor;
sh:property [
sh:path [ sh:inversePath :firstAuthor ];
sh:minCount 1;
sh:maxCount 1
];
sh:nodeKind sh:IRI.
However that looks quite convoluted (8 lines instead of 3) and error prone (:firstAuthor is mentioned twice). Is there a simpler way to model this?
For example, this could be like this, but sh:inverseMinCount doesn't exist:
:AuthorShape a sh:NodeShape;
sh:targetClass :Author;
sh:property [sh:path :firstAuthor; sh:minCount 1; sh:inverseMinCount 1; sh:inverseMaxCount 1].
The issue that :firstAuthor is mentioned twice can be avoided by attaching the property to Book, e.g.
:BookShape a sh:NodeShape ;
sh:targetClass :Book ;
sh:property [
sh:path [ sh:inversePath :firstAuthor ] ;
sh:maxCount 1 ;
] .
(You already have AuthorShape, so having BookShape would be a perfectly natural thing to do).
In any case you wouldn't need the sh:minCount 1 because the sh:targetObjectsOf already implies this, although I can see why you would want this from an UML point of view.
And I don't think the design above is much more complex than the forward direction, assuming you're OK with the sh:inversePath overhead, which is unavoidable.