Files
mercury/library/diet.m
Julien Fischer a7a6db5112 Delete obsolete predicates from set modules.
library/diet.m:
library/fat_sparse_bitset.m:
library/set.m:
library/set_bbbtree.m:
library/set_ctree234.m:
library/set_ordlist.m:
library/set_tree234.m:
library/set_unordlist.m:
library/sparse_bitset.m:
library/tree_bitset.m:
    Delete predicates and functions that have been marked as obsolete
    since at least 2019.

    Adjust documentation as required.

NEWS:
    Announce the deletions.
2022-04-13 19:53:47 +10:00

1849 lines
54 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%---------------------------------------------------------------------------%
% Copyright (C) 2012-2014 YesLogic Pty. Ltd.
% Copyright (C) 2014-2015, 2017-2018, 2022 The Mercury team.
% This file is distributed under the terms specified in COPYING.LIB.
%---------------------------------------------------------------------------%
%
% File: diet.m.
% Author: wangp.
% Stability: medium.
%
% Discrete Interval Encoding Trees are a highly efficient set implementation
% for fat sets, i.e. densely populated sets over a discrete linear order.
%
% M. Erwig: Diets for Fat Sets,
% Journal of Functional Programming, Vol. 8, No. 6, pp. 627-632.
%
% O. Friedmann, M. Lange: More on Balanced Diets,
% Journal of Functional Programming, volume 21, issue 02, pp. 135-157.
%
%---------------------------------------------------------------------------%
:- module diet.
:- interface.
:- import_module bool.
:- import_module enum.
:- import_module list.
%---------------------------------------------------------------------------%
:- type diet(T). % <= diet_element(T).
:- typeclass diet_element(T) where [
% less_than(X, Y) succeeds iff X < Y.
pred less_than(T::in, T::in) is semidet,
% successor(X) returns the successor of X, e.g. X + 1.
func successor(T) = T,
% predecessor(X) returns the predecessor of X, e.g. X - 1.
func predecessor(T) = T
].
:- instance diet_element(int).
%---------------------------------------------------------------------------%
%
% Initial creation of sets.
%
% Return an empty set.
%
:- func init = diet(T).
:- pred init(diet(T)::out) is det.
% make_singleton_set(Elem) returns a set containing just the single
% element Elem.
%
:- func make_singleton_set(T) = diet(T) <= diet_element(T).
% make_interval_set(X, Y) returns a set containing just the elements in
% the interval [X, Y]. Throws an exception if Y < X.
%
:- func make_interval_set(T, T) = diet(T) <= diet_element(T).
%---------------------------------------------------------------------------%
%
% Emptiness and singleton-ness tests.
%
:- pred is_empty(diet(T)::in) is semidet.
:- pred is_non_empty(diet(T)::in) is semidet.
% is_singleton(Set, X) is true iff Set is a singleton containing the
% element X.
%
:- pred is_singleton(diet(T)::in, T::out) is semidet <= diet_element(T).
%---------------------------------------------------------------------------%
%
% Membership tests.
%
% member(X, Set) is true iff X is a member of Set.
%
:- pred member(T, diet(T)) <= diet_element(T).
:- mode member(in, in) is semidet.
:- mode member(out, in) is nondet.
% contains(Set, X) is true iff X is a member of Set.
%
:- pred contains(diet(T)::in, T::in) is semidet <= diet_element(T).
%---------------------------------------------------------------------------%
%
% Insertions and deletions.
%
% insert(X, Set0, Set) is true iff Set is the union of
% Set0 and the set containing only X.
%
:- func insert(diet(T), T) = diet(T) <= diet_element(T).
:- pred insert(T::in, diet(T)::in, diet(T)::out) is det <= diet_element(T).
% insert_interval(X, Y, Set0, Set) is true iff Set is the union of
% Set0 and the set containing only the elements of the interval [X, Y].
% Throws an exception if Y < X.
%
:- pred insert_interval(T::in, T::in, diet(T)::in, diet(T)::out) is det
<= diet_element(T).
% insert_new(X, Set0, Set) is true iff Set0 does not contain
% X, and Set is the union of Set0 and the set containing only X.
%
:- pred insert_new(T::in, diet(T)::in, diet(T)::out) is semidet
<= diet_element(T).
% insert_list(Xs, Set0, Set) is true iff Set is the union of
% Set0 and the set containing only the members of Xs.
%
:- func insert_list(diet(T), list(T)) = diet(T) <= diet_element(T).
:- pred insert_list(list(T)::in, diet(T)::in, diet(T)::out) is det
<= diet_element(T).
% delete(X, Set0, Set) is true iff Set is the relative
% complement of Set0 and the set containing only X, i.e.
% if Set is the set which contains all the elements of Set0
% except X.
%
:- func delete(diet(T), T) = diet(T) <= diet_element(T).
:- pred delete(T::in, diet(T)::in, diet(T)::out) is det <= diet_element(T).
% delete_list(Set, X) returns the difference of Set and the set
% containing only the members of X. Same as
% `difference(Set, list_to_set(X))', but may be more efficient.
%
:- func delete_list(diet(T), list(T)) = diet(T) <= diet_element(T).
:- pred delete_list(list(T)::in, diet(T)::in, diet(T)::out) is det
<= diet_element(T).
% remove(X, Set0, Set) is true iff Set0 contains X,
% and Set is the relative complement of Set0 and the set
% containing only X, i.e. if Set is the set which contains
% all the elements of Set0 except X.
%
:- pred remove(T::in, diet(T)::in, diet(T)::out) is semidet <= diet_element(T).
% remove_list(X, Set0, Set) returns in Set the difference of Set0
% and the set containing all the elements of X, failing if any element
% of X is not in Set0. Same as `subset(list_to_set(X), Set0),
% difference(Set0, list_to_set(X), Set)', but may be more efficient.
%
:- pred remove_list(list(T)::in, diet(T)::in, diet(T)::out) is semidet
<= diet_element(T).
% remove_least(X, Set0, Set) is true iff X is the least element in
% Set0, and Set is the set which contains all the elements of Set0
% except X.
%
:- pred remove_least(T::out, diet(T)::in, diet(T)::out) is semidet
<= diet_element(T).
%---------------------------------------------------------------------------%
%
% Comparisons between sets.
%
% equal(SetA, SetB) is true iff SetA and SetB contain the same
% elements.
%
:- pred equal(diet(T)::in, diet(T)::in) is semidet <= diet_element(T).
% subset(Subset, Set) is true iff Subset is a subset of Set.
%
:- pred subset(diet(T)::in, diet(T)::in) is semidet <= diet_element(T).
% superset(Superset, Set) is true iff Superset is a superset of Set.
%
:- pred superset(diet(T)::in, diet(T)::in) is semidet <= diet_element(T).
%---------------------------------------------------------------------------%
%
% Operations on two or more sets.
%
% union(SetA, SetB, Set) is true iff Set is the union of SetA and SetB.
%
:- func union(diet(T), diet(T)) = diet(T) <= diet_element(T).
:- pred union(diet(T)::in, diet(T)::in, diet(T)::out) is det
<= diet_element(T).
% union_list(Sets, Set) returns the union of all the sets in Sets.
%
:- func union_list(list(diet(T))) = diet(T) <= diet_element(T).
:- pred union_list(list(diet(T))::in, diet(T)::out) is det <= diet_element(T).
% intersect(SetA, SetB, Set) is true iff Set is the
% intersection of SetA and SetB.
%
:- func intersect(diet(T), diet(T)) = diet(T) <= diet_element(T).
:- pred intersect(diet(T)::in, diet(T)::in, diet(T)::out) is det
<= diet_element(T).
% intersect_list(Sets, Set) returns the intersection of all the sets
% in Sets.
%
:- func intersect_list(list(diet(T))) = diet(T) <= diet_element(T).
:- pred intersect_list(list(diet(T))::in, diet(T)::out) is det
<= diet_element(T).
% difference(SetA, SetB) returns the set containing all the elements
% of SetA except those that occur in SetB.
%
:- func difference(diet(T), diet(T)) = diet(T) <= diet_element(T).
:- pred difference(diet(T)::in, diet(T)::in, diet(T)::out) is det
<= diet_element(T).
%---------------------------------------------------------------------------%
%
% Operations that divide a set into two parts.
%
% split(X, Set, Lesser, IsPresent, Greater) is true iff
% Lesser is the set of elements in Set which are less than X and
% Greater is the set of elements in Set which are greater than X.
% IsPresent is `yes' if Set contains X, and `no' otherwise.
%
:- pred split(T::in, diet(T)::in, diet(T)::out, bool::out, diet(T)::out) is det
<= diet_element(T).
% divide(Pred, Set, InPart, OutPart):
% InPart consists of those elements of Set for which Pred succeeds;
% OutPart consists of those elements of Set for which Pred fails.
%
:- pred divide(pred(T)::in(pred(in) is semidet), diet(T)::in,
diet(T)::out, diet(T)::out) is det <= diet_element(T).
% divide_by_set(DivideBySet, Set, InPart, OutPart):
% InPart consists of those elements of Set which are also in DivideBySet;
% OutPart consists of those elements of Set which are not in DivideBySet.
%
:- pred divide_by_set(diet(T)::in, diet(T)::in, diet(T)::out, diet(T)::out)
is det <= diet_element(T).
%---------------------------------------------------------------------------%
%
% Converting lists to sets.
%
% list_to_set(List) returns a set containing only the members of List.
%
:- func list_to_set(list(T)) = diet(T) <= diet_element(T).
:- pred list_to_set(list(T)::in, diet(T)::out) is det <= diet_element(T).
:- func from_list(list(T)) = diet(T) <= diet_element(T).
:- pred from_list(list(T)::in, diet(T)::out) is det <= diet_element(T).
% from_interval_list(Intervals, Set) returns a Set containing the
% elements of all intervals [X, Y] in Intervals, where each interval is
% represented by a tuple. Throws an exception if any interval has Y < X.
% The intervals may overlap.
%
:- pred from_interval_list(list({T, T})::in, diet(T)::out) is det
<= diet_element(T).
% sorted_list_to_set(List) returns a set containing only the members
% of List. List must be sorted.
%
:- func sorted_list_to_set(list(T)) = diet(T) <= diet_element(T).
:- pred sorted_list_to_set(list(T)::in, diet(T)::out) is det
<= diet_element(T).
%---------------------------------------------------------------------------%
%
% Converting sets to lists.
%
% to_sorted_list(Set) returns a list containing all the members of Set,
% in sorted order.
%
:- func to_sorted_list(diet(T)) = list(T) <= diet_element(T).
:- pred to_sorted_list(diet(T)::in, list(T)::out) is det <= diet_element(T).
% to_sorted_interval_list(Set) returns a list of intervals in Set
% in sorted order, where each interval is represented by a tuple.
% The intervals do not overlap.
%
:- pred to_sorted_interval_list(diet(T)::in, list({T, T})::out) is det
<= diet_element(T).
%---------------------------------------------------------------------------%
%
% Counting.
%
% count(Set) returns the number of elements in Set.
%
:- func count(diet(T)) = int <= enum(T).
%---------------------------------------------------------------------------%
%
% Standard higher order functions on collections.
%
% all_true(Pred, Set) succeeds iff Pred(Element) succeeds
% for all the elements of Set.
%
:- pred all_true(pred(T)::in(pred(in) is semidet), diet(T)::in) is semidet
<= diet_element(T).
% filter(Pred, Set) returns the elements of Set for which Pred succeeds.
%
:- func filter(pred(T), diet(T)) = diet(T) <= diet_element(T).
:- mode filter(pred(in) is semidet, in) = out is det.
% filter(Pred, Set, TrueSet, FalseSet) returns the elements of Set
% for which Pred succeeds, and those for which it fails.
%
:- pred filter(pred(T), diet(T), diet(T), diet(T)) <= diet_element(T).
:- mode filter(pred(in) is semidet, in, out, out) is det.
% foldl_intervals(Pred, Set, Start) calls Pred with each interval of
% Set (in sorted order) and an accumulator (with the initial value of
% Start), and returns the final value.
%
:- pred foldl_intervals(pred(T, T, A, A), diet(T), A, A) <= diet_element(T).
:- mode foldl_intervals(pred(in, in, in, out) is det, in, in, out) is det.
:- mode foldl_intervals(pred(in, in, di, uo) is det, in, di, uo) is det.
:- mode foldl_intervals(pred(in, in, in, out) is semidet, in, in, out)
is semidet.
% foldr_intervals(Pred, Set, Start) calls Pred with each interval of
% Set (in reverse sorted order) and an accumulator (with the initial
% value of Start), and returns the final value.
%
:- pred foldr_intervals(pred(T, T, A, A), diet(T), A, A) <= diet_element(T).
:- mode foldr_intervals(pred(in, in, in, out) is det, in, in, out) is det.
:- mode foldr_intervals(pred(in, in, di, uo) is det, in, di, uo) is det.
:- mode foldr_intervals(pred(in, in, in, out) is semidet, in, in, out)
is semidet.
% foldl(Func, Set, Start) calls Func with each element of Set
% (in sorted order) and an accumulator (with the initial value of Start),
% and returns the final value.
%
:- func foldl(func(T, A) = A, diet(T), A) = A <= diet_element(T).
:- pred foldl(pred(T, A, A), diet(T), A, A) <= diet_element(T).
:- mode foldl(pred(in, in, out) is det, in, in, out) is det.
:- mode foldl(pred(in, mdi, muo) is det, in, mdi, muo) is det.
:- mode foldl(pred(in, di, uo) is det, in, di, uo) is det.
:- mode foldl(pred(in, in, out) is semidet, in, in, out) is semidet.
:- mode foldl(pred(in, mdi, muo) is semidet, in, mdi, muo) is semidet.
:- mode foldl(pred(in, di, uo) is semidet, in, di, uo) is semidet.
:- pred foldl2(pred(T, A, A, B, B), diet(T), A, A, B, B) <= diet_element(T).
:- mode foldl2(pred(in, in, out, in, out) is det, in,
in, out, in, out) is det.
:- mode foldl2(pred(in, in, out, mdi, muo) is det, in,
in, out, mdi, muo) is det.
:- mode foldl2(pred(in, in, out, di, uo) is det, in,
in, out, di, uo) is det.
:- mode foldl2(pred(in, in, out, in, out) is semidet, in,
in, out, in, out) is semidet.
:- mode foldl2(pred(in, in, out, mdi, muo) is semidet, in,
in, out, mdi, muo) is semidet.
:- mode foldl2(pred(in, in, out, di, uo) is semidet, in,
in, out, di, uo) is semidet.
:- pred foldl3(pred(T, A, A, B, B, C, C), diet(T),
A, A, B, B, C, C) <= diet_element(T).
:- mode foldl3(pred(in, in, out, in, out, in, out) is det, in,
in, out, in, out, in, out) is det.
:- mode foldl3(pred(in, in, out, in, out, mdi, muo) is det, in,
in, out, in, out, mdi, muo) is det.
:- mode foldl3(pred(in, in, out, in, out, di, uo) is det, in,
in, out, in, out, di, uo) is det.
:- mode foldl3(pred(in, in, out, in, out, in, out) is semidet, in,
in, out, in, out, in, out) is semidet.
:- mode foldl3(pred(in, in, out, in, out, mdi, muo) is semidet, in,
in, out, in, out, mdi, muo) is semidet.
:- mode foldl3(pred(in, in, out, in, out, di, uo) is semidet, in,
in, out, in, out, di, uo) is semidet.
:- pred foldl4(pred(T, A, A, B, B, C, C, D, D), diet(T),
A, A, B, B, C, C, D, D) <= diet_element(T).
:- mode foldl4(pred(in, in, out, in, out, in, out, in, out) is det, in,
in, out, in, out, in, out, in, out) is det.
:- mode foldl4(pred(in, in, out, in, out, in, out, mdi, muo) is det, in,
in, out, in, out, in, out, mdi, muo) is det.
:- mode foldl4(pred(in, in, out, in, out, in, out, di, uo) is det, in,
in, out, in, out, in, out, di, uo) is det.
:- mode foldl4(pred(in, in, out, in, out, in, out, in, out) is semidet, in,
in, out, in, out, in, out, in, out) is semidet.
:- mode foldl4(pred(in, in, out, in, out, in, out, mdi, muo) is semidet, in,
in, out, in, out, in, out, mdi, muo) is semidet.
:- mode foldl4(pred(in, in, out, in, out, in, out, di, uo) is semidet, in,
in, out, in, out, in, out, di, uo) is semidet.
:- pred foldl5(pred(T, A, A, B, B, C, C, D, D, E, E), diet(T),
A, A, B, B, C, C, D, D, E, E) <= diet_element(T).
:- mode foldl5(
pred(in, in, out, in, out, in, out, in, out, in, out) is det,
in, in, out, in, out, in, out, in, out, in, out) is det.
:- mode foldl5(
pred(in, in, out, in, out, in, out, in, out, mdi, muo) is det,
in, in, out, in, out, in, out, in, out, mdi, muo) is det.
:- mode foldl5(
pred(in, in, out, in, out, in, out, in, out, di, uo) is det,
in, in, out, in, out, in, out, in, out, di, uo) is det.
:- mode foldl5(
pred(in, in, out, in, out, in, out, in, out, in, out) is semidet,
in, in, out, in, out, in, out, in, out, in, out) is semidet.
:- mode foldl5(
pred(in, in, out, in, out, in, out, in, out, mdi, muo) is semidet,
in, in, out, in, out, in, out, in, out, mdi, muo) is semidet.
:- mode foldl5(
pred(in, in, out, in, out, in, out, in, out, di, uo) is semidet,
in, in, out, in, out, in, out, in, out, di, uo) is semidet.
:- func foldr(func(T, A) = A, diet(T), A) = A <= diet_element(T).
:- pred foldr(pred(T, A, A), diet(T), A, A) <= diet_element(T).
:- mode foldr(pred(in, in, out) is det, in, in, out) is det.
:- mode foldr(pred(in, mdi, muo) is det, in, mdi, muo) is det.
:- mode foldr(pred(in, di, uo) is det, in, di, uo) is det.
:- mode foldr(pred(in, in, out) is semidet, in, in, out) is semidet.
:- mode foldr(pred(in, mdi, muo) is semidet, in, mdi, muo) is semidet.
:- mode foldr(pred(in, di, uo) is semidet, in, di, uo) is semidet.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
% This file is, in large parts, a translation of Caml Diet.
% https://github.com/tcsprojects/camldiets
/***********************************************************
* CAML DIET *
* *
* Copyright (c) 2010 *
* Distributed under the BSD license. *
* *
* Oliver Friedmann *
* Oliver.Friedmann@gmail.com *
* University of Munich *
* *
* Martin Lange *
* Martin.Lange@gmail.com *
* University of Kassel *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* The code for handling the AVL trees is borrowed from *
* the Objective Caml Standard Library Set module. *
* *
* (c) Xavier Leroy, projet Cristal, INRIA Rocquencourt *
* *
***********************************************************/
:- import_module int.
:- import_module maybe.
:- import_module require.
:- import_module string.
%---------------------------------------------------------------------------%
:- type diet(T)
---> empty
; node(
interval :: interval(T),
node_height :: int,
left :: diet(T),
right :: diet(T)
).
% It may be better to fold the arguments into node but it should be
% verified with benchmarking. The change would affect the arguments of
% take_min, etc.
%
:- type interval(T) == {T, T}. % inclusive
:- inst node for diet/1
---> node(ground, ground, ground, ground).
%---------------------------------------------------------------------------%
:- instance diet_element(int) where [
less_than(X, Y) :- int.'<'(X, Y),
successor(X) = X + 1,
predecessor(X) = X - 1
].
:- func safe_predecessor(T, T) = T <= diet_element(T).
safe_predecessor(Limit, X) =
( if less_than(Limit, X) then predecessor(X) else X ).
:- pred T < T <= diet_element(T).
:- mode in < in is semidet.
X < Y :-
less_than(X, Y).
:- pred T > T <= diet_element(T).
:- mode in > in is semidet.
X > Y :-
less_than(Y, X).
:- pred T >= T <= diet_element(T).
:- mode in >= in is semidet.
X >= Y :-
not less_than(X, Y).
:- pred T =< T <= diet_element(T).
:- mode in =< in is semidet.
X =< Y :-
not less_than(Y, X).
:- func min_elem(T, T) = T <= diet_element(T).
min_elem(X, Y) = ( if X < Y then X else Y ).
:- func max_elem(T, T) = T <= diet_element(T).
max_elem(X, Y) = ( if X > Y then X else Y ).
:- pred int_gt(int::in, int::in) is semidet.
int_gt(X, Y) :-
int.'>'(X, Y).
:- pred int_ge(int::in, int::in) is semidet.
int_ge(X, Y) :-
int.'>='(X, Y).
%---------------------------------------------------------------------------%
:- func bal_const = int.
bal_const = 1.
:- func singleton(interval(T)) = diet(T).
singleton(Z) = node(Z, 1, empty, empty).
:- func height(diet(T)) = int.
height(empty) = 0.
height(node(_, H, _, _)) = H.
:- func height_join(diet(T), diet(T)) = int.
height_join(L, R) = 1 + max(height(L), height(R)).
:- func create(interval(T), diet(T), diet(T)) = diet(T).
create(X, L, R) = node(X, height_join(L, R), L, R).
:- func balance(interval(T), diet(T), diet(T)) = diet(T).
balance(X, L, R) = T :-
HL = height(L),
HR = height(R),
( if int_gt(HL, HR + bal_const) then
(
L = empty,
unexpected($pred, "L empty")
;
L = node(LVX, _, LL, LR),
( if int_ge(height(LL), height(LR)) then
T = create(LVX, LL, create(X, LR, R))
else
(
LR = empty,
unexpected($pred, "LR empty")
;
LR = node(LRX, _, LRL, LRR),
T = create(LRX, create(LVX, LL, LRL), create(X, LRR, R))
)
)
)
else if int_gt(HR, HL + bal_const) then
(
R = empty,
unexpected($pred, "R empty")
;
R = node(RVX, _, RL, RR),
( if int_ge(height(RR), height(RL)) then
T = create(RVX, create(X, L, RL), RR)
else
(
RL = empty,
unexpected($pred, "RL empty")
;
RL = node(RLX, _, RLL, RLR),
T = create(RLX, create(X, L, RLL), create(RVX, RLR, RR))
)
)
)
else
HT = 1 + max(HL, HR),
T = node(X, HT, L, R)
).
:- func join(interval(T), diet(T), diet(T)) = diet(T) <= diet_element(T).
join(V, L, R) = T :-
(
L = empty,
T = myadd(yes, V, R)
;
R = empty,
L = node(_, _, _, _),
T = myadd(no, V, L)
;
L = node(LX, LH, LL, LR),
R = node(RX, RH, RL, RR),
( if int_gt(LH, RH + bal_const) then
T = balance(LX, LL, join(V, LR, R))
else if int_gt(RH, LH + bal_const) then
T = balance(RX, join(V, L, RL), RR)
else
T = create(V, L, R)
)
).
:- func myadd(bool, interval(T), diet(T)) = diet(T).
myadd(IsLeft, X, T0) = T :-
(
T0 = empty,
T = node(X, 1, empty, empty)
;
T0 = node(VX, _, L, R),
(
IsLeft = yes,
T = balance(VX, myadd(IsLeft, X, L), R)
;
IsLeft = no,
T = balance(VX, L, myadd(IsLeft, X, R))
)
).
:- pred take_min(diet(T)::in(node), interval(T)::out, diet(T)::out) is det
<= diet_element(T).
take_min(T0, X, T) :-
(
T0 = node(X, _, empty, T)
;
T0 = node(X0, _, node(_, _, _, _) @ L, R),
take_min(L, X, L1),
T = join(X0, L1, R)
).
:- pred take_max(diet(T)::in(node), interval(T)::out, diet(T)::out) is det
<= diet_element(T).
take_max(T0, X, T) :-
(
T0 = node(X, _, T, empty)
;
T0 = node(X0, _, L, node(_, _, _, _) @ R),
take_max(R, X, R1),
T = join(X0, L, R1)
).
:- func reroot(diet(T), diet(T)) = diet(T) <= diet_element(T).
reroot(L, R) = T :-
( if int_gt(height(L), height(R)) then
(
L = empty,
unexpected($pred, "L empty")
;
L = node(_, _, _, _),
take_max(L, I, L1),
T = join(I, L1, R)
)
else
(
R = empty,
T = empty
;
R = node(_, _, _, _),
take_min(R, I, R1),
T = join(I, L, R1)
)
).
:- pred take_min_iter(diet(T)::in(node), interval(T)::out, diet(T)::out)
is det <= diet_element(T).
take_min_iter(T0, X, T) :-
(
T0 = node(X, _, empty, T)
;
T0 = node(X0, _, node(A, _, L, M), R),
N0 = node(X0, height_join(M, R), M, R),
N1 = node(A, height_join(L, N0), L, N0),
take_min_iter(N1, X, T)
).
:- pred take_min_iter2(diet(T)::in, maybe(interval(T))::out, diet(T)::out)
is det <= diet_element(T).
take_min_iter2(T0, MaybeX, T) :-
(
T0 = empty,
MaybeX = no,
T = empty
;
T0 = node(_, _, _, _),
take_min_iter(T0, X, T),
MaybeX = yes(X)
).
%---------------------------------------------------------------------------%
:- pred unexpected_interval(string::in, T::in, T::in) is erroneous.
unexpected_interval(PredName, X, Y) :-
unexpected($module, PredName,
"bad interval [" ++ string(X) ++ ", " ++ string(Y) ++ "]").
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
init = empty.
init(empty).
make_singleton_set(X) = singleton({X, X}).
make_interval_set(X, Y) = T :-
( if X =< Y then
T = singleton({X, Y})
else
unexpected_interval($pred, X, Y)
).
%---------------------------------------------------------------------------%
is_empty(empty).
is_non_empty(node(_, _, _, _)).
is_singleton(Set, X) :-
Set = node({X, X}, _, empty, empty).
%---------------------------------------------------------------------------%
:- pragma promise_equivalent_clauses(pred(member/2)).
member(Elem::in, Set::in) :-
contains(Set, Elem).
member(Elem::out, Set::in) :-
Set = node({X, Y}, _, Left, Right),
(
member(Elem, Left)
;
member_in_range(X, Y, Elem)
;
member(Elem, Right)
).
:- pred member_in_range(T::in, T::in, T::out) is multi <= diet_element(T).
member_in_range(Lo, Hi, Elem) :-
% Leave a choice point only if there is at least one solution
% to find on backtracking.
( if Lo < Hi then
(
Elem = Lo
;
member_in_range(successor(Lo), Hi, Elem)
)
else
Elem = Lo
).
contains(T, Z) :-
T = node({X, Y}, _, L, R),
( if Z < X then
contains(L, Z)
else if Z > Y then
contains(R, Z)
else
true
).
%---------------------------------------------------------------------------%
insert(Set0, Elem) = Set :-
insert(Elem, Set0, Set).
insert(Elem, Set0, Set) :-
Set = add(Elem, Set0).
:- func add(T, diet(T)) = diet(T) <= diet_element(T).
add(P, T0) = T :-
(
T0 = empty,
T = node({P, P}, 1, empty, empty)
;
T0 = node({X, Y}, H, Left, Right),
( if P >= X then
( if P =< Y then
T = T0
else if P > successor(Y) then
T = join({X, Y}, Left, add(P, Right))
else
(
Right = empty,
T = node({X, P}, H, Left, Right)
;
Right = node(_, _, _, _),
take_min(Right, {U, V}, R),
( if predecessor(U) = P then
T = join({X, V}, Left, R)
else
T = node({X, P}, H, Left, Right)
)
)
)
else if P < predecessor(X) then
T = join({X, Y}, add(P, Left), Right)
else
(
Left = empty,
T = node({P, Y}, H, Left, Right)
;
Left = node(_, _, _, _),
take_max(Left, {U, V}, L),
( if successor(V) = P then
T = join({U, Y}, L, Right)
else
T = node({P, Y}, H, Left, Right)
)
)
)
).
%---------------------%
insert_interval(X, Y, Set0, Set) :-
( if X =< Y then
Set = do_insert({X, Y}, Set0)
else
unexpected_interval($pred, X, Y)
).
:- pred insert_interval({T, T}::in, diet(T)::in, diet(T)::out) is det
<= diet_element(T).
insert_interval({X, Y}, Set0, Set) :-
insert_interval(X, Y, Set0, Set).
:- func do_insert(interval(T), diet(T)) = diet(T) <= diet_element(T).
do_insert(PQ, T0) = T :-
PQ = {P, Q},
(
T0 = empty,
T = singleton(PQ)
;
T0 = node({X0, Y0}, _, Left0, Right0),
( if Q < predecessor(X0) then
T = join({X0, Y0}, do_insert(PQ, Left0), Right0)
else if P > successor(Y0) then
T = join({X0, Y0}, Left0, do_insert(PQ, Right0))
else
( if P >= X0 then
X1 = X0,
Left1 = Left0
else
find_del_left(P, Left0, X1, Left1)
),
( if Q =< Y0 then
Y1 = Y0,
Right1 = Right0
else
find_del_right(Q, Right0, Y1, Right1)
),
T = join({X1, Y1}, Left1, Right1)
)
).
:- pred find_del_left(T::in, diet(T)::in, T::out, diet(T)::out) is det
<= diet_element(T).
find_del_left(P0, T0, P, T) :-
(
T0 = empty,
P = P0,
T = empty
;
T0 = node({X, Y}, _, Left, Right0),
( if P0 > successor(Y) then
find_del_left(P0, Right0, P, Right1),
T = join({X, Y}, Left, Right1)
else
P = X,
T = Left
)
).
:- pred find_del_right(T::in, diet(T)::in, T::out, diet(T)::out) is det
<= diet_element(T).
find_del_right(P0, T0, P, T) :-
(
T0 = empty,
P = P0,
T = empty
;
T0 = node({X, Y}, _, Left0, Right),
( if P0 < predecessor(X) then
find_del_right(P0, Left0, P, Left1),
T = join({X, Y}, Left1, Right)
else
P = Y,
T = Right
)
).
%---------------------%
insert_new(P, T0, T) :-
(
T0 = empty,
T = node({P, P}, 1, empty, empty)
;
T0 = node({X, Y}, H, Left, Right),
( if P >= X then
( if P =< Y then
% Already exists.
fail
else if P > successor(Y) then
insert_new(P, Right, R),
T = join({X, Y}, Left, R)
else
(
Right = empty,
T = node({X, P}, H, Left, Right)
;
Right = node(_, _, _, _),
take_min(Right, {U, V}, R),
( if predecessor(U) = P then
T = join({X, V}, Left, R)
else
T = node({X, P}, H, Left, Right)
)
)
)
else if P < predecessor(X) then
insert_new(P, Left, L),
T = join({X, Y}, L, Right)
else
(
Left = empty,
T = node({P, Y}, H, Left, Right)
;
Left = node(_, _, _, _),
take_max(Left, {U, V}, L),
( if successor(V) = P then
T = join({U, V}, L, Right)
else
T = node({P, Y}, H, Left, Right)
)
)
)
).
%---------------------%
insert_list(Set0, Elems) = Set :-
insert_list(Elems, Set0, Set).
insert_list(Elems, Set0, Set) :-
foldl(insert, Elems, Set0, Set).
%---------------------%
delete(Set0, Elem) = Set :-
delete(Elem, Set0, Set).
delete(Elem, Set0, Set) :-
( if remove(Elem, Set0, Set1) then
Set = Set1
else
Set = Set0
).
%---------------------%
delete_list(Set0, List) = Set :-
delete_list(List, Set0, Set).
delete_list(List, Set0, Set) :-
difference(Set0, list_to_set(List), Set).
%---------------------------------------------------------------------------%
remove(_Z, empty, _T) :-
fail.
remove(Z, T0, T) :-
T0 = node({X, Y}, H, Left, Right),
compare(CZX, Z, X),
(
CZX = (<),
remove(Z, Left, L),
T = join({X, Y}, L, Right)
;
( CZX = (=)
; CZX = (>)
),
compare(CZY, Z, Y),
(
CZY = (=),
(
CZX = (=),
T = reroot(Left, Right)
;
CZX = (>),
T = node({X, predecessor(Y)}, H, Left, Right)
)
;
CZY = (<),
(
CZX = (=),
T = node({successor(X), Y}, H, Left, Right)
;
CZX = (>),
T = do_insert({successor(Z), Y},
node({X, predecessor(Z)}, H, Left, Right))
)
;
CZY = (>),
remove(Z, Right, R),
T = join({X, Y}, Left, R)
)
).
%---------------------%
remove_list(X, Set0, Set) :-
list_to_set(X, SetX),
subset(SetX, Set0),
difference(Set0, SetX, Set).
%---------------------%
remove_least(X, Set0, Set) :-
(
Set0 = empty,
fail
;
Set0 = node(_, _, _, _),
take_min(Set0, {X, Y}, Stream),
( if X = Y then
Set = Stream
else
Set = do_insert({successor(X), Y}, Stream)
)
).
%---------------------------------------------------------------------------%
equal(T1, T2) :-
(
T1 = empty,
T2 = empty
;
T1 = node(_, _, _, _),
T2 = node(_, _, _, _),
take_min_iter(T1, {X, Y}, R1),
take_min_iter(T2, {X, Y}, R2),
equal(R1, R2)
).
subset(T1, T2) :-
(
T1 = empty
;
T1 = node(_, _, _, _),
T2 = node(_, _, _, _),
take_min_iter(T1, XY1, R1),
take_min_iter(T2, XY2, R2),
subset_2(XY1, R1, XY2, R2, yes)
).
:- pred subset_2(interval(T)::in, diet(T)::in, interval(T)::in, diet(T)::in,
bool::out) is det <= diet_element(T).
subset_2({X1, Y1}, R1, {X2, Y2}, R2, IsSubset) :-
( if X1 < X2 then
IsSubset = no
else if X1 > Y2 then
(
R2 = empty,
IsSubset = no
;
R2 = node(_, _, _, _),
take_min_iter(R2, Min2, MinR2),
subset_2({X1, Y1}, R1, Min2, MinR2, IsSubset)
)
else
compare(Upper, Y1, Y2),
(
Upper = (<),
(
R1 = empty,
IsSubset = yes
;
R1 = node(_, _, _, _),
take_min_iter(R1, Min1, MinR1),
subset_2(Min1, MinR1, {X2, Y2}, R2, IsSubset)
)
;
Upper = (=),
(
R1 = empty,
IsSubset = yes
;
R1 = node(_, _, _, _),
R2 = empty,
IsSubset = no
;
R1 = node(_, _, _, _),
R2 = node(_, _, _, _),
take_min_iter(R1, Min1, MinR1),
take_min_iter(R2, Min2, MinR2),
subset_2(Min1, MinR1, Min2, MinR2, IsSubset)
)
;
Upper = (>),
IsSubset = no
)
).
superset(Superset, Set) :-
subset(Set, Superset).
%---------------------------------------------------------------------------%
union(DietA, DietB) = DietAB :-
union(DietA, DietB, DietAB).
union(Input, Stream0, Result) :-
( if int_gt(height(Stream0), height(Input)) then
Result = union(Stream0, Input)
else
take_min_iter2(Stream0, Head1, Stream1),
union_2(Input, no, Head1, Stream1, Left2, Head2, Stream2),
(
Head2 = no,
Result = Left2
;
Head2 = yes(I),
Result = join(I, Left2, Stream2)
)
).
:- pred union_2(diet(T)::in, maybe(T)::in, maybe({T, T})::in,
diet(T)::in, diet(T)::out, maybe({T, T})::out, diet(T)::out) is det
<= diet_element(T).
union_2(Input, Limit, Head0, Stream0, Left, Head, Stream) :-
(
Head0 = no,
Left = Input,
Head = no,
Stream = empty
;
Head0 = yes({X, _Y}),
(
Input = empty,
Left = empty,
Head = Head0,
Stream = Stream0
;
Input = node({A, B}, _, Left0, Right0),
( if X < A then
union_2(Left0, yes(predecessor(A)), Head0, Stream0,
Left1, Head1, Stream1)
else
Left1 = Left0,
Head1 = Head0,
Stream1 = Stream0
),
union_helper(Left1, {A, B}, Right0, Limit, Head1, Stream1,
Left, Head, Stream)
)
).
:- pred union_helper(diet(T)::in, {T, T}::in, diet(T)::in,
maybe(T)::in, maybe({T, T})::in, diet(T)::in,
diet(T)::out, maybe({T, T})::out, diet(T)::out) is det <= diet_element(T).
union_helper(Left0, {A, B}, Right0, Limit, Head0, Stream0,
Left, Head, Stream) :-
(
Head0 = no,
Left = join({A, B}, Left0, Right0),
Head = no,
Stream = empty
;
Head0 = yes({X, Y}),
( if
Y < A,
Y < predecessor(A)
then
Left1 = do_insert({X, Y}, Left0),
take_min_iter2(Stream0, Head1, Stream1),
union_helper(Left1, {A, B}, Right0, Limit, Head1, Stream1,
Left, Head, Stream)
else if
X > B,
X > successor(B)
then
union_2(Right0, Limit, Head0, Stream0,
Right1, Head1, Stream1),
Left = join({A, B}, Left0, Right1),
Head = Head1,
Stream = Stream1
else if
B >= Y
then
take_min_iter2(Stream0, Head1, Stream1),
union_helper(Left0, {min_elem(A, X), B}, Right0, Limit, Head1,
Stream1, Left, Head, Stream)
else if
Limit = yes(LimitValue),
Y >= LimitValue
then
Left = Left0,
Head = yes({min_elem(A, X), Y}),
Stream = Stream0
else
union_2(Right0, Limit, yes({min_elem(A, X), Y}), Stream0,
Right1, Head1, Stream1),
Left = reroot(Left0, Right1),
Head = Head1,
Stream = Stream1
)
).
%---------------------%
union_list(Sets) = Set :-
union_list(Sets, Set).
union_list(Sets, Set) :-
(
Sets = [],
Set = empty
;
Sets = [SetA | SetBs],
foldl(union, SetBs, SetA, Set)
).
%---------------------%
intersect(SetA, SetB) = inter(SetA, SetB).
intersect(SetA, SetB, inter(SetA, SetB)).
:- func inter(diet(T), diet(T)) = diet(T) <= diet_element(T).
inter(Input, Stream0) = Result :-
( if int_gt(height(Stream0), height(Input)) then
disable_warning [suspicious_recursion] (
Result = inter(Stream0, Input)
)
else
(
Stream0 = empty,
Result = empty
;
Stream0 = node(_, _, _, _),
take_min_iter(Stream0, Head, Stream),
inter_2(Input, yes(Head), Stream, Result, _, _)
)
).
:- pred inter_2(diet(T)::in, maybe({T, T})::in, diet(T)::in,
diet(T)::out, maybe({T, T})::out, diet(T)::out) is det <= diet_element(T).
inter_2(Input, Head0, Stream0, Result, Head, Stream) :-
(
Head0 = no,
Result = empty,
Head = no,
Stream = empty
;
Head0 = yes({X, _Y}),
(
Input = empty,
Result = empty,
Head = Head0,
Stream = Stream0
;
Input = node({A, B}, _, Left0, Right0),
( if X < A then
inter_2(Left0, Head0, Stream0, Left1, Head1, Stream1)
else
Left1 = empty,
Head1 = Head0,
Stream1 = Stream0
),
inter_help({A, B}, Right0, Left1, Head1, Stream1,
Result, Head, Stream)
)
).
:- pred inter_help({T, T}::in, diet(T)::in,
diet(T)::in, maybe({T, T})::in, diet(T)::in,
diet(T)::out, maybe({T, T})::out, diet(T)::out) is det <= diet_element(T).
inter_help({A, B}, Right0, Left0, Head0, Stream0,
Result, Head, Stream) :-
(
Head0 = no,
Result = Left0,
Head = no,
Stream = empty
;
Head0 = yes({X, Y}),
( if Y < A then
(
Stream0 = empty,
Result = Left0,
Head = no,
Stream = empty
;
Stream0 = node(_, _, _, _),
take_min_iter(Stream0, Head1, Stream1),
inter_help({A, B}, Right0, Left0, yes(Head1), Stream1,
Result, Head, Stream)
)
else if B < X then
inter_2(Right0, Head0, Stream0, Right1, Head1, Stream1),
Result = reroot(Left0, Right1),
Head = Head1,
Stream = Stream1
else if Y >= safe_predecessor(Y, B) then
inter_2(Right0, Head0, Stream0, Right1, Head1, Stream1),
Result = join({max_elem(X, A), min_elem(Y, B)}, Left0, Right1),
Head = Head1,
Stream = Stream1
else
Left1 = do_insert({max_elem(X, A), Y}, Left0),
inter_help({successor(Y), B}, Right0, Left1, Head0, Stream0,
Result, Head, Stream)
)
).
%---------------------%
intersect_list(Sets) = Set :-
intersect_list(Sets, Set).
intersect_list([], init).
intersect_list([Set0 | Sets], Set) :-
foldl(intersect, Sets, Set0, Set).
%---------------------%
difference(SetA, SetB) = Set :-
difference(SetA, SetB, Set).
difference(SetA, SetB, Set) :-
(
SetA = empty,
Set = empty
;
SetA = node(_, _, _, _),
SetB = empty,
Set = SetA
;
SetA = node(_, _, _, _),
SetB = node(_, _, _, _),
take_min_iter(SetB, Head, Stream),
diff(SetA, yes(Head), Stream, Set, _RemHead, _RemStream)
).
:- pred diff(diet(T)::in, maybe(interval(T))::in, diet(T)::in,
diet(T)::out, maybe(interval(T))::out, diet(T)::out) is det
<= diet_element(T).
diff(Input, Head0, Stream0, Output, Head, Stream) :-
(
Head0 = no,
Output = Input,
Head = no,
Stream = empty
;
Head0 = yes(_),
Input = empty,
Output = empty,
Head = Head0,
Stream = Stream0
;
Head0 = yes({X, _Y}),
Input = node({A, B}, _, Left0, Right0),
( if X < A then
diff(Left0, Head0, Stream0, Left1, Head1, Stream1)
else
Left1 = Left0,
Head1 = Head0,
Stream1 = Stream0
),
diff_helper({A, B}, Right0, Left1, Head1, Stream1,
Output, Head, Stream)
).
:- pred diff_helper(interval(T)::in, diet(T)::in, diet(T)::in,
maybe(interval(T))::in, diet(T)::in, diet(T)::out, maybe(interval(T))::out,
diet(T)::out) is det <= diet_element(T).
diff_helper({A, B}, Right0, Left0, Head0, Stream0,
Output, Head, Stream) :-
(
Head0 = no,
Output = join({A, B}, Left0, Right0),
Head = no,
Stream = empty
;
Head0 = yes({X, Y}),
( if Y < A then
take_min_iter2(Stream0, Head1, Stream1),
diff_helper({A, B}, Right0, Left0, Head1, Stream1,
Output, Head, Stream)
else if B < X then
diff(Right0, Head0, Stream0, Right1, Head, Stream),
Output = join({A, B}, Left0, Right1)
else if A < X then
Left1 = do_insert({A, predecessor(X)}, Left0),
diff_helper({X, B}, Right0, Left1, Head0, Stream0,
Output, Head, Stream)
else if Y < B then
take_min_iter2(Stream0, Head1, Stream1),
diff_helper({successor(Y), B}, Right0, Left0, Head1, Stream1,
Output, Head, Stream)
else
diff(Right0, Head0, Stream0, Right1, Head, Stream),
Output = reroot(Left0, Right1)
)
).
%---------------------------------------------------------------------------%
split(X, Set, Lesser, IsPresent, Greater) :-
(
Set = empty,
IsPresent = no,
Lesser = empty,
Greater = empty
;
Set = node({A, B}, _, L, R),
( if X < A then
split(X, L, Lesser, IsPresent, RL),
Greater = join({A, B}, RL, R)
else if B < X then
split(X, R, LR, IsPresent, Greater),
Lesser = join({A, B}, L, LR)
else
IsPresent = yes,
( if X = A then
Lesser = L
else
Lesser = do_insert({A, predecessor(X)}, L)
),
( if X = B then
Greater = R
else
Greater = do_insert({successor(X), B}, R)
)
)
).
%---------------------%
divide(Pred, Set, TrueSet, FalseSet) :-
% Can do better.
foldl2(divide_2(Pred), Set, init, TrueSet, init, FalseSet).
:- pred divide_2(pred(T), T, diet(T), diet(T), diet(T), diet(T))
<= diet_element(T).
:- mode divide_2(pred(in) is semidet, in, in, out, in, out) is det.
divide_2(Pred, Elem, !TrueSet, !FalseSet) :-
( if Pred(Elem) then
insert(Elem, !TrueSet)
else
insert(Elem, !FalseSet)
).
%---------------------%
divide_by_set(DivideBySet, Set, InPart, OutPart) :-
intersect(Set, DivideBySet, InPart),
difference(Set, DivideBySet, OutPart).
%---------------------------------------------------------------------------%
list_to_set(List) = Set :-
list_to_set(List, Set).
list_to_set(List, Set) :-
foldl(insert, List, init, Set).
from_list(List) = Set :-
list_to_set(List, Set).
from_list(List, Set) :-
list_to_set(List, Set).
from_interval_list(List, Set) :-
list.foldl(insert_interval, List, init, Set).
sorted_list_to_set(List) = Set :-
sorted_list_to_set(List, Set).
sorted_list_to_set(List, Set) :-
list_to_set(List, Set).
%---------------------------------------------------------------------------%
to_sorted_list(T) = List :-
to_sorted_list(T, List).
to_sorted_list(T, List) :-
foldr(list.cons, T, [], List).
to_sorted_interval_list(Set, List) :-
foldr_intervals(cons_interval, Set, [], List).
:- pred cons_interval(T::in, T::in, list({T, T})::in, list({T, T})::out)
is det.
cons_interval(X, Y, L, [{X, Y} | L]).
%---------------------------------------------------------------------------%
count(T) = Count :-
count(T, 0, Count).
:- pred count(diet(T)::in, int::in, int::out) is det <= enum(T).
count(T, Acc0, Acc) :-
(
T = empty,
Acc = Acc0
;
T = node({X, Y}, _, L, R),
Acc1 = Acc0 + (to_int(Y) - to_int(X)) + 1,
count(L, Acc1, Acc2),
count(R, Acc2, Acc)
).
%---------------------------------------------------------------------------%
all_true(P, Set) :-
(
Set = empty
;
Set = node({X, Y}, _, L, R),
all_true(P, L),
all_true_interval(P, X, Y),
all_true(P, R)
).
:- pred all_true_interval(pred(T)::in(pred(in) is semidet), T::in, T::in)
is semidet <= diet_element(T).
all_true_interval(P, Lo, Hi) :-
( if Lo =< Hi then
P(Lo),
all_true_interval(P, successor(Lo), Hi)
else
true
).
%---------------------%
filter(Pred, Set) = TrueSet :-
divide(Pred, Set, TrueSet, _FalseSet).
filter(Pred, Set, TrueSet, FalseSet) :-
divide(Pred, Set, TrueSet, FalseSet).
%---------------------%
foldl_intervals(P, T, !Acc) :-
(
T = empty
;
T = node({X, Y}, _, L, R),
foldl_intervals(P, L, !Acc),
P(X, Y, !Acc),
foldl_intervals(P, R, !Acc)
).
%---------------------%
foldr_intervals(P, T, !Acc) :-
(
T = empty
;
T = node({X, Y}, _, L, R),
foldr_intervals(P, R, !Acc),
P(X, Y, !Acc),
foldr_intervals(P, L, !Acc)
).
%---------------------%
foldl(F, Set, Acc0) = Acc :-
P = (pred(E::in, PAcc0::in, PAcc::out) is det :-
PAcc = F(E, PAcc0)
),
foldl(P, Set, Acc0, Acc).
%---------------------%
foldl(P, T, !Acc) :-
(
T = empty
;
T = node({X, Y}, _, L, R),
foldl(P, L, !Acc),
foldl_2(P, X, Y, !Acc),
foldl(P, R, !Acc)
).
:- pred foldl_2(pred(T, Acc, Acc), T, T, Acc, Acc) <= diet_element(T).
:- mode foldl_2(pred(in, in, out) is det, in, in, in, out) is det.
:- mode foldl_2(pred(in, mdi, muo) is det, in, in, mdi, muo) is det.
:- mode foldl_2(pred(in, di, uo) is det, in, in, di, uo) is det.
:- mode foldl_2(pred(in, in, out) is semidet, in, in, in, out) is semidet.
:- mode foldl_2(pred(in, mdi, muo) is semidet, in, in, mdi, muo) is semidet.
:- mode foldl_2(pred(in, di, uo) is semidet, in, in, di, uo) is semidet.
foldl_2(P, Lo, Hi, !Acc) :-
( if Lo =< Hi then
P(Lo, !Acc),
foldl_2(P, successor(Lo), Hi, !Acc)
else
true
).
%---------------------%
foldl2(P, T, !Acc1, !Acc2) :-
(
T = empty
;
T = node({X, Y}, _, L, R),
foldl2(P, L, !Acc1, !Acc2),
fold_up2(P, X, Y, !Acc1, !Acc2),
foldl2(P, R, !Acc1, !Acc2)
).
:- pred fold_up2(pred(T, Acc1, Acc1, Acc2, Acc2), T, T,
Acc1, Acc1, Acc2, Acc2) <= diet_element(T).
:- mode fold_up2(pred(in, in, out, in, out) is det, in, in,
in, out, in, out) is det.
:- mode fold_up2(pred(in, in, out, mdi, muo) is det, in, in,
in, out, mdi, muo) is det.
:- mode fold_up2(pred(in, in, out, di, uo) is det, in, in,
in, out, di, uo) is det.
:- mode fold_up2(pred(in, in, out, in, out) is semidet, in, in,
in, out, in, out) is semidet.
:- mode fold_up2(pred(in, in, out, mdi, muo) is semidet, in, in,
in, out, mdi, muo) is semidet.
:- mode fold_up2(pred(in, in, out, di, uo) is semidet, in, in,
in, out, di, uo) is semidet.
fold_up2(P, Lo, Hi, !A, !B) :-
( if Lo =< Hi then
P(Lo, !A, !B),
fold_up2(P, successor(Lo), Hi, !A, !B)
else
true
).
%---------------------%
foldl3(P, T, !Acc1, !Acc2, !Acc3) :-
(
T = empty
;
T = node({X, Y}, _, L, R),
foldl3(P, L, !Acc1, !Acc2, !Acc3),
fold_up3(P, X, Y, !Acc1, !Acc2, !Acc3),
foldl3(P, R, !Acc1, !Acc2, !Acc3)
).
:- pred fold_up3(pred(T, Acc1, Acc1, Acc2, Acc2, Acc3, Acc3), T, T,
Acc1, Acc1, Acc2, Acc2, Acc3, Acc3) <= diet_element(T).
:- mode fold_up3(pred(in, in, out, in, out, in, out) is det, in, in,
in, out, in, out, in, out) is det.
:- mode fold_up3(pred(in, in, out, in, out, mdi, muo) is det, in, in,
in, out, in, out, mdi, muo) is det.
:- mode fold_up3(pred(in, in, out, in, out, di, uo) is det, in, in,
in, out, in, out, di, uo) is det.
:- mode fold_up3(pred(in, in, out, in, out, in, out) is semidet, in, in,
in, out, in, out, in, out) is semidet.
:- mode fold_up3(pred(in, in, out, in, out, mdi, muo) is semidet, in, in,
in, out, in, out, mdi, muo) is semidet.
:- mode fold_up3(pred(in, in, out, in, out, di, uo) is semidet, in, in,
in, out, in, out, di, uo) is semidet.
fold_up3(P, Lo, Hi, !A, !B, !C) :-
( if Lo =< Hi then
P(Lo, !A, !B, !C),
fold_up3(P, successor(Lo), Hi, !A, !B, !C)
else
true
).
%---------------------%
foldl4(P, T, !A, !B, !C, !D) :-
(
T = empty
;
T = node({X, Y}, _, L, R),
foldl4(P, L, !A, !B, !C, !D),
fold_up4(P, X, Y, !A, !B, !C, !D),
foldl4(P, R, !A, !B, !C, !D)
).
:- pred fold_up4(pred(T, A, A, B, B, C, C, D, D),
T, T, A, A, B, B, C, C, D, D) <= diet_element(T).
:- mode fold_up4(pred(in, in, out, in, out, in, out, in, out) is det,
in, in, in, out, in, out, in, out, in, out) is det.
:- mode fold_up4(pred(in, in, out, in, out, in, out, mdi, muo) is det,
in, in, in, out, in, out, in, out, mdi, muo) is det.
:- mode fold_up4(pred(in, in, out, in, out, in, out, di, uo) is det,
in, in, in, out, in, out, in, out, di, uo) is det.
:- mode fold_up4(pred(in, in, out, in, out, in, out, in, out) is semidet,
in, in, in, out, in, out, in, out, in, out) is semidet.
:- mode fold_up4(pred(in, in, out, in, out, in, out, mdi, muo) is semidet,
in, in, in, out, in, out, in, out, mdi, muo) is semidet.
:- mode fold_up4(pred(in, in, out, in, out, in, out, di, uo) is semidet,
in, in, in, out, in, out, in, out, di, uo) is semidet.
fold_up4(P, Lo, Hi, !A, !B, !C, !D) :-
( if Lo =< Hi then
P(Lo, !A, !B, !C, !D),
fold_up4(P, successor(Lo), Hi, !A, !B, !C, !D)
else
true
).
%---------------------%
foldl5(P, T, !A, !B, !C, !D, !E) :-
(
T = empty
;
T = node({X, Y}, _, L, R),
foldl5(P, L, !A, !B, !C, !D, !E),
fold_up5(P, X, Y, !A, !B, !C, !D, !E),
foldl5(P, R, !A, !B, !C, !D, !E)
).
:- pred fold_up5(
pred(T, A, A, B, B, C, C, D, D, E, E),
T, T, A, A, B, B, C, C, D, D, E, E) <= diet_element(T).
:- mode fold_up5(
pred(in, in, out, in, out, in, out, in, out, in, out) is det,
in, in, in, out, in, out, in, out, in, out, in, out) is det.
:- mode fold_up5(
pred(in, in, out, in, out, in, out, in, out, mdi, muo) is det,
in, in, in, out, in, out, in, out, in, out, mdi, muo) is det.
:- mode fold_up5(
pred(in, in, out, in, out, in, out, in, out, di, uo) is det,
in, in, in, out, in, out, in, out, in, out, di, uo) is det.
:- mode fold_up5(
pred(in, in, out, in, out, in, out, in, out, in, out) is semidet,
in, in, in, out, in, out, in, out, in, out, in, out) is semidet.
:- mode fold_up5(
pred(in, in, out, in, out, in, out, in, out, mdi, muo) is semidet,
in, in, in, out, in, out, in, out, in, out, mdi, muo) is semidet.
:- mode fold_up5(
pred(in, in, out, in, out, in, out, in, out, di, uo) is semidet,
in, in, in, out, in, out, in, out, in, out, di, uo) is semidet.
fold_up5(P, Lo, Hi, !A, !B, !C, !D, !E) :-
( if Lo =< Hi then
P(Lo, !A, !B, !C, !D, !E),
fold_up5(P, successor(Lo), Hi, !A, !B, !C, !D, !E)
else
true
).
%---------------------%
foldr(F, Set, Acc0) = Acc :-
P = (pred(E::in, PAcc0::in, PAcc::out) is det :-
PAcc = F(E, PAcc0)
),
foldr(P, Set, Acc0, Acc).
foldr(P, T, !Acc) :-
(
T = empty
;
T = node({X, Y}, _, L, R),
foldr(P, R, !Acc),
fold_down(P, X, Y, !Acc),
foldr(P, L, !Acc)
).
:- pred fold_down(pred(T, A, A), T, T, A, A) <= diet_element(T).
:- mode fold_down(pred(in, in, out) is det, in, in, in, out) is det.
:- mode fold_down(pred(in, mdi, muo) is det, in, in, mdi, muo) is det.
:- mode fold_down(pred(in, di, uo) is det, in, in, di, uo) is det.
:- mode fold_down(pred(in, in, out) is semidet, in, in, in, out) is semidet.
:- mode fold_down(pred(in, mdi, muo) is semidet, in, in, mdi, muo) is semidet.
:- mode fold_down(pred(in, di, uo) is semidet, in, in, di, uo) is semidet.
fold_down(P, Lo, Hi, !A) :-
( if Lo =< Hi then
P(Hi, !A),
fold_down(P, Lo, predecessor(Hi), !A)
else
true
).
%---------------------------------------------------------------------------%
:- end_module diet.
%---------------------------------------------------------------------------%