Next: digraph, Previous: deconstruct, Up: Top [Contents]
%--------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%--------------------------------------------------%
% Copyright (C) 2012-2014 YesLogic Pty. Ltd.
% Copyright (C) 2014-2015, 2017-2018, 2022-2023, 2025 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 if-and-only-if 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 if-and-only-if 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 if-and-only-if 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 if-and-only-if X is a member of Set.
%
:- pred contains(diet(T)::in, T::in) is semidet <= diet_element(T).
% nondet_member(Set, X):
%
% Nondeterministically produce each element in Set.
% Each time this call succeeds, X will be bound to an element in Set.
%
:- pred nondet_member(diet(T)::in, T::out) is nondet <= diet_element(T).
%--------------------------------------------------%
%
% Insertions and deletions.
%
% insert(X, Set0, Set) is true if-and-only-if 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 if-and-only-if
% 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 if-and-only-if 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 if-and-only-if 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 if-and-only-if 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 if-and-only-if 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 if-and-only-if 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 if-and-only-if 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 if-and-only-if Subset is a subset of Set.
%
:- pred subset(diet(T)::in, diet(T)::in) is semidet <= diet_element(T).
% superset(Superset, Set) is true if-and-only-if
% 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 if-and-only-if
% 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 if-and-only-if 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 if-and-only-if
% 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).
% A synonym for sorted_list_to_set/1.
%
:- func from_sorted_list(list(T)) = diet(T) <= 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 if-and-only-if 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(in(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(in(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(in(pred(in, in, in, out) is det), in, in, out) is det.
:- mode foldl_intervals(in(pred(in, in, di, uo) is det), in, di, uo) is det.
:- mode foldl_intervals(in(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(in(pred(in, in, in, out) is det), in, in, out) is det.
:- mode foldr_intervals(in(pred(in, in, di, uo) is det), in, di, uo) is det.
:- mode foldr_intervals(in(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(in(pred(in, in, out) is det), in, in, out) is det.
:- mode foldl(in(pred(in, mdi, muo) is det), in, mdi, muo) is det.
:- mode foldl(in(pred(in, di, uo) is det), in, di, uo) is det.
:- mode foldl(in(pred(in, in, out) is semidet), in, in, out) is semidet.
:- mode foldl(in(pred(in, mdi, muo) is semidet), in, mdi, muo) is semidet.
:- mode foldl(in(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(in(pred(in, in, out, in, out) is det), in,
in, out, in, out) is det.
:- mode foldl2(in(pred(in, in, out, mdi, muo) is det), in,
in, out, mdi, muo) is det.
:- mode foldl2(in(pred(in, in, out, di, uo) is det), in,
in, out, di, uo) is det.
:- mode foldl2(in(pred(in, in, out, in, out) is semidet), in,
in, out, in, out) is semidet.
:- mode foldl2(in(pred(in, in, out, mdi, muo) is semidet), in,
in, out, mdi, muo) is semidet.
:- mode foldl2(in(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(in(pred(in, in, out, in, out, in, out) is det), in,
in, out, in, out, in, out) is det.
:- mode foldl3(in(pred(in, in, out, in, out, mdi, muo) is det), in,
in, out, in, out, mdi, muo) is det.
:- mode foldl3(in(pred(in, in, out, in, out, di, uo) is det), in,
in, out, in, out, di, uo) is det.
:- mode foldl3(in(pred(in, in, out, in, out, in, out) is semidet), in,
in, out, in, out, in, out) is semidet.
:- mode foldl3(in(pred(in, in, out, in, out, mdi, muo) is semidet), in,
in, out, in, out, mdi, muo) is semidet.
:- mode foldl3(in(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(in(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(in(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(in(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(in(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(in(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(in(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(
in(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(
in(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(
in(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(
in(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(
in(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(
in(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(in(pred(in, in, out) is det), in, in, out) is det.
:- mode foldr(in(pred(in, mdi, muo) is det), in, mdi, muo) is det.
:- mode foldr(in(pred(in, di, uo) is det), in, di, uo) is det.
:- mode foldr(in(pred(in, in, out) is semidet), in, in, out) is semidet.
:- mode foldr(in(pred(in, mdi, muo) is semidet), in, mdi, muo) is semidet.
:- mode foldr(in(pred(in, di, uo) is semidet), in, di, uo) is semidet.
%--------------------------------------------------%
%--------------------------------------------------%
Next: digraph, Previous: deconstruct, Up: Top [Contents]