1/* Part of ClioPatria SeRQL and SPARQL server 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2010-2018, University of Amsterdam, 7 VU University Amsterdam 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 17 2. Redistributions in binary form must reproduce the above copyright 18 notice, this list of conditions and the following disclaimer in 19 the documentation and/or other materials provided with the 20 distribution. 21 22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 POSSIBILITY OF SUCH DAMAGE. 34*/ 35 36:- module(rdf_abstract, 37 [ merge_sameas_graph/3, % +GraphIn, -GraphOut, +Options 38 bagify_graph/4, % +GraphIn, -GraphOut, -Bags, +Options 39 abstract_graph/3, % +GraphIn, -GraphOut, +Options 40 minimise_graph/2, % +GraphIn, -GraphOut 41 42 graph_resources/2, % +Graph, -Resources 43 graph_resources/4 % +Graph, -Resources, -Predicates, -Types 44 ]). 45:- use_module(library(semweb/rdf_db)). 46:- use_module(library(semweb/rdfs)). 47:- use_module(library(assoc)). 48:- use_module(library(option)). 49:- use_module(library(pairs)). 50:- use_module(library(ordsets)). 51:- use_module(library(debug)). 52:- use_module(library(apply)). 53:- use_module(library(lists)). 54:- use_module(library(settings)).
86:- rdf_meta 87 merge_sameas_graph(+, -, t). 88 89merge_sameas_graph(GraphIn, GraphOut, Options) :- 90 sameas_spec(Options, SameAs), 91 sameas_map(GraphIn, SameAs, Assoc), % R->EqSet 92 ( empty_assoc(Assoc) 93 -> GraphOut = GraphIn, 94 empty_assoc(EqMap) 95 ; assoc_to_list(Assoc, List), 96 pairs_values(List, EqSets), 97 sort(EqSets, UniqueEqSets), 98 map_list_to_pairs(rdf_representative, UniqueEqSets, Keyed), % Repr-EqSet 99 representer_map(Keyed, EqMap), 100 map_graph(GraphIn, EqMap, GraphOut), 101 ( debugging(abstract) 102 -> length(GraphIn, Before), 103 length(GraphOut, After), 104 debug(abstract, 'owl:sameAs reduction: ~D --> ~D edges', [Before, After]) 105 ; true 106 ) 107 ), 108 option(sameas_mapped(EqMap), Options, _). 109 110sameas_spec(Options, SameAs) :- 111 rdf_equal(owl:sameAs, OwlSameAs), 112 option(predicate(SameAs0), Options, OwlSameAs), 113 ( is_list(SameAs0) 114 -> SameAs = SameAs0 115 ; SameAs = [SameAs0] 116 ).
123sameas_map(Graph, SameAs, Assoc) :- 124 empty_assoc(Assoc0), 125 sameas_map(Graph, SameAs, Assoc0, Assoc). 126 127sameas_map([], _, Assoc, Assoc). 128sameas_map([rdf(S, P, O)|T], SameAs, Assoc0, Assoc) :- 129 same_as(P, SameAs), 130 S \== O, 131 !, 132 ( get_assoc(S, Assoc0, SetS) 133 -> ( get_assoc(O, Assoc0, SetO) 134 -> ord_union(SetO, SetS, Set) 135 ; ord_union([O], SetS, Set) 136 ) 137 ; ( get_assoc(O, Assoc0, SetO) 138 -> ord_union([S], SetO, Set) 139 ; sort([S,O], Set) 140 ) 141 ), 142 putall(Set, Assoc0, Set, Assoc1), 143 sameas_map(T, SameAs, Assoc1, Assoc). 144sameas_map([_|T], SameAs, Assoc0, Assoc) :- 145 sameas_map(T, SameAs, Assoc0, Assoc). 146 147putall([], Assoc, _, Assoc). 148putall([H|T], Assoc0, Value, Assoc) :- 149 put_assoc(H, Assoc0, Value, Assoc1), 150 putall(T, Assoc1, Value, Assoc).
157same_as(P, Super) :-
158 member(S, Super),
159 rdfs_subproperty_of(P, S),
160 !.
167representer_map(Keyed, EqMap) :- 168 empty_assoc(Assoc0), 169 representer_map(Keyed, Assoc0, EqMap). 170 171representer_map([], Assoc, Assoc). 172representer_map([R-Set|T], Assoc0, Assoc) :- 173 putall(Set, Assoc0, R, Assoc1), 174 representer_map(T, Assoc1, Assoc). 175 176 177 /******************************* 178 * BAGIFY * 179 *******************************/
true
(default), also try to put literals into a
bag. Works well to collapse non-preferred labels.204:- rdf_meta 205 bagify_graph(+, -, -, t). 206 207bagify_graph(GraphIn, GraphOut, Bags, Options) :- 208 canonise_options(Options, Options1), 209 partition_options(class, Options1, ClassOptions, Options2), 210 graph_node_edges(GraphIn, AssocNodesToEdges, Options2), 211 assoc_to_list(AssocNodesToEdges, NodesToEdges), 212 pairs_keys(NodesToEdges, Nodes), 213 group_resources_by_class(Nodes, ByClass, ClassOptions), 214 resource_bags(ByClass, NodesToEdges, RawBags), 215 ( debugging(abstract) 216 -> length(RawBags, Len), 217 maplist(length, RawBags, BagLens), 218 sumlist(BagLens, ObjCount), 219 debug(abstract, 'Created ~D bags holding ~D objects', [Len, ObjCount]) 220 ; true 221 ), 222 assign_bagids(RawBags, IDBags), 223 representer_map(IDBags, Assoc), 224 map_graph(GraphIn, Assoc, GraphOut0), 225 merge_properties(GraphOut0, GraphOut, Options2), 226 make_rdf_graphs(IDBags, Bags). 227 228partition_options(Name, Options, WithName, WithoutName) :- 229 partition(option_name(Name), Options, WithName, WithoutName). 230 231option_name(Name, Option) :- 232 functor(Option, Name, 1).
238canonise_options(In, Out) :- 239 memberchk(_=_, In), % speedup a bit if already ok. 240 !, 241 canonise_options2(In, Out). 242canonise_options(Options, Options). 243 244canonise_options2([], []). 245canonise_options2([Name=Value|T0], [H|T]) :- 246 !, 247 H =.. [Name,Value], 248 canonise_options2(T0, T). 249canonise_options2([H|T0], [H|T]) :- 250 !, 251 canonise_options2(T0, T).
261group_resources_by_class([], [], _) :- !. 262group_resources_by_class(Resources, ByClass, Options) :- 263 select_option(class(Class), Options, Options1), 264 !, 265 ( partition(has_class(sub_class, Class), Resources, InClass, NotInClass), 266 InClass \== [] 267 -> ByClass = [InClass|ByClass1], 268 group_resources_by_class(NotInClass, ByClass1, Options1) 269 ; group_resources_by_class(Resources, ByClass, Options1) 270 ). 271group_resources_by_class([H|T0], [[H|S]|T], Options) :- 272 class_of(H, exact, Class), 273 partition(has_class(exact, Class), T0, S, T1), 274 group_resources_by_class(T1, T, Options).
278has_class(Match, Class, Node) :-
279 class_of(Node, Match, Class).
284class_of(Node, sub_class, Class) :- 285 !, 286 rdfs_individual_of(Node, Class), 287 !. 288class_of(literal(_), exact, Literal) :- 289 !, 290 rdf_equal(Literal, rdfs:'Literal'). 291class_of(R, exact, Class) :- 292 rdf_has(R, rdf:type, Class), 293 !. 294class_of(_, exact, Class) :- 295 rdf_equal(Class, rdfs:'Resource').
304resource_bags(ByClass, NodeToEdges, Bags) :- 305 phrase(resource_bags(ByClass, NodeToEdges), Bags). 306 307resource_bags([], _) --> 308 []. 309resource_bags([ByClassH|ByClassT], NodeToEdges) --> 310 { sort(ByClassH, SortedNodes), 311 ord_subkeys(SortedNodes, NodeToEdges, SubNodeToEdges), 312 same_edges(SubNodeToEdges, Bags) 313 }, 314 , 315 resource_bags(ByClassT, NodeToEdges).
325ord_subkeys([], _, []). 326ord_subkeys([K|KT], [P|PT], Pairs) :- 327 P = PK-_, 328 compare(Diff, K, PK), 329 ord_subkeys(Diff, K, KT, P, PT, Pairs). 330 331ord_subkeys(=, _, KT, P, PT, [P|Pairs]) :- 332 !, 333 ord_subkeys(KT, PT, Pairs). 334ord_subkeys(<, _, [K|KT], P, PT, Pairs) :- 335 P = PK-_, 336 compare(Diff, K, PK), 337 ord_subkeys(Diff, K, KT, P, PT, Pairs). 338ord_subkeys(>, K, KT, _, [P|PT], Pairs) :- 339 P = PK-_, 340 compare(Diff, K, PK), 341 ord_subkeys(Diff, K, KT, P, PT, Pairs).
349same_edges(NodeToEdges, Bags) :- 350 transpose_pairs(NodeToEdges, ByEdges), % list(edges-node) 351 keysort(ByEdges, Sorted), 352 group_pairs_by_key(Sorted, Grouped), 353 pairs_values(Grouped, AllBySameEdge), 354 include(longer_than_one, AllBySameEdge, Bags). 355 356longer_than_one([_,_|_]).
Processes bagify_literals
and property
options
365graph_node_edges(Graph, Assoc, Options) :- 366 option(bagify_literals(LitToo), Options, true), 367 property_map(Options, Map0), 368 empty_assoc(Assoc0), 369 graph_node_edges(Graph, LitToo, Map0, Assoc0, Assoc1), 370 map_assoc(sort, Assoc1, Assoc). 371 372graph_node_edges([], _, _, Assoc, Assoc). 373graph_node_edges([rdf(S,P,O)|T], LitToo, Map, Assoc0, Assoc) :- 374 abstract_property(P, Map, SP, Map1), 375 add_assoc(S, Assoc0, rdf(-, SP, O), Assoc1), 376 ( (atom(O) ; LitToo == true ) 377 -> add_assoc(O, Assoc1, rdf(S, SP, -), Assoc2) 378 ; Assoc2 = Assoc1 379 ), 380 graph_node_edges(T, LitToo, Map1, Assoc2, Assoc). 381 382add_assoc(Key, Assoc0, Value, Assoc) :- 383 get_assoc(Key, Assoc0, Old, Assoc, [Value|Old]), 384 !. 385add_assoc(Key, Assoc0, Value, Assoc) :- 386 put_assoc(Key, Assoc0, [Value], Assoc).
394property_map(Options, Map) :- 395 empty_assoc(Map0), 396 property_map(Options, Map0, Map). 397 398property_map([], Map, Map). 399property_map([property(P)|T], Map0, Map) :- 400 !, 401 ( rdfs_subproperty_of(P, Super), 402 get_assoc(Super, Map0, Root) 403 -> put_assoc(P, Map0, Root, Map1) 404 ; put_assoc(P, Map0, P, Map1) 405 ), 406 property_map(T, Map1, Map). 407property_map([_|T], Map0, Map) :- 408 property_map(T, Map0, Map).
414abstract_property(P0, Map0, P, Map) :- 415 get_assoc(P0, Map0, P), 416 !, 417 Map = Map0. 418abstract_property(P, Map0, Root, Map) :- 419 rdfs_subproperty_of(P, Super), 420 get_assoc(Super, Map0, Root), 421 !, 422 debug(abstract(property), 'Mapped ~p --> ~p', [P, Root]), 423 put_assoc(P, Map0, Root, Map). 424abstract_property(P, Map, P, Map).
431assign_bagids(Bags, IDBags) :- 432 assign_bagids(Bags, 1, IDBags). 433 434assign_bagids([], _, []). 435assign_bagids([H|T0], I, [Id-H|T]) :- 436 atom_concat('_:bag_', I, Id), 437 I2 is I + 1, 438 assign_bagids(T0, I2, T).
445:- rdf_meta 446 statement(r,r,o,?,?). % statement//3 447 448make_rdf_graphs(IDBags, RDFBags) :- 449 phrase(make_rdf_graphs(IDBags), RDFBags). 450 451make_rdf_graphs([]) --> 452 []. 453make_rdf_graphs([ID-Members|T]) --> 454 statement(ID, rdf:type, rdf:'Bag'), 455 bag_members(Members, 0, ID), 456 make_rdf_graphs(T). 457 458bag_members([], _, _) --> 459 []. 460bag_members([H|T], I, ID) --> 461 { I2 is I + 1, 462 atom_concat('_:', I, P) 463 }, 464 statement(ID, P, H), 465 bag_members(T, I2, ID). 466 467statement(S, P, O) --> 468 [ rdf(S, P, O) ]. 469 470 471 472 /******************************* 473 * MERGE PROPERTIES * 474 *******************************/
485merge_properties([], [], _). 486merge_properties([rdf(S,P,O)|GraphIn], GraphOut, Options) :- 487 memberchk(rdf(S,_,O), GraphIn), 488 !, 489 partition(same_so(S,O), GraphIn, Same, Rest), 490 maplist(pred, Same, Preds), 491 sort([P|Preds], UniquePreds), 492 common_ancestor_forest(sub_property_of, UniquePreds, Forest), 493 pairs_keys(Forest, Roots), 494 debug(abstract, 'Merged ~p --> ~p', [UniquePreds, Roots]), 495 mk_p_triples(Roots, S, O, GraphOut, Out2), 496 merge_properties(Rest, Out2, Options). 497merge_properties([Triple|GraphIn], [Triple|GraphOut], Options) :- 498 merge_properties(GraphIn, GraphOut, Options). 499 500same_so(S, O, rdf(S, _, O)). 501pred(rdf(_,P,_), P). 502 503mk_p_triples([], _, _) --> []. 504mk_p_triples([P|T], S, O) --> 505 [rdf(S,P,O)], 506 mk_p_triples(T, S, O). 507 508sub_property_of(P, Super) :- 509 rdf_has(P, rdfs:subPropertyOf, Super).
call(Pred, +Node, -Parent)
.
539:- meta_predicate 540 common_ancestor_forest( , , ). 541 542common_ancestor_forest(Pred, Objects, Forest) :- 543 strip_module(Pred, M, P), 544 sort(Objects, Objects1), 545 keys_to_assoc(Objects1, target*[], Nodes0), 546 ancestor_tree(Objects1, M:P, Nodes0, Nodes, Roots), 547 prune_forest(Nodes, Roots, Forest), 548 debug(common_ancestor, 'Ancestors of ~p: ~p', [Objects1, Forest]).
554keys_to_assoc(Keys, Value, Assoc) :- 555 empty_assoc(Assoc0), 556 keys_to_assoc(Keys, Assoc0, Value, Assoc). 557 558keys_to_assoc([], Assoc, _, Assoc). 559keys_to_assoc([H|T], Assoc0, Value, Assoc) :- 560 put_assoc(H, Assoc0, Value, Assoc1), 561 keys_to_assoc(T, Assoc1, Value, Assoc). 562 563 564ancestor_tree(Objects, Pred, Nodes0, Nodes, Roots) :- 565 ancestor_tree(Objects, [], Objects, Pred, Nodes0, Nodes, Roots).
585ancestor_tree([One], [], _, _, Nodes, Nodes, [One]) :- !. 586ancestor_tree([], Closed, _, _, Nodes, Nodes, Closed) :- !. 587ancestor_tree(Open, _, Objects, _, Nodes, Nodes, [One]) :- 588 member(One, Open), 589 tree_covers(One, Nodes, Objects), 590 !. 591ancestor_tree(Open, Closed, Objects, Pred, Nodes0, Nodes, Roots) :- 592 expand_ancestor_tree(Open, NewOpen, NewClosed, Closed, Nodes0, Nodes1, Pred), 593 ancestor_tree(NewOpen, NewClosed, Objects, Pred, Nodes1, Nodes, Roots).
607expand_ancestor_tree([], [], Closed, Closed, Nodes, Nodes, _). 608expand_ancestor_tree([H|T], Open, Closed0, Closed, Nodes0, Nodes, Pred) :- 609 setof(Parent, call(Pred, H, Parent), Parents), 610 !, 611 add_parents(Parents, H, Open, OpenT, Nodes0, Nodes1), 612 expand_ancestor_tree(T, OpenT, Closed0, Closed, Nodes1, Nodes, Pred). 613expand_ancestor_tree([H|T], Open, [H|ClosedT], Closed, Nodes0, Nodes, Pred) :- 614 expand_ancestor_tree(T, Open, ClosedT, Closed, Nodes0, Nodes, Pred).
622add_parents([], _, NP, NP, Nodes, Nodes). 623add_parents([H|T], Child, NP, NPT, Nodes0, Nodes) :- 624 in_tree(Child, H, Nodes0), 625 !, 626 add_parents(T, Child, NP, NPT, Nodes0, Nodes). 627add_parents([H|T], Child, NP, NPT, Nodes0, Nodes) :- 628 get_assoc(H, 629 Nodes0, State*Children, 630 Nodes1, State*[Child|Children]), 631 !, 632 add_parents(T, Child, NP, NPT, Nodes1, Nodes). 633add_parents([H|T], Child, [H|NP], NPT, Nodes0, Nodes) :- 634 put_assoc(H, Nodes0, node*[Child], Nodes1), 635 add_parents(T, Child, NP, NPT, Nodes1, Nodes).
642in_tree(Node, Node, _). 643in_tree(Node, Root, Nodes) :- 644 get_assoc(Root, Nodes, _State*Children), 645 member(Child, Children), 646 in_tree(Node, Child, Nodes).
655prune_forest(Nodes, Roots, Forest) :-
656 maplist(prune_root(Nodes), Roots, Roots1),
657 sort(Roots1, Roots2),
658 maplist(prune_ancestor_tree(Nodes), Roots2, Forest0),
659 sort(Forest0, Forest).
668prune_root(Nodes, Root0, Root) :- 669 get_assoc(Root0, Nodes, node*[One]), 670 !, 671 prune_root(Nodes, One, Root). 672prune_root(_, Root, Root).
679prune_ancestor_tree(Nodes, Root, Tree) :-
680 get_assoc(Root, Nodes, Value),
681 ( Value = node*[One]
682 -> prune_ancestor_tree(Nodes, One, Tree)
683 ; Tree = (Root-Children),
684 Value = _*Children0,
685 maplist(prune_ancestor_tree(Nodes), Children0, Children)
686 ).
693tree_covers(Root, Nodes, Targets) :- 694 phrase(tree_covers(Root, Nodes), Targets0), 695 sort(Targets0, Targets). 696 697tree_covers(Root, Nodes) --> 698 { get_assoc(Root, Nodes, State*Children) }, 699 ( {State == target} 700 -> [Root] 701 ; [] 702 ), 703 tree_covers_list(Children, Nodes). 704 705tree_covers_list([], _) --> 706 []. 707tree_covers_list([H|T], Nodes) --> 708 tree_covers(H, Nodes), 709 tree_covers_list(T, Nodes). 710 711 712 /******************************* 713 * PRIMITIVES * 714 *******************************/
rdf(S,P,S)
links that did not appear before the
mapping.
726map_graph(GraphIn, Map, GraphOut) :- 727 phrase(map_triples(GraphIn, Map), Graph2), 728 sort(Graph2, GraphOut). 729 730map_triples([], _) --> 731 []. 732map_triples([H0|T0], Map) --> 733 map_triple(H0, Map), 734 map_triples(T0, Map). 735 736map_triple(rdf(S0,P0,O0), Map) --> 737 { map_resource(S0, Map, S), 738 map_resource(P0, Map, P), 739 map_object(O0, Map, O) 740 }, 741 ( { S == O, S0 \== O0 } 742 -> [] 743 ; [ rdf(S,P,O) ] 744 ). 745 746map_resource(N0, Map, N) :- 747 get_assoc(N0, Map, N), 748 !. 749map_resource(N, _, N). 750 751map_object(O0, Map, O) :- 752 get_assoc(O0, Map, O), 753 !. 754map_object(literal(type(T0, V)), Map, L) :- 755 get_assoc(T0, Map, T), 756 !, 757 L = literal(type(T, V)). 758map_object(O, _, O).
list(concrete)
.
769map_graph(GraphIn, Map, GraphOut, AbstractMap) :-
770 map_graph(GraphIn, Map, GraphOut),
771 assoc_to_list(Map, ConcAbstr), % Concrete->Abstract
772 graph_nodes(GraphIn, AllConcrete),
773 pairs_keys_intersection(ConcAbstr, AllConcrete, UsedConcAbstr),
774 transpose_pairs(UsedConcAbstr, AbstrConc),
775 group_pairs_by_key(AbstrConc, Grouped),
776 list_to_assoc(Grouped, AbstractMap).
?- pairs_keys_intersection([a-1,b-2,c-3], [a,c], X). X = [a-1,c-3]
789pairs_keys_intersection(Pairs, [K], Int) :- % One key: happens quite often 790 !, 791 find_one_key(Pairs, K, Int). 792pairs_keys_intersection([P1|TP], [K1|TK], Int) :- 793 !, 794 compare_pair_key(Diff, P1, K1), 795 pairs_keys_isect(Diff, P1, TP, K1, TK, Int). 796pairs_keys_intersection(_, _, []). 797 798pairs_keys_isect(<, _, [P1|TP], K1, TK, Int) :- 799 !, 800 compare_pair_key(Diff, P1, K1), 801 pairs_keys_isect(Diff, P1, TP, K1, TK, Int). 802pairs_keys_isect(=, P, [P1|TP], K1, TK, [P|Int]) :- 803 !, 804 compare_pair_key(Diff, P1, K1), 805 pairs_keys_isect(Diff, P1, TP, K1, TK, Int). 806pairs_keys_isect(>, P1, TP, _, [K1|TK], Int) :- 807 !, 808 compare_pair_key(Diff, P1, K1), 809 pairs_keys_isect(Diff, P1, TP, K1, TK, Int). 810pairs_keys_isect(=, P, _, _, _, [P]) :- !. 811pairs_keys_isect(_, _, _, _, _, []). 812 813compare_pair_key(Order, K1-_, K2) :- 814 !, 815 compare(Order, K1, K2). 816 817find_one_key([], _, []). 818find_one_key([K0-V|T0], K, List) :- 819 ( K0 == K 820 -> List = [k0-V|T], 821 find_one_key(T0, K, T) 822 ; find_one_key(T0, K, List) 823 ).
831map_to_bagged_graph(GraphIn, Map, GraphOut, Bags) :- 832 map_graph(GraphIn, Map, AbstractGraph, AbstractMap), 833% assertion(map_assoc(is_ordset, AbstractMap)), 834 empty_assoc(Nodes), 835 rdf_to_paired_graph(GraphIn, PairGraph), 836 phrase(bagify_triples(AbstractGraph, PairGraph, AbstractMap, 837 Nodes, Bags, []), 838 GraphOut). 839 840bagify_triples([], _, _, _, Bags, Bags) --> []. 841bagify_triples([rdf(S0,_P,O0)|T], PairGraph, Map, Nodes, Bags, BagsT) --> 842 { bagify_resource(S0, S, Map, Nodes, Nodes1, Bags, BagsT0), 843 bagify_object(O0, O, Map, Nodes1, Nodes2, BagsT0, BagsT1), 844 845 % normal properties 846 used_properties(S0, O0, PairGraph, Map, PList), 847 common_ancestor_forest(sub_property_of, PList, Forest), 848 debug(used_properties, 'Forest = ~p', [Forest]), 849 pairs_keys(Forest, PRoots), 850 % inverse properties 851 used_properties(O0, S0, PairGraph, Map, IPList), 852 common_ancestor_forest(sub_property_of, IPList, IForest), 853 debug(used_properties, 'IForest = ~p', [IForest]), 854 pairs_keys(IForest, IPRoots) 855 }, 856 mk_p_triples(PRoots, S, O), 857 mk_p_triples(IPRoots, O, S), 858 bagify_triples(T, PairGraph, Map, Nodes2, BagsT1, BagsT). 859 860 861bagify_resource(R0, R, _Map, Nodes, Nodes) --> 862 { get_assoc(R0, Nodes, R) }, 863 !. 864bagify_resource(R0, BagID, Map, Nodes0, Nodes) --> 865 { get_assoc(R0, Map, Set), Set = [_,_|_], 866 !, 867 atom_concat('_:rbag_', R0, BagID), 868 put_assoc(R0, Nodes0, BagID, Nodes) 869 }, 870 make_rdf_graphs([BagID-Set]). 871bagify_resource(R0, One, Map, Nodes, Nodes) --> 872 { get_assoc(R0, Map, [One]) }, 873 !. 874bagify_resource(R, R, _, Nodes, Nodes) --> []. 875 876bagify_object(R0, R, Map, Nodes0, Nodes) --> 877 bagify_resource(R0, R, Map, Nodes0, Nodes).
886rdf_to_paired_graph(Triples, Pairs) :- 887 subject_pairs(Triples, Pairs0), 888 keysort(Pairs0, Pairs1), 889 group_pairs_by_key(Pairs1, Pairs2), 890 maplist(keysort_values, Pairs2, Pairs). 891 892subject_pairs([], []). 893subject_pairs([rdf(S,P,O)|T0], [S-(O-P)|T]) :- 894 subject_pairs(T0, T). 895 896keysort_values(K-V0, K-V) :- 897 keysort(V0, V).
910used_properties(S0, O0, GraphIn, Map, PList) :-
911 get_assoc(S0, Map, SList),
912 get_assoc(O0, Map, OList),
913 pairs_keys_intersection(GraphIn, SList, Intersection),
914 pairs_values(Intersection, OPList0),
915 append(OPList0, OPList1),
916 keysort(OPList1, OPList),
917 pairs_keys_intersection(OPList, OList, IntPList),
918 pairs_values(IntPList, PListDupl),
919 sort(PListDupl, PList),
920 debug(used_properties, ' --> ~p', [PList]).
932graph_resources(Graph, Resources) :-
933 graph_resources(Graph, R, P, P, T, T, [], _, _),
934 sort(R, Resources).
943graph_nodes(Graph, Nodes) :-
944 graph_resources(Graph, Nodes0, P, P, L, _, _, L, []),
945 sort(Nodes0, Nodes).
958graph_resources(Graph, Resources, Preds, Types) :- 959 graph_resources(Graph, R, [], P, [], T, [], _, _), 960 sort(R, Resources), 961 sort(P, Preds), 962 sort(T, Types). 963 964graph_resources([], R, R, P, P, T, T, L, L). 965graph_resources([rdf(S,P,O)|T], [S|RT0], RT, [P|PTl0], PTl, Tl0, Tl, L0, L) :- 966 object_resources(O, RT0, RT1, Tl0, Tl1, L0, L1), 967 graph_resources(T, RT1, RT, PTl0, PTl, Tl1, Tl, L1, L). 968 969 970object_resources(O, R0, R, T0, T, L0, L) :- 971 ( atom(O) 972 -> R0 = [O|R], T0 = T, L0 = L 973 ; O = literal(Val) 974 -> R0 = R, L0 = [O|L], 975 ( Val = type(Type, _) 976 -> T0 = [Type|T] 977 ; T0 = T 978 ) 979 ; assertion(fail) 980 ). 981 982 983 /******************************* 984 * ABSTRACT * 985 *******************************/
rdf(s,p,o)
, we must abstract the subject of rdf(o,
p2, o2)
to the same resource.
If we want to do incremental growing we must keep track which nodes where mapped to which resources. Option?
We must also decide on the abstraction level for a node. This can be based on the weight in the search graph, the involved properties and focus such as location and time. Should we express this focus in the weight?
Options:
true
(default), merge nodes of one is a super-concept
of another.1018abstract_graph(GraphIn, GraphOut, Options) :- 1019 map_in(Options, MapIn), 1020 graph_resources(GraphIn, Nodes, NT, Edges, [], _T0, _TT, NT, []), 1021 node_map(Nodes, MapIn, Map2, Options), 1022 edge_map(Edges, Map2, MapOut), 1023 map_out(Options, MapOut), 1024 ( option(bags(Bags), Options) 1025 -> map_to_bagged_graph(GraphIn, MapOut, GraphOut, Bags) 1026 ; map_graph(GraphIn, MapOut, GraphOut) 1027 ). 1028 1029map_in(Options, Map) :- 1030 option(map_in(Map), Options, Map), 1031 (var(Map) -> empty_assoc(Map) ; true). 1032 1033map_out(Options, Map) :- 1034 option(map_out(Map), Options, _).
1046node_map(Nodes, Map0, Map, Options) :- 1047 concepts_of(Nodes, Map0, Map1, _NewConcepts), 1048 ( option(merge_concepts_with_super(true), Options, true) 1049 -> assoc_to_values(Map1, Concepts), 1050 sort(Concepts, Unique), 1051 identity_map(Unique, SuperMap0), 1052 find_broaders(Unique, SuperMap0, SuperMap1), 1053 deref_map(SuperMap1, SuperMap), 1054 map_assoc(map_over(SuperMap), Map1, Map) 1055 ; Map = Map1 1056 ). 1057 1058map_over(Map, V0, V) :- 1059 ( get_assoc(V0, Map, V1) 1060 -> V = V1 1061 ; V = V0 1062 ). 1063 1064concepts_of([], Map, Map, []). 1065concepts_of([R|T], Map0, Map, New) :- 1066 get_assoc(R, Map0, _), 1067 !, 1068 concepts_of(T, Map0, Map, New). 1069concepts_of([R|T], Map0, Map, [C|New]) :- 1070 concept_of(R, C), 1071 put_assoc(R, Map0, C, Map1), 1072 concepts_of(T, Map1, Map, New).
1078identity_map(List, Map) :- 1079 map_list_to_pairs(=, List, Pairs), 1080 list_to_assoc(Pairs, Map). 1081 1082find_broaders([], Map, Map). 1083find_broaders([C|T], Map0, Map) :- 1084 broader(C, Super), 1085 get_assoc(Super, Map0, SuperSuper), 1086 !, 1087 debug(rdf_abstract, 'Mapped ~p to super concept ~p', [C, SuperSuper]), 1088 put_assoc(C, Map0, SuperSuper, Map1), 1089 find_broaders(T, Map1, Map). 1090find_broaders([_|T], Map0, Map) :- 1091 find_broaders(T, Map0, Map). 1092 1093 1094deref_map(Map0, Map) :- 1095 findall(KV, mapped_kv(KV, Map0), Pairs), 1096 deref(Pairs, NewPairs), 1097 list_to_assoc(NewPairs, Map). 1098 1099mapped_kv(K-V, Assoc) :- 1100 gen_assoc(K, Assoc, V), 1101 K \== V.
1110deref(Pairs, NewPairs) :- 1111 list_to_assoc(Pairs, Assoc), 1112 deref(Pairs, Assoc, NewPairs). 1113 1114deref([], _, []). 1115deref([K-V0|T0], Map, [K-V|T]) :- 1116 deref2(V0, Map, [V0], EqSet, V), 1117 ( EqSet == [] 1118 -> deref(T0, Map, T) 1119 ; rdf_representative(EqSet, V), 1120 deref_cycle(T0, EqSet, V, Cycle, T1), 1121 append(Cycle, T2, T), 1122 deref(T1, Map, T2) 1123 ). 1124 1125deref2(V0, Map, Visited, EqSet, V) :- 1126 get_assoc(V0, Map, V1), 1127 !, 1128 ( memberchk(V1, Visited) 1129 -> EqSet = Visited 1130 ; deref2(V1, Map, [V1|Visited], EqSet, V) 1131 ). 1132deref2(V, _, _, [], V). 1133 1134deref_cycle([], _, _, [], []). 1135deref_cycle([K-V0|T0], EqSet, V, [K-V|CT], Rest) :- 1136 memberchk(V0, EqSet), 1137 !, 1138 deref_cycle(T0, EqSet, V, CT, Rest). 1139deref_cycle([H|T0], EqSet, V, CT, [H|RT]) :- 1140 deref_cycle(T0, EqSet, V, CT, RT).
1145edge_map([], Map, Map). 1146edge_map([R|T], Map0, Map) :- 1147 get_assoc(R, Map0, _), 1148 !, 1149 edge_map(T, Map0, Map). 1150%edge_map([R|T], Map0, Map) :- 1151% iface_abstract_predicate(R, C), 1152% put_assoc(R, Map0, C, Map1), 1153% edge_map(T, Map1, Map).
1163concept_of(O, O) :- 1164 rdfs_individual_of(O, skos:'Concept'), 1165 !. 1166concept_of(O, C) :- 1167 rdf_has(O, rdf:type, C), 1168 !. 1169concept_of(O, O).
1177broader(Term, Broader) :-
1178 rdf_reachable(Term, skos:broader, Broader),
1179 Broader \== Term.
1190rdf_representative(List, Representative) :- 1191 ( exclude(rdf_is_bnode, List, NonBNodes), 1192 NonBNodes \== [] 1193 -> representative(NonBNodes, Representative) 1194 ; representative(List, Representative) 1195 ). 1196 1197representative([H], Representative) :- 1198 !, 1199 Representative = H. 1200representative([H|T], Representative) :- 1201 fan_in_out(H, Fan0), 1202 best(T, Fan0, H, Representative). 1203 1204best([], _, R, R). 1205best([H|T], S0, R0, R) :- 1206 fan_in_out(H, S1), 1207 ( S1 > S0 1208 -> best(T, S1, H, R) 1209 ; best(T, S0, R0, R) 1210 ). 1211 1212fan_in_out(R, Fan) :- 1213 count(rdf(R, _, _), 100, FanOut), 1214 count(rdf(_, _, R), 100, FanIn), 1215 Fan is FanOut + FanIn. 1216 1217 1218 /******************************* 1219 * SIMPLIFY * 1220 *******************************/
1234minimise_graph(RDF0, RDF) :- 1235 partition(object_triple, RDF0, ObjRDF, LitRDF), 1236 map_list_to_pairs(os_rdf, ObjRDF, Pairs), 1237 group_pairs_by_key(Pairs, Grouped), 1238 maplist(key_remove_reduntant_relations, Grouped, MinGroups), 1239 append([LitRDF|MinGroups], RDF). 1240 1241object_triple(rdf(_,_,O)) :- 1242 atom(O). 1243 1244os_rdf(rdf(S,_,O), (A+B)) :- 1245 ( S @< O 1246 -> A = S, B = O 1247 ; A = O, B = S 1248 ). 1249 1250key_remove_reduntant_relations(_-Rs0, Rs) :- 1251 remove_reduntant_relations(Rs0, Rs). 1252 1253remove_reduntant_relations([R], [R]) :- !. 1254remove_reduntant_relations(List0, List) :- 1255 select(rdf(S,P1,O), List0, List1), 1256 select(rdf(S,P2,O), List1, List2), 1257 rdfs_subproperty_of(P1, P2), 1258 !, 1259 remove_reduntant_relations([rdf(S,P1,O)|List2], List). 1260remove_reduntant_relations(List0, List) :- 1261 select(rdf(S,P,O), List0, List1), 1262 select(rdf(O,P,S), List1, List2), 1263 rdfs_individual_of(P, owl:'SymmetricProperty'), 1264 !, 1265 remove_reduntant_relations([rdf(S,P,O)|List2], List). 1266remove_reduntant_relations(List0, List) :- 1267 select(rdf(S,P1,O), List0, List1), 1268 select(rdf(O,P2,S), List1, List2), 1269 rdf_has(P1, owl:inverseOf, P2), 1270 !, 1271 remove_reduntant_relations([rdf(S,P2,O)|List2], List). 1272remove_reduntant_relations(List, List). 1273 1274 1275 /******************************* 1276 * UTIL * 1277 *******************************/ 1278 1279:- meta_predicate 1280 count( , , ). 1281 1282count(G, Max, Count) :- 1283 C = c(0), 1284 ( , 1285 arg(1, C, C0), 1286 C1 is C0+1, 1287 nb_setarg(1, C, C1), 1288 C1 == Max 1289 -> Count = Max 1290 ; arg(1, C, Count) 1291 )
Abstract RDF graphs
The task of this module is to do some simple manipulations on RDF graphs represented as lists of
rdf(S,P,O)
. Supported operations: