git-subtree-dir: software/mza git-subtree-split: f970a59b177c13ca3dd8aaef8cc6681d83b7e813
299 lines
11 KiB
MiniZinc
299 lines
11 KiB
MiniZinc
/***
|
|
@groupdef builtins.logic Logical operations
|
|
|
|
Logical operations are the standard operators of Boolean logic.
|
|
*/
|
|
|
|
/** @group builtins.logic Return truth value of the negation of \a x */
|
|
function bool: op_not(bool: x) = not x;
|
|
/** @group builtins.logic Return truth value of the negation of \a x */
|
|
function var bool: op_not(var bool: x) ::promise_total =
|
|
let {
|
|
var bool: y;
|
|
constraint bool_not(x, y);
|
|
} in y;
|
|
|
|
/** @group builtins.compare Return if array \a x is equal to array \a y */
|
|
function bool: op_equals(array[$T] of int: x,array[$T] of int: y) =
|
|
let {
|
|
array[int] of int: xx = array1d(x);
|
|
array[int] of int: yy = array1d(y);
|
|
} in
|
|
assert(index_sets_agree(x,y), "array index sets do not match",
|
|
forall (i in index_set(xx)) (xx[i]=yy[i])
|
|
);
|
|
|
|
/** @group builtins.compare Return if array \a x is equal to array \a y */
|
|
function var bool: op_equals(array[$T] of var int: x, array[$T] of var int: y) =
|
|
let {
|
|
array[int] of var int: xx = array1d(x);
|
|
array[int] of var int: yy = array1d(y);
|
|
} in
|
|
assert(index_sets_agree(x,y), "array index sets do not match",
|
|
forall (i in index_set(xx)) (xx[i]=yy[i])
|
|
);
|
|
|
|
/** @group builtins.compare Return if array \a x is equal to array \a y */
|
|
function bool: op_equals(array[$T] of bool: x, array[$T] of bool: y) =
|
|
let {
|
|
array[int] of bool: xx = array1d(x);
|
|
array[int] of bool: yy = array1d(y);
|
|
} in
|
|
assert(index_sets_agree(x,y), "array index sets do not match",
|
|
forall (i in index_set(xx)) (xx[i]=yy[i])
|
|
);
|
|
|
|
/** @group builtins.compare Return if array \a x is equal to array \a y */
|
|
function var bool: op_equals(array[$T] of var bool: x,array[$T] of var bool: y) =
|
|
let {
|
|
array[int] of var bool: xx = array1d(x);
|
|
array[int] of var bool: yy = array1d(y);
|
|
} in
|
|
assert(index_sets_agree(x,y), "array index sets do not match",
|
|
forall (i in index_set(xx)) (xx[i]=yy[i])
|
|
);
|
|
|
|
|
|
/***
|
|
@groupdef builtins.arithmetic Arithmetic Builtins
|
|
|
|
These builtins implement arithmetic operations.
|
|
*/
|
|
|
|
predicate int_minus(var int:x, var int:y, var int:z);
|
|
|
|
/** @group builtins.arithmetic Return \a -x */
|
|
function int: op_minus(int: x) ::promise_total = -x;
|
|
/** @group builtins.arithmetic Return \a x - \a y */
|
|
function var int: op_minus(var int: x) ::promise_total =
|
|
let {
|
|
var int: y;
|
|
constraint int_minus(0,x,y);
|
|
} in y;
|
|
|
|
/** @group builtins.arithmetic Return \a x - \a y */
|
|
function int: op_minus(int: x, int: y) ::promise_total = x - y;
|
|
/** @group builtins.arithmetic Return \a x - \a y */
|
|
function var int: op_minus(var int: x, int: y) ::promise_total =
|
|
if y = 0 then
|
|
x
|
|
else
|
|
let {
|
|
var int: z;
|
|
constraint int_minus(x,y,z);
|
|
} in z
|
|
endif;
|
|
/** @group builtins.arithmetic Return \a x - \a y */
|
|
function var int: op_minus(var int: x, var int: y) ::promise_total =
|
|
let {
|
|
var int: z;
|
|
constraint int_minus(x, y, z);
|
|
} in z;
|
|
/** @group builtins.arithmetic Return \a x + \a y */
|
|
function int: op_plus(int: x, int: y) = x + y;
|
|
/** @group builtins.arithmetic Return \a x + \a y */
|
|
function var int: op_plus(int: x, var int: y) ::promise_total =
|
|
if x = 0 then
|
|
y
|
|
else
|
|
let {
|
|
var int: z;
|
|
constraint int_plus(x, y, z);
|
|
} in z
|
|
endif;
|
|
/** @group builtins.arithmetic Return \a x + \a y */
|
|
function var int: op_plus(var int: x, int: y) = op_plus(y, x);
|
|
/** @group builtins.arithmetic Return \a x + \a y */
|
|
function var int: op_plus(var int: x, var int: y) ::promise_total =
|
|
let {
|
|
var int: z;
|
|
constraint int_plus(x, y, z);
|
|
} in z;
|
|
|
|
/** @group builtins.arithmetic Return \a x * \a y */
|
|
function int: op_times(int: x, int: y) = x * y;
|
|
function var int: op_times(int: x, var int: y) ::promise_total =
|
|
if x = 1 then
|
|
y
|
|
else
|
|
let {
|
|
var int: z;
|
|
constraint int_times(x, y, z);
|
|
} in z
|
|
endif;
|
|
function var int: op_times(var int: x, int: y) = op_times(y, x);
|
|
/** @group builtins.arithmetic Return \a x * \a y */
|
|
function var int: op_times(var int: x, var int: y) ::promise_total =
|
|
let {
|
|
var int: z;
|
|
constraint int_times(x, y, z);
|
|
} in z;
|
|
|
|
/* Negated versions of FlatZinc builtins */
|
|
predicate int_lin_le_neg(array[int] of int: as, array[int] of var int: bs, int: c) =
|
|
int_lin_le([-a | a in as], bs, -c-1);
|
|
predicate int_lin_eq_neg(array[int] of int: as, array[int] of var int: bs, int: c) =
|
|
int_lin_ne(as, bs, c);
|
|
|
|
predicate pre_int_lin_eq(array[int] of int: as, array[int] of var int: bs, int: c) = if length(as)=0 then c=0 else int_lin_eq(as,bs,c) endif;
|
|
|
|
predicate pre_int_lin_eq_neg(array[int] of int: as, array[int] of var int: bs, int: c) = if length(as)=0 then c!=0 else int_lin_ne(as,bs,c) endif;
|
|
|
|
predicate pre_int_lin_le(array[int] of int: as, array[int] of var int: bs, int: c) = if length(as)=0 then 0<=c else int_lin_le(as,bs,c) endif;
|
|
|
|
predicate pre_int_lin_le_neg(array[int] of int: as, array[int] of var int: bs, int: c) = if length(as)=0 then 0>c else int_lin_le_neg(as,bs,c) endif;
|
|
|
|
|
|
/** @group builtins.arithmetic Return result of integer division \a x / \a y */
|
|
function int: op_int_division(int: x, int: y) = x div y;
|
|
/** @group builtins.arithmetic Return result of integer division \a x / \a y */
|
|
function var int: op_int_division(var int: x, var int: y) =
|
|
if mzn_in_root_context(y) \/ not (0 in dom(y)) then div_t(x,y) else
|
|
let { constraint y != 0 } in div_mt(x,y) endif;
|
|
|
|
/** @group builtins.arithmetic Return result of integer division \a x / \a y */
|
|
function int: op_modulus(int: x, int: y) = x mod y;
|
|
/** @group builtins.arithmetic Return result of integer division \a x / \a y */
|
|
function var int: op_modulus(var int: x, var int: y) =
|
|
if mzn_in_root_context(y) \/ not (0 in dom(y)) then mod_t(x,y) else
|
|
let { constraint y != 0 } in mod_mt(x,y) endif;
|
|
|
|
/** @group builtins.arithmetic Return result of floating point division \a x / \a y */
|
|
function float: op_float_division(float: x, float: y) = x / y;
|
|
/** @group builtins.arithmetic Return result of floating point division \a x / \a y */
|
|
function var float: op_float_division(var float: x, var float: y) =
|
|
if mzn_in_root_context(y) \/ lb(y) > 0.0 \/ ub(y) < 0.0 then fldiv_t(x,y) else
|
|
let { constraint y != 0.0 } in fldiv_mt(x,y) endif;
|
|
|
|
|
|
function int: internal_max(array[$U] of int: x);
|
|
function int: internal_set_max(set of int: x);
|
|
function bool: internal_max(array[$U] of bool: x);
|
|
/** @group builtins.arithmetic Return maximum of \a x and \a y */
|
|
function $T: max($T: x, $T: y) =
|
|
if x > y then
|
|
x
|
|
else
|
|
y
|
|
endif;
|
|
/** @group builtins.arithmetic Return maximum of elements in set \a x */
|
|
function int: max(set of int: x) = internal_set_max(x);
|
|
/** @group builtins.arithmetic Return maximum of elements in array \a x */
|
|
function int: max(array[$U] of int: x) = internal_max(array1d(x));
|
|
/** @group builtins.arithmetic Return maximum of elements in array \a x */
|
|
function bool: max(array[$U] of bool: x) = internal_max(array1d(x));
|
|
|
|
function int: internal_min(array[$U] of int: x);
|
|
function int: internal_set_min(set of int: x);
|
|
function bool: internal_min(array[$U] of bool: x);
|
|
/** @group builtins.arithmetic Return minimum of \a x and \a y */
|
|
function $T: min($T: x, $T: y) =
|
|
if x < y then
|
|
x
|
|
else
|
|
y
|
|
endif;
|
|
function int: min(set of int: x) = internal_set_min(x);
|
|
function int: min(array[$U] of int: x) = internal_min(array1d(x));
|
|
function bool: min(array[$U] of bool: x) = internal_min(array1d(x));
|
|
|
|
predicate int_sum(array[int] of var int: xs, var int: x);
|
|
/** @group builtins.arithmetic Return sum of elements in array \a x */
|
|
function var int: sum_cc(array[$T] of var int: x) ::promise_total =
|
|
let {
|
|
array[int] of var int: xs = array1d(x);
|
|
var int: res;
|
|
constraint int_sum(xs, res);
|
|
} in res;
|
|
|
|
function int: abs(int: x) =
|
|
if x<0 then
|
|
-x
|
|
else
|
|
x
|
|
endif;
|
|
|
|
% ---------------
|
|
|
|
/***
|
|
@groupdef builtins.ifthenelse Conditionals
|
|
|
|
These functions implement conditional (if-then-else-endif) constraints.
|
|
*/
|
|
|
|
/** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\)
|
|
|
|
This constraint is generated by the compiler for if-then-else expressions.
|
|
The last entry in the \a c array is always the constant true, corresponding
|
|
to the else case.
|
|
*/
|
|
function var int: if_then_else(array[int] of var bool: c, array[int] of int: x) ::promise_total =
|
|
let {
|
|
var dom_array(x): y;
|
|
constraint fzn_if_then_else_int(c, x, y);
|
|
} in y;
|
|
|
|
/** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\)
|
|
|
|
This constraint is generated by the compiler for if-then-else expressions.
|
|
The last entry in the \a c array is always the constant true, corresponding
|
|
to the else case.
|
|
*/
|
|
function var int: if_then_else(array[int] of var bool: c, array[int] of var int: x) ::promise_total =
|
|
let {
|
|
var dom_array(x): y;
|
|
constraint fzn_if_then_else_var_int(c, x, y);
|
|
} in y;
|
|
|
|
/** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\)
|
|
|
|
This constraint is generated by the compiler for if-then-else expressions.
|
|
The last entry in the \a c array is always the constant true, corresponding
|
|
to the else case.
|
|
*/
|
|
function var bool: if_then_else(array[int] of var bool: c, array[int] of bool: x) ::promise_total =
|
|
let {
|
|
var bool: y;
|
|
constraint fzn_if_then_else_bool(c, x, y);
|
|
} in y;
|
|
|
|
/** @group builtins.ifthenelse Conditional constraint \(\{\a c[i]\land\not\exists \a c[1..i-1]\ \rightarrow\ y=x[i] \}\)
|
|
|
|
This constraint is generated by the compiler for if-then-else expressions.
|
|
The last entry in the \a c array is always the constant true, corresponding
|
|
to the else case.
|
|
*/
|
|
function var bool: if_then_else(array[int] of var bool: c, array[int] of var bool: x) ::promise_total =
|
|
let {
|
|
var bool: y;
|
|
constraint fzn_if_then_else_var_bool(c, x, y);
|
|
} in y;
|
|
|
|
/** @group builtins.ifthenelse Conditional partiality constraint
|
|
|
|
This constraint is generated by the compiler for if-then-else expressions
|
|
with potentially undefined cases.
|
|
The last entry in the \a c array is always the constant true, corresponding
|
|
to the else case.
|
|
The \a d[i] variable represents whether case
|
|
\p i is defined. Constrains that if \b is defined, then the selected case must be defined, and
|
|
if the selected case is undefined, then \a b must be undefined.
|
|
*/
|
|
function var bool: if_then_else_partiality(array[int] of var bool: c, array[int] of var bool: d) ::promise_total =
|
|
let {
|
|
var bool: b;
|
|
constraint fzn_if_then_else_partiality(c, d, b);
|
|
} in b;
|
|
|
|
|
|
|
|
% Include solver-specific redefinitions for any FlatZinc built-ins.
|
|
%
|
|
include "fzn_if_then_else_int.mzn";
|
|
include "fzn_if_then_else_var_int.mzn";
|
|
include "fzn_if_then_else_bool.mzn";
|
|
include "fzn_if_then_else_var_bool.mzn";
|
|
include "fzn_if_then_else_partiality.mzn";
|
|
% Include interpreter definitions always to be included
|
|
include "mznasm_builtins.mzn";
|