Daniel@0: /* Part of DML (Digital Music Laboratory) Daniel@0: Copyright 2014-2015 Samer Abdallah, University of London Daniel@0: Daniel@0: This program is free software; you can redistribute it and/or Daniel@0: modify it under the terms of the GNU General Public License Daniel@0: as published by the Free Software Foundation; either version 2 Daniel@0: of the License, or (at your option) any later version. Daniel@0: Daniel@0: This program is distributed in the hope that it will be useful, Daniel@0: but WITHOUT ANY WARRANTY; without even the implied warranty of Daniel@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Daniel@0: GNU General Public License for more details. Daniel@0: Daniel@0: You should have received a copy of the GNU General Public Daniel@0: License along with this library; if not, write to the Free Software Daniel@0: Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Daniel@0: */ Daniel@0: Daniel@0: :- module(p2r_entailment,[ op(1200,xfx,<==), op(1200,xfx,==>), assert_all/1 ]). Daniel@0: Daniel@0: /** Prolog-to-RDF mapping entailment module Daniel@0: Daniel@0: This module provides a mechanism for exposing information in the Prolog Daniel@0: database as RDF triples. The basis of this is a syntax for multiheaded Daniel@0: Horn clauses with RDF triples in the head and Prolog goals in the body. Daniel@0: The rules can be written in either direction: as =|Heads <== Body|= Daniel@0: or =|Body ==> Heads|=, whichever is most convenient. Daniel@0: Daniel@0: There is also a grammar for writing URI patterns. These are used to Daniel@0: to build URIs from Prolog values and to parse URIs to extract Prolog Daniel@0: values. The cost of this URI processing can be completely avoided by Daniel@0: writing only variables in the head rdf/3 terms. Daniel@0: */ Daniel@0: Daniel@0: :- use_module(library(uripattern_detdcg)). Daniel@0: :- use_module(library(semweb/rdf_db),[]). Daniel@0: Daniel@0: :- rdf_meta rdf(r,r,o). Daniel@0: :- rdf_meta rdf(r,r,o,-). Daniel@0: Daniel@0: :- multifile cliopatria:entailment/2. Daniel@0: :- multifile rdf/4. Daniel@0: :- op(1200,xfx,<==). Daniel@0: :- op(1200,xfx,==>). Daniel@0: Daniel@0: Daniel@0: cliopatria:entailment(p2r, p2r_entailment). Daniel@0: Daniel@0: rdf(S,P,O) :- rdf(S,P,O,_). Daniel@0: Daniel@0: user:term_expansion( (Body ==> Heads), Clauses) :- Daniel@0: user:term_expansion( (Heads <== Body), Clauses). Daniel@0: user:term_expansion( (Heads <== Body), Clauses) :- Daniel@0: debug(p2r,'Expanding: ~w',[Heads<==Body]), Daniel@0: prolog_load_context(module,Mod), Daniel@0: expand_clauses(Heads,Mod:Body,Clauses,[]). Daniel@0: Daniel@0: Daniel@0: expand_clauses((H1,H2),Body) --> !, Daniel@0: expand_clauses(H1,Body), Daniel@0: expand_clauses(H2,Body). Daniel@0: Daniel@0: expand_clauses(rdf(SPat,PPat,OPat),Mod:Body) --> Daniel@0: { call_dcg( ( opt_match(resource,SPat,S), Daniel@0: opt_match(resource,PPat,P), Daniel@0: opt_match(object,OPat,O) ), Mod:Body, Body1), Daniel@0: Clause = (p2r_entailment:rdf(S,P,O,Mod) :- Body1), Daniel@0: debug(p2r,'Asserting clause: ~w',[Clause]) Daniel@0: }, Daniel@0: [Clause]. Daniel@0: Daniel@0: % builds an optimised goal to do pattern matching Daniel@0: opt_match(_,X,X) --> {var(X)}, !. Daniel@0: opt_match(object,X,Y) --> {X=literal(_)}, !, {rdf_global_object(X,Y)}. Daniel@0: opt_match(_,P1,URI) --> Daniel@0: {debug(p2r,'Simplifying URI pattern: ~w',[P1])}, Daniel@0: {simplify(P1,P2)}, opt_match(P2,URI). Daniel@0: opt_match(X,X) --> {atomic(X)}, !. Daniel@0: opt_match(P,U) --> by_inst(U,uripattern:pattern_uri(P,U)). Daniel@0: Daniel@0: % this generates code to call G and G1 in an order determined Daniel@0: % by the instantiation state of X at run time. Daniel@0: by_inst(X,G1,G, (var(X) -> G, G1; G1, G)). Daniel@0: Daniel@0: Daniel@0: %% assert_all(+Module) is det. Daniel@0: % This asserts all the RDF triples entailed by the p2r module Module. Daniel@0: % Informational messages are printed, including the time taken. Daniel@0: assert_all(G) :- Daniel@0: forall(p2r_entailment:rdf(S,P,O,G), rdf_assert(S,P,O,G)). Daniel@0: