Chris@0
|
1 /* $Id$
|
Chris@0
|
2
|
Chris@0
|
3 Part of SWI-Prolog
|
Chris@0
|
4
|
Chris@0
|
5 Author: Jan Wielemaker
|
Chris@0
|
6 E-mail: jan@swi.psy.uva.nl
|
Chris@0
|
7 WWW: http://www.swi-prolog.org
|
Chris@0
|
8 Copyright (C): 1985-2002, University of Amsterdam
|
Chris@0
|
9
|
Chris@0
|
10 This program is free software; you can redistribute it and/or
|
Chris@0
|
11 modify it under the terms of the GNU General Public License
|
Chris@0
|
12 as published by the Free Software Foundation; either version 2
|
Chris@0
|
13 of the License, or (at your option) any later version.
|
Chris@0
|
14
|
Chris@0
|
15 This program is distributed in the hope that it will be useful,
|
Chris@0
|
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
Chris@0
|
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
Chris@0
|
18 GNU General Public License for more details.
|
Chris@0
|
19
|
Chris@0
|
20 You should have received a copy of the GNU Lesser General Public
|
Chris@0
|
21 License along with this library; if not, write to the Free Software
|
Chris@0
|
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
Chris@0
|
23
|
Chris@0
|
24 As a special exception, if you link this library with other files,
|
Chris@0
|
25 compiled with a Free Software compiler, to produce an executable, this
|
Chris@0
|
26 library does not by itself cause the resulting executable to be covered
|
Chris@0
|
27 by the GNU General Public License. This exception does not however
|
Chris@0
|
28 invalidate any other reasons why the executable file might be covered by
|
Chris@0
|
29 the GNU General Public License.
|
Chris@0
|
30 */
|
Chris@0
|
31
|
Chris@0
|
32 :- module(owl,
|
Chris@0
|
33 [ owl_restriction_on/2, % ?Class, ?Restriction
|
Chris@0
|
34 owl_merged_restriction/3, % ?Class, ?Property, ?Restriction
|
Chris@0
|
35 owl_restriction/2, % +Resource, -Restriction
|
Chris@0
|
36 owl_description/2, % +Resource, -Description
|
Chris@0
|
37 owl_cardinality_on_subject/3, % +Subject, +Predicate, -Card
|
Chris@0
|
38 owl_cardinality_on_class/3, % idem BJW
|
Chris@0
|
39 owl_satisfies/2, % +Spec, +Resource
|
Chris@0
|
40 owl_individual_of/2, % ?Resource, +Description
|
Chris@0
|
41
|
Chris@0
|
42 owl_direct_subclass_of/2, % ?Resource, ?Class
|
Chris@0
|
43 owl_subclass_of/2, % ?Class, ?Super
|
Chris@0
|
44
|
Chris@0
|
45 owl_has/3, % ?Subject, ?Predicate, ?Object
|
Chris@0
|
46 owl_has_direct/3, % ?Subject, ?Predicate, ?Object
|
Chris@0
|
47 owl_same_as/2, % ?X, ?Y
|
Chris@0
|
48
|
Chris@0
|
49 owl_find/5 % +For, +Dom, ?Props, +Method, -Subj
|
Chris@0
|
50 ]).
|
Chris@0
|
51 :- use_module(library(lists)).
|
Chris@0
|
52 :- use_module(library('semweb/rdf_db')).
|
Chris@0
|
53 :- use_module(library('semweb/rdfs')).
|
Chris@0
|
54
|
Chris@0
|
55
|
Chris@0
|
56 /*******************************
|
Chris@0
|
57 * EXPANSION *
|
Chris@0
|
58 *******************************/
|
Chris@0
|
59
|
Chris@0
|
60 % user:goal_expansion(+NSGoal, -Goal)
|
Chris@0
|
61 %
|
Chris@0
|
62 % This predicate allows for writing down rdf queries in a friendly
|
Chris@0
|
63 % name-space fashion.
|
Chris@0
|
64
|
Chris@0
|
65 :- multifile
|
Chris@0
|
66 user:goal_expansion/2.
|
Chris@0
|
67
|
Chris@0
|
68 :- rdf_register_ns(swrl,
|
Chris@0
|
69 'http://www.w3.org/2003/11/swrl#',
|
Chris@0
|
70 [ keep(true)
|
Chris@0
|
71 ]).
|
Chris@0
|
72
|
Chris@0
|
73 :- rdf_meta
|
Chris@0
|
74 owl_restriction_on(r, t),
|
Chris@0
|
75 owl_merged_restriction(r, r, t),
|
Chris@0
|
76 owl_restriction(r, -),
|
Chris@0
|
77 owl_description(r, -),
|
Chris@0
|
78 owl_cardinality_on_subject(r, r, -),
|
Chris@0
|
79 owl_cardinality_on_class(r, r, -),
|
Chris@0
|
80 owl_satisfies(r, t),
|
Chris@0
|
81 owl_individual_of(r, t),
|
Chris@0
|
82 owl_direct_subclass_of(r, r),
|
Chris@0
|
83 owl_subclass_of(r, r),
|
Chris@0
|
84 owl_has(r, r, o),
|
Chris@0
|
85 owl_has_direct(r, r, o),
|
Chris@0
|
86 owl_same_as(r, r),
|
Chris@0
|
87 owl_find(+, t, t, +, -).
|
Chris@0
|
88
|
Chris@0
|
89
|
Chris@0
|
90 /*******************************
|
Chris@0
|
91 * FACTS *
|
Chris@0
|
92 *******************************/
|
Chris@0
|
93
|
Chris@0
|
94 % owl_individual(?IndividualID, ?Type)
|
Chris@0
|
95 % owl_property(?IndividualID, ?PropertyID, ?PropertyValue)
|
Chris@0
|
96 % owl_same_individual(?IndividualID1, ?IndividualID2)
|
Chris@0
|
97 % owl_different_individual(?IndividualID1, ?IndividualID2)
|
Chris@0
|
98
|
Chris@0
|
99
|
Chris@0
|
100 /*******************************
|
Chris@0
|
101 * AXIOMS *
|
Chris@0
|
102 *******************************/
|
Chris@0
|
103
|
Chris@0
|
104 % owl_class(?ClassID, ?Super)
|
Chris@0
|
105 % owl_class_modality(?ClassID, ?Modality)
|
Chris@0
|
106 % owl_same_class(?ClassID1, ?ClassID2)
|
Chris@0
|
107
|
Chris@0
|
108
|
Chris@0
|
109 /*******************************
|
Chris@0
|
110 * RESTRICTIONS *
|
Chris@0
|
111 *******************************/
|
Chris@0
|
112
|
Chris@0
|
113 %% owl_restriction_on(+ClassID,
|
Chris@0
|
114 %% -Restriction:restriction(?PropertyID, ?Restriction)) is nondet.
|
Chris@0
|
115 %
|
Chris@0
|
116 % Enumerate the restrictions that apply to PropertyID for Class.
|
Chris@0
|
117 % Restriction is one of
|
Chris@0
|
118 %
|
Chris@0
|
119 % * all_values_from(Class)
|
Chris@0
|
120 % * some_values_from(Class)
|
Chris@0
|
121 % * has_value(Value)
|
Chris@0
|
122 % * cardinality(Min, Max)
|
Chris@0
|
123
|
Chris@0
|
124 :- rdf_meta
|
Chris@0
|
125 rdf_phas(r,r,o).
|
Chris@0
|
126
|
Chris@0
|
127 owl_restriction_on(Class, Restriction) :-
|
Chris@0
|
128 owl_subclass_of(Class, Super),
|
Chris@0
|
129 ( rdfs_individual_of(Super, owl:'Restriction'),
|
Chris@0
|
130 owl_restriction(Super, Restriction)
|
Chris@0
|
131 ; Restriction = restriction(Property,
|
Chris@0
|
132 all_values_from(Range)),
|
Chris@0
|
133 rdf_phas(Property, rdfs:domain, Super),
|
Chris@0
|
134 ( rdf_phas(Property, rdfs:range, Range)
|
Chris@0
|
135 *-> true
|
Chris@0
|
136 ; rdf_equal(Range, rdfs:'Resource')
|
Chris@0
|
137 )
|
Chris@0
|
138 ).
|
Chris@0
|
139
|
Chris@0
|
140 rdf_phas(Property, P, O) :-
|
Chris@0
|
141 rdfs_subproperty_of(Property, Super),
|
Chris@0
|
142 rdf_has(Super, P, O2), !,
|
Chris@0
|
143 O = O2.
|
Chris@0
|
144
|
Chris@0
|
145 %% owl_restriction(+Resource, -Prolog) is det.
|
Chris@0
|
146 %
|
Chris@0
|
147 % Translate Resource, an individual of owl:restriction into a Prolog term.
|
Chris@0
|
148 %
|
Chris@0
|
149 % @see owl_restriction_on/2 for the Prolog representation.
|
Chris@0
|
150
|
Chris@0
|
151 owl_restriction(RestrictionID, restriction(Property, Restriction)) :-
|
Chris@0
|
152 rdf_has(RestrictionID, owl:onProperty, Property),
|
Chris@0
|
153 restriction_facet(RestrictionID, Restriction).
|
Chris@0
|
154
|
Chris@0
|
155 restriction_facet(RestrictionID, R) :-
|
Chris@0
|
156 ( rdf_has(RestrictionID, owl:allValuesFrom, Class)
|
Chris@0
|
157 -> R = all_values_from(Class)
|
Chris@0
|
158 ; rdf_has(RestrictionID, owl:someValuesFrom, Class)
|
Chris@0
|
159 -> R = some_values_from(Class)
|
Chris@0
|
160 ).
|
Chris@0
|
161 restriction_facet(RestrictionID, has_value(Value)) :-
|
Chris@0
|
162 rdf_has(RestrictionID, owl:hasValue, Value).
|
Chris@0
|
163 restriction_facet(R, cardinality(Min, Max)) :-
|
Chris@0
|
164 ( rdf_has(R, owl:cardinality, literal(Atom))
|
Chris@0
|
165 -> non_negative_integer(Atom, Min, R, owl:cardinality),
|
Chris@0
|
166 Max = Min
|
Chris@0
|
167 ; rdf_has(R, owl:minCardinality, literal(MinAtom))
|
Chris@0
|
168 -> non_negative_integer(MinAtom, Min, R, owl:minCardinality),
|
Chris@0
|
169 ( rdf_has(R, owl:maxCardinality, literal(MaxAtom))
|
Chris@0
|
170 -> non_negative_integer(MaxAtom, Max, R, owl:maxCardinality)
|
Chris@0
|
171 ; Max = inf
|
Chris@0
|
172 )
|
Chris@0
|
173 ; rdf_has(R, owl:maxCardinality, literal(MaxAtom))
|
Chris@0
|
174 -> non_negative_integer(MaxAtom, Max, R, owl:maxCardinality),
|
Chris@0
|
175 Min = 0
|
Chris@0
|
176 ).
|
Chris@0
|
177
|
Chris@0
|
178 % non_negative_integer(+Atom, -Integer, +Subject, +Predicate)
|
Chris@0
|
179 %
|
Chris@0
|
180 % Deduce integer value from rdf(Subject, Predicate, literal(Atom))
|
Chris@0
|
181 % and if a conversion error occurs warn compatible to the rdfs_validate
|
Chris@0
|
182 % library.
|
Chris@0
|
183 %
|
Chris@0
|
184 % TBD: If argument is typed we should check the type is compatible
|
Chris@0
|
185 % to xsd:nonNegativeInteger.
|
Chris@0
|
186
|
Chris@0
|
187 non_negative_integer(type(_Type, Atom), Int, S, P) :-
|
Chris@0
|
188 nonvar(Atom), !,
|
Chris@0
|
189 non_negative_integer(Atom, Int, S, P).
|
Chris@0
|
190 non_negative_integer(Atom, Int, _, _) :-
|
Chris@0
|
191 catch(atom_number(Atom, Int), _, fail), !,
|
Chris@0
|
192 integer(Int),
|
Chris@0
|
193 Int >= 0.
|
Chris@0
|
194 non_negative_integer(Atom, _, S, P) :-
|
Chris@0
|
195 rdf_equal(xsd:nonNegativeInteger, Range),
|
Chris@0
|
196 rdf_global_id(P, Pred),
|
Chris@0
|
197 print_message(error,
|
Chris@0
|
198 rdf_illegal_object(S,Pred,literal(Atom),Range)),
|
Chris@0
|
199 fail.
|
Chris@0
|
200
|
Chris@0
|
201 %% owl_merged_restriction(+Class, ?Property, ?Restriction) is nondet.
|
Chris@0
|
202 %
|
Chris@0
|
203 % As owl_restriction_on/2, but combines multiple restrictions into
|
Chris@0
|
204 % the least strict restriction satisfying the declared
|
Chris@0
|
205 % restrictions.
|
Chris@0
|
206
|
Chris@0
|
207 owl_merged_restriction(Class, Property, Restriction) :-
|
Chris@0
|
208 setof(Decl,
|
Chris@0
|
209 owl_restriction_on(Class, restriction(Property, Decl)),
|
Chris@0
|
210 Decls),
|
Chris@0
|
211 join_decls(Decls, Minimal),
|
Chris@0
|
212 member(Restriction, Minimal).
|
Chris@0
|
213
|
Chris@0
|
214 % input is sorted, thus the following holds:
|
Chris@0
|
215 %
|
Chris@0
|
216 % cardinality < has_value < values_from
|
Chris@0
|
217
|
Chris@0
|
218 join_decls([], []).
|
Chris@0
|
219 join_decls([cardinality(Min1, Max1), cardinality(Min2, Max2)|T], Set) :- !,
|
Chris@0
|
220 Min is max(Min1, Min2),
|
Chris@0
|
221 max_cardinality(Max1, Max2, Max),
|
Chris@0
|
222 join_decls([cardinality(Min, Max)|T], Set).
|
Chris@0
|
223 join_decls([has_value(Value)|T], [has_value(Value)]) :- !,
|
Chris@0
|
224 satisfies_restrictions(T, Value).
|
Chris@0
|
225 join_decls([values_from(AS1, C1), values_from(AS2, C2)|T], Set) :-
|
Chris@0
|
226 merge_values_from(AS1, C1, AS2, C2, AS, C), !,
|
Chris@0
|
227 join_decls([values_from(AS, C)|T], Set).
|
Chris@0
|
228 join_decls([H|T0], [H|T]) :-
|
Chris@0
|
229 join_decls(T0, T).
|
Chris@0
|
230
|
Chris@0
|
231 max_cardinality(infinite, Min, Min) :- !.
|
Chris@0
|
232 max_cardinality(Min, infinite, Min) :- !.
|
Chris@0
|
233 max_cardinality(Min1, Min2, Min) :-
|
Chris@0
|
234 Min is min(Min1, Min2).
|
Chris@0
|
235
|
Chris@0
|
236 % satisfies_restrictions(+Restrictions, +Value)
|
Chris@0
|
237 %
|
Chris@0
|
238 % See whether Value satisfies all restrictions, so we can indeed
|
Chris@0
|
239 % use it as a value.
|
Chris@0
|
240
|
Chris@0
|
241 satisfies_restrictions([], _).
|
Chris@0
|
242 satisfies_restrictions([H|T], Value) :-
|
Chris@0
|
243 satisfies_restriction(H, Value),
|
Chris@0
|
244 satisfies_restrictions(T, Value).
|
Chris@0
|
245
|
Chris@0
|
246 satisfies_restriction(has_value(Value), Value).
|
Chris@0
|
247 satisfies_restriction(values_from(some, _), _).
|
Chris@0
|
248 satisfies_restriction(values_from(all, Class), Value) :-
|
Chris@0
|
249 rdfs_individual_of(Value, Class).
|
Chris@0
|
250
|
Chris@0
|
251 % merge_values_from(+AllSome2, +C1, +AllSome2, +C2, -AllSome, -C)
|
Chris@0
|
252 %
|
Chris@0
|
253 % Merge multiple allValuesFrom and someValuesFrom restrictions.
|
Chris@0
|
254 % This needs some thought, but as we don't need it for the MIA
|
Chris@0
|
255 % tool right now we'll leave it.
|
Chris@0
|
256
|
Chris@0
|
257 merge_values_from(all, C1, all, C2, all, C) :-
|
Chris@0
|
258 rdfs_subclass_of(C, C1),
|
Chris@0
|
259 rdfs_subclass_of(C, C2).
|
Chris@0
|
260
|
Chris@0
|
261
|
Chris@0
|
262 /*******************************
|
Chris@0
|
263 * CARDINALITY *
|
Chris@0
|
264 *******************************/
|
Chris@0
|
265
|
Chris@0
|
266 %% owl_cardinality_on_subject(+Subject, +Pred, -Card:cardinality(Min, Max)) is semidet.
|
Chris@0
|
267 %
|
Chris@0
|
268 % Deduces the minimum and maximum cardinality for a property of a
|
Chris@0
|
269 % resource. This predicate may fail if no information is available.
|
Chris@0
|
270 %
|
Chris@0
|
271 % NOTE: used to use rdf_subclass_of. Will owl_direct_subclass_of lead to
|
Chris@0
|
272 % cycles?
|
Chris@0
|
273
|
Chris@0
|
274 owl_cardinality_on_subject(Subject, Predicate, Cardinality) :-
|
Chris@0
|
275 findall(C, cardinality_on_subject(Subject, Predicate, C), L),
|
Chris@0
|
276 join_decls(L, [Cardinality]).
|
Chris@0
|
277
|
Chris@0
|
278 cardinality_on_subject(Subject, Predicate, cardinality(Min, Max)) :-
|
Chris@0
|
279 rdf_has(Subject, rdf:type, Class),
|
Chris@0
|
280 owl_direct_subclass_of(Class, RestrictionID),
|
Chris@0
|
281 rdfs_individual_of(RestrictionID, owl:'Restriction'),
|
Chris@0
|
282 rdf_has(RestrictionID, owl:onProperty, Predicate),
|
Chris@0
|
283 restriction_facet(RestrictionID, cardinality(Min, Max)).
|
Chris@0
|
284
|
Chris@0
|
285 %% owl_cardinality_on_class(+Class, ?Predicate, -Card:cardinality(Min, Max)) is semidet.
|
Chris@0
|
286
|
Chris@0
|
287 owl_cardinality_on_class(Class, Predicate, Cardinality) :-
|
Chris@0
|
288 findall(C, cardinality_on_class(Class, Predicate, C), L),
|
Chris@0
|
289 join_decls(L, [Cardinality]).
|
Chris@0
|
290
|
Chris@0
|
291 cardinality_on_class(Class, Predicate, cardinality(Min, Max)) :-
|
Chris@0
|
292 owl_direct_subclass_of(Class, RestrictionID),
|
Chris@0
|
293 rdfs_individual_of(RestrictionID, owl:'Restriction'),
|
Chris@0
|
294 rdf_has(RestrictionID, owl:onProperty, Predicate),
|
Chris@0
|
295 restriction_facet(RestrictionID, cardinality(Min, Max)).
|
Chris@0
|
296
|
Chris@0
|
297 %% owl_satisfies_restriction(?Resource, +Restriction)
|
Chris@0
|
298 %
|
Chris@0
|
299 % True if Restriction satisfies the restriction imposed by Restriction.
|
Chris@0
|
300 % The current implementation makes the following assumptions:
|
Chris@0
|
301 %
|
Chris@0
|
302 % * Only one of owl:hasValue, owl:allValuesFrom or owl:someValuesFrom
|
Chris@0
|
303 % is present.
|
Chris@0
|
304
|
Chris@0
|
305 owl_satisfies_restriction(Resource, Restriction) :-
|
Chris@0
|
306 rdf_has(Restriction, owl:onProperty, Property),
|
Chris@0
|
307 ( rdf_has(Restriction, owl:hasValue, Value)
|
Chris@0
|
308 -> owl_has(Resource, Property, Value)
|
Chris@0
|
309 ; rdf_has(Restriction, owl:allValuesFrom, Class)
|
Chris@0
|
310 -> setof(V, owl_has(Resource, Property, V), Vs),
|
Chris@0
|
311 all_individual_of(Vs, Class)
|
Chris@0
|
312 ; rdf_has(Restriction, owl:someValuesFrom, Class)
|
Chris@0
|
313 -> owl_has(Resource, Property, Value),
|
Chris@0
|
314 owl_individual_of(Value, Class)
|
Chris@0
|
315 ; rdf_subject(Resource)
|
Chris@0
|
316 ),
|
Chris@0
|
317 owl_satisfies_cardinality(Resource, Restriction).
|
Chris@0
|
318
|
Chris@0
|
319 all_individual_of([], _).
|
Chris@0
|
320 all_individual_of([H|T], Class) :-
|
Chris@0
|
321 owl_individual_of(H, Class), !,
|
Chris@0
|
322 all_individual_of(T, Class).
|
Chris@0
|
323
|
Chris@0
|
324 % owl_satisfies_cardinality(?Resource[, +Property], +Restriction)
|
Chris@0
|
325 %
|
Chris@0
|
326 % True if Resource satisfies the cardinality restrictions on
|
Chris@0
|
327 % Property imposed by Restriction.
|
Chris@0
|
328
|
Chris@0
|
329 owl_satisfies_cardinality(Resource, Restriction) :-
|
Chris@0
|
330 rdf_has(Restriction, owl:onProperty, Property),
|
Chris@0
|
331 owl_satisfies_cardinality(Resource, Property, Restriction).
|
Chris@0
|
332
|
Chris@0
|
333 owl_satisfies_cardinality(Resource, Property, Restriction) :-
|
Chris@0
|
334 rdf_has(Restriction, owl:cardinality, literal(Atom)), !,
|
Chris@0
|
335 non_negative_int(Atom, Card),
|
Chris@0
|
336 findall(V, rdf_has(Resource, Property, V), Vs0),
|
Chris@0
|
337 sort(Vs0, Vs), % remove duplicates
|
Chris@0
|
338 length(Vs, Card).
|
Chris@0
|
339 owl_satisfies_cardinality(Resource, Property, Restriction) :-
|
Chris@0
|
340 rdf_has(Restriction, owl:minCardinality, literal(MinAtom)),
|
Chris@0
|
341 non_negative_int(MinAtom, Min), !,
|
Chris@0
|
342 findall(V, owl_has(Resource, Property, V), Vs0),
|
Chris@0
|
343 sort(Vs0, Vs), % remove duplicates
|
Chris@0
|
344 length(Vs, Count),
|
Chris@0
|
345 Count >= Min,
|
Chris@0
|
346 ( rdf_has(Restriction, owl:maxCardinality, literal(MaxAtom)),
|
Chris@0
|
347 atom_number(MaxAtom, Max)
|
Chris@0
|
348 -> Count =< Max
|
Chris@0
|
349 ; true
|
Chris@0
|
350 ).
|
Chris@0
|
351 owl_satisfies_cardinality(Resource, Property, Restriction) :-
|
Chris@0
|
352 rdf_has(Restriction, owl:maxCardinality, literal(MaxAtom)),
|
Chris@0
|
353 non_negative_int(MaxAtom, Max), !,
|
Chris@0
|
354 findall(V, owl_has(Resource, Property, V), Vs0),
|
Chris@0
|
355 sort(Vs0, Vs), % remove duplicates
|
Chris@0
|
356 length(Vs, Count),
|
Chris@0
|
357 Count =< Max.
|
Chris@0
|
358 owl_satisfies_cardinality(Resource, _, _) :-
|
Chris@0
|
359 rdf_subject(Resource).
|
Chris@0
|
360
|
Chris@0
|
361 non_negative_int(type(Type, Atom), Number) :-
|
Chris@0
|
362 rdf_equal(xsd:nonNegativeInteger, Type),
|
Chris@0
|
363 catch(atom_number(Atom, Number), _, fail).
|
Chris@0
|
364 non_negative_int(Atom, Number) :-
|
Chris@0
|
365 atom(Atom),
|
Chris@0
|
366 catch(atom_number(Atom, Number), _, fail).
|
Chris@0
|
367
|
Chris@0
|
368
|
Chris@0
|
369 /*******************************
|
Chris@0
|
370 * DESCRIPTION *
|
Chris@0
|
371 *******************************/
|
Chris@0
|
372
|
Chris@0
|
373 %% owl_description(+DescriptionID, -Prolog) is det.
|
Chris@0
|
374 %
|
Chris@0
|
375 % Convert an owl description into a Prolog representation. This
|
Chris@0
|
376 % representation is:
|
Chris@0
|
377 %
|
Chris@0
|
378 % * class(Class)
|
Chris@0
|
379 % * restriction(Property, Restriction)
|
Chris@0
|
380 % * union_of(ListOfDescriptions)
|
Chris@0
|
381 % * intersection_of(ListOfDescriptions)
|
Chris@0
|
382 % * complement_of(Description)
|
Chris@0
|
383 % * one_of(Individuals)
|
Chris@0
|
384 % * thing
|
Chris@0
|
385 % * nothing
|
Chris@0
|
386 %
|
Chris@0
|
387 % where Restriction is defined by owl_restriction_on/2.
|
Chris@0
|
388 % For example, the union-of can be the result of
|
Chris@0
|
389 %
|
Chris@0
|
390 % ==
|
Chris@0
|
391 % <rdfs:Class rdf:ID="myclass">
|
Chris@0
|
392 % <owl:unionOf parseType=Collection>
|
Chris@0
|
393 % <rdf:Description rdf:about="gnu"/>
|
Chris@0
|
394 % <rdf:Description rdf:about="gnat"/>
|
Chris@0
|
395 % </owl:unionOf>
|
Chris@0
|
396 % </rdfs:Class>
|
Chris@0
|
397 % ==
|
Chris@0
|
398
|
Chris@0
|
399 owl_description(ID, Restriction) :-
|
Chris@0
|
400 ( rdf_equal(owl:'Thing', ID)
|
Chris@0
|
401 -> Restriction = thing
|
Chris@0
|
402 ; rdf_equal(owl:'Nothing', ID)
|
Chris@0
|
403 -> Restriction = nothing
|
Chris@0
|
404 ; rdf_has(ID, rdf:type, owl:'Restriction')
|
Chris@0
|
405 -> owl_restriction(ID, Restriction)
|
Chris@0
|
406 ; rdf_has(ID, rdf:type, owl:'Class')
|
Chris@0
|
407 -> ( ( rdf_has(ID, owl:unionOf, Set)
|
Chris@0
|
408 -> Restriction = union_of(SubDescriptions)
|
Chris@0
|
409 ; rdf_has(ID, owl:intersectionOf, Set)
|
Chris@0
|
410 -> Restriction = intersection_of(SubDescriptions)
|
Chris@0
|
411 )
|
Chris@0
|
412 -> rdfs_list_to_prolog_list(Set, Members),
|
Chris@0
|
413 maplist(owl_description, Members, SubDescriptions)
|
Chris@0
|
414 ; rdf_has(ID, owl:complementOf, Arg)
|
Chris@0
|
415 -> Restriction = complement_of(SubDescription),
|
Chris@0
|
416 owl_description(Arg, SubDescription)
|
Chris@0
|
417 ; rdf_has(ID, owl:oneOf, Arg)
|
Chris@0
|
418 -> Restriction = one_of(Individuals),
|
Chris@0
|
419 rdfs_list_to_prolog_list(Arg, Individuals)
|
Chris@0
|
420 ; Restriction = class(ID)
|
Chris@0
|
421 )
|
Chris@0
|
422 ).
|
Chris@0
|
423
|
Chris@0
|
424
|
Chris@0
|
425 /*******************************
|
Chris@0
|
426 * OWL_SATISFIES *
|
Chris@0
|
427 *******************************/
|
Chris@0
|
428
|
Chris@0
|
429 %% owl_satisfies(+Specification, ?Resource) is nondet.
|
Chris@0
|
430 %
|
Chris@0
|
431 % Test whether Resource satisfies Specification. All resources are
|
Chris@0
|
432 % considered to belong to rdfs:Resource, which is not really
|
Chris@0
|
433 % enforced. Domain is one of
|
Chris@0
|
434 %
|
Chris@0
|
435 % | rdfs:Resource | Allow for any resource |
|
Chris@0
|
436 % | class(Class) | Allow for a subclass of Class|
|
Chris@0
|
437 % | union_of(Domains) | |
|
Chris@0
|
438 % | intersection_of(Domains) | |
|
Chris@0
|
439 % | complement_of(Domain) | |
|
Chris@0
|
440 % | one_of(Resources) | One of these values |
|
Chris@0
|
441 % | all_values_from(Class) | Individual of this class |
|
Chris@0
|
442 % | some_values_from(Class) | Not used |
|
Chris@0
|
443 % | has_value(Value) | Must have this value |
|
Chris@0
|
444 %
|
Chris@0
|
445 % Resource can be a term individual_of(Class), in which case this
|
Chris@0
|
446 % predicate succeeds if any individual of Class is accepted by
|
Chris@0
|
447 % Domain.
|
Chris@0
|
448
|
Chris@0
|
449 % Short-cut
|
Chris@0
|
450 owl_satisfies(Domain, Resource) :-
|
Chris@0
|
451 rdf_equal(rdfs:'Resource', Domain), !,
|
Chris@0
|
452 ( atom(Resource)
|
Chris@0
|
453 -> true
|
Chris@0
|
454 ; var(Resource)
|
Chris@0
|
455 -> rdf_subject(Resource)
|
Chris@0
|
456 ; Resource = individual_of(_)
|
Chris@0
|
457 ).
|
Chris@0
|
458 % Descriptions
|
Chris@0
|
459 owl_satisfies(class(Domain), Resource) :- !,
|
Chris@0
|
460 ( rdf_equal(Domain, rdfs:'Resource')
|
Chris@0
|
461 -> true
|
Chris@0
|
462 ; Resource = individual_of(Class),
|
Chris@0
|
463 atom(Class)
|
Chris@0
|
464 -> fail
|
Chris@0
|
465 ; owl_subclass_of(Resource, Domain)
|
Chris@0
|
466 ).
|
Chris@0
|
467 owl_satisfies(union_of(Domains), Resource) :- !,
|
Chris@0
|
468 member(Domain, Domains),
|
Chris@0
|
469 owl_satisfies(Domain, Resource).
|
Chris@0
|
470 owl_satisfies(intersection_of(Domains), Resource) :- !,
|
Chris@0
|
471 in_all_domains(Domains, Resource).
|
Chris@0
|
472 owl_satisfies(complement_of(Domain), Resource) :- !,
|
Chris@0
|
473 ( atom(Resource)
|
Chris@0
|
474 -> true
|
Chris@0
|
475 ; var(Resource)
|
Chris@0
|
476 -> rdf_subject(Resource)
|
Chris@0
|
477 ; fail % individual_of(Class)
|
Chris@0
|
478 ),
|
Chris@0
|
479 \+ owl_satisfies(Domain, Resource).
|
Chris@0
|
480 owl_satisfies(one_of(List), Resource) :- !,
|
Chris@0
|
481 member(Resource, List).
|
Chris@0
|
482 % Restrictions
|
Chris@0
|
483 owl_satisfies(all_values_from(Domain), Resource) :- !,
|
Chris@0
|
484 ( Resource = individual_of(Class),
|
Chris@0
|
485 atom(Class)
|
Chris@0
|
486 -> owl_subclass_of(Class, Domain)
|
Chris@0
|
487 ; owl_individual_of(Resource, Domain)
|
Chris@0
|
488 ).
|
Chris@0
|
489 owl_satisfies(some_values_from(_Domain), _Resource) :- !.
|
Chris@0
|
490 owl_satisfies(has_value(Value), Resource) :-
|
Chris@0
|
491 rdf_equal(Value, Resource). % TBD: equality
|
Chris@0
|
492
|
Chris@0
|
493
|
Chris@0
|
494 in_all_domains([], _).
|
Chris@0
|
495 in_all_domains([H|T], Resource) :-
|
Chris@0
|
496 owl_satisfies(H, Resource),
|
Chris@0
|
497 in_all_domains(T, Resource).
|
Chris@0
|
498
|
Chris@0
|
499
|
Chris@0
|
500 /*******************************
|
Chris@0
|
501 * INDIVIDUAL OF *
|
Chris@0
|
502 *******************************/
|
Chris@0
|
503
|
Chris@0
|
504 %% owl_individual_of(?Resource, +Description) is nondet.
|
Chris@0
|
505 %
|
Chris@0
|
506 % Test or generate the resources that satisfy Description
|
Chris@0
|
507 % according the the OWL-Description entailment rules.
|
Chris@0
|
508
|
Chris@0
|
509 owl_individual_of(Resource, Thing) :-
|
Chris@0
|
510 rdf_equal(Thing, owl:'Thing'), !,
|
Chris@0
|
511 ( atom(Resource)
|
Chris@0
|
512 -> true
|
Chris@0
|
513 ; rdf_subject(Resource)
|
Chris@0
|
514 ).
|
Chris@0
|
515 owl_individual_of(_Resource, Nothing) :-
|
Chris@0
|
516 rdf_equal(Nothing, owl:'Nothing'), !,
|
Chris@0
|
517 fail.
|
Chris@0
|
518 owl_individual_of(Resource, Description) :- % RDFS
|
Chris@0
|
519 rdfs_individual_of(Resource, Description).
|
Chris@0
|
520 /*owl_individual_of(Resource, Class) :-
|
Chris@0
|
521 nonvar(Resource),
|
Chris@0
|
522 setof(C, rdf_has(Resource, rdf:type, C), Cs), !,
|
Chris@0
|
523 member(C, Cs),
|
Chris@0
|
524 owl_subclass_of(C, Class).
|
Chris@0
|
525 */
|
Chris@0
|
526 owl_individual_of(Resource, Class) :-
|
Chris@0
|
527 nonvar(Resource),
|
Chris@0
|
528 rdf_has(Resource, rdf:type, C),
|
Chris@0
|
529 owl_subclass_of(C, Class).
|
Chris@0
|
530
|
Chris@0
|
531 owl_individual_of(Resource, Class) :-
|
Chris@0
|
532 rdfs_individual_of(Class, owl:'Class'),
|
Chris@0
|
533 ( rdf_has(Class, owl:equivalentClass, EQ)
|
Chris@0
|
534 -> owl_individual_of(Resource, EQ)
|
Chris@0
|
535 ; rdfs_individual_of(Class, owl:'Restriction')
|
Chris@0
|
536 -> owl_satisfies_restriction(Resource, Class)
|
Chris@0
|
537 ; owl_individual_of_description(Resource, Class, HasDescription),
|
Chris@0
|
538 findall(SC, rdf_has(Class, rdfs:subClassOf, SC), SuperClasses),
|
Chris@0
|
539 ( HasDescription == false
|
Chris@0
|
540 -> SuperClasses \== []
|
Chris@0
|
541 ; true
|
Chris@0
|
542 ),
|
Chris@0
|
543 owl_individual_of_all(SuperClasses, Resource)
|
Chris@0
|
544 ).
|
Chris@0
|
545 owl_individual_of(Resource, Description) :- % RDFS
|
Chris@0
|
546 owl_individual_from_range(Resource, Description).
|
Chris@0
|
547
|
Chris@0
|
548
|
Chris@0
|
549 %% owl_individual_of_description(?Resource, +Description, -HasDescription) is nondet.
|
Chris@0
|
550 %
|
Chris@0
|
551 % @tbd Can a description have multiple of these facets?
|
Chris@0
|
552
|
Chris@0
|
553 owl_individual_of_description(Resource, Description, true) :-
|
Chris@0
|
554 rdf_has(Description, owl:unionOf, Set), !,
|
Chris@0
|
555 rdfs_member(Sub, Set),
|
Chris@0
|
556 owl_individual_of(Resource, Sub).
|
Chris@0
|
557 owl_individual_of_description(Resource, Description, true) :-
|
Chris@0
|
558 rdf_has(Description, owl:intersectionOf, Set), !,
|
Chris@0
|
559 intersection_of(Set, Resource).
|
Chris@0
|
560 owl_individual_of_description(Resource, Description, true) :-
|
Chris@0
|
561 rdf_has(Description, owl:complementOf, Arg), !,
|
Chris@0
|
562 rdf_subject(Resource),
|
Chris@0
|
563 \+ owl_individual_of(Resource, Arg).
|
Chris@0
|
564 owl_individual_of_description(Resource, Description, true) :-
|
Chris@0
|
565 rdf_has(Description, owl:oneOf, Arg), !,
|
Chris@0
|
566 rdfs_member(Resource, Arg).
|
Chris@0
|
567 owl_individual_of_description(_, _, false).
|
Chris@0
|
568
|
Chris@0
|
569
|
Chris@0
|
570 owl_individual_of_all([], _).
|
Chris@0
|
571 owl_individual_of_all([C|T], Resource) :-
|
Chris@0
|
572 owl_individual_of(Resource, C),
|
Chris@0
|
573 owl_individual_of_all(T, Resource).
|
Chris@0
|
574
|
Chris@0
|
575
|
Chris@0
|
576 owl_individual_from_range(Resource, Class) :-
|
Chris@0
|
577 nonvar(Resource), !,
|
Chris@0
|
578 rdf_has(_, P, Resource),
|
Chris@0
|
579 rdf_has(P, rdfs:range, Class), !.
|
Chris@0
|
580 owl_individual_from_range(Resource, Class) :-
|
Chris@0
|
581 rdf_has(P, rdfs:range, Class),
|
Chris@0
|
582 rdf_has(_, P, Resource). % owl_has?
|
Chris@0
|
583
|
Chris@0
|
584 intersection_of(List, Resource) :-
|
Chris@0
|
585 rdf_has(List, rdf:first, First),
|
Chris@0
|
586 owl_individual_of(Resource, First),
|
Chris@0
|
587 ( rdf_has(List, rdf:rest, Rest)
|
Chris@0
|
588 -> intersection_of(Rest, Resource)
|
Chris@0
|
589 ; true
|
Chris@0
|
590 ).
|
Chris@0
|
591 intersection_of(Nil, _) :-
|
Chris@0
|
592 rdf_equal(rdf:nil, Nil).
|
Chris@0
|
593
|
Chris@0
|
594
|
Chris@0
|
595 /*******************************
|
Chris@0
|
596 * OWL PROPERTIES *
|
Chris@0
|
597 *******************************/
|
Chris@0
|
598
|
Chris@0
|
599 %% owl_has(?Subject, ?Predicate, ?Object)
|
Chris@0
|
600 %
|
Chris@0
|
601 % True if this relation is specified or can be deduced using OWL
|
Chris@0
|
602 % inference rules. It adds transitivity to owl_has_direct/3.
|
Chris@0
|
603
|
Chris@0
|
604 owl_has(S, P, O) :-
|
Chris@0
|
605 ( var(P)
|
Chris@0
|
606 -> rdfs_individual_of(P, rdf:'Property')
|
Chris@0
|
607 ; true
|
Chris@0
|
608 ),
|
Chris@0
|
609 rdf_reachable(SP, rdfs:subPropertyOf, P),
|
Chris@0
|
610 owl_has_transitive(S, SP, O).
|
Chris@0
|
611
|
Chris@0
|
612
|
Chris@0
|
613 %% owl_has_transitive(?Subject, ?Predicate, ?Object)
|
Chris@0
|
614 %
|
Chris@0
|
615 % If Predicate is transitive, do a transitive closure on the
|
Chris@0
|
616 % relation.
|
Chris@0
|
617
|
Chris@0
|
618 owl_has_transitive(S, P, O) :-
|
Chris@0
|
619 rdfs_individual_of(P, owl:'TransitiveProperty'), !,
|
Chris@0
|
620 owl_has_transitive(S, P, O, [P]).
|
Chris@0
|
621 owl_has_transitive(S, P, O) :-
|
Chris@0
|
622 owl_has_equivalent(S, P, O).
|
Chris@0
|
623
|
Chris@0
|
624 owl_has_transitive(S, P, O, Visited) :-
|
Chris@0
|
625 owl_has_equivalent(S, P, O1),
|
Chris@0
|
626 O1 \= literal(_),
|
Chris@0
|
627 \+ memberchk(O1, Visited),
|
Chris@0
|
628 ( O = O1
|
Chris@0
|
629 ; owl_has_transitive(O1, P, O, [O1|Visited])
|
Chris@0
|
630 ).
|
Chris@0
|
631
|
Chris@0
|
632 % owl_has_equivalent(?Subject, ?Predicate, ?Object)
|
Chris@0
|
633 %
|
Chris@0
|
634 % Adds owl:sameAs on Subject and Object to owl_has_direct/3
|
Chris@0
|
635
|
Chris@0
|
636 owl_has_equivalent(S, P, O) :-
|
Chris@0
|
637 nonvar(S), !,
|
Chris@0
|
638 owl_same_as(S, S1),
|
Chris@0
|
639 owl_has_direct(S1, P, O0),
|
Chris@0
|
640 owl_same_as(O0, O).
|
Chris@0
|
641 owl_has_equivalent(S, P, O) :-
|
Chris@0
|
642 nonvar(O), !,
|
Chris@0
|
643 owl_same_as(O1, O),
|
Chris@0
|
644 owl_has_direct(S0, P, O1),
|
Chris@0
|
645 owl_same_as(S0, S).
|
Chris@0
|
646 owl_has_equivalent(S, P, O) :-
|
Chris@0
|
647 owl_has_direct(S0, P, O0),
|
Chris@0
|
648 owl_same_as(S0, S),
|
Chris@0
|
649 owl_same_as(O0, O).
|
Chris@0
|
650
|
Chris@0
|
651
|
Chris@0
|
652 %% owl_same_as(?X, ?Y) is nondet.
|
Chris@0
|
653 %
|
Chris@0
|
654 % True if X and Y are identical or connected by the owl:sameAs
|
Chris@0
|
655 % relation. Considers owl:sameAs transitive and symetric.
|
Chris@0
|
656
|
Chris@0
|
657 owl_same_as(literal(X), literal(X)) :- !.
|
Chris@0
|
658 owl_same_as(X, Y) :-
|
Chris@0
|
659 nonvar(X), !,
|
Chris@0
|
660 owl_same_as(X, Y, [X]).
|
Chris@0
|
661 owl_same_as(X, Y) :-
|
Chris@0
|
662 owl_same_as(Y, X, [X]).
|
Chris@0
|
663
|
Chris@0
|
664 owl_same_as(X, X, _).
|
Chris@0
|
665 owl_same_as(X, Y, Visited) :-
|
Chris@0
|
666 ( rdf_has(X, owl:sameAs, X1)
|
Chris@0
|
667 ; rdf_has(X1, owl:sameAs, X)
|
Chris@0
|
668 ),
|
Chris@0
|
669 X1 \= literal(_),
|
Chris@0
|
670 \+ memberchk(X1, Visited),
|
Chris@0
|
671 owl_same_as(X1, Y, [X1|Visited]).
|
Chris@0
|
672
|
Chris@0
|
673
|
Chris@0
|
674 %% owl_has_direct(?Subject, ?Predicate, ?Object)
|
Chris@0
|
675 %
|
Chris@0
|
676 % Deals with `One-step' OWL inferencing: inverse properties,
|
Chris@0
|
677 % symmetric properties and being subtype of a restriction with an
|
Chris@0
|
678 % owl:hasValue statement on this property.
|
Chris@0
|
679 %
|
Chris@0
|
680 % @bug owl_has_direct/3 also uses SWRL rules. This should be
|
Chris@0
|
681 % moved elsewhere.
|
Chris@0
|
682
|
Chris@0
|
683 owl_has_direct(S, P, O) :-
|
Chris@0
|
684 rdf(S, P, O).
|
Chris@0
|
685 owl_has_direct(S, P, O) :-
|
Chris@0
|
686 ( rdf_has(P, owl:inverseOf, P2)
|
Chris@0
|
687 -> true
|
Chris@0
|
688 ; rdf_has(P2, owl:inverseOf, P)
|
Chris@0
|
689 ),
|
Chris@0
|
690 rdf_has(O, P2, S). % TBD: must call owl_has_direct/3
|
Chris@0
|
691 owl_has_direct(S, P, O) :-
|
Chris@0
|
692 rdfs_individual_of(P, owl:'SymmetricProperty'),
|
Chris@0
|
693 rdf(O, P, S).
|
Chris@0
|
694 owl_has_direct(S, P, O) :-
|
Chris@0
|
695 owl_use_has_value(S, P, O).
|
Chris@0
|
696
|
Chris@0
|
697
|
Chris@0
|
698 %----------------------------------------------------------
|
Chris@0
|
699 % added by BJW for use of OWL with SWRL rules, highly experimental
|
Chris@0
|
700 % see http://www.daml.org/rules/proposal/rules-all.html for SWRL.
|
Chris@0
|
701 % It implements simple Prolog-like inferencing were order of antecedents
|
Chris@0
|
702 % may matter and some assumptions about instantiation of variables are
|
Chris@0
|
703 % made (see comments below).
|
Chris@0
|
704 % Currently is doesnot cater for arbitrary OWL descriptions mixed with
|
Chris@0
|
705 % SWRL.
|
Chris@0
|
706
|
Chris@0
|
707 owl_has_direct(S, P, O) :-
|
Chris@0
|
708 owl_use_rule(S, P, O).
|
Chris@0
|
709
|
Chris@0
|
710 owl_use_rule(S, P, O):-
|
Chris@0
|
711 rdf(Rule, rdf:type, swrl:'Impl'), % pick a rule
|
Chris@0
|
712 rdf(Rule, swrl:head, HeadList),
|
Chris@0
|
713 rdfs_member(IPA, HeadList), % can we use the rule?
|
Chris@0
|
714 rdf(IPA, rdf:type, swrl:'IndividualPropertyAtom'),
|
Chris@0
|
715 rdf(IPA, swrl:propertyPredicate, P), % IndividualPropertyAtom
|
Chris@0
|
716 rdf(Rule, swrl:body, BodyList), % yes
|
Chris@0
|
717 rdfs_list_to_prolog_list(BodyList, BL),
|
Chris@0
|
718 rdf_has(IPA, swrl:argument1, A1),
|
Chris@0
|
719 rdf_has(IPA, swrl:argument2, A2),
|
Chris@0
|
720 ( nonvar(S)
|
Chris@0
|
721 -> ( nonvar(O) -> SL = [A1/S, A2/O]
|
Chris@0
|
722 ; SL= [A1/S]
|
Chris@0
|
723 )
|
Chris@0
|
724 ; nonvar(O)
|
Chris@0
|
725 -> SL = [A2/O]
|
Chris@0
|
726 ; SL = []
|
Chris@0
|
727 ),
|
Chris@0
|
728 owl_evaluate_body(BL, SL, Subst),
|
Chris@0
|
729 ignore(member(A1/S, Subst)), % make sure S and O are instantiated
|
Chris@0
|
730 ignore(member(A2/O, Subst)). % could probably be done more elegantly
|
Chris@0
|
731
|
Chris@0
|
732 owl_evaluate_body([], Subst, Subst).
|
Chris@0
|
733 owl_evaluate_body([IPA| Rest], SL, Subst):-
|
Chris@0
|
734 rdf(IPA, rdf:type, swrl:'IndividualPropertyAtom'),
|
Chris@0
|
735 rdf(IPA, swrl:propertyPredicate, P), % IPA = IndividualPropertyAtom
|
Chris@0
|
736 rdf_has(IPA, swrl:argument1, A1), % maybe rdf instead of rdf_has? BJW
|
Chris@0
|
737 rdf_has(IPA, swrl:argument2, A2),
|
Chris@0
|
738 owl_has_swrl(A1, P, A2, SL, Subst1),
|
Chris@0
|
739 owl_evaluate_body(Rest, Subst1, Subst).
|
Chris@0
|
740 owl_evaluate_body([DF| Rest], SL, Subst):-
|
Chris@0
|
741 rdf(DF, rdf:type, swrl:'DifferentIndividualsAtom'),
|
Chris@0
|
742 rdf_has(DF, swrl:argument1, A1),
|
Chris@0
|
743 instantiated(A1, S, SL), % assume both arguments are instantiated
|
Chris@0
|
744 rdf_has(DF, swrl:argument2, A2),
|
Chris@0
|
745 instantiated(A2, O, SL), % this assumption is to be discussed
|
Chris@0
|
746 \+ owl_same_as(S,O),
|
Chris@0
|
747 owl_evaluate_body(Rest, SL, Subst).
|
Chris@0
|
748 owl_evaluate_body([SF| Rest], SL, Subst):-
|
Chris@0
|
749 rdf(SF, rdf:type, swrl:'SameIndividualAtom'),
|
Chris@0
|
750 rdf_has(SF, swrl:argument1, A1),
|
Chris@0
|
751 instantiated(A1, S, SL), % assume both arguments are instantiated
|
Chris@0
|
752 rdf_has(SF, swrl:argument2, A2),
|
Chris@0
|
753 instantiated(A2, O, SL), % this assumption is to be discussed
|
Chris@0
|
754 owl_same_as(S,O), %
|
Chris@0
|
755 owl_evaluate_body(Rest, SL, Subst).
|
Chris@0
|
756 owl_evaluate_body([CA| Rest], SL, Subst):-
|
Chris@0
|
757 rdf(CA, rdf:type, swrl:'ClassAtom'),
|
Chris@0
|
758 rdf_has(CA, swrl:argument1, A1),
|
Chris@0
|
759 ( instantiated(A1, S, SL) -> SL1=SL
|
Chris@0
|
760 ; SL1 = [A1/S|SL]),
|
Chris@0
|
761 rdf(CA, swrl:classPredicate, Class),
|
Chris@0
|
762 owl_individual_of(S, Class),
|
Chris@0
|
763 owl_evaluate_body(Rest, SL1, Subst).
|
Chris@0
|
764
|
Chris@0
|
765 owl_has_swrl(A1, P, A2, Subst, Subst):- % this can probably be done better BJW
|
Chris@0
|
766 instantiated(A1, S, Subst),
|
Chris@0
|
767 instantiated(A2, O, Subst),!, % dont backtrack here, proof complete
|
Chris@0
|
768 owl_has(S, P, O).
|
Chris@0
|
769 owl_has_swrl(A1, P, A2, Subst, [A1/S|Subst]):-
|
Chris@0
|
770 is_swrl_variable(A1),
|
Chris@0
|
771 instantiated(A2, O, Subst),
|
Chris@0
|
772 owl_has(S, P, O).
|
Chris@0
|
773 owl_has_swrl(A1, P, A2, Subst, [A2/O| Subst] ):-
|
Chris@0
|
774 instantiated(A1, S, Subst),
|
Chris@0
|
775 is_swrl_variable(A2),
|
Chris@0
|
776 owl_has(S, P, O).
|
Chris@0
|
777 owl_has_swrl(A1, P, A2, Subst, [A1/S, A2/O| Subst]):- % too general?
|
Chris@0
|
778 \+ instantiated(A1, S, Subst),
|
Chris@0
|
779 \+ instantiated(A2, O, Subst),
|
Chris@0
|
780 owl_has(S, P, O).
|
Chris@0
|
781
|
Chris@0
|
782 is_swrl_variable(V):-
|
Chris@0
|
783 rdf_has(V, rdf:type, swrl:'Variable').
|
Chris@0
|
784
|
Chris@0
|
785 instantiated(A, A, _Subst):-
|
Chris@0
|
786 \+ rdf_has(A, rdf:type, swrl:'Variable').
|
Chris@0
|
787 instantiated(A, S, Subst):-
|
Chris@0
|
788 rdf_has(A, rdf:type, swrl:'Variable'),
|
Chris@0
|
789 member(A/S, Subst).
|
Chris@0
|
790
|
Chris@0
|
791 %end additions BJW
|
Chris@0
|
792 %----------------------------------------------------------
|
Chris@0
|
793 owl_use_has_value(S, P, O) :-
|
Chris@0
|
794 nonvar(P), !,
|
Chris@0
|
795 rdf_has(Super, owl:onProperty, P),
|
Chris@0
|
796 rdf_has(Super, owl:hasValue, O),
|
Chris@0
|
797 owl_direct_subclass_of(Type, Super),
|
Chris@0
|
798 rdf_has(S, rdf:type, Type).
|
Chris@0
|
799 owl_use_has_value(S, P, O) :-
|
Chris@0
|
800 rdf_has(S, rdf:type, Type),
|
Chris@0
|
801 owl_direct_subclass_of(Type, Super),
|
Chris@0
|
802 rdfs_individual_of(Super, owl:'Restriction'),
|
Chris@0
|
803 rdf_has(Super, owl:onProperty, P),
|
Chris@0
|
804 rdf_has(Super, owl:hasValue, O).
|
Chris@0
|
805
|
Chris@0
|
806
|
Chris@0
|
807 /*******************************
|
Chris@0
|
808 * OWL CLASS HIERARCHY *
|
Chris@0
|
809 *******************************/
|
Chris@0
|
810
|
Chris@0
|
811 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
Chris@0
|
812 TBD: It is here that we must use a DL classifier!
|
Chris@0
|
813 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
Chris@0
|
814
|
Chris@0
|
815 %% owl_direct_subclass_of(-SubClass, +Class) is nondet.
|
Chris@0
|
816 %% owl_direct_subclass_of(+SubClass, -Class) is nondet.
|
Chris@0
|
817 %
|
Chris@0
|
818 % Returns both the RDFS subclasses and subclass relations implied by
|
Chris@0
|
819 % owl:intersectionOf and owl:unionOf descriptions.
|
Chris@0
|
820 %
|
Chris@0
|
821 % @tbd Should use full DL reasoning
|
Chris@0
|
822
|
Chris@0
|
823 owl_direct_subclass_of(Class, R) :-
|
Chris@0
|
824 rdf_has(Class, rdfs:subClassOf, R).
|
Chris@0
|
825 owl_direct_subclass_of(Class, R) :- % added BJW (hack for symetry)
|
Chris@0
|
826 rdf_has(R, owl:equivalentClass, Class).
|
Chris@0
|
827 owl_direct_subclass_of(Class, R) :-
|
Chris@0
|
828 ( nonvar(R)
|
Chris@0
|
829 -> ( rdf_has(R, owl:unionOf, Union),
|
Chris@0
|
830 rdfs_member(Class, Union)
|
Chris@0
|
831 ; rdf_has(List, rdf:first, R),
|
Chris@0
|
832 list_head(List, Head),
|
Chris@0
|
833 rdf_has(Class, owl:intersectionOf, Head)
|
Chris@0
|
834 )
|
Chris@0
|
835 ; nonvar(Class)
|
Chris@0
|
836 -> ( rdf_has(Class, owl:intersectionOf, List),
|
Chris@0
|
837 rdfs_member(R, List)
|
Chris@0
|
838 ; rdf_has(List, rdf:first, Class),
|
Chris@0
|
839 list_head(List, Head),
|
Chris@0
|
840 rdf_has(R, owl:unionOf, Head)
|
Chris@0
|
841 )
|
Chris@0
|
842 ; throw(error(instantiation_error, _))
|
Chris@0
|
843 ).
|
Chris@0
|
844
|
Chris@0
|
845 list_head(List, Head) :-
|
Chris@0
|
846 ( rdf_has(H, rdf:rest, List)
|
Chris@0
|
847 -> list_head(H, Head)
|
Chris@0
|
848 ; Head = List
|
Chris@0
|
849 ).
|
Chris@0
|
850
|
Chris@0
|
851
|
Chris@0
|
852 %% owl_subclass_of(+Sub, -Super) is nondet.
|
Chris@0
|
853 %% owl_subclass_of(-Sub, +Super) is nondet.
|
Chris@0
|
854 %
|
Chris@0
|
855 % Transitive version of owl_direct_subclass_of/2.
|
Chris@0
|
856
|
Chris@0
|
857 owl_subclass_of(Class, Super) :-
|
Chris@0
|
858 rdf_equal(rdfs:'Resource', Resource),
|
Chris@0
|
859 Super == Resource, !,
|
Chris@0
|
860 ( nonvar(Class)
|
Chris@0
|
861 -> true
|
Chris@0
|
862 ; rdfs_individual_of(Class, owl:'Class')
|
Chris@0
|
863 ).
|
Chris@0
|
864 owl_subclass_of(Class, Super) :-
|
Chris@0
|
865 nonvar(Class), nonvar(Super), !,
|
Chris@0
|
866 owl_test_subclass(Class, Super).
|
Chris@0
|
867 owl_subclass_of(Class, Super) :-
|
Chris@0
|
868 nonvar(Class), !,
|
Chris@0
|
869 owl_gen_supers(Class, [], Super).
|
Chris@0
|
870 owl_subclass_of(Class, Super) :-
|
Chris@0
|
871 nonvar(Super), !,
|
Chris@0
|
872 owl_gen_subs(Super, [], Class).
|
Chris@0
|
873 owl_subclass_of(_, _) :-
|
Chris@0
|
874 throw(error(instantiation_error, _)).
|
Chris@0
|
875
|
Chris@0
|
876 owl_gen_supers(Class, _, Class).
|
Chris@0
|
877 owl_gen_supers(Class, Visited, Super) :-
|
Chris@0
|
878 ( owl_direct_subclass_of(Class, Super0)
|
Chris@0
|
879 *-> true
|
Chris@0
|
880 ; rdf_equal(Super0, rdfs:'Resource')
|
Chris@0
|
881 ),
|
Chris@0
|
882 \+ memberchk(Super0, Visited),
|
Chris@0
|
883 owl_gen_supers(Super0, [Super0|Visited], Super).
|
Chris@0
|
884
|
Chris@0
|
885 owl_gen_subs(Class, _, Class).
|
Chris@0
|
886 owl_gen_subs(Class, Visited, Sub) :-
|
Chris@0
|
887 owl_direct_subclass_of(Sub0, Class),
|
Chris@0
|
888 \+ memberchk(Sub0, Class),
|
Chris@0
|
889 owl_gen_subs(Sub0, [Sub0|Visited], Sub).
|
Chris@0
|
890
|
Chris@0
|
891
|
Chris@0
|
892 %% owl_test_subclass(+Class, +Super) is semidet.
|
Chris@0
|
893 %
|
Chris@0
|
894 % Cached check for OWL subclass relation.
|
Chris@0
|
895
|
Chris@0
|
896 :- dynamic
|
Chris@0
|
897 subclass_cache/3, % +C1, +C2, -Boolean
|
Chris@0
|
898 subclass_generation/1. % RDF generation of last compute
|
Chris@0
|
899
|
Chris@0
|
900 owl_test_subclass(Class, Super) :-
|
Chris@0
|
901 ( rdf_generation(G),
|
Chris@0
|
902 subclass_generation(G2),
|
Chris@0
|
903 G \== G2
|
Chris@0
|
904 -> retractall(subclass_cache(_,_,_))
|
Chris@0
|
905 ; true
|
Chris@0
|
906 ),
|
Chris@0
|
907 ( subclass_cache(Class, Super, Bool)
|
Chris@0
|
908 -> Bool = true
|
Chris@0
|
909 ; ( owl_gen_supers(Class, [], Super)
|
Chris@0
|
910 -> assert(subclass_cache(Class, Super, true))
|
Chris@0
|
911 ; assert(subclass_cache(Class, Super, false)),
|
Chris@0
|
912 fail
|
Chris@0
|
913 )
|
Chris@0
|
914 ).
|
Chris@0
|
915
|
Chris@0
|
916
|
Chris@0
|
917 /*******************************
|
Chris@0
|
918 * SEARCH IN HIERARCHY *
|
Chris@0
|
919 *******************************/
|
Chris@0
|
920
|
Chris@0
|
921 %% owl_find(+String, +Domain, ?Properties, +Method, -Subject) is nondet.
|
Chris@0
|
922 %
|
Chris@0
|
923 % Search all classes below Domain for a literal property with
|
Chris@0
|
924 % that matches String. Method is one of
|
Chris@0
|
925 %
|
Chris@0
|
926 % * substring
|
Chris@0
|
927 % * word
|
Chris@0
|
928 % * prefix
|
Chris@0
|
929 % * exact
|
Chris@0
|
930 %
|
Chris@0
|
931 % domain is defined by owl_satisfies/2 from owl.pl
|
Chris@0
|
932 %
|
Chris@0
|
933 % Note that the rdfs:label field is handled by rdfs_label/2,
|
Chris@0
|
934 % making the URI-ref fragment name the last resort to determine
|
Chris@0
|
935 % the label.
|
Chris@0
|
936 %
|
Chris@0
|
937 % @tbd Use the RDF literal primitives
|
Chris@0
|
938
|
Chris@0
|
939 owl_find(String, Domain, Fields, Method, Subject) :-
|
Chris@0
|
940 var(Fields), !,
|
Chris@0
|
941 For =.. [Method,String],
|
Chris@0
|
942 rdf_has(Subject, Field, literal(For, _)),
|
Chris@0
|
943 owl_satisfies(Domain, Subject),
|
Chris@0
|
944 Fields = [Field]. % report where we found it.
|
Chris@0
|
945 owl_find(String, Domain, Fields, Method, Subject) :-
|
Chris@0
|
946 globalise_list(Fields, GlobalFields),
|
Chris@0
|
947 For =.. [Method,String],
|
Chris@0
|
948 member(Field, GlobalFields),
|
Chris@0
|
949 ( Field == resource
|
Chris@0
|
950 -> rdf_subject(Subject),
|
Chris@0
|
951 rdf_match_label(Method, String, Subject)
|
Chris@0
|
952 ; rdf_has(Subject, Field, literal(For, _))
|
Chris@0
|
953 ),
|
Chris@0
|
954 owl_satisfies(Domain, Subject).
|
Chris@0
|
955
|
Chris@0
|
956 globalise_list([], []) :- !.
|
Chris@0
|
957 globalise_list([H0|T0], [H|T]) :- !,
|
Chris@0
|
958 globalise_list(H0, H),
|
Chris@0
|
959 globalise_list(T0, T).
|
Chris@0
|
960 globalise_list(X, G) :-
|
Chris@0
|
961 rdf_global_id(X, G).
|