annotate jamendo/sparql-archived/SeRQL/lib/semweb/owl.pl @ 27:d95e683fbd35 tip

Enable CORS on urispace redirects as well
author Chris Cannam
date Tue, 20 Feb 2018 14:52:02 +0000
parents df9685986338
children
rev   line source
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).