-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexample-file.rls
191 lines (151 loc) · 7.71 KB
/
example-file.rls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
%! This is just a top level documentation comment,
%! that is more than one line long
%! It should be able to have new lines inbetween.
@import triple :- csv {abc=abc}.
@export test :- turtle {abc = abc, abc = abc , } .
@base <https://example.org/>.
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@declare test(string, middle: any, int).
@output a, b , c,d,e.
% OWL EL Reasoning from OWL/RDF
% See https://github.com/knowsys/nemo-examples/tree/main/examples/owl-el/from-owl-rdf
%
% This example shows how Nemo can be used to reason in the ontology language OWL EL,
% based on input that is the W3C standard encoding of an OWN ontology in RDF, using
% the NTriples syntax.
% owl-rdf-complete-reasoning.rls:
%
% Complete reasoner, producing all inferred class subsumptions as output.
%
% This ruleset normalises an EL ontology in OWL/RDF encoding.
% Unsupported OWL EL features include: oneOf, allDisjoint.
% The encoding used for property chains is also slightly antique.
%
% The ruleset computes facts for the following predicates:
% nf:isMainClass(?C): ?C is an "interesting" class (not just an auxiliary class expression)
% nf:isSubClass(?C): ?C occurs in a subclass position (i.e., negatively)
% nf:conj(?C,?D1,?D2): ?C is the conjunction of ?D1 and ?D2
% nf:exists(?C,?P,?D): ?C is the existential restriction of property ?P with values from ?D
% nf:subClassOf(?C,?D): ?C is syntactically specified to be a subclass of ?D
% nf:subPropChain(?S1,?S2,?R): there was a role chain axiom ?S1 o ?S2 -> ?R
% nf:subProp(?R,?S): ?R is a subproperty of ?S (directly or indirectly)
@prefix nf: <http://rulewerk.semantic-web.org/normalForm/> .
@prefix inf: <http://rulewerk.semantic-web.org/inferred/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix sct: <http://www.ihtsdo.org/owlname#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
% Read data from NT file:
@import TRIPLE :- rdf{resource="https://raw.githubusercontent.com/knowsys/nemo-examples/main/examples/owl-el/from-owl-rdf/galen-el.nt.gz"} .
%%% Mark classes:
ClassObject(owl:someValuesFrom) .
ClassObject(rdf:first) .
ClassObject(rdfs:subClassOf) .
ClassObject(owl:equivalentClass) .
ClassSubject(rdfs:subClassOf) .
ClassSubject(owl:equivalentClass) .
class(?O) :- TRIPLE(?X, ?P, ?O), ClassObject(?P) .
class(?X) :- TRIPLE(?X, ?P, ?O), ClassSubject(?P) .
%%% Distinguish auxiliary class expressions from primary classes:
%% Mark auxiliary existential role restrictions:
synEx(?Y,?P,?X), auxClass(?X) :- TRIPLE(?X, owl:someValuesFrom, ?Y), TRIPLE(?X, owl:onProperty, ?P) .
%% Mark auxiliary conjunctions:
next(?L1,?L2) :- TRIPLE(?L1,rdf:rest,?L2) .
first(?L1) :- TRIPLE(?X, owl:intersectionOf, ?L1) .
nonfirst(?L2) :- first(?L1), next(?L1,?L2) .
nonfirst(?L2) :- nonfirst(?L1), next(?L1,?L2) .
last(?Ln) :- next(?Ln,rdf:nil) .
nonlast(?L) :- next(?L,?Ln), last(?Ln) .
nonlast(?L1) :- next(?L1,?L2), nonlast(?L2) .
in(?L,?C) :- TRIPLE(?L,rdf:first,?C) .
% Mark conjunctions:
synConj(?X,?C1,?C2), auxClass(?X) :-
TRIPLE(?X, owl:intersectionOf, ?L1), next(?L1,?L2), last(?L2), in(?L1,?C1), in(?L2,?C2) .
synConj(?X,?C1,?L2), auxClass(?X) :-
TRIPLE(?X, owl:intersectionOf, ?L1), next(?L1,?L2), nonlast(?L2), in(?L1,?C1) .
synConj(?L1,?C1,?L2), auxClass(?L1) :-
nonfirst(?L1), next(?L1,?L2), nonlast(?L2), in(?L1,?C1) .
synConj(?L1,?C1,?C2), auxClass(?L1) :-
nonfirst(?L1), next(?L1,?L2), last(?L2), in(?L1,?C1), in(?L2,?C2) .
%%% The other classes are "main classes" that are not normalised:
nf:isMainClass(?X) :- class(?X), ~auxClass(?X) .
%%% Normalise auxiliary nested class expressions:
repOf(?X,?X) :- nf:isMainClass(?X) . % keep main classes unchanged
synExRep(?X,?P,?Rep) :- synEx(?Y,?P,?X), repOf(?Y,?Rep) .
nf:exists(!New,?P,?Rep) :- synExRep(?X,?P,?Rep) .
repOf(?X,?N) :- synExRep(?X,?P,?Rep), nf:exists(?N,?P,?Rep) .
% nf:exists(!New,?P,?Rep) :- synEx(?Y,?P,?X), repOf(?Y,?Rep) .
% repOf(?X,?N) :- synEx(?Y,?P), repOf(?Y,?Rep), nf:exists(?N,?P,?Rep) .
nf:conj(!New,?R1,?R2) :- synConj(?X,?C1,?C2), repOf(?C1,?R1), repOf(?C2,?R2) .
repOf(?X,?N) :- synConj(?X,?C1,?C2), repOf(?C1,?R1), repOf(?C2,?R2), nf:conj(?N,?R1,?R2) .
%%% Extract old-style property chains:
nf:subPropChain(?S,?T,?R), nf:subProp(?R,?R) :-
TRIPLE(?L,rdfs:subPropertyOf,?R), TRIPLE(?L,owl:propertyChain,?L1),
in(?L1,?S), next(?L1,?L2), in(?L2,?T) .
%%% Initialise subsumption axioms:
prepareSco(?X,?Y) :- TRIPLE(?X, rdfs:subClassOf, ?Y) .
prepareSco(?X,?Y), prepareSco(?Y,?X) :- TRIPLE(?X, owl:equivalentClass, ?Y) .
nf:subClassOf(?RX,?RY), nf:isSubClass(?RX) :- prepareSco(?X,?Y), repOf(?X,?RX), repOf(?Y,?RY) .
%%% Initialise disjointness:
nf:subClassOf(!C,owl:Nothing), nf:conj(!C,?X,?Y), nf:isSubClass(!C), nf:isSubClass(?X), nf:isSubClass(?Y)
:- TRIPLE(?X,owl:disjointWith,?Y) .
%%% Mark classes in subclass position recursively:
nf:isSubClass(?D) :- nf:exists(?C, ?P, ?D), nf:isSubClass(?C) .
nf:isSubClass(?C1), nf:isSubClass(?C2) :- nf:conj(?X, ?C1, ?C2), nf:isSubClass(?X) .
%%% Precompute role hierarchy:
directSubProp(?R,?S) :- TRIPLE(?R,rdfs:subPropertyOf,?S) .
% Initialise role hierarchy only for roles in subclass positions:
nf:subProp(?P,?P) :- nf:exists(?C,?P,?D), nf:isSubClass(?C) .
nf:subProp(?R,?T) :- nf:subProp(?R,?S), directSubProp(?S,?T) .
%%% Start classification for all named classes:
inf:init(?C) :- nf:isMainClass(?C) .
%%% Inference rules (from "The Incredible ELK", Fig. 3)
% R_0
inf:subClassOf(?C,?C) :- inf:init(?C) .
% R_\top
inf:subClassOf(?C,owl:Thing) :-
nf:isMainClass(?C), nf:isSubClass(owl:Thing) .
% R_\sqcap^-
inf:subClassOf(?C,?D1), inf:subClassOf(?C,?D2) :-
inf:subClassOf(?C,?Y), nf:conj(?Y,?D1,?D2) .
% R_\sqcap^+
inf:subClassOf(?C,?Y) :-
inf:subClassOf(?C,?D1), inf:subClassOf(?C,?D2),
nf:conj(?Y,?D1,?D2), nf:isSubClass(?Y) .
% R_\exists^-
inf:ex(?E,?R,?C) :- inf:subClassOf(?E,?Y), nf:exists(?Y,?R,?C) .
% R_\exists^+
inf:subClassOf(?E,?Y) :-
inf:ex(?E,?R,?C), inf:subClassOf(?C,?D),
nf:subProp(?R,?S), nf:exists(?Y,?S,?D), nf:isSubClass(?Y) .
% R_\sqsubseteq
inf:subClassOf(?C,?E) :-
inf:subClassOf(?C,?D), nf:subClassOf(?D,?E) .
% R_\circ
inf:ex(?E,?S,?D) :-
inf:ex(?E,?R1,?C), inf:ex(?C,?R2,?D),
nf:subProp(?R1,?S1), nf:subProp(?R2,?S2), nf:subPropChain(?S1,?S2,?S) .
% R_\bot
inf:subClassOf(?E,owl:Nothing) :-
inf:ex(?E,?R,?C), inf:subClassOf(?C,owl:Nothing) .
% R_init
inf:init(?C) :- inf:ex(?E,?R,?C) .
%%% Extract final results for main classes
mainSubClassOf(?A,?B) :-
inf:subClassOf(?A,?B), nf:isMainClass(?A), nf:isMainClass(?B) .
@output mainSubClassOf .
/* test */
% This example finds trees of (some species of lime/linden tree) in Dresden,
% which are more than 200 years old.
%
% It shows how to load (typed) data from (compressed) CSV files, how to
% perform a recursive reachability query, and how to use datatype built-in to
% find old trees. It can be modified to use a different species or genus of
% plant, and by changing the required age.
@import tree :- csv{format=(string, string, int, int), resource="https://raw.githubusercontent.com/knowsys/nemo-examples/main/examples/lime-trees/dresden-trees-ages-heights.csv"} . % location URL, species, age, height in m
@import taxon :- csv{format=(string, string, string), resource="https://raw.githubusercontent.com/knowsys/nemo-examples/main/examples/lime-trees/wikidata-taxon-name-parent.csv.gz"} . % Wikidata ID, taxon name, Wikidata ID of parent taxon
limeSpecies(?X, "Tilia") :- taxon(?X, "Tilia", ?P).
limeSpecies(?X, ?Name) :- taxon(?X, ?Name, ?Y), limeSpecies(?Y, ?N).
oldLime(?location,?species,?age) :- tree(?location,?species,?age,?heightInMeters), ?age > 100 + 2 * 50, limeSpecies(?id,?species) .
@output oldLime.