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)