1%----------------------------------------------------------------------
2% BEGIN LICENSE BLOCK
3% Version: CMPL 1.1
4%
5% The contents of this file are subject to the Cisco-style Mozilla Public
6% License Version 1.1 (the "License"); you may not use this file except
7% in compliance with the License.  You may obtain a copy of the License
8% at www.eclipse-clp.org/license.
9% 
10% Software distributed under the License is distributed on an "AS IS"
11% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
12% the License for the specific language governing rights and limitations
13% under the License. 
14% 
15% The Original Code is  The Zinc Modelling Interface for ECLiPSe
16% The Initial Developer of the Original Code is  Joachim Schimpf
17% Portions created by the Initial Developer are
18% Copyright (C) 2007 Cisco Systems, Inc.  All Rights Reserved.
19% 
20% Contributor(s): Joachim Schimpf
21% 
22% END LICENSE BLOCK
23%
24%
25% TODO:
26% X+Y#=C should be done as ac_eq(X,Y,C) if ac is wanted, X#=Y+c for bc
27%
28%----------------------------------------------------------------------
29
30:- module(fzn_ic).
31
32:- comment(categories, ["Interfacing","Constraints"]).
33:- comment(summary, "Mapping from FlatZinc to lib(ic) and lib(ic_sets)").
34:- comment(author, "Joachim Schimpf, supported by Cisco Systems and NICTA Victoria").
35:- comment(copyright, "Cisco Systems Inc, licensed under CMPL").
36:- comment(date, "$Date: 2015/01/14 01:31:09 $").
37:- comment(see_also, [library(flatzinc),
38	library(ic),library(ic_sets),library(ic_global),
39	library(propia),library(branch_and_bound)]).
40:- comment(desc, html("
41This module defines a mapping from FlatZinc operations to lib(ic), 
42lib(ic_sets) and lib(ic_global), and is intended to be used in
43conjunction with lib(flatzinc).  It uses lib(propia) to implement
44variants of the element constraint that are not supported by lib(ic).
45Moreover, lib(branch_and_bound) is used to provide optimization.
46</P><P>
47This mapping supports bool, integer, float and set variables.
48It does currently not support all constraints in reified form,
49in particular set constraints, according to the limitations of
50the underlying solvers.
51</P><P>
52The following extra annotations are supported by this mapping:
53<DL>
54<DT>annotation strategy(string:s)</DT>
55    <DD>the branch-and-bound strategy (default: \"continue\"). Valid names
56    are \"continue\", \"restart\", \"dichotomic\", See bb_min/3.</DD>
57<DT>annotation delta(float:f)</DT>
58    <DD>minimal absolute improvement for branch-and-bound steps (default 1.0).
59    See bb_min/3.</DD>
60<DT>annotation factor(float:f)</DT>
61    <DD>minimal improvement ratio (with respect to the lower cost bound)
62    for strategies 'continue' and 'restart' (default 1.0), or split factor
63    for strategy 'dichotomic' (default 0.5). See bb_min/3.</DD>
64<DT>annotation timeout(float:f)</DT>
65    <DD>timeout for branch-and-bound in seconds (default: unlimited).
66    See bb_min/3.</DD>
67</DL>
68You must include \"eclipse.mzn\" in your MiniZinc model to use these
69annotations.
70<P>
71")).
72
73
74% Lazy person's way of exporting (almost) all locally defined predicates:
75:- local initialization(
76    (
77	current_module_predicate(local, Pred),
78	get_flag(Pred, auxiliary, off),
79	nonmember(Pred, [
80		arg_nd/3,
81		array_any_element/3,
82		vector_sum/3,
83		search_ann/1,
84		set_choice/3,
85		termify/2
86	    ]),
87	export(Pred),
88	fail
89    ;
90	true
91    )).
92
93:- lib(ic).			% the actual solver libraries
94:- lib(ic_sets).
95:- lib(propia).
96:- lib(branch_and_bound).
97
98:- import			% resolve ambiguous imports
99	(::)/2,
100	intersection/3,
101	subset/2,
102	union/3
103    from ic_sets.
104
105:- import
106	fzn_write/2,
107	fzn_error/2
108    from flatzinc.
109
110
111% Declarations -----------------------------------------------
112
113% Single variable declarations
114bool_declare(X) :- X #:: 0..1.
115int_declare(X) :- integers(X).
116float_declare(X) :- reals(X).
117int_declare(X, Min, Max) :- X #:: Min..Max.
118int_declare(X, Elems) :- X #:: Elems.
119float_declare(X, Min, Max) :- X $:: Min..Max.
120set_declare(X, Min, Max) :- intset(X, Min, Max).
121set_declare(X, Elems) :- X :: Elems.
122
123% Variable array declarations
124% Unfortunately not all primitives can handle arrays
125bool_declare_array(Xs) :- Xs #:: 0..1.
126int_declare_array(Xs) :- ( foreacharg(X,Xs) do integers(X) ).
127float_declare_array(Xs) :- ( foreacharg(X,Xs) do reals(X) ).
128int_declare_array(Xs, Min, Max) :- Xs #:: Min..Max.
129int_declare_array(Xs, Elems) :- Xs #:: Elems.
130float_declare_array(Xs, Min, Max) :- Xs $:: Min..Max.
131set_declare_array(Xs, Min, Max) :-
132	( foreacharg(X,Xs), param(Min,Max) do intset(X, Min, Max) ).
133set_declare_array(Xs, Elems) :-
134	( foreacharg(X,Xs), param(Elems) do X :: Elems ).
135
136
137% Comparisons -----------------------------------------------
138
139% int_??(var int, var int)
140int_eq(X, Y) :- X = Y.
141int_ne(X, Y) :- X #\= Y.
142int_le(X, Y) :- X #=< Y.
143int_ge(X, Y) :- X #>= Y.        % OBSOLETE 1.2
144int_lt(X, Y) :- X #< Y.
145int_gt(X, Y) :- X #> Y. % OBSOLETE 1.2
146
147% float_??(var float, var float)
148float_eq(X, Y) :- X = Y.
149float_ne(X, Y) :- X $\= Y.
150float_le(X, Y) :- X $=< Y.
151float_ge(X, Y) :- X $>= Y.      % OBSOLETE 1.2
152float_lt(X, Y) :- X $< Y.
153float_gt(X, Y) :- X $> Y.       % OBSOLETE 1.2
154
155% bool_??(var bool, var bool)
156bool_eq(X, Y) :- X = Y.
157bool_ne(X, Y) :- X #\= Y.       % OBSOLETE 1.2
158bool_le(X, Y) :- X #=< Y.
159bool_ge(X, Y) :- X #>= Y.       % OBSOLETE 1.2
160bool_lt(X, Y) :- X #< Y.
161bool_gt(X, Y) :- X #> Y.        % OBSOLETE 1.2
162
163% set_??(var set, var set)
164set_eq(X, Y) :- X = Y.
165%set_ne(X, Y) :-
166%set_le(X, Y) :-
167%set_ge(X, Y) :-       % OBSOLETE 1.2
168%set_lt(X, Y) :-
169%set_gt(X, Y) :-       % OBSOLETE 1.2
170
171% int_lin_??(array[int] of int, array[int] of var int, int)
172int_lin_eq(Cs, Xs, Rhs) :- vector_sum(Cs, Xs, CXs), sum(CXs) #= Rhs.
173int_lin_ne(Cs, Xs, Rhs) :- vector_sum(Cs, Xs, CXs), sum(CXs) #\= Rhs.
174int_lin_le(Cs, Xs, Rhs) :- vector_sum(Cs, Xs, CXs), sum(CXs) #=< Rhs.
175int_lin_ge(Cs, Xs, Rhs) :- vector_sum(Cs, Xs, CXs), sum(CXs) #>= Rhs.   % OBSOLETE 1.2
176int_lin_lt(Cs, Xs, Rhs) :- vector_sum(Cs, Xs, CXs), sum(CXs) #< Rhs.    % OBSOLETE 1.2
177int_lin_gt(Cs, Xs, Rhs) :- vector_sum(Cs, Xs, CXs), sum(CXs) #> Rhs.    % OBSOLETE 1.2
178
179% float_lin_??(array[int] of float, array[int] of var float, float)
180float_lin_eq(Cs, Xs, Rhs) :- vector_sum(Cs, Xs, CXs), sum(CXs) $= Rhs.
181float_lin_ne(Cs, Xs, Rhs) :- vector_sum(Cs, Xs, CXs), sum(CXs) $\= Rhs.
182float_lin_le(Cs, Xs, Rhs) :- vector_sum(Cs, Xs, CXs), sum(CXs) $=< Rhs.
183float_lin_ge(Cs, Xs, Rhs) :- vector_sum(Cs, Xs, CXs), sum(CXs) $>= Rhs. % OBSOLETE 1.2
184float_lin_lt(Cs, Xs, Rhs) :- vector_sum(Cs, Xs, CXs), sum(CXs) $< Rhs.
185float_lin_gt(Cs, Xs, Rhs) :- vector_sum(Cs, Xs, CXs), sum(CXs) $> Rhs.  % OBSOLETE 1.2
186
187
188% int_??(var int, var int, var bool)
189int_eq_reif(X, Y, B) :- #=(X, Y, B).
190int_ne_reif(X, Y, B) :- #\=(X, Y, B).
191int_le_reif(X, Y, B) :- #=<(X, Y, B).
192int_ge_reif(X, Y, B) :- #>=(X, Y, B).   % OBSOLETE 1.2
193int_lt_reif(X, Y, B) :- #<(X, Y, B).
194int_gt_reif(X, Y, B) :- #>(X, Y, B).    % OBSOLETE 1.2
195
196% float_??(var float, var float, B)
197float_eq_reif(X, Y, B) :- $=(X, Y, B).
198float_ne_reif(X, Y, B) :- $\=(X, Y, B).
199float_le_reif(X, Y, B) :- $=<(X, Y, B).
200float_ge_reif(X, Y, B) :- $>=(X, Y, B). % OBSOLETE 1.2
201float_lt_reif(X, Y, B) :- $<(X, Y, B).
202float_gt_reif(X, Y, B) :- $>(X, Y, B).  % OBSOLETE 1.2
203
204% bool_??(var bool, var bool)
205bool_eq_reif(X, Y, B) :- #=(X, Y, B).
206bool_ne_reif(X, Y, B) :- #\=(X, Y, B).  % OBSOLETE 1.2
207bool_le_reif(X, Y, B) :- #=<(X, Y, B).
208bool_ge_reif(X, Y, B) :- #>=(X, Y, B).  % OBSOLETE 1.2
209bool_lt_reif(X, Y, B) :- #<(X, Y, B).
210bool_gt_reif(X, Y, B) :- #>(X, Y, B).   % OBSOLETE 1.2
211
212% set_??(var set, var set, B)
213%set_eq_reif(X, Y, B) :-
214%set_ne_reif(X, Y, B) :-
215%set_le_reif(X, Y, B) :-        % OBSOLETE?
216%set_ge_reif(X, Y, B) :-        % OBSOLETE 1.2
217%set_lt_reif(X, Y, B) :-        % OBSOLETE?
218%set_gt_reif(X, Y, B) :-        % OBSOLETE 1.2
219
220% int_lin_??(array[int] of int, array[int] of var int, int, var bool)
221int_lin_eq_reif(Cs, Xs, Rhs, B) :- vector_sum(Cs, Xs, CXs), #=(sum(CXs), Rhs, B).
222int_lin_ne_reif(Cs, Xs, Rhs, B) :- vector_sum(Cs, Xs, CXs), #\=(sum(CXs), Rhs, B).
223int_lin_le_reif(Cs, Xs, Rhs, B) :- vector_sum(Cs, Xs, CXs), #=<(sum(CXs), Rhs, B).
224int_lin_ge_reif(Cs, Xs, Rhs, B) :- vector_sum(Cs, Xs, CXs), #>=(sum(CXs), Rhs, B).      % OBSOLETE 1.2
225int_lin_lt_reif(Cs, Xs, Rhs, B) :- vector_sum(Cs, Xs, CXs), #<(sum(CXs), Rhs, B).       % OBSOLETE 1.2
226int_lin_gt_reif(Cs, Xs, Rhs, B) :- vector_sum(Cs, Xs, CXs), #>(sum(CXs), Rhs, B).       % OBSOLETE 1.2
227
228% float_lin_??(array[int] of float, array[int] of var float, float, B)
229float_lin_eq_reif(Cs, Xs, Rhs, B) :- vector_sum(Cs, Xs, CXs), $=(sum(CXs), Rhs, B).
230float_lin_ne_reif(Cs, Xs, Rhs, B) :- vector_sum(Cs, Xs, CXs), $\=(sum(CXs), Rhs, B).
231float_lin_le_reif(Cs, Xs, Rhs, B) :- vector_sum(Cs, Xs, CXs), $=<(sum(CXs), Rhs, B).
232float_lin_ge_reif(Cs, Xs, Rhs, B) :- vector_sum(Cs, Xs, CXs), $>=(sum(CXs), Rhs, B).    % OBSOLETE 1.2
233float_lin_lt_reif(Cs, Xs, Rhs, B) :- vector_sum(Cs, Xs, CXs), $<(sum(CXs), Rhs, B).
234float_lin_gt_reif(Cs, Xs, Rhs, B) :- vector_sum(Cs, Xs, CXs), $>(sum(CXs), Rhs, B).     % OBSOLETE 1.2
235
236    vector_sum(Cs, Xs, CXs) :-
237	arity(Cs, N),
238	( arity(Xs, N) ->
239	    ( for(I,1,N), foreach(C*X,CXs), param(Cs,Xs) do
240		arg(I, Cs, C), arg(I, Xs, X)
241	    )
242	;
243	    fzn_error("Mismatched vector product %w %w", [Cs, Xs])
244	).
245
246
247% Arithmetic operations -----------------------------------------------
248
249% int_???(var int, var int, var int)
250int_negate(X, Z) :- Z #= -X.    % OBSOLETE 1.2
251int_plus(X, Y, Z) :- Z #= X+Y.
252int_minus(X, Y, Z) :- Z #= X-Y. % OBSOLETE 1.2
253int_times(X, Y, Z) :- Z #= X*Y.
254int_div(Dividend, Divisor, Quotient) :-
255 	Remainder #>=0, Remainder #< abs(Divisor),
256 	Dividend #= Quotient*Divisor + Remainder.
257int_mod(Dividend, Divisor, Remainder) :-
258 	Remainder #>=0, Remainder #< abs(Divisor),
259 	Dividend #= _Quotient*Divisor + Remainder.
260int_min(X, Y, Z) :- Z #= min(X,Y).
261int_max(X, Y, Z) :- Z #= max(X,Y).
262int_abs(X, Z) :- Z #= abs(X).
263
264% float_???(var float, var float, var float)
265float_negate(X, Z) :- Z $= -X.          % OBSOLETE 1.2
266float_plus(X, Y, Z) :- Z $= X+Y.
267float_minus(X, Y, Z) :- Z $= X-Y.       % OBSOLETE 1.2
268float_times(X, Y, Z) :- Z $= X*Y.       % OBSOLETE?
269float_div(X, Y, Z) :- Z $= X/Y.         % OBSOLETE?
270float_min(X, Y, Z) :- Z $= min(X,Y).
271float_max(X, Y, Z) :- Z $= max(X,Y).
272float_abs(X, Z) :- Z $= abs(X).
273float_cos(X, Z) :- Z $= cos(X).
274float_sin(X, Z) :- Z $= sin(X).
275float_atan(X, Z) :- Z $= atan(X).
276float_sqrt(X, Z) :- Z $= sqrt(X).
277float_exp(X, Z) :- Z $= exp(X).
278float_ln(X, Z) :- Z $= ln(X).
279
280
281% Logical operations -----------------------------------------------
282
283% bool_???(var bool, var bool, var bool)
284bool_and(X, Y, Z) :- and(X, Y, Z).
285bool_or(X, Y, Z) :- or(X, Y, Z).
286bool_left_imp(X, Y, Z) :- =>(Y, X, Z).  % OBSOLETE 1.2
287bool_right_imp(X, Y, Z) :- =>(X, Y, Z). % OBSOLETE 1.2
288bool_xor(X, Y, Z) :- #\=(X, Y, Z).
289bool_not(X, Z) :- neg(X, Z).
290
291% array_bool_???(array[int] of var bool, var bool)
292array_bool_and(Xs, B) :- ic_global:minlist(Xs, B).
293array_bool_or(Xs, B) :- ic_global:maxlist(Xs, B).
294
295% bool_clause(array[int] of var bool, array[int] of var bool)
296bool_clause(Ps, Ns) :-
297	bool_clause_reif(Ps, Ns, 1).
298bool_clause_reif(Ps, Ns, B) :-          % OBSOLETE 1.2
299	ic_global:maxlist(Ps, B1),
300	ic_global:minlist(Ns, B2),
301	#>=(B1,B2,B).
302
303
304% Set operations -----------------------------------------------
305
306% set_???(... var set of int ...)
307set_in(I, S) :- I in S.
308%set_in_reif(I, S, B) :-
309set_subset(Sub, Super) :- subset(Sub, Super).
310%set_subset_reif(Sub, Super, B) :-
311set_intersect(X, Y, Z) :- intersection(X, Y, Z).
312set_union(X, Y, Z) :- union(X, Y, Z).
313set_diff(X, Y, Z) :- difference(X, Y, Z).
314set_symdiff(X, Y, Z) :- symdiff(X, Y, Z).
315set_card(S, I) :- #(S, I).
316
317set_in_reif(I, S, B) :- in(I, S, B).
318
319
320% Array operations -----------------------------------------------
321
322% array_xx_yy_element(var int, array[int] of xx yy, var yy)
323array_bool_element(I, Array, E) :- element(I, Array, E).
324array_int_element(I, Array, E) :- element(I, Array, E).
325array_float_element(I, Array, E) :- array_any_element(I, Array, E).
326%array_set_element(I, Array, E) :- array_any_element(I, Array, E).
327array_var_bool_element(I, Array, E) :- array_any_element(I, Array, E).
328array_var_int_element(I, Array, E) :- array_any_element(I, Array, E).
329array_var_float_element(I, Array, E) :- array_any_element(I, Array, E).
330%array_var_set_element(I, Array, E) :- array_any_element(I, Array, E).
331
332    array_any_element(I, Array, E) :-
333	arity(Array, N),
334	I #:: 1..N,
335	arg_nd(I, Array, E) infers ic.
336
337    arg_nd(I, Array, E) :-
338	indomain(I),
339	arg(I, Array, E).
340
341
342% Coercion operations -----------------------------------------------
343
344% Caution: this needs to correctly handle various combinations
345% of variables and constants of different types (was bug 741).
346int2float(I, F) :- I $= F.
347
348bool2int(X, X).
349
350
351% FZN data <-> ECLiPSe data -----------------------------------------------
352
353bool_fzn_to_solver(false, 0).
354bool_fzn_to_solver(true, 1).
355
356bool_solver_to_fzn(0, false).
357bool_solver_to_fzn(1, true).
358
359% convert FlatZinc floats to breals for lib(ic)
360float_fzn_to_solver(X, Real) :- Real is breal(X).
361
362% IC real variables may be instantiated to integers, floats or breals.
363% Convert integers to floats so the type is obvious for the Zinc user.
364float_solver_to_fzn(X, X) :- real(X).
365float_solver_to_fzn(X, F) :- integer(X), F is float(X).
366
367% Set constants are ordered lists in ic_sets
368set_fzn_to_solver(List, Set) :- eclipse_language:sort(List, Set).
369
370set_solver_to_fzn(List, List) :- is_list(List).
371
372% Set constants are ordered lists in ic_sets
373range_fzn_to_solver(Min, Max, Set) :-
374	( for(I,Min,Max), foreach(I,Set) do true ).
375
376
377% Search -----------------------------------------------
378
379satisfy(Anns) :-
380	( foreach(Ann,Anns) do
381	    termify(Ann, Ann1),	% for Flatzinc<1.0 compatibility
382	    search_ann(Ann1)
383	).
384
385:- export minimize/3.		% silence redefinition warning
386minimize(Expr, Anns, Cost) :-
387	extract_bb_anns(Anns, Anns1, BbOptions),
388	Cost $= Expr, 
389	bb_min(satisfy(Anns1), Cost, BbOptions).
390
391maximize(Expr, Anns, ObjVal) :-
392	extract_bb_anns(Anns, Anns1, BbOptions),
393	Cost $= -Expr, 
394	bb_min(satisfy(Anns1), Cost, BbOptions),
395	ObjVal is -Cost.
396
397    termify(In, Out) :-
398	functor(In, F, N), functor(Out, F, N),
399    	( for(I,1,N),param(In,Out) do
400	    arg(I,In,InI), arg(I,Out,OutI),
401	    ( string(InI) -> term_string(OutI,InI) ; OutI=InI )
402	).
403
404
405    % CAUTION: these must accept both arrays and lists!
406    search_ann(seq_search(Searches)) :- !,
407    	( foreacharg(Search,Searches) do search_ann(Search) ).
408
409    search_ann(bool_search(Vars, Select, Choice, Explore)) :- !,
410	search(Vars, 0, Select, Choice, Explore, []).
411
412    search_ann(int_search(Vars, Select, Choice, Explore)) :- !,
413	search(Vars, 0, Select, Choice, Explore, []).
414
415    search_ann(float_search(Vars, Prec, input_order, indomain_split, complete)) :-
416    	real(Prec), !,
417	FPrec is float(Prec),
418	locate(Vars, Vars, FPrec, log),
419        % instantiate variables atomically
420        call_priority(
421            ( functor(Vars, [], _) ->
422                ( foreacharg(X,Vars) do
423                    ( nonvar(X) -> true ;
424                        X is breal_from_bounds(get_min(X),get_max(X))
425                    )
426                )
427            ;
428                ( foreach(X,Vars) do
429                    ( nonvar(X) -> true ;
430                        X is breal_from_bounds(get_min(X),get_max(X))
431                    )
432                )
433            ), 2).
434
435    search_ann(set_search(Sets, input_order, Choice, complete)) :-
436	set_choice(Choice, ElemSel, Order), !,
437	( functor(Sets, [], _) ->
438	    ( foreacharg(Set,Sets), param(ElemSel,Order) do
439		insetdomain(Set, any, ElemSel, Order)
440	    )
441	;
442	    ( foreach(Set,Sets), param(ElemSel,Order) do
443		insetdomain(Set, any, ElemSel, Order)
444	    )
445	).
446
447    search_ann(Ann) :-
448	fzn_error("Unsupported search annotation: %w", [Ann]).
449
450
451    :- mode set_choice(+,-,-).
452    set_choice(indomain_min, small_first, in_notin).
453    set_choice(indomain_max, big_first, in_notin).
454    set_choice(outdomain_min, small_first, notin_in).
455    set_choice(outdomain_max, big_first, notin_in).
456
457
458    extract_bb_anns(Anns, RestAnns, BbOptions) :-
459    	(
460	    foreach(Ann,Anns),
461	    fromto(RestAnns,Anns2,Anns1,[]),
462	    param(BbOptions)
463	do
464	    ( bb_ann(Ann, BbOptions) -> Anns2 = Anns1 ; Anns2 = [Ann|Anns1] )
465	).
466
467    % Corresponding annotation-declarations are in eclipse.mzn
468    bb_ann(delta(R), bb_options{delta:F}) :- float(R, F).
469    bb_ann(factor(R), bb_options{factor:F}) :- float(R, F).
470    bb_ann(timeout(R), bb_options{timeout:F}) :- float(R, F).
471    bb_ann(strategy(S), bb_options{strategy:A}) :- atom_string(A, S).
472
473
474% Global Constraints (see fzn_ic/globals.mzn) -------------------
475
476all_different_int(Xs) :- ic_global:alldifferent(Xs).
477
478at_most_int(N,Xs,V) :- ic_global:atmost(N, Xs, V).
479%at_most(N,Xs,V) :- Count #=< N, ic_global:occurrences(V, Xs, Count).
480
481at_least_int(N,Xs,V) :- Count #>= N, ic_global:occurrences(V, Xs, Count).
482
483exactly_int(N,Xs,V) :- ic_global:occurrences(V, Xs, N).
484
485count_avint_int_int(Xs,V,N) :- ic_global:occurrences(V, Xs, N).
486
487minimum_int(M, Xs) :- ic:min(Xs, M).
488minimum_float(M, Xs) :- ic:min(Xs, M).
489
490maximum_int(M, Xs) :- ic:max(Xs, M).
491maximum_float(M, Xs) :- ic:max(Xs, M).
492
493%cumulative_avint_aint_aint_vint(Ss,Ds,Rs,B) :- ic_cumulative:cumulative(Ss,Ds,Rs,B).
494cumulative_avint_aint_aint_vint(Ss,Ds,Rs,B) :- ic_edge_finder:cumulative(Ss,Ds,Rs,B).
495%cumulative_avint_aint_aint_vint(Ss,Ds,Rs,B) :- ic_edge_finder3:cumulative(Ss,Ds,Rs,B).
496
497:- export sort/2.	% to resolve ambiguity with sort/2 builtin
498sort(Xs,Ss) :- ic_global:sorted(Xs, _Ps, Ss).
499
500
501:- reexport disjoint/2 from ic_sets.
502
503:- export all_disjoint/1.
504all_disjoint(Array) :- Array =.. [[]|List], ic_sets:all_disjoint(List).
505
506link_set_to_booleans(Set, Bools) :- ic_sets:membership_booleans(Set, Bools).
507
508