--- /dev/null
+/* Author: Jan Wielemaker
+ WWW: http://www.swi-prolog.org
+ Copyright (c) 2001-2014, University of Amsterdam
+ VU University Amsterdam
+ All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+:- module(ordsets,
+ [ is_ordset/1, % @Term
+ list_to_ord_set/2, % +List, -OrdSet
+ ord_add_element/3, % +Set, +Element, -NewSet
+ ord_del_element/3, % +Set, +Element, -NewSet
+ ord_selectchk/3, % +Item, ?Set1, ?Set2
+ ord_intersect/2, % +Set1, +Set2 (test non-empty)
+ ord_intersect/3, % +Set1, +Set2, -Intersection
+ ord_intersection/3, % +Set1, +Set2, -Intersection
+ ord_intersection/4, % +Set1, +Set2, -Intersection, -Diff
+ ord_disjoint/2, % +Set1, +Set2
+ ord_subtract/3, % +Set, +Delete, -Remaining
+ ord_union/2, % +SetOfOrdSets, -Set
+ ord_union/3, % +Set1, +Set2, -Union
+ ord_union/4, % +Set1, +Set2, -Union, -New
+ ord_subset/2, % +Sub, +Super (test Sub is in Super)
+ % Non-Quintus extensions
+ ord_empty/1, % ?Set
+ ord_memberchk/2, % +Element, +Set,
+ ord_symdiff/3, % +Set1, +Set2, ?Diff
+ % SICSTus extensions
+ ord_seteq/2, % +Set1, +Set2
+ ord_intersection/2 % +PowerSet, -Intersection
+ ]).
+
+:- use_module(library(lists)).
+
+/** <module> Ordered set manipulation
+Ordered sets are lists with unique elements sorted to the standard order
+of terms (see sort/2). Exploiting ordering, many of the set operations
+can be expressed in order N rather than N^2 when dealing with unordered
+sets that may contain duplicates. The library(ordsets) is available in a
+number of Prolog implementations. Our predicates are designed to be
+compatible with common practice in the Prolog community. The
+implementation is incomplete and relies partly on library(oset), an
+older ordered set library distributed with SWI-Prolog. New applications
+are advised to use library(ordsets).
+Some of these predicates match directly to corresponding list
+operations. It is advised to use the versions from this library to make
+clear you are operating on ordered sets. An exception is member/2. See
+ord_memberchk/2.
+The ordsets library is based on the standard order of terms. This
+implies it can handle all Prolog terms, including variables. Note
+however, that the ordering is not stable if a term inside the set is
+further instantiated. Also note that variable ordering changes if
+variables in the set are unified with each other or a variable in the
+set is unified with a variable that is `older' than the newest variable
+in the set. In practice, this implies that it is allowed to use
+member(X, OrdSet) on an ordered set that holds variables only if X is a
+fresh variable. In other cases one should cease using it as an ordset
+because the order it relies on may have been changed.
+*/
+
+%! is_ordset(@Term) is semidet.
+%
+% True if Term is an ordered set. All predicates in this library
+% expect ordered sets as input arguments. Failing to fullfil this
+% assumption results in undefined behaviour. Typically, ordered
+% sets are created by predicates from this library, sort/2 or
+% setof/3.
+
+is_ordset(Term) :-
+ '$skip_max_list'(_, -1, Term, Tail), Tail == [], %% is_list(Term),
+ is_ordset2(Term).
+
+is_ordset2([]).
+is_ordset2([H|T]) :-
+ is_ordset3(T, H).
+
+is_ordset3([], _).
+is_ordset3([H2|T], H) :-
+ H2 @> H,
+ is_ordset3(T, H2).
+
+
+%! ord_empty(?List) is semidet.
+%
+% True when List is the empty ordered set. Simply unifies list
+% with the empty list. Not part of Quintus.
+
+ord_empty([]).
+
+
+%! ord_seteq(+Set1, +Set2) is semidet.
+%
+% True if Set1 and Set2 have the same elements. As both are
+% canonical sorted lists, this is the same as ==/2.
+%
+% @compat sicstus
+
+ord_seteq(Set1, Set2) :-
+ Set1 == Set2.
+
+
+%! list_to_ord_set(+List, -OrdSet) is det.
+%
+% Transform a list into an ordered set. This is the same as
+% sorting the list.
+
+list_to_ord_set(List, Set) :-
+ sort(List, Set).
+
+
+%! ord_intersect(+Set1, +Set2) is semidet.
+%
+% True if both ordered sets have a non-empty intersection.
+
+ord_intersect([H1|T1], L2) :-
+ ord_intersect_(L2, H1, T1).
+
+ord_intersect_([H2|T2], H1, T1) :-
+ compare(Order, H1, H2),
+ ord_intersect__(Order, H1, T1, H2, T2).
+
+ord_intersect__(<, _H1, T1, H2, T2) :-
+ ord_intersect_(T1, H2, T2).
+ord_intersect__(=, _H1, _T1, _H2, _T2).
+ord_intersect__(>, H1, T1, _H2, T2) :-
+ ord_intersect_(T2, H1, T1).
+
+
+%! ord_disjoint(+Set1, +Set2) is semidet.
+%
+% True if Set1 and Set2 have no common elements. This is the
+% negation of ord_intersect/2.
+
+ord_disjoint(Set1, Set2) :-
+ \+ ord_intersect(Set1, Set2).
+
+
+%! ord_intersect(+Set1, +Set2, -Intersection)
+%
+% Intersection holds the common elements of Set1 and Set2.
+%
+% @deprecated Use ord_intersection/3
+
+ord_intersect(Set1, Set2, Intersection) :-
+ oset_int(Set1, Set2, Intersection).
+
+
+%! ord_intersection(+PowerSet, -Intersection)
+%
+% Intersection of a powerset. True when Intersection is an ordered
+% set holding all elements common to all sets in PowerSet.
+%
+% @compat sicstus
+
+ord_intersection(PowerSet, Intersection) :-
+ key_by_length(PowerSet, Pairs),
+ keysort(Pairs, [_-S|Sorted]),
+ l_int(Sorted, S, Intersection).
+
+key_by_length([], []).
+key_by_length([H|T0], [L-H|T]) :-
+ length(H, L),
+ key_by_length(T0, T).
+
+l_int([], S, S).
+l_int([_-H|T], S0, S) :-
+ ord_intersection(S0, H, S1),
+ l_int(T, S1, S).
+
+
+%! ord_intersection(+Set1, +Set2, -Intersection) is det.
+%
+% Intersection holds the common elements of Set1 and Set2. Uses
+% ord_disjoint/2 if Intersection is bound to `[]` on entry.
+
+ord_intersection(Set1, Set2, Intersection) :-
+ ( Intersection == []
+ -> ord_disjoint(Set1, Set2)
+ ; oset_int(Set1, Set2, Intersection)
+ ).
+
+
+%! ord_intersection(+Set1, +Set2, ?Intersection, ?Difference) is det.
+%
+% Intersection and difference between two ordered sets.
+% Intersection is the intersection between Set1 and Set2, while
+% Difference is defined by ord_subtract(Set2, Set1, Difference).
+%
+% @see ord_intersection/3 and ord_subtract/3.
+
+ord_intersection([], L, [], L) :- !.
+ord_intersection([_|_], [], [], []) :- !.
+ord_intersection([H1|T1], [H2|T2], Intersection, Difference) :-
+ compare(Diff, H1, H2),
+ ord_intersection2(Diff, H1, T1, H2, T2, Intersection, Difference).
+
+ord_intersection2(=, H1, T1, _H2, T2, [H1|T], Difference) :-
+ ord_intersection(T1, T2, T, Difference).
+ord_intersection2(<, _, T1, H2, T2, Intersection, Difference) :-
+ ord_intersection(T1, [H2|T2], Intersection, Difference).
+ord_intersection2(>, H1, T1, H2, T2, Intersection, [H2|HDiff]) :-
+ ord_intersection([H1|T1], T2, Intersection, HDiff).
+
+
+%! ord_add_element(+Set1, +Element, ?Set2) is det.
+%
+% Insert an element into the set. This is the same as
+% ord_union(Set1, [Element], Set2).
+
+ord_add_element(Set1, Element, Set2) :-
+ oset_addel(Set1, Element, Set2).
+
+
+%! ord_del_element(+Set, +Element, -NewSet) is det.
+%
+% Delete an element from an ordered set. This is the same as
+% ord_subtract(Set, [Element], NewSet).
+
+ord_del_element(Set, Element, NewSet) :-
+ oset_delel(Set, Element, NewSet).
+
+
+%! ord_selectchk(+Item, ?Set1, ?Set2) is semidet.
+%
+% Selectchk/3, specialised for ordered sets. Is true when
+% select(Item, Set1, Set2) and Set1, Set2 are both sorted lists
+% without duplicates. This implementation is only expected to work
+% for Item ground and either Set1 or Set2 ground. The "chk" suffix
+% is meant to remind you of memberchk/2, which also expects its
+% first argument to be ground. ord_selectchk(X, S, T) =>
+% ord_memberchk(X, S) & \+ ord_memberchk(X, T).
+%
+% @author Richard O'Keefe
+
+ord_selectchk(Item, [X|Set1], [X|Set2]) :-
+ X @< Item,
+ !,
+ ord_selectchk(Item, Set1, Set2).
+ord_selectchk(Item, [Item|Set1], Set1) :-
+ ( Set1 == []
+ -> true
+ ; Set1 = [Y|_]
+ -> Item @< Y
+ ).
+
+
+%! ord_memberchk(+Element, +OrdSet) is semidet.
+%
+% True if Element is a member of OrdSet, compared using ==. Note
+% that _enumerating_ elements of an ordered set can be done using
+% member/2.
+%
+% Some Prolog implementations also provide ord_member/2, with the
+% same semantics as ord_memberchk/2. We believe that having a
+% semidet ord_member/2 is unacceptably inconsistent with the *_chk
+% convention. Portable code should use ord_memberchk/2 or
+% member/2.
+%
+% @author Richard O'Keefe
+
+ord_memberchk(Item, [X1,X2,X3,X4|Xs]) :-
+ !,
+ compare(R4, Item, X4),
+ ( R4 = (>) -> ord_memberchk(Item, Xs)
+ ; R4 = (<) ->
+ compare(R2, Item, X2),
+ ( R2 = (>) -> Item == X3
+ ; R2 = (<) -> Item == X1
+ ;/* R2 = (=), Item == X2 */ true
+ )
+ ;/* R4 = (=) */ true
+ ).
+ord_memberchk(Item, [X1,X2|Xs]) :-
+ !,
+ compare(R2, Item, X2),
+ ( R2 = (>) -> ord_memberchk(Item, Xs)
+ ; R2 = (<) -> Item == X1
+ ;/* R2 = (=) */ true
+ ).
+ord_memberchk(Item, [X1]) :-
+ Item == X1.
+
+
+%! ord_subset(+Sub, +Super) is semidet.
+%
+% Is true if all elements of Sub are in Super
+
+ord_subset([], _).
+ord_subset([H1|T1], [H2|T2]) :-
+ compare(Order, H1, H2),
+ ord_subset_(Order, H1, T1, T2).
+
+ord_subset_(>, H1, T1, [H2|T2]) :-
+ compare(Order, H1, H2),
+ ord_subset_(Order, H1, T1, T2).
+ord_subset_(=, _, T1, T2) :-
+ ord_subset(T1, T2).
+
+
+%! ord_subtract(+InOSet, +NotInOSet, -Diff) is det.
+%
+% Diff is the set holding all elements of InOSet that are not in
+% NotInOSet.
+
+ord_subtract(InOSet, NotInOSet, Diff) :-
+ oset_diff(InOSet, NotInOSet, Diff).
+
+
+%! ord_union(+SetOfSets, -Union) is det.
+%
+% True if Union is the union of all elements in the superset
+% SetOfSets. Each member of SetOfSets must be an ordered set, the
+% sets need not be ordered in any way.
+%
+% @author Copied from YAP, probably originally by Richard O'Keefe.
+
+ord_union([], []).
+ord_union([Set|Sets], Union) :-
+ length([Set|Sets], NumberOfSets),
+ ord_union_all(NumberOfSets, [Set|Sets], Union, []).
+
+ord_union_all(N, Sets0, Union, Sets) :-
+ ( N =:= 1
+ -> Sets0 = [Union|Sets]
+ ; N =:= 2
+ -> Sets0 = [Set1,Set2|Sets],
+ ord_union(Set1,Set2,Union)
+ ; A is N>>1,
+ Z is N-A,
+ ord_union_all(A, Sets0, X, Sets1),
+ ord_union_all(Z, Sets1, Y, Sets),
+ ord_union(X, Y, Union)
+ ).
+
+
+%! ord_union(+Set1, +Set2, ?Union) is det.
+%
+% Union is the union of Set1 and Set2
+
+ord_union(Set1, Set2, Union) :-
+ oset_union(Set1, Set2, Union).
+
+
+%! ord_union(+Set1, +Set2, -Union, -New) is det.
+%
+% True iff ord_union(Set1, Set2, Union) and
+% ord_subtract(Set2, Set1, New).
+
+ord_union([], Set2, Set2, Set2).
+ord_union([H|T], Set2, Union, New) :-
+ ord_union_1(Set2, H, T, Union, New).
+
+ord_union_1([], H, T, [H|T], []).
+ord_union_1([H2|T2], H, T, Union, New) :-
+ compare(Order, H, H2),
+ ord_union(Order, H, T, H2, T2, Union, New).
+
+ord_union(<, H, T, H2, T2, [H|Union], New) :-
+ ord_union_2(T, H2, T2, Union, New).
+ord_union(>, H, T, H2, T2, [H2|Union], [H2|New]) :-
+ ord_union_1(T2, H, T, Union, New).
+ord_union(=, H, T, _, T2, [H|Union], New) :-
+ ord_union(T, T2, Union, New).
+
+ord_union_2([], H2, T2, [H2|T2], [H2|T2]).
+ord_union_2([H|T], H2, T2, Union, New) :-
+ compare(Order, H, H2),
+ ord_union(Order, H, T, H2, T2, Union, New).
+
+
+%! ord_symdiff(+Set1, +Set2, ?Difference) is det.
+%
+% Is true when Difference is the symmetric difference of Set1 and
+% Set2. I.e., Difference contains all elements that are not in the
+% intersection of Set1 and Set2. The semantics is the same as the
+% sequence below (but the actual implementation requires only a
+% single scan).
+%
+% ==
+% ord_union(Set1, Set2, Union),
+% ord_intersection(Set1, Set2, Intersection),
+% ord_subtract(Union, Intersection, Difference).
+% ==
+%
+% For example:
+%
+% ==
+% ?- ord_symdiff([1,2], [2,3], X).
+% X = [1,3].
+% ==
+
+ord_symdiff([], Set2, Set2).
+ord_symdiff([H1|T1], Set2, Difference) :-
+ ord_symdiff(Set2, H1, T1, Difference).
+
+ord_symdiff([], H1, T1, [H1|T1]).
+ord_symdiff([H2|T2], H1, T1, Difference) :-
+ compare(Order, H1, H2),
+ ord_symdiff(Order, H1, T1, H2, T2, Difference).
+
+ord_symdiff(<, H1, Set1, H2, T2, [H1|Difference]) :-
+ ord_symdiff(Set1, H2, T2, Difference).
+ord_symdiff(=, _, T1, _, T2, Difference) :-
+ ord_symdiff(T1, T2, Difference).
+ord_symdiff(>, H1, T1, H2, Set2, [H2|Difference]) :-
+ ord_symdiff(Set2, H1, T1, Difference).
+
+/* The osets library on which ordsets depends.
+
+ Author: Jon Jagger
+ Copyright (c) 1993-2011, Jon Jagger
+ All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+/** <module> Ordered set manipulation
+
+This library defines set operations on sets represented as ordered
+lists.
+
+@author Jon Jagger
+@deprecated Use the de-facto library ordsets.pl
+*/
+
+
+%% oset_is(+OSet)
+% check that OSet in correct format (standard order)
+
+oset_is(-) :- !, fail. % var filter
+oset_is([]).
+oset_is([H|T]) :-
+ oset_is(T, H).
+
+oset_is(-, _) :- !, fail. % var filter
+oset_is([], _H).
+oset_is([H|T], H0) :-
+ H0 @< H, % use standard order
+ oset_is(T, H).
+
+
+
+%% oset_union(+OSet1, +OSet2, -Union).
+
+oset_union([], Union, Union).
+oset_union([H1|T1], L2, Union) :-
+ union2(L2, H1, T1, Union).
+
+union2([], H1, T1, [H1|T1]).
+union2([H2|T2], H1, T1, Union) :-
+ compare(Order, H1, H2),
+ union3(Order, H1, T1, H2, T2, Union).
+
+union3(<, H1, T1, H2, T2, [H1|Union]) :-
+ union2(T1, H2, T2, Union).
+union3(=, H1, T1, _H2, T2, [H1|Union]) :-
+ oset_union(T1, T2, Union).
+union3(>, H1, T1, H2, T2, [H2|Union]) :-
+ union2(T2, H1, T1, Union).
+
+
+%% oset_int(+OSet1, +OSet2, -Int)
+% ordered set intersection
+
+oset_int([], _Int, []).
+oset_int([H1|T1], L2, Int) :-
+ isect2(L2, H1, T1, Int).
+
+isect2([], _H1, _T1, []).
+isect2([H2|T2], H1, T1, Int) :-
+ compare(Order, H1, H2),
+ isect3(Order, H1, T1, H2, T2, Int).
+
+isect3(<, _H1, T1, H2, T2, Int) :-
+ isect2(T1, H2, T2, Int).
+isect3(=, H1, T1, _H2, T2, [H1|Int]) :-
+ oset_int(T1, T2, Int).
+isect3(>, H1, T1, _H2, T2, Int) :-
+ isect2(T2, H1, T1, Int).
+
+
+%% oset_diff(+InOSet, +NotInOSet, -Diff)
+% ordered set difference
+
+oset_diff([], _Not, []).
+oset_diff([H1|T1], L2, Diff) :-
+ diff21(L2, H1, T1, Diff).
+
+diff21([], H1, T1, [H1|T1]).
+diff21([H2|T2], H1, T1, Diff) :-
+ compare(Order, H1, H2),
+ diff3(Order, H1, T1, H2, T2, Diff).
+
+diff12([], _H2, _T2, []).
+diff12([H1|T1], H2, T2, Diff) :-
+ compare(Order, H1, H2),
+ diff3(Order, H1, T1, H2, T2, Diff).
+
+diff3(<, H1, T1, H2, T2, [H1|Diff]) :-
+ diff12(T1, H2, T2, Diff).
+diff3(=, _H1, T1, _H2, T2, Diff) :-
+ oset_diff(T1, T2, Diff).
+diff3(>, H1, T1, _H2, T2, Diff) :-
+ diff21(T2, H1, T1, Diff).
+
+
+%% oset_dunion(+SetofSets, -DUnion)
+% distributed union
+
+oset_dunion([], []).
+oset_dunion([H|T], DUnion) :-
+ oset_dunion(T, H, DUnion).
+
+oset_dunion([], DUnion, DUnion).
+oset_dunion([H|T], DUnion0, DUnion) :-
+ oset_union(H, DUnion0, DUnion1),
+ oset_dunion(T, DUnion1, DUnion).
+
+
+%% oset_dint(+SetofSets, -DInt)
+% distributed intersection
+
+oset_dint([], []).
+oset_dint([H|T], DInt) :-
+ dint(T, H, DInt).
+
+dint([], DInt, DInt).
+dint([H|T], DInt0, DInt) :-
+ oset_int(H, DInt0, DInt1),
+ dint(T, DInt1, DInt).
+
+
+%! oset_power(+Set, -PSet)
+%
+% True when PSet is the powerset of Set. That is, Pset is a set of
+% all subsets of Set, where each subset is a proper ordered set.
+
+oset_power(S, PSet) :-
+ reverse(S, R),
+ pset(R, [[]], PSet0),
+ sort(PSet0, PSet).
+
+
+% The powerset of a set is the powerset of a set of one smaller,
+% together with the set of one smaller where each subset is extended
+% with the new element. Note that this produces the elements of the set
+% in reverse order. Hence the reverse in oset_power/2.
+
+pset([], PSet, PSet).
+pset([H|T], PSet0, PSet) :-
+ happ(PSet0, H, PSet1),
+ pset(T, PSet1, PSet).
+
+happ([], _, []).
+happ([S|Ss], H, [[H|S],S|Rest]) :-
+ happ(Ss, H, Rest).
+
+%% oset_addel(+Set, +El, -Add)
+% ordered set element addition
+
+oset_addel([], El, [El]).
+oset_addel([H|T], El, Add) :-
+ compare(Order, H, El),
+ addel(Order, H, T, El, Add).
+
+addel(<, H, T, El, [H|Add]) :-
+ oset_addel(T, El, Add).
+addel(=, H, T, _El, [H|T]).
+addel(>, H, T, El, [El,H|T]).
+
+%% oset_delel(+Set, +El, -Del)
+% ordered set element deletion
+
+oset_delel([], _El, []).
+oset_delel([H|T], El, Del) :-
+ compare(Order, H, El),
+ delel(Order, H, T, El, Del).
+
+delel(<, H, T, El, [H|Del]) :-
+ oset_delel(T, El, Del).
+delel(=, _H, T, _El, T).
+delel(>, H, T, _El, [H|T]).