this repo has no description
at develop 16 kB view raw
1/* 2% FlatZinc built-in redefinitions for linear solvers. 3% 4% AUTHORS 5% Sebastian Brand 6% Gleb Belov 7*/ 8 9%-----------------------------------------------------------------------------% 10% 11% Linear equations and inequations 12% TODO Use indicators for (half)reifs. 13% Otherwise and more using unary encoding for reasonable domains 14% 15%-----------------------------------------------------------------------------% 16 17% Domains: reduce all to aux_ stuff? 18%% never use Concert's reif feature 19 20%% var, var 21predicate int_le_reif(var int: x, var int: y, var bool: b) = 22%% trace(" int_le_reif VV: \(x), \(y), \(b) \n") /\ 23 if is_fixed(b) then 24 if true==fix(b) then x<=y else x>y endif 25 elseif ub(x)<=lb(y) then b==true 26 elseif lb(x)>ub(y) then b==false 27 elseif fPostprocessDomains /\ fPostproDom_DIFF then 28 int_le_reif__POST(x-y, 0, b) 29 else 30 int_le_reif__NOPOST(x, y, b) 31 endif 32; 33 34%% const, var 35predicate int_le_reif(int: x, var int: y, var bool: b) = 36%% trace(" int_le_reif CV: \(x), \(y), \(b) \n") /\ 37 if is_fixed(b) then 38 if true==fix(b) then x<=y else x>y endif 39 elseif ub(x)<=lb(y) then b==true 40 elseif lb(x)>ub(y) then b==false 41 elseif not (x in dom(y)) then %% dom(y) has holes 42 let { 43 set of int: sDom2 = dom(y) intersect x+1..infinity, 44 constraint assert( card( sDom2 ) > 0, 45 "Variable: dom(\(y)) = \(dom(y)), but dom() intersect \(x)..inf: \(sDom2)\n" ), 46 } in 47 b <-> min( sDom2 ) <= y 48 elseif fPostprocessDomains then 49 int_ge_reif__POST(y, x, b) 50 else 51 int_le_reif(-y, -x, b) 52 endif 53; 54 55%% var, const 56predicate int_le_reif(var int: x, int: y, var bool: b) = 57%% trace(" int_le_reif VC: \(x), \(y), \(b) \n") /\ 58 if is_fixed(b) then 59 if true==fix(b) then x<=y else x>y endif 60 elseif ub(x)<=lb(y) then b==true 61 elseif lb(x)>ub(y) then b==false 62 elseif not (y in dom(x)) then %% dom(x) has holes 63 let { 64 set of int: sDom2 = dom(x) intersect -infinity..y-1, 65 constraint assert( card( sDom2 ) > 0, 66 "Variable: dom(\(x)) = \(dom(x)), but dom() intersect -inf..\(y): \(sDom2)\n" ), 67 } in 68 b <-> x <= max( sDom2 ) 69 else 70 if fPostprocessDomains then 71 int_le_reif__POST(x, y, b) 72 else 73 int_le_reif__NOPOST(x, y, b) 74 endif 75 endif 76; 77 78%% var int, var int 79predicate int_le_reif__NOPOST(var int: x, var int: y, var bool: b) = 80 aux_int_le_if_1(x, y, b) /\ %% This can call POSTs... TODO 81 aux_int_gt_if_0(x, y, b) 82 ; 83 84%% var, var 85predicate int_lt_reif(var int: x, var int: y, var bool: b) = 86 %% int_le_reif(x-y, -1, b); %% This would produce a new variable x-y and possibly POST it 87 %% but it looks like differences should not be 88 if is_fixed( x ) then 89 int_le_reif(x+1, y, b) 90 else 91 int_le_reif(x, y-1, b) 92 endif; 93 94%% var, var 95predicate int_ne(var int: x, var int: y) = 96 if fPostproDom_DIFF then 97 int_ne(x-y, 0) 98 else 99 int_ne__SIMPLE(x-y, 0) 100 endif; 101 102%% var, const 103predicate int_ne(var int: x, int: y) = 104 if y in dom(x) then 105 if y==ub(x) then 106 x <= y-1 107 elseif y==lb(x) then 108 x >= y+1 109 elseif fPostprocessDomains then 110 int_ne__POST(x, y) 111 elseif card(dom(x))<nMZN__UnaryLenMax_neq then 112 let { 113 array[int] of var int: p = eq_encode(x); 114 } in 115 p[y]==false 116 else int_ne__SIMPLE(x, y) 117 endif 118 else 119 true 120 endif; 121 122%% var, const. No postprocessing 123predicate int_ne__SIMPLE(var int: x, int: y) = 124 if true then 125 let { var 0..1: p } 126 in 127 aux_int_lt_if_1(x, y, p) /\ 128 aux_int_gt_if_0(x, y, p) 129 else %TODO: Why is this not half-reified? 130 1 == (x<y) + (x>y) 131 endif; 132 133%% var, var 134predicate int_eq_reif(var int: x, var int: y, var bool: b) = 135%% trace(" int_eq_reif VV: \(x), \(y), \(b) \n") /\ 136 if is_fixed(b) then 137 if fix(b) then x==y else x!=y endif 138 elseif card(dom(x) intersect dom(y))>0 then 139 if is_fixed(x) then 140 if is_fixed(y) then 141 b <-> fix(x)==fix(y) 142 else 143 int_eq_reif(y, fix(x), b) 144 endif 145 elseif is_fixed(y) then 146 int_eq_reif(x, fix(y), b) 147 elseif fPostprocessDomains /\ fPostproDom_DIFF then 148 int_eq_reif(x-y, 0, b) 149 else 150 aux_int_eq_iff_1(x, y, b) 151 endif 152 else 153 not b 154 endif; 155 156%% var, const 157predicate int_eq_reif(var int: x, int: y, var bool: b) = 158%% trace(" int_eq_reif VC: \(x), \(y), \(b) \n") /\ 159 if is_fixed(b) then 160 if fix(b) then x==y else x!=y endif 161 elseif y in dom(x) then 162 if is_fixed(x) then 163 b <-> y==fix(x) 164 elseif card(dom(x))==2 then 165 x == max(dom(x) diff {y}) + b*(y - max(dom(x) diff {y})) %% This should directly connect b to var 0..1: x 166 elseif fPostprocessDomains then 167 int_eq_reif__POST(x, y, b) 168%%% THIS seems pretty complex, especially for binaries, and does not connect to eq_encoding (/ MIPD?) 169%% elseif y==lb(x) then 170%% int_lt_reif(y, x, not b) 171%% elseif y==ub(x) then 172%% int_lt_reif(x, y, not b) 173 elseif card(dom(x))<nMZN__UnaryLenMax_eq then 174 let { 175 array[int] of var int: p = eq_encode(x); 176 } in 177 p[y]==b 178 else 179 aux_int_eq_iff_1(x, y, bool2int(b)) 180 endif 181 else 182 b==false 183 endif; 184 185 186predicate int_ne_reif(var int: x, var int: y, var bool: b) = 187 int_eq_reif(x, y, not b); 188 189predicate int_ne_reif(var int: x, int: y, var bool: b) = 190 int_eq_reif(x, y, not b); 191 192%-----------------------------------------------------------------------------% 193 194%% To avoid creating a new int var = sum... 195function var float: sum2float( array[int] of int: c, array[int] of var int: x ) = 196 let { 197 array[int] of float: cF = c; 198 array[int] of var float: xF = x; 199 } in 200 sum(i in index_set(xF))( cF[i]*xF[i] ); 201 202%% lin_expr, const 203predicate int_lin_le_reif(array[int] of int: c, array[int] of var int: x, 204 int: d, var bool: b) = 205 if length(c) == 1 /\ (d mod c[1] = 0) then % TODO: modulus not required when floating point calculations are possible 206 if c[1] > 0 then 207 int_le_reif(x[1], d div c[1], b) 208 else 209 int_le_reif(d div c[1], x[1], b) 210 endif 211 elseif fPostprocessDomains /\ fPostproDom_DIFF then 212 int_le_reif(sum(i in index_set(x))( c[i] * x[i] ), d, b) 213 elseif fAvoidNI then 214 aux_float_le_if_1(sum2float( c, x ), d, b) /\ 215 aux_float_ge_if_0(sum2float( c, x ), d+1, b) 216 else 217 int_le_reif__NOPOST(sum(i in index_set(x))( c[i] * x[i] ), d, b) 218 endif; 219 220 221predicate int_lin_lt_reif(array[int] of int: c, array[int] of var int: x, 222 int: d, var bool: b) = 223 if true then 224 abort("int_lin_lt_reif not supposed to be called") 225 else 226 int_lin_le_reif(c, x, d - 1, b) 227 endif; 228 229%% lin_expr, const 230predicate int_lin_eq_reif(array[int] of int: c, array[int] of var int: x, 231 int: d, var bool: b) = 232 if length(c) == 1 then 233 if d mod c[1] != 0 then 234 not b 235 else 236 int_eq_reif(x[1], d div c[1], b) 237 endif 238 elseif fPostprocessDomains /\ fPostproDom_DIFF then 239 int_eq_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b) 240 elseif fAvoidNI /\ fAuxIntEqOLD00 then 241 aux_int_eq_iff_1__float(sum2float( c, x ), d, b) 242 else 243 aux_int_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, b) 244 endif; 245 246%% lin_expr, const 247predicate int_lin_ne(array[int] of int: c, array[int] of var int: x, int: d) = 248 if length(c) == 1 then 249 (d mod c[1] = 0) -> int_ne(x[1], d div c[1]) 250 elseif fPostprocessDomains /\ fPostproDom_DIFF then 251 int_ne(sum(i in index_set(x))( c[i]*x[i] ),d) 252 elseif fAvoidNI then 253 int_lin_eq_reif(c, x, d, false) 254 else 255 int_ne__SIMPLE(sum(i in index_set(x))( c[i]*x[i] ),d) 256 endif; 257 258%% lin_expr, const 259predicate int_lin_ne_reif(array[int] of int: c, array[int] of var int: x, 260 int: d, var bool: b) = 261 if length(c) == 1 then 262 if d mod c[1] != 0 then 263 b 264 else 265 int_ne_reif(x[1], d div c[1], b) 266 endif 267 elseif fPostprocessDomains /\ fPostproDom_DIFF then 268 int_ne_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b) 269 else 270 int_lin_eq_reif(c, x, d, not (b)) 271 endif; 272 273 274%-----------------------------------------------------------------------------% 275 276%% var float, const 277predicate float_le_reif(var float: x, float: y, var bool: b) = 278%% trace( "float_le_reif(\(x), \(y), \(b))\n" ) /\ 279 if is_fixed(b) then 280 if true==fix(b) then x<=y else x>y endif 281 elseif false then 282 float_lin_le_reif__IND( [1.0, -1.0], [x, y], 0.0, b) 283 elseif ub(x) <= y then 284 b == true 285 elseif lb(x) > y then 286 b == false 287 elseif fPostprocessDomains then 288 float_le_reif__POST(x, y, b, float_lt_EPS) 289 else 290 float_le_reif__NOPOST(x, y, b) 291 endif; 292 293%% const, var float 294predicate float_le_reif(float: x, var float: y, var bool: b) = 295 if is_fixed(b) then 296 if true==fix(b) then x<=y else x>y endif 297 elseif false then 298 float_lin_le_reif__IND( [1.0, -1.0], [x, y], 0.0, b) 299 elseif ub(x) <= lb(y) then 300 b == true 301 elseif lb(x) > ub(y) then 302 b == false 303 elseif fPostprocessDomains then 304 float_ge_reif__POST(y, x, b, float_lt_EPS) 305 else 306 float_le_reif(-y, -x, b) 307 endif; 308 309%% var float, var float 310predicate float_le_reif(var float: x, var float: y, var bool: b) = 311 if is_fixed(b) then 312 if true==fix(b) then x<=y else x>y endif 313 elseif ub(x)<=lb(y) then b==true 314 elseif lb(x)>ub(y) then b==false 315 elseif fPostprocessDomains /\ fPostproDom_DIFF then 316 float_le_reif(x-y, 0.0, b) 317 else 318 float_le_reif__NOPOST(x-y, 0, b) 319 endif 320; 321 322%% var float, var float 323predicate float_le_reif__NOPOST(var float: x, var float: y, var bool: b) = 324 aux_float_le_if_1(x, y, (b)) /\ %% Can call __POSTs TODO 325 aux_float_gt_if_0(x, y, (b)) 326 ; 327 328%% TODO 329predicate float_lt_reif(var float: x, var float: y, var bool: b) = 330 %% Actually = float_le_reif(x, y-eps, b). 331 if is_fixed(b) then 332 if true==fix(b) then x<y else x>=y endif 333 elseif fPostprocessDomains /\ fPostproDom_DIFF then 334 aux_float_lt_zero_iff_1__POST(x - y, b, float_lt_EPS) 335 else 336 aux_float_lt_if_1(x, y, (b)) /\ 337 aux_float_ge_if_0(x, y, (b)) 338 endif; 339 340%% var, const 341predicate float_ne(var float: x, float: y) = 342 if fPostprocessDomains then 343 float_ne__POST(x, y, float_lt_EPS) 344 else 345 float_ne__SIMPLE(x, y) 346 endif; 347 348predicate float_ne__SIMPLE(var float: x, var float: y) = 349 if true then 350 let { var 0..1: p } 351 in 352 aux_float_lt_if_1(x, y, (p)) /\ 353 aux_float_gt_if_0(x, y, (p)) 354 else %TODO: Why is this not half-reified? 355 1 == (x>y) + (x<y) 356 endif; 357 358%% var, var 359predicate float_ne(var float: x, var float: y) = 360 if fPostprocessDomains /\ fPostproDom_DIFF then 361 float_ne(x-y, 0.0) 362 else 363 float_ne__SIMPLE(x-y, 0.0) 364 endif; 365 366%% TODO Why is disequality with EPS but equality not?? 367 368%% var, var? TODO 369predicate float_eq_reif(var float: x, var float: y, var bool: b) = 370 if is_fixed(b) then 371 if true==fix(b) then x==y else x!=y endif 372 elseif ub(x)<lb(y) \/ lb(x)>ub(y) then 373 b == false 374 elseif is_fixed(x) /\ is_fixed(y) then 375 b == (fix(x) == fix(y)) 376 elseif fPostprocessDomains /\ fPostproDom_DIFF then 377 float_eq_reif__POST(x-y, 0, b, float_lt_EPS) 378 else 379 aux_float_eq_iff_1(x, y, (bool2int(b))) 380 endif; 381 382predicate float_ne_reif(var float: x, var float: y, var bool: b) = 383 float_eq_reif(x, y, not (b)); 384 385%-----------------------------------------------------------------------------% 386 387predicate float_lin_eq_reif(array[int] of float: c, array[int] of var float: x, 388 float: d, var bool: b) = 389 if fPostprocessDomains /\ fPostproDom_DIFF then 390 float_eq_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b) 391 else 392 aux_float_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, b) 393 endif; 394 395predicate float_lin_ne_reif(array[int] of float: c, array[int] of var float: x, 396 float: d, var bool: b) = 397 if fPostprocessDomains /\ fPostproDom_DIFF then 398 float_ne_reif(sum(i in index_set(x))( c[i]*x[i] ), d, not b) 399 else 400 aux_float_eq_iff_1(sum(i in index_set(x))( c[i]*x[i] ), d, not b) 401 endif; 402 403predicate float_lin_le_reif(array[int] of float: c, array[int] of var float: x, 404 float: d, var bool: b) = 405 if fPostprocessDomains /\ fPostproDom_DIFF then 406 float_le_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b) 407 else 408 float_le_reif__NOPOST(sum(i in index_set(x))( c[i]*x[i] ), d, b) 409 endif; 410 411predicate float_lin_lt_reif(array[int] of float: c, array[int] of var float: x, 412 float: d, var bool: b) = 413 float_lt_reif(sum(i in index_set(x))( c[i]*x[i] ), d, b); 414 415 416%-----------------------------------------------------------------------------% 417% Auxiliary: equality reified onto a 0/1 variable 418 419predicate aux_int_eq_iff_1(var int: x, var int: y, var int: p) = 420 if is_fixed(p) then 421 if 1==fix(p) then x==y else x!=y endif 422 elseif fPostprocessDomains /\ fPostproDom_DIFF then 423 abort(" aux_int_eq_iff_1 should not be used with full domain postprocessing") 424 elseif false then 425 true 426 elseif fAuxIntEqOLD00 then 427 let { array[1..2] of var 0..1: q } 428 in 429 aux_int_le_if_1(x, y, p) /\ 430 aux_int_ge_if_1(x, y, p) /\ 431 aux_int_lt_if_0(x, y, q[1]) /\ 432 aux_int_gt_if_0(x, y, q[2]) /\ 433 sum(q) == p + 1 434 else 435 %% redundant p == (x<=y /\ y<=x) /\ 436 1+p == (x<=y) + (y<=x) 437 endif; 438 439predicate aux_int_eq_iff_1__float(var float: x, float: y, var int: p) = 440 if fAuxIntEqOLD00 then 441 assert( false, "Don't use aux_int_eq_iff_1__float" ) 442/* let { array[1..2] of var 0..1: q } 443 in 444 aux_int_le_if_1(x, y, p) /\ 445 aux_int_ge_if_1(x, y, p) /\ 446 aux_int_lt_if_0(x, y, q[1]) /\ 447 aux_int_gt_if_0(x, y, q[2]) /\ 448 sum(q) == p + 1 */ 449 else 450 assert( false, "Don't use aux_int_eq_iff_1__float with fAuxIntEqOLD00" ) 451 endif; 452 453 % Alternative 2 454predicate aux_int_eq_iff_1__WEAK1(var int: x, var int: y, var int: p) = 455 let { array[1..2] of var 0..1: q_458 } 456 in 457 aux_int_lt_if_0(x - p, y, q_458[1]) /\ 458 aux_int_gt_if_0(x + p, y, q_458[2]) /\ 459 sum(q_458) <= 2 - 2*p /\ 460 sum(q_458) <= 1 + p; 461 462 % Alternative 1 463predicate alt_1_aux_int_eq_iff_1(var int: x, var int: y, var int: p) = 464 let { array[1..2] of var 0..1: q } 465 in 466 aux_int_lt_if_0(x - p, y, q[1]) /\ 467 aux_int_gt_if_0(x + p, y, q[2]) /\ 468 q[1] <= 1 - p /\ 469 q[2] <= 1 - p /\ 470 sum(q) <= 1 + p; 471 472predicate aux_float_eq_iff_1(var float: x, var float: y, var int: p) = 473 if is_fixed(p) then 474 if 1==fix(p) then x==y else x!=y endif 475 elseif fPostprocessDomains /\ fPostproDom_DIFF then 476 abort(" aux_float_eq_iff_1 should not be used with full domain postprocessing") 477 elseif fAuxFloatEqOLD00 then 478 let { array[1..2] of var 0..1: q } 479 in 480 aux_float_le_if_1(x, y, p) /\ 481 aux_float_ge_if_1(x, y, p) /\ 482 aux_float_lt_if_0(x, y, (q[1])) /\ 483 aux_float_gt_if_0(x, y, (q[2])) /\ 484 sum(i in 1..2)((q[i])) == 1 + p 485 else 486 %% redundant p == (x<=y /\ y<=x) /\ 487 1+p == (x<=y) + (y<=x) 488 endif; 489 490 491 492% ----------------------------- Domains postpro --------------------------- 493 494%%%%%%%%%%%%%%%%%% predicate int_le_reif__POST(var int: x, var int: y, var int: b); 495%%%%%%%%%%%%%%%%%% predicate int_le_reif__POST(int: x, var int: y, var int: b); 496%%%%%%% var int: b: bool2int is a reverse_map, not passed to .fzn 497%% var, const 498predicate int_le_reif__POST(var int: x, int: y, var int: b); 499%% var, const 500predicate int_ge_reif__POST(var int: x, int: y, var int: b); 501 502%% var, const 503predicate int_eq_reif__POST(var int: x, int: y, var int: b); 504%% var, const 505predicate int_ne__POST(var int: x, int: y); 506 507%%%%%%%%%%%%%%%%%% predicate float_le_reif__POST(var float: x, var float: y, var int: b); 508%%%%%%%%%%%%%%%%%% predicate float_le_reif__POST(float: x, var float: y, var int: b); 509%% var, const 510predicate float_le_reif__POST(var float: x, float: y, var int: b, float: epsRel); 511%% var, const 512predicate float_ge_reif__POST(var float: x, float: y, var int: b, float: epsRel); 513 514%% var, var 515predicate aux_float_lt_zero_iff_1__POST(var float: x, var int: b, float: epsRel); 516 517%% var, const 518predicate float_eq_reif__POST(var float: x, float: y, var int: b, float: epsRel); 519%% var, const 520predicate float_ne__POST(var float: x, float: y, float: epsRel); 521 522