N3 rule examples
© Jean-Marc Vanel - $Date: 2012-09-30$ - under Creative Commons License
The rule examples are classified by domain. For a comprehensive presentation by design patterns, see companion document "N3 rules: good practices, design patterns, refactoring".
Some of the examples are "a priori" N3 rules, some were obtained from Attempto Controlled English (ACE, see in EulerGUI Manual Working with controlled (formal) english through Ace View ). In the latter case the ACE text is in italics. We leave as an exercise to the reader how to write an ACE sentence that will match the a priori N3 rules.
Thanks to: Kaarel Kaljurand, Norbert E. Fuchs, Jos de Roo, Olivier Rossel, Nassim Douali .
TOC
Business rules are rules that are purely logical and manipulate only domain (business) concepts, as the examples in this documentation.
The "applicative" rules express application requirements on the application itself: under what circumstances it will show something, or offer the user to update the data.
The "constructive"rules create information, such as the "friend suggestions" rule below.
Constraints are imposed by "integrity constraints" rules, which have false in the right hand side.
{ antecedent } => { consequent }
If something R has a n : length L1 ,
and R has a n : length L2 ,
and S = ( L1 * L2 )
then R v : has-surface S .
===
If an n:appartment A v:has-surface S and P = ( S * 7000 ) then A v:has-price P .
Why it is useless to generate Java classes from an ontology ?
Because the business logic can be specified completely in N3. Moreover, with the availability of semantic web-aware UI components, there is no need to write code for for table, forms, etc. Finally, with the availability of API's to manipulate the semantic web triples, the last reason generate Java classes from an ontology disappears.
If there is an order there is a demand for payment associated:
{ ?O a Order } => { ?D a DemandForPayment . ?O hasPaymentRequest ?D. }. |
ACE: If there is an order O then there is a demand-for-payment D, and D is associated-to O .
If the bearer has had an incident of payment, then the order is canceled:
{ ?C hasHolder ?H .?H hasPaymentIncident ?PI } =>{ ?C hasStatus cancelled }. |
If one customer has Ordered items in same Domain but different Category than the last items, propose this different Category to customer:
{ ?CUSTOMER :hasOrderedItem ?ITEM .?ITEM :domain ?DOMAIN . ?ITEM :category ?CATEGORY .?ITEM2 :belongsTo :lastItems . ?ITEM2 :domain ?DOMAIN .?ITEM2 :category ?CATEGORY2 . ?CATEGORY2 log:notEqualTo ?CATEGORY . } => {:proposal :category ?CATEGORY2 } . |
This other example starts from an ACE sentence:
If a customer has an addrress whose country is not France then the customer is a foreign-customer . |
Via ACE View it is translated this way in OWL :
customer and (have some (addrress and (country some (owl:Thing and (not ({France})))))) SubClassOf foreign-customer |
If a busLine X1 has-as-departure a town X2,
and X1 has-as-arrival a town X4,
and the town X4 belongs-to a country X3,
and the town X2 belongs-to the country X3
then the busLine X1 is a nationalBusLine .
{?t0 a ns1:busLine. ?t3 a ns1:country. ?t2 a ns1:town. ?t1 a ns1:town. ?t2 ns1:belongs-to ?t3. ?t1 ns1:belongs-to ?t3. ?t0 ns1:has-as-arrival ?t1. ?t0 ns1:has_as_departure ?t2} => {?t0 a ns1:nationalBusLine}. |
N3 data example:
Ind172872104613704311 has-as-departure Toulouse .
Ind172872104613704311 has-as-arrival Paris .
Paris belongs-to France .
Toulouse belongs-to France .
France is a country .
Every town belongs-to one country .
There are currently problems with algebraic expressions in core ACE Prolog .
In some cases OWL Functional-Style Syntax works, but OWL-RDF does not.
Some problems have been corrected by Kaarel and EulerGUI team, but is not yet in the APE (ACE) distribution.
.
The ACE to OWL+SWRL translator used in ACE View has its own limitations, in addition to ACE (ATTEMPTO) limitations. So one must adapt the sentences to ACE View by transforming one intransitive verb into 2 transitive verbs ( e.g. travels ==> travels-during ) . This snippet works:
For each mobile M
for each n : acceleration G
for each n:elapsed-time T
there is a distance D
such that M v:travels-during the n:elapsed-time T ,
and M travels the distance D,
and D is ( 1 / 2 ) * G * T * T .
Same for the simpler sentence (variable D has been removed, but semantics is downgraded):
For each mobile M for each n : acceleration G for each n:elapsed-time T there is a distance D such that M v:travels-during the n:elapsed-time T , and M travels ( 1 / 2 ) * G * T * T .
Here is a simpler example with an algebraic formula :
If a n : rectangle R has a n : length L1 ,
and R has a n : length L2 ,
and S = ( L1 * L2 )
then R v : has-surface S .
The SWRL translation gives:
length(?x2) , length(?x4) , rectangle(?x1) , Thing(?x6) , have(?x1, ?x2) , have(?x1, ?x4) , multiply(?x6, ?x2, ?x4) -> has-surface(?x1, ?x6)
After translation to N3 this becomes:
{?t2 a ns1:length. ?t3 a ns1:length. ?t0 a ns1:rectangle. ?t0 ns1:have ?t2. ?t0 ns1:have ?t3. (ns1:x2 ns1:x4) math:product ?t1} => {?t0 ns1:has-surface ?t1}. |
Note how nicely the semantics (not only the formula) has been preserved along the processing chain.
% ape.exe -text 'Every n:concrete v:contains a n:cement and v:contains an n:aggregate.' -solo paraphrase Every n:concrete v:contains a n:cement and v:contains an aggregate. % ape.exe -text 'Every n:concrete v:contains a n:cement and v:contains an n:aggregate.' -solo owlfsspp Prefix(:=<http://attempto.ifi.uzh.ch/ontologies/owlswrl/test#>) Ontology(<http://attempto.ifi.uzh.ch/ontologies/owlswrl/test> SubClassOf( :concrete ObjectIntersectionOf( ObjectSomeValuesFrom( :contains :cement ) ObjectSomeValuesFrom( :contains :aggregate ) ) ) )
In EulerGUI, this gives:
{ ?VAR a ns2:concrete } => { ?t0 a ns2:aggregate. ?t1 a ns2:cement. ?VAR ns2:contains ?t0. ?VAR ns2:contains ?t1 }.
Here is Facebook style rule :
If a user U has-as-friend a person X, and has-as-friend a person Y, and X is not Y,
and X has-as-friend Z, and Y has-as-friend Z, and Z is not U
then Z is-a-proposed-friend-for U.
Note the composite verbs that express a property assignment, typical of ACE View.
After translation to N3 (through SWRL) this becomes:
{?t0 a ns1:person. ?t1 a ns1:person. ?t2 a ns1:user. ?t2 ns1:has-as-friend ?t0. ?t2 ns1:has-as-friend ?t1. ?t0 ns1:has-as-friend ?t3. ?t1 ns1:has-as-friend ?t3. ?t0 owl:differentFrom ?t1. ?t3 owl:differentFrom ?t2} => {?t3 ns1:is-a-proposed-friend-for ?t2}. |
Adult Body Mass Index rule, created by Hans Cools:
{ ?adult fos:complexity ?body. ?body a humanbody:Body; quex:hasPhysicalQuantity ?length, ?weight. ?length a humanbody:Length; quex:hasValue ?lengthValue; quex:hasUnit ?lengthUnit. ?weight a humanbody:Weight; quex:hasValue ?weightValue; quex:hasUnit ?weightUnit. (?lengthValue 2) math:exponentiation ?lengthValue2. (?weightValue ?lengthValue2) math:quotient ?X. (?X 10) math:product ?Y. ?Y math:rounded ?Z. (?Z 10) math:quotient ?BMI. } => {?adult humanbody:hasBMI ?BMI.}.
Jos de Roo is developing a series of OWL ontologies and rules in N3, mostly related to medicine :
http://eulersharp.svn.sourceforge.net/viewvc/eulersharp/trunk/2003/03swap/?sortby=date#dirlist
There are rules for fuzzy logic.
Everybody who lives-at a place that he/she works-at is a home-worker.
Alas currently ACE introduces an unnecessary extra variable in the SWRL translation:
Consequent( description( Class(:home-worker) I-variable(5) ) sameAs( I-variable(1) I-variable(5) ) )
You can open in EulerGUI any ontolgy in RDFS, OWL/RDF, or OWL/XML, and apply rules in N3, such as :
{ ?C a owl:Class. _:e e:findall (?CS { ?C rdfs:subClassOf ?SC } ?LIST ). ?LIST math:memberCount ?C. ?C math:greaterThan 2 } => { ?C :class :having_more_than_two_superclasses }.
?CLASS rdfs:subClassOf ?SUPERCLASS. ?PROP rdfs:domain ?SUPERCLASS } => { ?PROP :inheritedPropertyOf ?CLASS }.
Leveraging on the dynamic (stateful) capability of the Drools/N3 engine, it is possible to implement a Finite State Machine (FSM) in N3 in EulerGUI, and embed it in your application with the EulerGUI API.
The possible transitions (a.k.a. transition table) are determined by
statements :possible_transition :s1 :s2
. Of course, these
statements can be either facts, or infered by some rules.
The transition rule is triggered when :event :current
:a_new_event
is asserted :
{ :state :current ?S0. :event :current ?E. :possible_transition ?S0 ?S1. } => { _:d kb:retract (:state :current ?S0). _:d kb:retract (:event :current ?E). :state :current ?S1. }. |
Other examples with dynamic behavior include :
examples/domotic.n3p : leverage on Drools' insertLogical()
test/builtins.n3p : usage of
kb:retract
The make utility brings things up-to-date with their dependencies. This can be useful within a ruuning application as well, e.g for implementing caches, lazy evaluations, etc. A RETE (forward chaining) engine is well suited to implement that.
The generic rule for triggering a redo is:
{ ?TARGET :hasDependency ?DEP. ?TARGET :hasTimestamp ?TT. ?DEP :hasTimestamp ?TDEP. ?TT math:lessThan ?TDEP. } => { ?TARGET :state :needsRedo. }.
A user rule for redoing a target must include the update of the timestamp.
{ ?TARGET :state :needsRedo. } => { # target specific commands ... ?TARGET :update :timestamp. }. |
The generic rule for updating timestamp is:
{ ?TARGET :update :timestamp. } => { _:d kb:retract (?TARGET :hasTimestamp ?TT). ?NOW a java:java-util-Date. ?NOW java:time ?TNOW. ?TARGET :hasTimestamp ?TNOW. }. |
We sketch a rule base on kinship with:
(We could add marriedTo)
hasParent -> sibling,
sibling -> brother, sister, uncle, aunt -> Cousin
hasGrandParent -> hasGrandUncle
For instance the rule for sibling is:
{ ?X hasParent ?P . ?Y hasParent ?P . ?X log:notEqualTo ?Y . } => { ?X hasSibling ?Y }.
The rule for uncle is:
{ ?X hasParent ?P . ?P hasBrother ?B . } => { ?X hasUncle ?B }.
The rest is left as exercise :) .
Here is an example of a rule about rules, see complete rule base in model-rules-coherence.n3 :
{ ?A => ?C . ?A log:includes { ?S ?P ?O } . _:d e:findall ( () {?P a rdf:Property} () ). } => { ?P :message ( "predicate not declared as Property " "; appears in antecedent of rule " { ?A => ?C } ). } . |
There are 2 rules bases that create N3 rules, one from SWRL rules, one from OWL axioms:
Both are activated within EulerGUI when an RDF or OWL URI is loaded .