View source with formatted comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker and Wouter Beek
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2016, VU University Amsterdam
    7    All rights reserved.
    8
    9    Redistribution and use in source and binary forms, with or without
   10    modification, are permitted provided that the following conditions
   11    are met:
   12
   13    1. Redistributions of source code must retain the above copyright
   14       notice, this list of conditions and the following disclaimer.
   15
   16    2. Redistributions in binary form must reproduce the above copyright
   17       notice, this list of conditions and the following disclaimer in
   18       the documentation and/or other materials provided with the
   19       distribution.
   20
   21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   25    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   29    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   31    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32    POSSIBILITY OF SUCH DAMAGE.
   33*/
   34
   35:- module(rdf11_containers,
   36          [ rdf_alt/3,                            % ?Alt, -Default, -Others
   37            rdf_assert_alt/3,                     % ?Alt, +Default, +Others
   38            rdf_assert_alt/4,                     % ?Alt, +Default, +Others, +G
   39            rdf_assert_bag/2,                     % ?Bag, +Set
   40            rdf_assert_bag/3,                     % ?Bag, +Set, +G
   41            rdf_assert_seq/2,                     % ?Seq, +List
   42            rdf_assert_seq/3,                     % ?Seq, +List, +G
   43            rdf_bag/2,                            % ?Bag, -List
   44            rdf_seq/2,                            % ?Seq, -List
   45            rdfs_container/2,                     % ?Container, -List
   46            rdfs_container_membership_property/1, % ?Property
   47            rdfs_container_membership_property/2, % ?Property, ?Number
   48            rdfs_member/2,                        % ?Elem, ?Container
   49            rdfs_nth0/3                           % ?N, ?Container, ?Elem
   50          ]).   51:- use_module(library(semweb/rdf_prefixes),
   52              [ (rdf_meta)/1, op(_,_,rdf_meta)
   53              ]).   54:- use_module(rdf11,
   55              [ rdf_default_graph/1, rdf_transaction/1, rdf_create_bnode/1,
   56                rdf_assert/4, rdf_equal/2, rdf_is_subject/1, rdf_has/3
   57              ]).   58
   59:- autoload(library(apply),[maplist/3]).   60:- autoload(library(error),[must_be/2,type_error/2]).   61:- autoload(library(lists),[member/2]).   62:- autoload(library(pairs),[group_pairs_by_key/2,pairs_values/2]).   63
   64/** <module> RDF 1.1 Containers
   65
   66Implementation of the conventional human interpretation of RDF 1.1 containers.
   67
   68RDF containers are open enumeration structures as opposed to RDF collections or
   69RDF lists which are closed enumeration structures.
   70The same resource may appear in a container more than once.
   71A container may be contained in itself.
   72
   73---
   74
   75@author Wouter Beek
   76@author Jan Wielemaker
   77@compat RDF 1.1
   78@see http://www.w3.org/TR/2014/REC-rdf-schema-20140225/#ch_containervocab
   79@version 2016/01
   80*/
   81
   82:- rdf_meta
   83    rdf_alt(r, -, -),
   84    rdf_assert_alt(r, r, t),
   85    rdf_assert_alt(r, r, t, r),
   86    rdf_assert_bag(r, t),
   87    rdf_assert_bag(r, t, r),
   88    rdf_assert_seq(r, t),
   89    rdf_assert_seq(r, t, r),
   90    rdf_bag(r, -),
   91    rdf_seq(r, -),
   92    rdfs_assert_container(r, t),
   93    rdfs_assert_container(r, t, r),
   94    rdfs_assert_container(r, r, t, r),
   95    rdfs_container(r, -),
   96    rdfs_container_membership_property(r),
   97    rdfs_container_membership_property(r,?),
   98    rdfs_member(r, -).   99
  100
  101%!  rdf_alt(+Alt, ?Default, ?Others) is nondet.
  102%
  103%   True when Alt is an instance of `rdf:Alt` with first member
  104%   Default and remaining members Others.
  105%
  106%   Notice that this construct adds no machine-processable semantics
  107%   but is conventionally used to indicate   to  a human reader that
  108%   the numerical ordering of the container membership properties of
  109%   Container is intended to  only   be  relevant  in distinguishing
  110%   between the first and all non-first members.
  111%
  112%   Default denotes the default option to  take when choosing one of
  113%   the alternatives container in  Container.   Others  denotes  the
  114%   non-default options that can be chosen from.
  115
  116rdf_alt(Alt, Default, Others) :-
  117    rdfs_container(Alt, [Default|Others]).
  118
  119%!  rdf_assert_alt(?Alt, +Default, +Others:list) is det.
  120%!  rdf_assert_alt(?Alt, +Default, +Others:list, +Graph) is det.
  121%
  122%   Create an rdf:Alt with the given Default and Others. Default and
  123%   the  members  of  Others  must  be    valid   object  terms  for
  124%   rdf_assert/3.
  125
  126rdf_assert_alt(Alt, H, T) :-
  127    rdf_default_graph(G),
  128    rdf_assert_alt(Alt, H, T, G).
  129
  130rdf_assert_alt(Alt, H, T, G) :-
  131    rdfs_assert_container(Alt, rdf:'Alt', [H|T], G).
  132
  133
  134%!  rdf_bag(+Bag, -List:list) is nondet.
  135%
  136%   True when Bag is an rdf:Bag and   set  is the set values related
  137%   through container membership properties to Bag.
  138%
  139%   Notice that this construct adds no machine-processable semantics
  140%   but is conventionally used to indicate   to  a human reader that
  141%   the numerical ordering of the container membership properties of
  142%   Container is intended to not be significant.
  143
  144rdf_bag(Bag, List) :-
  145    rdfs_container(Bag, List).
  146
  147
  148%!  rdf_assert_bag(?Bag, +Set:list) is det.
  149%!  rdf_assert_bag(?Bag, +Set:list, +Graph) is det.
  150%
  151%   Create an rdf:Bag from the given set   of values. The members of
  152%   Set must be valid object terms for rdf_assert/3.
  153
  154rdf_assert_bag(Bag, L) :-
  155    rdf_default_graph(G),
  156    rdf_assert_bag(Bag, L, G).
  157
  158rdf_assert_bag(Bag, L, G) :-
  159    rdfs_assert_container(Bag, rdf:'Bag', L, G).
  160
  161
  162%!  rdf_seq(+Seq, -List:list) is nondet.
  163%
  164%   True when Seq is an instance of rdf:Seq   and  List is a list of
  165%   associated values, ordered according to the container membership
  166%   property used.
  167%
  168%   Notice that this construct adds no machine-processable semantics
  169%   but is conventionally used to indicate   to  a human reader that
  170%   the numerical ordering of the container membership properties of
  171%   Container is intended to be significant.
  172
  173rdf_seq(Seq, L) :-
  174    rdfs_container(Seq, L).
  175
  176
  177%!  rdf_assert_seq(?Seq, +List) is det.
  178%!  rdf_assert_seq(?Seq, +List, +Graph) is det.
  179
  180rdf_assert_seq(Seq, L) :-
  181    rdf_default_graph(G),
  182    rdf_assert_seq(Seq, L, G).
  183rdf_assert_seq(Seq, L, G) :-
  184    rdfs_assert_container(Seq, rdf:'Seq', L, G).
  185
  186
  187%!  rdfs_assert_container(?Container, +Class, +Elems, +Graph)
  188
  189rdfs_assert_container(Container, Class, Elems, G) :-
  190    must_be(list, Elems),
  191    rdf_transaction(rdfs_assert_container_(Container, Class, Elems, G)).
  192
  193rdfs_assert_container_(Container, Class, Elems, G) :-
  194    (var(Container) -> rdf_create_bnode(Container) ; true),
  195    rdf_assert(Container, rdf:type, Class, G),
  196    rdfs_assert_members(Elems, 1, Container, G).
  197
  198rdfs_assert_members([], _, _, _).
  199rdfs_assert_members([H|T], N1, Resource, G) :-
  200    !,
  201    rdf_equal(rdf:'_', Prefix),
  202    atom_concat(Prefix, N1, P),
  203    rdf_assert(Resource, P, H, G),
  204    N2 is N1 + 1,
  205    rdfs_assert_members(T, N2, Resource, G).
  206
  207
  208%!  rdfs_container(+Container, -List) is nondet.
  209%
  210%   True when List is the  list   of  objects  attached to Container
  211%   using a container membership property  (rdf:_0, rdf:_1, ...). If
  212%   multiple objects are connected to the   Container using the same
  213%   membership  property,  this   predicate    selects   one   value
  214%   non-deterministically.
  215
  216rdfs_container(Container, List) :-
  217    rdf_is_subject(Container),
  218    !,
  219    findall(N-Elem, rdfs_member0(Container, N, Elem), Pairs),
  220    keysort(Pairs, Sorted),
  221    group_pairs_by_key(Sorted, GroupedPairs),
  222    pairs_values(GroupedPairs, Groups),
  223    maplist(member, List, Groups).
  224rdfs_container(Container, _) :-
  225    type_error(rdf_subject, Container).
  226
  227
  228%!  rdfs_container_membership_property(?Property) is nondet.
  229%
  230%   True when Property is a   container membership property (rdf:_1,
  231%   rdf:_2, ...).
  232
  233rdfs_container_membership_property(P) :-
  234    rdfs_container_membership_property(P, _).
  235
  236
  237%!  rdfs_container_membership_property(?Property, ?Number:nonneg) is nondet.
  238%
  239%   True when Property is the Nth container membership property.
  240%
  241%   Success of this goal does not imply that Property is present
  242%   in the database.
  243
  244rdfs_container_membership_property(P, N) :-
  245    var(P),
  246    !,
  247    between(1, inf, N),
  248    rdf_equal(rdf:'_', Prefix),
  249    atom_concat(Prefix, N, P).
  250rdfs_container_membership_property(P, N) :-
  251    atom(P),
  252    rdf_equal(rdf:'_', Prefix),
  253    string_concat(Prefix, NumS, P),
  254    number_string(N, NumS),
  255    integer(N),
  256    N >= 0.
  257
  258
  259%!  rdfs_member(?Elem, ?Container) is nondet.
  260%
  261%   True if rdf(Container, P, Elem) is true   and P is a container
  262%   membership property.
  263
  264rdfs_member(Elem, Container) :-
  265    rdfs_member0(Container, _, Elem).
  266
  267%!  rdfs_nth0(?N, ?Container, ?Elem) is nondet.
  268%
  269%   True if rdf(Container, P, Elem)  is  true   and  P  is the N-th
  270%   (0-based) container membership property.
  271
  272rdfs_nth0(N, Container, Elem) :-
  273    rdfs_member0(Container, N, Elem).
  274
  275
  276%!  rdfs_member0(?Container, ?N, ?Elem) is nondet.
  277%
  278%   What is the most efficient way to enumerate rdfs_member(-,-)?
  279%
  280%   1. If we enumerate over all   container membership properties (= the
  281%   current implementation) then it  takes  N   steps  before  we get to
  282%   triple `<Container, rdf:_N, Elem>`, for arbitrary N.
  283%
  284%   2. The alternative is  to  enumerate   over  all  triples  and check
  285%   whether the predicate term is a container membership property.
  286%
  287%   3. The choice between (1) and (2)   depends on whether the number of
  288%   currently loaded triples in larger/smaller   than the largest number
  289%   that  appears  in  a  container   membership  property.  This  means
  290%   enumerating over all predicate terms using rdf_predicate/1.
  291
  292rdfs_member0(Container, N, Elem) :-
  293    (nonvar(Container) ; nonvar(Elem)),
  294    !,
  295    rdf_has(Container, P, Elem),
  296    rdfs_container_membership_property(P, N).
  297rdfs_member0(Container, N, Elem) :-
  298    rdfs_container_membership_property(P, N),
  299    rdf_has(Container, P, Elem)