First, perhaps you could remodel things, getting rid of :EquipmentPoints. They are possibly just artefacts of relational modeling. RDF properties may have multiple values. See here for more details.
For the sake of clarity, I'll simplify your data model slightly:
Equipment (EquipmentId)
EquipmentPoints (EquipmentId, PointId)
Point (PointId)
RDF
RDF is schemaless, there is no constraints in RDF.
You could model things as shown in another answer:
@prefix : <https://stackoverflow.com/q/51974155/7879193#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
:equipment1 rdf:type :Equipment .
:equipment2 rdf:type :Equipment .
:point1 rdf:type :Point .
:point2 rdf:type :Point .
:equipmentPoint1 rdf:type :EquipmentPoint .
:equipmentPoint2 rdf:type :EquipmentPoint .
:equipmentPoint1 :hasEquipment :equipment1 ;
:hasPoint :point1 .
:equipmentPoint2 :hasEquipment :equipment1 ;
:hasPoint :point1 . # "constraint violation"
In order to define constraints, you could use languages like SHACL. Unfortunately, there is no core constraint components for compound keys in SHACL, one should use SPARQL-based constraints:
:EquipmentPointShape a sh:NodeShape ;
sh:targetClass :EquipmentPoint ;
sh:sparql [
sh:message "Violation!" ;
sh:severity sh:Violation ;
sh:select """
SELECT ?this {
?point1 ^:hasPoint ?this, ?that .
?equipment ^:hasEquipment ?this, ?that .
FILTER (?this != ?that)
}
"""
] .
OWL
OWL was designed for inferencing, not for constraint checking. See this answer for more details. However, you could use OWL 2 keys.
First, add some ontological "boilerplate":
[] rdf:type owl:Ontology .
:Equipment rdf:type owl:Class .
:Point rdf:type owl:Class .
:EquipmentPoint rdf:type owl:Class .
:hasPoint rdf:type owl:ObjectProperty .
:hasEquipment rdf:type owl:ObjectProperty .
:equipment1 rdf:type owl:NamedIndividual .
:equipment2 rdf:type owl:NamedIndividual .
:point1 rdf:type owl:NamedIndividual .
:point2 rdf:type owl:NamedIndividual .
:equipmentPoint1 rdf:type owl:NamedIndividual .
:equipmentPoint2 rdf:type owl:NamedIndividual .
Now you have correct Turtle-serialized ontology. Then add:
:EquipmentPoint owl:hasKey (:hasEquipment
:hasPoint
) .
[ rdf:type owl:AllDifferent ;
owl:distinctMembers (:equipmentPoint1
:equipmentPoint2
)
] .
A reasoner will infer that your ontology is inconsistent.
Note, there is no Unique Name Assumption and there is Open World Assumption in OWL.
After removing
[ rdf:type owl:AllDifferent ;
owl:distinctMembers (:equipmentPoint1
:equipmentPoint2
)
] .
a reasoner will infer that
:equipmentPoint1 owl:sameAs :equipmentPoint2 .