/* $Id$ Part of SWI-Prolog Author: Jan Wielemaker E-mail: jan@swi.psy.uva.nl WWW: http://www.swi-prolog.org Copyright (C): 1985-2002, University of Amsterdam This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA As a special exception, if you link this library with other files, compiled with a Free Software compiler, to produce an executable, this library does not by itself cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. */ :- module(owl, [ owl_restriction_on/2, % ?Class, ?Restriction owl_merged_restriction/3, % ?Class, ?Property, ?Restriction owl_restriction/2, % +Resource, -Restriction owl_description/2, % +Resource, -Description owl_cardinality_on_subject/3, % +Subject, +Predicate, -Card owl_cardinality_on_class/3, % idem BJW owl_satisfies/2, % +Spec, +Resource owl_individual_of/2, % ?Resource, +Description owl_direct_subclass_of/2, % ?Resource, ?Class owl_subclass_of/2, % ?Class, ?Super owl_has/3, % ?Subject, ?Predicate, ?Object owl_has_direct/3, % ?Subject, ?Predicate, ?Object owl_same_as/2, % ?X, ?Y owl_find/5 % +For, +Dom, ?Props, +Method, -Subj ]). :- use_module(library(lists)). :- use_module(library('semweb/rdf_db')). :- use_module(library('semweb/rdfs')). /******************************* * EXPANSION * *******************************/ % user:goal_expansion(+NSGoal, -Goal) % % This predicate allows for writing down rdf queries in a friendly % name-space fashion. :- multifile user:goal_expansion/2. :- rdf_register_ns(swrl, 'http://www.w3.org/2003/11/swrl#', [ keep(true) ]). :- rdf_meta owl_restriction_on(r, t), owl_merged_restriction(r, r, t), owl_restriction(r, -), owl_description(r, -), owl_cardinality_on_subject(r, r, -), owl_cardinality_on_class(r, r, -), owl_satisfies(r, t), owl_individual_of(r, t), owl_direct_subclass_of(r, r), owl_subclass_of(r, r), owl_has(r, r, o), owl_has_direct(r, r, o), owl_same_as(r, r), owl_find(+, t, t, +, -). /******************************* * FACTS * *******************************/ % owl_individual(?IndividualID, ?Type) % owl_property(?IndividualID, ?PropertyID, ?PropertyValue) % owl_same_individual(?IndividualID1, ?IndividualID2) % owl_different_individual(?IndividualID1, ?IndividualID2) /******************************* * AXIOMS * *******************************/ % owl_class(?ClassID, ?Super) % owl_class_modality(?ClassID, ?Modality) % owl_same_class(?ClassID1, ?ClassID2) /******************************* * RESTRICTIONS * *******************************/ %% owl_restriction_on(+ClassID, %% -Restriction:restriction(?PropertyID, ?Restriction)) is nondet. % % Enumerate the restrictions that apply to PropertyID for Class. % Restriction is one of % % * all_values_from(Class) % * some_values_from(Class) % * has_value(Value) % * cardinality(Min, Max) :- rdf_meta rdf_phas(r,r,o). owl_restriction_on(Class, Restriction) :- owl_subclass_of(Class, Super), ( rdfs_individual_of(Super, owl:'Restriction'), owl_restriction(Super, Restriction) ; Restriction = restriction(Property, all_values_from(Range)), rdf_phas(Property, rdfs:domain, Super), ( rdf_phas(Property, rdfs:range, Range) *-> true ; rdf_equal(Range, rdfs:'Resource') ) ). rdf_phas(Property, P, O) :- rdfs_subproperty_of(Property, Super), rdf_has(Super, P, O2), !, O = O2. %% owl_restriction(+Resource, -Prolog) is det. % % Translate Resource, an individual of owl:restriction into a Prolog term. % % @see owl_restriction_on/2 for the Prolog representation. owl_restriction(RestrictionID, restriction(Property, Restriction)) :- rdf_has(RestrictionID, owl:onProperty, Property), restriction_facet(RestrictionID, Restriction). restriction_facet(RestrictionID, R) :- ( rdf_has(RestrictionID, owl:allValuesFrom, Class) -> R = all_values_from(Class) ; rdf_has(RestrictionID, owl:someValuesFrom, Class) -> R = some_values_from(Class) ). restriction_facet(RestrictionID, has_value(Value)) :- rdf_has(RestrictionID, owl:hasValue, Value). restriction_facet(R, cardinality(Min, Max)) :- ( rdf_has(R, owl:cardinality, literal(Atom)) -> non_negative_integer(Atom, Min, R, owl:cardinality), Max = Min ; rdf_has(R, owl:minCardinality, literal(MinAtom)) -> non_negative_integer(MinAtom, Min, R, owl:minCardinality), ( rdf_has(R, owl:maxCardinality, literal(MaxAtom)) -> non_negative_integer(MaxAtom, Max, R, owl:maxCardinality) ; Max = inf ) ; rdf_has(R, owl:maxCardinality, literal(MaxAtom)) -> non_negative_integer(MaxAtom, Max, R, owl:maxCardinality), Min = 0 ). % non_negative_integer(+Atom, -Integer, +Subject, +Predicate) % % Deduce integer value from rdf(Subject, Predicate, literal(Atom)) % and if a conversion error occurs warn compatible to the rdfs_validate % library. % % TBD: If argument is typed we should check the type is compatible % to xsd:nonNegativeInteger. non_negative_integer(type(_Type, Atom), Int, S, P) :- nonvar(Atom), !, non_negative_integer(Atom, Int, S, P). non_negative_integer(Atom, Int, _, _) :- catch(atom_number(Atom, Int), _, fail), !, integer(Int), Int >= 0. non_negative_integer(Atom, _, S, P) :- rdf_equal(xsd:nonNegativeInteger, Range), rdf_global_id(P, Pred), print_message(error, rdf_illegal_object(S,Pred,literal(Atom),Range)), fail. %% owl_merged_restriction(+Class, ?Property, ?Restriction) is nondet. % % As owl_restriction_on/2, but combines multiple restrictions into % the least strict restriction satisfying the declared % restrictions. owl_merged_restriction(Class, Property, Restriction) :- setof(Decl, owl_restriction_on(Class, restriction(Property, Decl)), Decls), join_decls(Decls, Minimal), member(Restriction, Minimal). % input is sorted, thus the following holds: % % cardinality < has_value < values_from join_decls([], []). join_decls([cardinality(Min1, Max1), cardinality(Min2, Max2)|T], Set) :- !, Min is max(Min1, Min2), max_cardinality(Max1, Max2, Max), join_decls([cardinality(Min, Max)|T], Set). join_decls([has_value(Value)|T], [has_value(Value)]) :- !, satisfies_restrictions(T, Value). join_decls([values_from(AS1, C1), values_from(AS2, C2)|T], Set) :- merge_values_from(AS1, C1, AS2, C2, AS, C), !, join_decls([values_from(AS, C)|T], Set). join_decls([H|T0], [H|T]) :- join_decls(T0, T). max_cardinality(infinite, Min, Min) :- !. max_cardinality(Min, infinite, Min) :- !. max_cardinality(Min1, Min2, Min) :- Min is min(Min1, Min2). % satisfies_restrictions(+Restrictions, +Value) % % See whether Value satisfies all restrictions, so we can indeed % use it as a value. satisfies_restrictions([], _). satisfies_restrictions([H|T], Value) :- satisfies_restriction(H, Value), satisfies_restrictions(T, Value). satisfies_restriction(has_value(Value), Value). satisfies_restriction(values_from(some, _), _). satisfies_restriction(values_from(all, Class), Value) :- rdfs_individual_of(Value, Class). % merge_values_from(+AllSome2, +C1, +AllSome2, +C2, -AllSome, -C) % % Merge multiple allValuesFrom and someValuesFrom restrictions. % This needs some thought, but as we don't need it for the MIA % tool right now we'll leave it. merge_values_from(all, C1, all, C2, all, C) :- rdfs_subclass_of(C, C1), rdfs_subclass_of(C, C2). /******************************* * CARDINALITY * *******************************/ %% owl_cardinality_on_subject(+Subject, +Pred, -Card:cardinality(Min, Max)) is semidet. % % Deduces the minimum and maximum cardinality for a property of a % resource. This predicate may fail if no information is available. % % NOTE: used to use rdf_subclass_of. Will owl_direct_subclass_of lead to % cycles? owl_cardinality_on_subject(Subject, Predicate, Cardinality) :- findall(C, cardinality_on_subject(Subject, Predicate, C), L), join_decls(L, [Cardinality]). cardinality_on_subject(Subject, Predicate, cardinality(Min, Max)) :- rdf_has(Subject, rdf:type, Class), owl_direct_subclass_of(Class, RestrictionID), rdfs_individual_of(RestrictionID, owl:'Restriction'), rdf_has(RestrictionID, owl:onProperty, Predicate), restriction_facet(RestrictionID, cardinality(Min, Max)). %% owl_cardinality_on_class(+Class, ?Predicate, -Card:cardinality(Min, Max)) is semidet. owl_cardinality_on_class(Class, Predicate, Cardinality) :- findall(C, cardinality_on_class(Class, Predicate, C), L), join_decls(L, [Cardinality]). cardinality_on_class(Class, Predicate, cardinality(Min, Max)) :- owl_direct_subclass_of(Class, RestrictionID), rdfs_individual_of(RestrictionID, owl:'Restriction'), rdf_has(RestrictionID, owl:onProperty, Predicate), restriction_facet(RestrictionID, cardinality(Min, Max)). %% owl_satisfies_restriction(?Resource, +Restriction) % % True if Restriction satisfies the restriction imposed by Restriction. % The current implementation makes the following assumptions: % % * Only one of owl:hasValue, owl:allValuesFrom or owl:someValuesFrom % is present. owl_satisfies_restriction(Resource, Restriction) :- rdf_has(Restriction, owl:onProperty, Property), ( rdf_has(Restriction, owl:hasValue, Value) -> owl_has(Resource, Property, Value) ; rdf_has(Restriction, owl:allValuesFrom, Class) -> setof(V, owl_has(Resource, Property, V), Vs), all_individual_of(Vs, Class) ; rdf_has(Restriction, owl:someValuesFrom, Class) -> owl_has(Resource, Property, Value), owl_individual_of(Value, Class) ; rdf_subject(Resource) ), owl_satisfies_cardinality(Resource, Restriction). all_individual_of([], _). all_individual_of([H|T], Class) :- owl_individual_of(H, Class), !, all_individual_of(T, Class). % owl_satisfies_cardinality(?Resource[, +Property], +Restriction) % % True if Resource satisfies the cardinality restrictions on % Property imposed by Restriction. owl_satisfies_cardinality(Resource, Restriction) :- rdf_has(Restriction, owl:onProperty, Property), owl_satisfies_cardinality(Resource, Property, Restriction). owl_satisfies_cardinality(Resource, Property, Restriction) :- rdf_has(Restriction, owl:cardinality, literal(Atom)), !, non_negative_int(Atom, Card), findall(V, rdf_has(Resource, Property, V), Vs0), sort(Vs0, Vs), % remove duplicates length(Vs, Card). owl_satisfies_cardinality(Resource, Property, Restriction) :- rdf_has(Restriction, owl:minCardinality, literal(MinAtom)), non_negative_int(MinAtom, Min), !, findall(V, owl_has(Resource, Property, V), Vs0), sort(Vs0, Vs), % remove duplicates length(Vs, Count), Count >= Min, ( rdf_has(Restriction, owl:maxCardinality, literal(MaxAtom)), atom_number(MaxAtom, Max) -> Count =< Max ; true ). owl_satisfies_cardinality(Resource, Property, Restriction) :- rdf_has(Restriction, owl:maxCardinality, literal(MaxAtom)), non_negative_int(MaxAtom, Max), !, findall(V, owl_has(Resource, Property, V), Vs0), sort(Vs0, Vs), % remove duplicates length(Vs, Count), Count =< Max. owl_satisfies_cardinality(Resource, _, _) :- rdf_subject(Resource). non_negative_int(type(Type, Atom), Number) :- rdf_equal(xsd:nonNegativeInteger, Type), catch(atom_number(Atom, Number), _, fail). non_negative_int(Atom, Number) :- atom(Atom), catch(atom_number(Atom, Number), _, fail). /******************************* * DESCRIPTION * *******************************/ %% owl_description(+DescriptionID, -Prolog) is det. % % Convert an owl description into a Prolog representation. This % representation is: % % * class(Class) % * restriction(Property, Restriction) % * union_of(ListOfDescriptions) % * intersection_of(ListOfDescriptions) % * complement_of(Description) % * one_of(Individuals) % * thing % * nothing % % where Restriction is defined by owl_restriction_on/2. % For example, the union-of can be the result of % % == % % % % % % % == owl_description(ID, Restriction) :- ( rdf_equal(owl:'Thing', ID) -> Restriction = thing ; rdf_equal(owl:'Nothing', ID) -> Restriction = nothing ; rdf_has(ID, rdf:type, owl:'Restriction') -> owl_restriction(ID, Restriction) ; rdf_has(ID, rdf:type, owl:'Class') -> ( ( rdf_has(ID, owl:unionOf, Set) -> Restriction = union_of(SubDescriptions) ; rdf_has(ID, owl:intersectionOf, Set) -> Restriction = intersection_of(SubDescriptions) ) -> rdfs_list_to_prolog_list(Set, Members), maplist(owl_description, Members, SubDescriptions) ; rdf_has(ID, owl:complementOf, Arg) -> Restriction = complement_of(SubDescription), owl_description(Arg, SubDescription) ; rdf_has(ID, owl:oneOf, Arg) -> Restriction = one_of(Individuals), rdfs_list_to_prolog_list(Arg, Individuals) ; Restriction = class(ID) ) ). /******************************* * OWL_SATISFIES * *******************************/ %% owl_satisfies(+Specification, ?Resource) is nondet. % % Test whether Resource satisfies Specification. All resources are % considered to belong to rdfs:Resource, which is not really % enforced. Domain is one of % % | rdfs:Resource | Allow for any resource | % | class(Class) | Allow for a subclass of Class| % | union_of(Domains) | | % | intersection_of(Domains) | | % | complement_of(Domain) | | % | one_of(Resources) | One of these values | % | all_values_from(Class) | Individual of this class | % | some_values_from(Class) | Not used | % | has_value(Value) | Must have this value | % % Resource can be a term individual_of(Class), in which case this % predicate succeeds if any individual of Class is accepted by % Domain. % Short-cut owl_satisfies(Domain, Resource) :- rdf_equal(rdfs:'Resource', Domain), !, ( atom(Resource) -> true ; var(Resource) -> rdf_subject(Resource) ; Resource = individual_of(_) ). % Descriptions owl_satisfies(class(Domain), Resource) :- !, ( rdf_equal(Domain, rdfs:'Resource') -> true ; Resource = individual_of(Class), atom(Class) -> fail ; owl_subclass_of(Resource, Domain) ). owl_satisfies(union_of(Domains), Resource) :- !, member(Domain, Domains), owl_satisfies(Domain, Resource). owl_satisfies(intersection_of(Domains), Resource) :- !, in_all_domains(Domains, Resource). owl_satisfies(complement_of(Domain), Resource) :- !, ( atom(Resource) -> true ; var(Resource) -> rdf_subject(Resource) ; fail % individual_of(Class) ), \+ owl_satisfies(Domain, Resource). owl_satisfies(one_of(List), Resource) :- !, member(Resource, List). % Restrictions owl_satisfies(all_values_from(Domain), Resource) :- !, ( Resource = individual_of(Class), atom(Class) -> owl_subclass_of(Class, Domain) ; owl_individual_of(Resource, Domain) ). owl_satisfies(some_values_from(_Domain), _Resource) :- !. owl_satisfies(has_value(Value), Resource) :- rdf_equal(Value, Resource). % TBD: equality in_all_domains([], _). in_all_domains([H|T], Resource) :- owl_satisfies(H, Resource), in_all_domains(T, Resource). /******************************* * INDIVIDUAL OF * *******************************/ %% owl_individual_of(?Resource, +Description) is nondet. % % Test or generate the resources that satisfy Description % according the OWL-Description entailment rules. owl_individual_of(Resource, Thing) :- rdf_equal(Thing, owl:'Thing'), !, ( atom(Resource) -> true ; rdf_subject(Resource) ). owl_individual_of(_Resource, Nothing) :- rdf_equal(Nothing, owl:'Nothing'), !, fail. owl_individual_of(Resource, Description) :- % RDFS rdfs_individual_of(Resource, Description). /*owl_individual_of(Resource, Class) :- nonvar(Resource), setof(C, rdf_has(Resource, rdf:type, C), Cs), !, member(C, Cs), owl_subclass_of(C, Class). */ owl_individual_of(Resource, Class) :- nonvar(Resource), rdf_has(Resource, rdf:type, C), owl_subclass_of(C, Class). owl_individual_of(Resource, Class) :- rdfs_individual_of(Class, owl:'Class'), ( rdf_has(Class, owl:equivalentClass, EQ) -> owl_individual_of(Resource, EQ) ; rdfs_individual_of(Class, owl:'Restriction') -> owl_satisfies_restriction(Resource, Class) ; owl_individual_of_description(Resource, Class, HasDescription), findall(SC, rdf_has(Class, rdfs:subClassOf, SC), SuperClasses), ( HasDescription == false -> SuperClasses \== [] ; true ), owl_individual_of_all(SuperClasses, Resource) ). owl_individual_of(Resource, Description) :- % RDFS owl_individual_from_range(Resource, Description). %% owl_individual_of_description(?Resource, +Description, -HasDescription) is nondet. % % @tbd Can a description have multiple of these facets? owl_individual_of_description(Resource, Description, true) :- rdf_has(Description, owl:unionOf, Set), !, rdfs_member(Sub, Set), owl_individual_of(Resource, Sub). owl_individual_of_description(Resource, Description, true) :- rdf_has(Description, owl:intersectionOf, Set), !, intersection_of(Set, Resource). owl_individual_of_description(Resource, Description, true) :- rdf_has(Description, owl:complementOf, Arg), !, rdf_subject(Resource), \+ owl_individual_of(Resource, Arg). owl_individual_of_description(Resource, Description, true) :- rdf_has(Description, owl:oneOf, Arg), !, rdfs_member(Resource, Arg). owl_individual_of_description(_, _, false). owl_individual_of_all([], _). owl_individual_of_all([C|T], Resource) :- owl_individual_of(Resource, C), owl_individual_of_all(T, Resource). owl_individual_from_range(Resource, Class) :- nonvar(Resource), !, rdf_has(_, P, Resource), rdf_has(P, rdfs:range, Class), !. owl_individual_from_range(Resource, Class) :- rdf_has(P, rdfs:range, Class), rdf_has(_, P, Resource). % owl_has? intersection_of(List, Resource) :- rdf_has(List, rdf:first, First), owl_individual_of(Resource, First), ( rdf_has(List, rdf:rest, Rest) -> intersection_of(Rest, Resource) ; true ). intersection_of(Nil, _) :- rdf_equal(rdf:nil, Nil). /******************************* * OWL PROPERTIES * *******************************/ %% owl_has(?Subject, ?Predicate, ?Object) % % True if this relation is specified or can be deduced using OWL % inference rules. It adds transitivity to owl_has_direct/3. owl_has(S, P, O) :- ( var(P) -> rdfs_individual_of(P, rdf:'Property') ; true ), rdf_reachable(SP, rdfs:subPropertyOf, P), owl_has_transitive(S, SP, O). %% owl_has_transitive(?Subject, ?Predicate, ?Object) % % If Predicate is transitive, do a transitive closure on the % relation. owl_has_transitive(S, P, O) :- rdfs_individual_of(P, owl:'TransitiveProperty'), !, owl_has_transitive(S, P, O, [P]). owl_has_transitive(S, P, O) :- owl_has_equivalent(S, P, O). owl_has_transitive(S, P, O, Visited) :- owl_has_equivalent(S, P, O1), O1 \= literal(_), \+ memberchk(O1, Visited), ( O = O1 ; owl_has_transitive(O1, P, O, [O1|Visited]) ). % owl_has_equivalent(?Subject, ?Predicate, ?Object) % % Adds owl:sameAs on Subject and Object to owl_has_direct/3 owl_has_equivalent(S, P, O) :- nonvar(S), !, owl_same_as(S, S1), owl_has_direct(S1, P, O0), owl_same_as(O0, O). owl_has_equivalent(S, P, O) :- nonvar(O), !, owl_same_as(O1, O), owl_has_direct(S0, P, O1), owl_same_as(S0, S). owl_has_equivalent(S, P, O) :- owl_has_direct(S0, P, O0), owl_same_as(S0, S), owl_same_as(O0, O). %% owl_same_as(?X, ?Y) is nondet. % % True if X and Y are identical or connected by the owl:sameAs % relation. Considers owl:sameAs transitive and symetric. owl_same_as(literal(X), literal(X)) :- !. owl_same_as(X, Y) :- nonvar(X), !, owl_same_as(X, Y, [X]). owl_same_as(X, Y) :- owl_same_as(Y, X, [X]). owl_same_as(X, X, _). owl_same_as(X, Y, Visited) :- ( rdf_has(X, owl:sameAs, X1) ; rdf_has(X1, owl:sameAs, X) ), X1 \= literal(_), \+ memberchk(X1, Visited), owl_same_as(X1, Y, [X1|Visited]). %% owl_has_direct(?Subject, ?Predicate, ?Object) % % Deals with `One-step' OWL inferencing: inverse properties, % symmetric properties and being subtype of a restriction with an % owl:hasValue statement on this property. % % @bug owl_has_direct/3 also uses SWRL rules. This should be % moved elsewhere. owl_has_direct(S, P, O) :- rdf(S, P, O). owl_has_direct(S, P, O) :- ( rdf_has(P, owl:inverseOf, P2) -> true ; rdf_has(P2, owl:inverseOf, P) ), rdf_has(O, P2, S). % TBD: must call owl_has_direct/3 owl_has_direct(S, P, O) :- rdfs_individual_of(P, owl:'SymmetricProperty'), rdf(O, P, S). owl_has_direct(S, P, O) :- owl_use_has_value(S, P, O). %---------------------------------------------------------- % added by BJW for use of OWL with SWRL rules, highly experimental % see http://www.daml.org/rules/proposal/rules-all.html for SWRL. % It implements simple Prolog-like inferencing were order of antecedents % may matter and some assumptions about instantiation of variables are % made (see comments below). % Currently is doesnot cater for arbitrary OWL descriptions mixed with % SWRL. owl_has_direct(S, P, O) :- owl_use_rule(S, P, O). owl_use_rule(S, P, O):- rdf(Rule, rdf:type, swrl:'Impl'), % pick a rule rdf(Rule, swrl:head, HeadList), rdfs_member(IPA, HeadList), % can we use the rule? rdf(IPA, rdf:type, swrl:'IndividualPropertyAtom'), rdf(IPA, swrl:propertyPredicate, P), % IndividualPropertyAtom rdf(Rule, swrl:body, BodyList), % yes rdfs_list_to_prolog_list(BodyList, BL), rdf_has(IPA, swrl:argument1, A1), rdf_has(IPA, swrl:argument2, A2), ( nonvar(S) -> ( nonvar(O) -> SL = [A1/S, A2/O] ; SL= [A1/S] ) ; nonvar(O) -> SL = [A2/O] ; SL = [] ), owl_evaluate_body(BL, SL, Subst), ignore(member(A1/S, Subst)), % make sure S and O are instantiated ignore(member(A2/O, Subst)). % could probably be done more elegantly owl_evaluate_body([], Subst, Subst). owl_evaluate_body([IPA| Rest], SL, Subst):- rdf(IPA, rdf:type, swrl:'IndividualPropertyAtom'), rdf(IPA, swrl:propertyPredicate, P), % IPA = IndividualPropertyAtom rdf_has(IPA, swrl:argument1, A1), % maybe rdf instead of rdf_has? BJW rdf_has(IPA, swrl:argument2, A2), owl_has_swrl(A1, P, A2, SL, Subst1), owl_evaluate_body(Rest, Subst1, Subst). owl_evaluate_body([DF| Rest], SL, Subst):- rdf(DF, rdf:type, swrl:'DifferentIndividualsAtom'), rdf_has(DF, swrl:argument1, A1), instantiated(A1, S, SL), % assume both arguments are instantiated rdf_has(DF, swrl:argument2, A2), instantiated(A2, O, SL), % this assumption is to be discussed \+ owl_same_as(S,O), owl_evaluate_body(Rest, SL, Subst). owl_evaluate_body([SF| Rest], SL, Subst):- rdf(SF, rdf:type, swrl:'SameIndividualAtom'), rdf_has(SF, swrl:argument1, A1), instantiated(A1, S, SL), % assume both arguments are instantiated rdf_has(SF, swrl:argument2, A2), instantiated(A2, O, SL), % this assumption is to be discussed owl_same_as(S,O), % owl_evaluate_body(Rest, SL, Subst). owl_evaluate_body([CA| Rest], SL, Subst):- rdf(CA, rdf:type, swrl:'ClassAtom'), rdf_has(CA, swrl:argument1, A1), ( instantiated(A1, S, SL) -> SL1=SL ; SL1 = [A1/S|SL]), rdf(CA, swrl:classPredicate, Class), owl_individual_of(S, Class), owl_evaluate_body(Rest, SL1, Subst). owl_has_swrl(A1, P, A2, Subst, Subst):- % this can probably be done better BJW instantiated(A1, S, Subst), instantiated(A2, O, Subst),!, % dont backtrack here, proof complete owl_has(S, P, O). owl_has_swrl(A1, P, A2, Subst, [A1/S|Subst]):- is_swrl_variable(A1), instantiated(A2, O, Subst), owl_has(S, P, O). owl_has_swrl(A1, P, A2, Subst, [A2/O| Subst] ):- instantiated(A1, S, Subst), is_swrl_variable(A2), owl_has(S, P, O). owl_has_swrl(A1, P, A2, Subst, [A1/S, A2/O| Subst]):- % too general? \+ instantiated(A1, S, Subst), \+ instantiated(A2, O, Subst), owl_has(S, P, O). is_swrl_variable(V):- rdf_has(V, rdf:type, swrl:'Variable'). instantiated(A, A, _Subst):- \+ rdf_has(A, rdf:type, swrl:'Variable'). instantiated(A, S, Subst):- rdf_has(A, rdf:type, swrl:'Variable'), member(A/S, Subst). %end additions BJW %---------------------------------------------------------- owl_use_has_value(S, P, O) :- nonvar(P), !, rdf_has(Super, owl:onProperty, P), rdf_has(Super, owl:hasValue, O), owl_direct_subclass_of(Type, Super), rdf_has(S, rdf:type, Type). owl_use_has_value(S, P, O) :- rdf_has(S, rdf:type, Type), owl_direct_subclass_of(Type, Super), rdfs_individual_of(Super, owl:'Restriction'), rdf_has(Super, owl:onProperty, P), rdf_has(Super, owl:hasValue, O). /******************************* * OWL CLASS HIERARCHY * *******************************/ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TBD: It is here that we must use a DL classifier! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ %% owl_direct_subclass_of(-SubClass, +Class) is nondet. %% owl_direct_subclass_of(+SubClass, -Class) is nondet. % % Returns both the RDFS subclasses and subclass relations implied by % owl:intersectionOf and owl:unionOf descriptions. % % @tbd Should use full DL reasoning owl_direct_subclass_of(Class, R) :- rdf_has(Class, rdfs:subClassOf, R). owl_direct_subclass_of(Class, R) :- % added BJW (hack for symetry) rdf_has(R, owl:equivalentClass, Class). owl_direct_subclass_of(Class, R) :- ( nonvar(R) -> ( rdf_has(R, owl:unionOf, Union), rdfs_member(Class, Union) ; rdf_has(List, rdf:first, R), list_head(List, Head), rdf_has(Class, owl:intersectionOf, Head) ) ; nonvar(Class) -> ( rdf_has(Class, owl:intersectionOf, List), rdfs_member(R, List) ; rdf_has(List, rdf:first, Class), list_head(List, Head), rdf_has(R, owl:unionOf, Head) ) ; throw(error(instantiation_error, _)) ). list_head(List, Head) :- ( rdf_has(H, rdf:rest, List) -> list_head(H, Head) ; Head = List ). %% owl_subclass_of(+Sub, -Super) is nondet. %% owl_subclass_of(-Sub, +Super) is nondet. % % Transitive version of owl_direct_subclass_of/2. owl_subclass_of(Class, Super) :- rdf_equal(rdfs:'Resource', Resource), Super == Resource, !, ( nonvar(Class) -> true ; rdfs_individual_of(Class, owl:'Class') ). owl_subclass_of(Class, Super) :- nonvar(Class), nonvar(Super), !, owl_test_subclass(Class, Super). owl_subclass_of(Class, Super) :- nonvar(Class), !, owl_gen_supers(Class, [], Super). owl_subclass_of(Class, Super) :- nonvar(Super), !, owl_gen_subs(Super, [], Class). owl_subclass_of(_, _) :- throw(error(instantiation_error, _)). owl_gen_supers(Class, _, Class). owl_gen_supers(Class, Visited, Super) :- ( owl_direct_subclass_of(Class, Super0) *-> true ; rdf_equal(Super0, rdfs:'Resource') ), \+ memberchk(Super0, Visited), owl_gen_supers(Super0, [Super0|Visited], Super). owl_gen_subs(Class, _, Class). owl_gen_subs(Class, Visited, Sub) :- owl_direct_subclass_of(Sub0, Class), \+ memberchk(Sub0, Class), owl_gen_subs(Sub0, [Sub0|Visited], Sub). %% owl_test_subclass(+Class, +Super) is semidet. % % Cached check for OWL subclass relation. :- dynamic subclass_cache/3, % +C1, +C2, -Boolean subclass_generation/1. % RDF generation of last compute owl_test_subclass(Class, Super) :- ( rdf_generation(G), subclass_generation(G2), G \== G2 -> retractall(subclass_cache(_,_,_)) ; true ), ( subclass_cache(Class, Super, Bool) -> Bool = true ; ( owl_gen_supers(Class, [], Super) -> assert(subclass_cache(Class, Super, true)) ; assert(subclass_cache(Class, Super, false)), fail ) ). /******************************* * SEARCH IN HIERARCHY * *******************************/ %% owl_find(+String, +Domain, ?Properties, +Method, -Subject) is nondet. % % Search all classes below Domain for a literal property with % that matches String. Method is one of % % * substring % * word % * prefix % * exact % % domain is defined by owl_satisfies/2 from owl.pl % % Note that the rdfs:label field is handled by rdfs_label/2, % making the URI-ref fragment name the last resort to determine % the label. % % @tbd Use the RDF literal primitives owl_find(String, Domain, Fields, Method, Subject) :- var(Fields), !, For =.. [Method,String], rdf_has(Subject, Field, literal(For, _)), owl_satisfies(Domain, Subject), Fields = [Field]. % report where we found it. owl_find(String, Domain, Fields, Method, Subject) :- globalise_list(Fields, GlobalFields), For =.. [Method,String], member(Field, GlobalFields), ( Field == resource -> rdf_subject(Subject), rdf_match_label(Method, String, Subject) ; rdf_has(Subject, Field, literal(For, _)) ), owl_satisfies(Domain, Subject). globalise_list([], []) :- !. globalise_list([H0|T0], [H|T]) :- !, globalise_list(H0, H), globalise_list(T0, T). globalise_list(X, G) :- rdf_global_id(X, G).