35
36:- module(rdf_abstract,
37 [ merge_sameas_graph/3, 38 bagify_graph/4, 39 abstract_graph/3, 40 minimise_graph/2, 41
42 graph_resources/2, 43 graph_resources/4 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)). 55
72
85
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), 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), 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 ).
117
122
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).
151
152
156
157same_as(P, Super) :-
158 member(S, Super),
159 rdfs_subproperty_of(P, S),
160 !.
161
162
166
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 180
203
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).
233
237
238canonise_options(In, Out) :-
239 memberchk(_=_, In), 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).
252
253
254
255
260
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).
275
277
278has_class(Match, Class, Node) :-
279 class_of(Node, Match, Class).
280
283
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').
296
297
303
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 Bags,
315 resource_bags(ByClassT, NodeToEdges).
316
324
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).
342
343
348
349same_edges(NodeToEdges, Bags) :-
350 transpose_pairs(NodeToEdges, ByEdges), 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([_,_|_]).
357
364
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).
387
388
393
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).
409
413
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).
425
426
430
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).
439
440
444
445:- rdf_meta
446 statement(r,r,o,?,?). 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 475
484
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).
510
511
538
539:- meta_predicate
540 common_ancestor_forest(2, +, -). 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]).
549
553
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).
566
584
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).
594
595
606
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).
615
616
621
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).
636
637
641
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).
647
648
654
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).
660
667
668prune_root(Nodes, Root0, Root) :-
669 get_assoc(Root0, Nodes, node*[One]),
670 !,
671 prune_root(Nodes, One, Root).
672prune_root(_, Root, Root).
673
678
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 ).
687
692
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 715
725
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).
759
760
768
769map_graph(GraphIn, Map, GraphOut, AbstractMap) :-
770 map_graph(GraphIn, Map, GraphOut),
771 assoc_to_list(Map, ConcAbstr), 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).
777
778
788
789pairs_keys_intersection(Pairs, [K], Int) :- 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 ).
824
825
830
831map_to_bagged_graph(GraphIn, Map, GraphOut, Bags) :-
832 map_graph(GraphIn, Map, AbstractGraph, 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 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 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).
878
879
885
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).
898
899
909
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]).
921
922
931
932graph_resources(Graph, Resources) :-
933 graph_resources(Graph, R, P, P, T, T, [], _, _),
934 sort(R, Resources).
935
942
943graph_nodes(Graph, Nodes) :-
944 graph_resources(Graph, Nodes0, P, P, L, _, _, L, []),
945 sort(Nodes0, Nodes).
946
947
957
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 986
1017
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, _).
1035
1045
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).
1073
1077
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.
1102
1109
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).
1141
1142
1144
1145edge_map([], Map, Map).
1146edge_map([R|T], Map0, Map) :-
1147 get_assoc(R, Map0, _),
1148 !,
1149 edge_map(T, Map0, Map).
1154
1162
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).
1170
1176
1177broader(Term, Broader) :-
1178 rdf_reachable(Term, skos:broader, Broader),
1179 Broader \== Term.
1180
1189
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 1221
1233
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 1278
1279:- meta_predicate
1280 count(:, +, -). 1281
1282count(G, Max, Count) :-
1283 C = c(0),
1284 ( G,
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 )