mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-17 18:33:58 +00:00
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.
1849 lines
54 KiB
Mathematica
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.
|
|
%---------------------------------------------------------------------------%
|