/* % 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))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)) 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 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) + (xub(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);