diff jamendo/sparql-archived/SeRQL/lib/semweb/owl.pl @ 0:df9685986338

Import scripts for Jamendo and Magnatune, with new static-rdf-server.pl working towards serving the static dumps
author Chris Cannam
date Thu, 19 Oct 2017 15:27:05 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jamendo/sparql-archived/SeRQL/lib/semweb/owl.pl	Thu Oct 19 15:27:05 2017 +0100
@@ -0,0 +1,961 @@
+/*  $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
+%	
+%	==
+%	<rdfs:Class rdf:ID="myclass">
+%	  <owl:unionOf parseType=Collection>
+%	    <rdf:Description rdf:about="gnu"/>
+%	    <rdf:Description rdf:about="gnat"/>
+%	  </owl:unionOf>
+%	</rdfs:Class>
+%	==
+
+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 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).