1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.

523 lines
16 KiB
MiniZinc

/*
% FlatZinc built-in redefinitions for linear solvers.
%
% AUTHORS
% Sebastian Brand
% Gleb Belov
*/
%-----------------------------------------------------------------------------%
%
% Linear equations and inequations
% TODO Use indicators for (half)reifs.
% Otherwise and more using unary encoding for reasonable domains
%
%-----------------------------------------------------------------------------%
% Domains: reduce all to aux_ stuff?
%% never use Concert's reif feature
%% var, var
predicate int_le_reif(var int: x, var int: y, var bool: b) =
%% trace(" int_le_reif VV: \(x), \(y), \(b) \n") /\
if is_fixed(b) then
if true==fix(b) then x<=y else x>y endif
elseif ub(x)<=lb(y) then b==true
elseif lb(x)>ub(y) then b==false
elseif fPostprocessDomains /\ fPostproDom_DIFF then
int_le_reif__POST(x-y, 0, b)
else
int_le_reif__NOPOST(x, y, b)
endif
;
%% const, var
predicate int_le_reif(int: x, var int: y, var bool: b) =
%% trace(" int_le_reif CV: \(x), \(y), \(b) \n") /\
if is_fixed(b) then
if true==fix(b) then x<=y else x>y endif
elseif ub(x)<=lb(y) then b==true
elseif lb(x)>ub(y) then b==false
elseif not (x in dom(y)) then %% dom(y) has holes
let {
set of int: sDom2 = dom(y) intersect x+1..infinity,
constraint assert( card( sDom2 ) > 0,
"Variable: dom(\(y)) = \(dom(y)), but dom() intersect \(x)..inf: \(sDom2)\n" ),
} in
b <-> min( sDom2 ) <= y
elseif fPostprocessDomains then
int_ge_reif__POST(y, x, b)
else
int_le_reif(-y, -x, b)
endif
;
%% var, const
predicate int_le_reif(var int: x, int: y, var bool: b) =
%% trace(" int_le_reif VC: \(x), \(y), \(b) \n") /\
if is_fixed(b) then
if true==fix(b) then x<=y else x>y endif
elseif ub(x)<=lb(y) then b==true
elseif lb(x)>ub(y) then b==false
elseif not (y in dom(x)) then %% dom(x) has holes
let {
set of int: sDom2 = dom(x) intersect -infinity..y-1,
constraint assert( card( sDom2 ) > 0,
"Variable: dom(\(x)) = \(dom(x)), but dom() intersect -inf..\(y): \(sDom2)\n" ),
} in
b <-> x <= max( sDom2 )
else
if fPostprocessDomains then
int_le_reif__POST(x, y, b)
else
int_le_reif__NOPOST(x, y, b)
endif
endif
;
%% var int, var int
predicate int_le_reif__NOPOST(var int: x, var int: y, var bool: b) =
aux_int_le_if_1(x, y, b) /\ %% This can call POSTs... TODO
aux_int_gt_if_0(x, y, b)
;
%% var, var
predicate int_lt_reif(var int: x, var int: y, var bool: b) =
%% int_le_reif(x-y, -1, b); %% This would produce a new variable x-y and possibly POST it
%% but it looks like differences should not be
if is_fixed( x ) then
int_le_reif(x+1, y, b)
else
int_le_reif(x, y-1, b)
endif;
%% var, var
predicate int_ne(var int: x, var int: y) =
if fPostproDom_DIFF then
int_ne(x-y, 0)
else
int_ne__SIMPLE(x-y, 0)
endif;
%% var, const
predicate int_ne(var int: x, int: y) =
if y in dom(x) then
if y==ub(x) then
x <= y-1
elseif y==lb(x) then
x >= y+1
elseif fPostprocessDomains then
int_ne__POST(x, y)
elseif card(dom(x))<nMZN__UnaryLenMax_neq then
let {
array[int] of var int: p = eq_encode(x);
} in
p[y]==false
else int_ne__SIMPLE(x, y)
endif
else
true
endif;
%% var, const. No postprocessing
predicate int_ne__SIMPLE(var int: x, int: y) =
if true then
let { var 0..1: p }
in
aux_int_lt_if_1(x, y, p) /\
aux_int_gt_if_0(x, y, p)
else %TODO: Why is this not half-reified?
1 == (x<y) + (x>y)
endif;
%% var, var
predicate int_eq_reif(var int: x, var int: y, var bool: b) =
%% trace(" int_eq_reif VV: \(x), \(y), \(b) \n") /\
if is_fixed(b) then
if fix(b) then x==y else x!=y endif
elseif card(dom(x) intersect dom(y))>0 then
if is_fixed(x) then
if is_fixed(y) then
b <-> fix(x)==fix(y)
else
int_eq_reif(y, fix(x), b)
endif
elseif is_fixed(y) then
int_eq_reif(x, fix(y), b)
elseif fPostprocessDomains /\ fPostproDom_DIFF then
int_eq_reif(x-y, 0, b)
else
aux_int_eq_iff_1(x, y, b)
endif
else
not b
endif;
%% var, const
predicate int_eq_reif(var int: x, int: y, var bool: b) =
%% trace(" int_eq_reif VC: \(x), \(y), \(b) \n") /\
if is_fixed(b) then
if fix(b) then x==y else x!=y endif
elseif y in dom(x) then
if is_fixed(x) then
b <-> y==fix(x)
elseif card(dom(x))==2 then
x == max(dom(x) diff {y}) + b*(y - max(dom(x) diff {y})) %% This should directly connect b to var 0..1: x
elseif fPostprocessDomains then
int_eq_reif__POST(x, y, b)
%%% THIS seems pretty complex, especially for binaries, and does not connect to eq_encoding (/ MIPD?)
%% elseif y==lb(x) then
%% int_lt_reif(y, x, not b)
%% elseif y==ub(x) then
%% int_lt_reif(x, y, not b)
elseif card(dom(x))<nMZN__UnaryLenMax_eq then
let {
array[int] of var int: p = eq_encode(x);
} in
p[y]==b
else
aux_int_eq_iff_1(x, y, bool2int(b))
endif
else
b==false
endif;
predicate int_ne_reif(var int: x, var int: y, var bool: b) =
int_eq_reif(x, y, not b);
predicate int_ne_reif(var int: x, int: y, var bool: b) =
int_eq_reif(x, y, not b);
%-----------------------------------------------------------------------------%
%% To avoid creating a new int var = sum...
function var float: sum2float( array[int] of int: c, array[int] of var int: x ) =
let {
array[int] of float: cF = c;
array[int] of var float: xF = x;
} in
sum(i in index_set(xF))( cF[i]*xF[i] );
%% lin_expr, const
predicate int_lin_le_reif(array[int] of int: c, array[int] of var int: x,
int: d, var bool: b) =
if length(c) == 1 /\ (d mod c[1] = 0) then % TODO: modulus not required when floating point calculations are possible
if c[1] > 0 then
int_le_reif(x[1], d div c[1], b)
else
int_le_reif(d div c[1], x[1], b)
endif
elseif fPostprocessDomains /\ fPostproDom_DIFF then
int_le_reif(sum(i in index_set(x))( c[i] * x[i] ), d, b)
elseif fAvoidNI then
aux_float_le_if_1(sum2float( c, x ), d, b) /\
aux_float_ge_if_0(sum2float( c, x ), d+1, b)
else
int_le_reif__NOPOST(sum(i in index_set(x))( c[i] * x[i] ), d, b)
endif;
predicate int_lin_lt_reif(array[int] of int: c, array[int] of var int: x,
int: d, var bool: b) =
if true then
abort("int_lin_lt_reif not supposed to be called")
else
int_lin_le_reif(c, x, d - 1, b)
endif;
%% lin_expr, const
predicate int_lin_eq_reif(array[int] of int: c, array[int] of var int: x,
int: d, var bool: b) =
if length(c) == 1 then
if d mod c[1] != 0 then
not b
else
int_eq_reif(x[1], d div c[1], b)
endif
elseif fPostprocessDomains /\ fPostproDom_DIFF then
int_eq_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b)
elseif fAvoidNI /\ fAuxIntEqOLD00 then
aux_int_eq_iff_1__float(sum2float( c, x ), d, b)
else
aux_int_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, b)
endif;
%% lin_expr, const
predicate int_lin_ne(array[int] of int: c, array[int] of var int: x, int: d) =
if length(c) == 1 then
(d mod c[1] = 0) -> int_ne(x[1], d div c[1])
elseif fPostprocessDomains /\ fPostproDom_DIFF then
int_ne(sum(i in index_set(x))( c[i]*x[i] ),d)
elseif fAvoidNI then
int_lin_eq_reif(c, x, d, false)
else
int_ne__SIMPLE(sum(i in index_set(x))( c[i]*x[i] ),d)
endif;
%% lin_expr, const
predicate int_lin_ne_reif(array[int] of int: c, array[int] of var int: x,
int: d, var bool: b) =
if length(c) == 1 then
if d mod c[1] != 0 then
b
else
int_ne_reif(x[1], d div c[1], b)
endif
elseif fPostprocessDomains /\ fPostproDom_DIFF then
int_ne_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b)
else
int_lin_eq_reif(c, x, d, not (b))
endif;
%-----------------------------------------------------------------------------%
%% var float, const
predicate float_le_reif(var float: x, float: y, var bool: b) =
%% trace( "float_le_reif(\(x), \(y), \(b))\n" ) /\
if is_fixed(b) then
if true==fix(b) then x<=y else x>y endif
elseif false then
float_lin_le_reif__IND( [1.0, -1.0], [x, y], 0.0, b)
elseif ub(x) <= y then
b == true
elseif lb(x) > y then
b == false
elseif fPostprocessDomains then
float_le_reif__POST(x, y, b, float_lt_EPS)
else
float_le_reif__NOPOST(x, y, b)
endif;
%% const, var float
predicate float_le_reif(float: x, var float: y, var bool: b) =
if is_fixed(b) then
if true==fix(b) then x<=y else x>y endif
elseif false then
float_lin_le_reif__IND( [1.0, -1.0], [x, y], 0.0, b)
elseif ub(x) <= lb(y) then
b == true
elseif lb(x) > ub(y) then
b == false
elseif fPostprocessDomains then
float_ge_reif__POST(y, x, b, float_lt_EPS)
else
float_le_reif(-y, -x, b)
endif;
%% var float, var float
predicate float_le_reif(var float: x, var float: y, var bool: b) =
if is_fixed(b) then
if true==fix(b) then x<=y else x>y endif
elseif ub(x)<=lb(y) then b==true
elseif lb(x)>ub(y) then b==false
elseif fPostprocessDomains /\ fPostproDom_DIFF then
float_le_reif(x-y, 0.0, b)
else
float_le_reif__NOPOST(x-y, 0, b)
endif
;
%% var float, var float
predicate float_le_reif__NOPOST(var float: x, var float: y, var bool: b) =
aux_float_le_if_1(x, y, (b)) /\ %% Can call __POSTs TODO
aux_float_gt_if_0(x, y, (b))
;
%% TODO
predicate float_lt_reif(var float: x, var float: y, var bool: b) =
%% Actually = float_le_reif(x, y-eps, b).
if is_fixed(b) then
if true==fix(b) then x<y else x>=y endif
elseif fPostprocessDomains /\ fPostproDom_DIFF then
aux_float_lt_zero_iff_1__POST(x - y, b, float_lt_EPS)
else
aux_float_lt_if_1(x, y, (b)) /\
aux_float_ge_if_0(x, y, (b))
endif;
%% var, const
predicate float_ne(var float: x, float: y) =
if fPostprocessDomains then
float_ne__POST(x, y, float_lt_EPS)
else
float_ne__SIMPLE(x, y)
endif;
predicate float_ne__SIMPLE(var float: x, var float: y) =
if true then
let { var 0..1: p }
in
aux_float_lt_if_1(x, y, (p)) /\
aux_float_gt_if_0(x, y, (p))
else %TODO: Why is this not half-reified?
1 == (x>y) + (x<y)
endif;
%% var, var
predicate float_ne(var float: x, var float: y) =
if fPostprocessDomains /\ fPostproDom_DIFF then
float_ne(x-y, 0.0)
else
float_ne__SIMPLE(x-y, 0.0)
endif;
%% TODO Why is disequality with EPS but equality not??
%% var, var? TODO
predicate float_eq_reif(var float: x, var float: y, var bool: b) =
if is_fixed(b) then
if true==fix(b) then x==y else x!=y endif
elseif ub(x)<lb(y) \/ lb(x)>ub(y) then
b == false
elseif is_fixed(x) /\ is_fixed(y) then
b == (fix(x) == fix(y))
elseif fPostprocessDomains /\ fPostproDom_DIFF then
float_eq_reif__POST(x-y, 0, b, float_lt_EPS)
else
aux_float_eq_iff_1(x, y, (bool2int(b)))
endif;
predicate float_ne_reif(var float: x, var float: y, var bool: b) =
float_eq_reif(x, y, not (b));
%-----------------------------------------------------------------------------%
predicate float_lin_eq_reif(array[int] of float: c, array[int] of var float: x,
float: d, var bool: b) =
if fPostprocessDomains /\ fPostproDom_DIFF then
float_eq_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b)
else
aux_float_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, b)
endif;
predicate float_lin_ne_reif(array[int] of float: c, array[int] of var float: x,
float: d, var bool: b) =
if fPostprocessDomains /\ fPostproDom_DIFF then
float_ne_reif(sum(i in index_set(x))( c[i]*x[i] ), d, not b)
else
aux_float_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, not b)
endif;
predicate float_lin_le_reif(array[int] of float: c, array[int] of var float: x,
float: d, var bool: b) =
if fPostprocessDomains /\ fPostproDom_DIFF then
float_le_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b)
else
float_le_reif__NOPOST(sum(i in index_set(x))( c[i]*x[i] ), d, b)
endif;
predicate float_lin_lt_reif(array[int] of float: c, array[int] of var float: x,
float: d, var bool: b) =
float_lt_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b);
%-----------------------------------------------------------------------------%
% Auxiliary: equality reified onto a 0/1 variable
predicate aux_int_eq_iff_1(var int: x, var int: y, var int: p) =
if is_fixed(p) then
if 1==fix(p) then x==y else x!=y endif
elseif fPostprocessDomains /\ fPostproDom_DIFF then
abort(" aux_int_eq_iff_1 should not be used with full domain postprocessing")
elseif false then
true
elseif fAuxIntEqOLD00 then
let { array[1..2] of var 0..1: q }
in
aux_int_le_if_1(x, y, p) /\
aux_int_ge_if_1(x, y, p) /\
aux_int_lt_if_0(x, y, q[1]) /\
aux_int_gt_if_0(x, y, q[2]) /\
sum(q) == p + 1
else
%% redundant p == (x<=y /\ y<=x) /\
1+p == (x<=y) + (y<=x)
endif;
predicate aux_int_eq_iff_1__float(var float: x, float: y, var int: p) =
if fAuxIntEqOLD00 then
assert( false, "Don't use aux_int_eq_iff_1__float" )
/* let { array[1..2] of var 0..1: q }
in
aux_int_le_if_1(x, y, p) /\
aux_int_ge_if_1(x, y, p) /\
aux_int_lt_if_0(x, y, q[1]) /\
aux_int_gt_if_0(x, y, q[2]) /\
sum(q) == p + 1 */
else
assert( false, "Don't use aux_int_eq_iff_1__float with fAuxIntEqOLD00" )
endif;
% Alternative 2
predicate aux_int_eq_iff_1__WEAK1(var int: x, var int: y, var int: p) =
let { array[1..2] of var 0..1: q_458 }
in
aux_int_lt_if_0(x - p, y, q_458[1]) /\
aux_int_gt_if_0(x + p, y, q_458[2]) /\
sum(q_458) <= 2 - 2*p /\
sum(q_458) <= 1 + p;
% Alternative 1
predicate alt_1_aux_int_eq_iff_1(var int: x, var int: y, var int: p) =
let { array[1..2] of var 0..1: q }
in
aux_int_lt_if_0(x - p, y, q[1]) /\
aux_int_gt_if_0(x + p, y, q[2]) /\
q[1] <= 1 - p /\
q[2] <= 1 - p /\
sum(q) <= 1 + p;
predicate aux_float_eq_iff_1(var float: x, var float: y, var int: p) =
if is_fixed(p) then
if 1==fix(p) then x==y else x!=y endif
elseif fPostprocessDomains /\ fPostproDom_DIFF then
abort(" aux_float_eq_iff_1 should not be used with full domain postprocessing")
elseif fAuxFloatEqOLD00 then
let { array[1..2] of var 0..1: q }
in
aux_float_le_if_1(x, y, p) /\
aux_float_ge_if_1(x, y, p) /\
aux_float_lt_if_0(x, y, (q[1])) /\
aux_float_gt_if_0(x, y, (q[2])) /\
sum(i in 1..2)((q[i])) == 1 + p
else
%% redundant p == (x<=y /\ y<=x) /\
1+p == (x<=y) + (y<=x)
endif;
% ----------------------------- Domains postpro ---------------------------
%%%%%%%%%%%%%%%%%% predicate int_le_reif__POST(var int: x, var int: y, var int: b);
%%%%%%%%%%%%%%%%%% predicate int_le_reif__POST(int: x, var int: y, var int: b);
%%%%%%% var int: b: bool2int is a reverse_map, not passed to .fzn
%% var, const
predicate int_le_reif__POST(var int: x, int: y, var int: b);
%% var, const
predicate int_ge_reif__POST(var int: x, int: y, var int: b);
%% var, const
predicate int_eq_reif__POST(var int: x, int: y, var int: b);
%% var, const
predicate int_ne__POST(var int: x, int: y);
%%%%%%%%%%%%%%%%%% predicate float_le_reif__POST(var float: x, var float: y, var int: b);
%%%%%%%%%%%%%%%%%% predicate float_le_reif__POST(float: x, var float: y, var int: b);
%% var, const
predicate float_le_reif__POST(var float: x, float: y, var int: b, float: epsRel);
%% var, const
predicate float_ge_reif__POST(var float: x, float: y, var int: b, float: epsRel);
%% var, var
predicate aux_float_lt_zero_iff_1__POST(var float: x, var int: b, float: epsRel);
%% var, const
predicate float_eq_reif__POST(var float: x, float: y, var int: b, float: epsRel);
%% var, const
predicate float_ne__POST(var float: x, float: y, float: epsRel);