I need to implement an OWL-ontology in Protégé, which contains a two classes: s1
and s2
, both are the instances of System
class. These two classes are connected by the connection class s1_s2
, which contains property omega
. This property has to take a value according to the following law:
omega = 1 * s1.complete
How can I implement it in Protégé in a such way, I could use it in SWRL-rule in the future?
In general, you'd start by defining the classes and the properties that you need:
At this point you could add some axioms that govern how the systems have to interact, how the properties work, etc. E.g., you might declare domains and ranges on your properties. Here's a domain and range on the hasS2 property:
You might also want to say that each InterSystem has exactly one associate S1 and S2:
To put in the mathematical constraints, you'll actually need SWRL; you won't be able to enforce the constraint using other kinds of OWL axioms. The rule you'd want is along the lines of the following. If you declare domains and ranges on your predicates, then you won't need all the type predicates that appear in this rule, since they could be inferred from the property usage.
S1(?s1) ∧ InterSystem(?i) ∧ hasS1(?i,?s1) ∧ hasComplete(?s1,?complete) multiply(?omega,1,?complete) → hasOmega(?i,?omega)
The multiplication here actually seems redundant, since you're multiplying by 1, so omega = alpha, in which case the head of that rule could simply be hasOmega(?i,?alpha). In Protégé the rule looks like this:
(In the version of Protégé that I'm using (not the latest), I had to Window > Create New Tab to create a Rules tab, and then Window > Views > Ontology Views > Rules to add the Rules list to the interface.)
The Turtle serialization of the RDF representation of this OWL ontology (which you can save and load into Protégé) is:
@prefix : <http://stackoverflow.com/q/21499126/1281433/systems#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix swrl: <http://www.w3.org/2003/11/swrl#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix swrlb: <http://www.w3.org/2003/11/swrlb#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
<urn:swrl#s1> a swrl:Variable .
:hasComplete a owl:DatatypeProperty .
[ a swrl:Imp ;
swrl:body [ a swrl:AtomList ;
rdf:first [ a swrl:ClassAtom ;
swrl:argument1 <urn:swrl#i> ;
swrl:classPredicate :InterSystem
] ;
rdf:rest [ a swrl:AtomList ;
rdf:first [ a swrl:ClassAtom ;
swrl:argument1 <urn:swrl#s1> ;
swrl:classPredicate :S1
] ;
rdf:rest [ a swrl:AtomList ;
rdf:first [ a swrl:IndividualPropertyAtom ;
swrl:argument1 <urn:swrl#i> ;
swrl:argument2 <urn:swrl#s1> ;
swrl:propertyPredicate :hasS1
] ;
rdf:rest [ a swrl:AtomList ;
rdf:first [ a swrl:DatavaluedPropertyAtom ;
swrl:argument1 <urn:swrl#s1> ;
swrl:argument2 <urn:swrl#complete> ;
swrl:propertyPredicate :hasComplete
] ;
rdf:rest [ a swrl:AtomList ;
rdf:first [ a swrl:BuiltinAtom ;
swrl:arguments [ a rdf:List ;
rdf:first <urn:swrl#omega> ;
rdf:rest [ a rdf:List ;
rdf:first 1 ;
rdf:rest ( <urn:swrl#complete> )
]
] ;
swrl:builtin swrlb:multiply
] ;
rdf:rest ()
]
]
]
]
] ;
swrl:head [ a swrl:AtomList ;
rdf:first [ a swrl:DatavaluedPropertyAtom ;
swrl:argument1 <urn:swrl#i> ;
swrl:argument2 <urn:swrl#omega> ;
swrl:propertyPredicate :hasOmega
] ;
rdf:rest ()
]
] .
:S2 a owl:Class ;
rdfs:subClassOf :System .
<urn:swrl#omega> a swrl:Variable .
:S1 a owl:Class ;
rdfs:subClassOf :System .
:InterSystem a owl:Class ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onClass :S1 ;
owl:onProperty :hasS1 ;
owl:qualifiedCardinality "1"^^xsd:nonNegativeInteger
] ;
rdfs:subClassOf [ a owl:Restriction ;
owl:onClass :S2 ;
owl:onProperty :hasS2 ;
owl:qualifiedCardinality "1"^^xsd:nonNegativeInteger
] .
<urn:swrl#complete> a swrl:Variable .
<http://stackoverflow.com/q/21499126/1281433/systems>
a owl:Ontology .
:hasS2 a owl:ObjectProperty .
:hasOmega a owl:DatatypeProperty .
:System a owl:Class .
:hasS1 a owl:ObjectProperty .
<urn:swrl#i> a swrl:Variable .
That's a good start, but it's worthwhile to see how it all works. To see a place where the rules could be applied, we'll need some instance data and a reasoner. You mentioned that you can use Pellet from within Protégé, so we're all set on that count. For some instance data, let's create and InterSystem, its S1, and assign the S1's complete value.
You'll need to select the Pellet reasoner from the Reasoner menu, and then select Reasoner > Start Reasoner. At this point, you could run a DL query for “hasOmega value 42” to confirm that the individual has the desired property (make sure that you check the “Individuals” checkbox on the right):
If you navigate to the intersystem individual, you probably won't see the inferred value though. To show it, go to Reasoner > Configure… and check the Data Property Assertions option:
After that, you may need to restart the reasoner (Reasoner > None; Reasoner > Pellet; Reasoner > Start Reasoner), but afterward you'll be able to see the inferred values: