001package org.clafer.choco.constraint.propagator; 002 003import gnu.trove.set.TIntSet; 004import solver.ICause; 005import solver.exception.ContradictionException; 006import solver.variables.IntVar; 007import solver.variables.SetVar; 008import solver.variables.delta.IIntDeltaMonitor; 009import solver.variables.delta.monitor.SetDeltaMonitor; 010 011/** 012 * Various static utility functions for writing Choco propagators. 013 * 014 * @author jimmy 015 */ 016public class PropUtil { 017 018 private PropUtil() { 019 } 020 021 /** 022 * Monitor the deltas for all the variables. 023 * 024 * @param vars the variables 025 * @param propagator the propagator 026 * @return the variables delta monitors 027 */ 028 public static IIntDeltaMonitor[] monitorDeltas(IntVar[] vars, ICause propagator) { 029 IIntDeltaMonitor[] deltas = new IIntDeltaMonitor[vars.length]; 030 for (int i = 0; i < vars.length; i++) { 031 deltas[i] = vars[i].monitorDelta(propagator); 032 } 033 return deltas; 034 } 035 036 /** 037 * Monitor the deltas for all the variables. 038 * 039 * @param vars the variables 040 * @param propagator the propagator 041 * @return the variables delta monitors 042 */ 043 public static SetDeltaMonitor[] monitorDeltas(SetVar[] vars, ICause propagator) { 044 SetDeltaMonitor[] deltas = new SetDeltaMonitor[vars.length]; 045 for (int i = 0; i < vars.length; i++) { 046 deltas[i] = vars[i].monitorDelta(propagator); 047 } 048 return deltas; 049 } 050 051 /** 052 * Enumerate the domain of a integer variable. 053 * 054 * @param ivar the integer variable 055 * @return {@code dom(int)} 056 */ 057 public static int[] iterateDom(IntVar ivar) { 058 int[] iterate = new int[ivar.getDomainSize()]; 059 int count = 0; 060 int ub = ivar.getUB(); 061 for (int i = ivar.getLB(); i <= ub; i = ivar.nextValue(i)) { 062 iterate[count++] = i; 063 } 064 assert count == iterate.length; 065 return iterate; 066 } 067 068 /** 069 * Enumerate the envelope of a set variable. 070 * 071 * @param set the set variable 072 * @return {@code env(set)} 073 */ 074 public static int[] iterateEnv(SetVar set) { 075 int[] iterate = new int[set.getEnvelopeSize()]; 076 int count = 0; 077 for (int i = set.getEnvelopeFirst(); i != SetVar.END; i = set.getEnvelopeNext()) { 078 iterate[count++] = i; 079 } 080 assert count == iterate.length; 081 return iterate; 082 } 083 084 /** 085 * Enumerate the kernel of a set variable. 086 * 087 * @param set the set variable 088 * @return {@code ker(set)} 089 */ 090 public static int[] iterateKer(SetVar set) { 091 int[] iterate = new int[set.getKernelSize()]; 092 int count = 0; 093 for (int i = set.getKernelFirst(); i != SetVar.END; i = set.getKernelNext()) { 094 iterate[count++] = i; 095 } 096 assert count == iterate.length; 097 return iterate; 098 } 099 100 /** 101 * Checks if at least one of the integer's domain contains a value. 102 * 103 * @param union the integers 104 * @param value the value 105 * @return {@code true} if 106 * {@code value ∈ dom(union[i]) for some i}, {@code false} otherwise 107 */ 108 public static boolean domsContain(IntVar[] union, int value) { 109 for (IntVar var : union) { 110 if (var.contains(value)) { 111 return true; 112 } 113 } 114 return false; 115 } 116 117 /** 118 * Checks if at least one of the set's envelope contains a value. 119 * 120 * @param union the sets 121 * @param value the value 122 * @return {@code true} if 123 * {@code value ∈ env(union[i]) for some i}, {@code false} otherwise 124 */ 125 public static boolean envsContain(SetVar[] union, int value) { 126 for (SetVar var : union) { 127 if (var.envelopeContains(value)) { 128 return true; 129 } 130 } 131 return false; 132 } 133 134 /** 135 * Checks if at least one of the set's kernel contains a value. 136 * 137 * @param union the sets 138 * @param value the value 139 * @return {@code true} if 140 * {@code value ∈ kernel(union[i]) for some i}, {@code false} otherwise 141 */ 142 public static boolean kersContain(SetVar[] union, int value) { 143 for (SetVar var : union) { 144 if (var.kernelContains(value)) { 145 return true; 146 } 147 } 148 return false; 149 } 150 151 /** 152 * Checks if an integer's domain is contained entirely in the other 153 * integer's domain. 154 * 155 * @param i1 the first operand 156 * @param i2 the second operand 157 * @return {@code true} if {@code dom(i1) ⋂ dom(i2) ≠ {}}, {@code false} 158 * otherwise 159 */ 160 public static boolean isDomIntersectDom(IntVar i1, IntVar i2) { 161 int s1 = i1.getDomainSize(); 162 int s2 = i2.getDomainSize(); 163 IntVar small = i1; 164 IntVar large = i2; 165 int s = s1; 166 if (s1 > s2) { 167 small = i2; 168 large = i1; 169 s = s2; 170 } 171 if (s == 1) { 172 return large.contains(small.getLB()); 173 } 174 int lb = small.getLB(); 175 int largeLb = large.getLB(); 176 if (largeLb > lb) { 177 lb = small.nextValue(largeLb - 1); 178 } 179 int ub = Math.min(small.getUB(), large.getUB()); 180 for (int i = lb; i <= ub; i = small.nextValue(i)) { 181 if (large.contains(i)) { 182 return true; 183 } 184 } 185 return false; 186 } 187 188 /** 189 * Checks if an integer's domain is contained entirely in the set's 190 * envelope. 191 * 192 * @param i1 the first operand 193 * @param i2 the second operand 194 * @return {@code true} if {@code dom(i1) ⋂ env(i2) ≠ {}}, {@code false} 195 * otherwise 196 */ 197 public static boolean isDomIntersectEnv(IntVar i1, SetVar i2) { 198 if (i1.getDomainSize() < i2.getEnvelopeSize()) { 199 int i = i1.getLB(); 200 int envFirst = i2.getEnvelopeFirst(); 201 if (envFirst >= i) { 202 if (envFirst == i || i1.contains(envFirst)) { 203 return true; 204 } 205 i = i1.nextValue(envFirst); 206 } 207 int ub = i1.getUB(); 208 for (; i <= ub; i = i1.nextValue(i)) { 209 if (i2.envelopeContains(i)) { 210 return true; 211 } 212 } 213 } else { 214 for (int i = i2.getEnvelopeFirst(); i != SetVar.END;) { 215 int next = i1.nextValue(i - 1); 216 while (i < next && i != SetVar.END) { 217 i = i2.getEnvelopeNext(); 218 } 219 if (i == next) { 220 return true; 221 } 222 } 223 } 224 return false; 225 } 226 227 /** 228 * Checks if an integer's domain is contained entirely in the set's kernel. 229 * 230 * @param i1 the first operand 231 * @param i2 the second operand 232 * @return {@code true} if {@code dom(i1) ⋂ ker(i2) ≠ {}}, {@code false} 233 * otherwise 234 */ 235 public static boolean isDomIntersectKer(IntVar i1, SetVar i2) { 236 if (i1.getDomainSize() < i2.getKernelSize()) { 237 int i = i1.getLB(); 238 int envFirst = i2.getKernelFirst(); 239 if (envFirst >= i) { 240 if (envFirst == i || i1.contains(envFirst)) { 241 return true; 242 } 243 i = i1.nextValue(envFirst); 244 } 245 int ub = i1.getUB(); 246 for (; i <= ub; i = i1.nextValue(i)) { 247 if (i2.kernelContains(i)) { 248 return true; 249 } 250 } 251 } else { 252 for (int i = i2.getKernelFirst(); i != SetVar.END;) { 253 int next = i1.nextValue(i - 1); 254 while (i < next && i != SetVar.END) { 255 i = i2.getKernelNext(); 256 } 257 if (i == next) { 258 return true; 259 } 260 } 261 } 262 return false; 263 } 264 265 /** 266 * Checks if a set's envelope is contained entirely in the other set's 267 * envelope. 268 * 269 * @param i1 the first operand 270 * @param i2 the second operand 271 * @return {@code true} if {@code env(i1) ⋂ env(i2) ≠ {}}, {@code false} 272 * otherwise 273 */ 274 public static boolean isEnvIntersectEnv(SetVar i1, SetVar i2) { 275 SetVar small = i1; 276 SetVar large = i2; 277 if (i1.getEnvelopeSize() > i2.getEnvelopeSize()) { 278 small = i2; 279 large = i1; 280 } 281 for (int i = small.getEnvelopeFirst(); i != SetVar.END; i = small.getEnvelopeNext()) { 282 if (large.envelopeContains(i)) { 283 return true; 284 } 285 } 286 return false; 287 } 288 289 /** 290 * Checks if a set's envelope is contained entirely in the set's kernel. 291 * 292 * @param i1 the first operand 293 * @param i2 the second operand 294 * @return {@code true} if {@code env(i1) ⋂ ker(i2) ≠ {}}, {@code false} 295 * otherwise 296 */ 297 public static boolean isEnvIntersectKer(SetVar i1, SetVar i2) { 298 if (i1.getEnvelopeSize() < i2.getEnvelopeSize()) { 299 for (int i = i1.getEnvelopeFirst(); i != SetVar.END; i = i1.getEnvelopeNext()) { 300 if (i2.kernelContains(i)) { 301 return true; 302 } 303 } 304 } else { 305 for (int i = i2.getKernelFirst(); i != SetVar.END; i = i2.getKernelNext()) { 306 if (i1.envelopeContains(i)) { 307 return true; 308 } 309 } 310 } 311 312 return false; 313 } 314 315 /** 316 * Checks if a set's kernel is contained entirely in the other set's kernel. 317 * 318 * @param i1 the first operand 319 * @param i2 the second operand 320 * @return {@code true} if {@code ker(i1) ⋂ ker(i2) ≠ {}}, {@code false} 321 * otherwise 322 */ 323 public static boolean isKerIntersectKer(SetVar i1, SetVar i2) { 324 SetVar small = i1; 325 SetVar large = i2; 326 if (i1.getKernelSize() > i2.getKernelSize()) { 327 small = i2; 328 large = i1; 329 } 330 for (int i = small.getKernelFirst(); i != SetVar.END; i = small.getKernelNext()) { 331 if (large.kernelContains(i)) { 332 return true; 333 } 334 } 335 return false; 336 } 337 338 /** 339 * Checks if an integer's domain is contained entirely in the other 340 * integer's domain. 341 * 342 * @param sub the subset 343 * @param sup the superset 344 * @return {@code true} if {@code dom(sub) ⊆ dom(sup)}, {@code false} 345 * otherwise 346 */ 347 public static boolean isDomSubsetDom(IntVar sub, IntVar sup) { 348 if (sub.getDomainSize() > sup.getDomainSize()) { 349 return false; 350 } 351 int ub = sub.getUB(); 352 for (int i = sub.getLB(); i <= ub; i = sub.nextValue(i)) { 353 if (!sup.contains(i)) { 354 return false; 355 } 356 } 357 return true; 358 } 359 360 /** 361 * Checks if an integer's domain is contained entirely in the set's 362 * envelope. 363 * 364 * @param sub the subset 365 * @param sup the superset 366 * @return {@code true} if {@code dom(sub) ⊆ env(sup)}, {@code false} 367 * otherwise 368 */ 369 public static boolean isDomSubsetEnv(IntVar sub, SetVar sup) { 370 if (sub.getDomainSize() > sup.getEnvelopeSize()) { 371 return false; 372 } 373 int ub = sub.getUB(); 374 for (int i = sub.getLB(); i <= ub; i = sub.nextValue(i)) { 375 if (!sup.envelopeContains(i)) { 376 return false; 377 } 378 } 379 return true; 380 } 381 382 /** 383 * Checks if an integer's domain is contained entirely in the set's kernel. 384 * 385 * @param sub the subset 386 * @param sup the superset 387 * @return {@code true} if {@code dom(sub) ⊆ ker(sup)}, {@code false} 388 * otherwise 389 */ 390 public static boolean isDomSubsetKer(IntVar sub, SetVar sup) { 391 if (sub.getDomainSize() > sup.getKernelSize()) { 392 return false; 393 } 394 int ub = sub.getUB(); 395 for (int i = sub.getLB(); i <= ub; i = sub.nextValue(i)) { 396 if (!sup.kernelContains(i)) { 397 return false; 398 } 399 } 400 return true; 401 } 402 403 /** 404 * Checks if a set's envelope is contained entirely in the integer's domain. 405 * 406 * @param sub the subset 407 * @param sup the superset 408 * @return {@code true} if {@code env(sub) ⊆ dom(sup)}, {@code false} 409 * otherwise 410 */ 411 public static boolean isEnvSubsetDom(SetVar sub, IntVar sup) { 412 if (sub.getEnvelopeSize() > sup.getDomainSize()) { 413 return false; 414 } 415 for (int i = sub.getEnvelopeFirst(); i != SetVar.END; i = sub.getEnvelopeNext()) { 416 if (!sup.contains(i)) { 417 return false; 418 } 419 } 420 return true; 421 } 422 423 /** 424 * Checks if a set's envelope is contained entirely in the other set's 425 * envelope. 426 * 427 * @param sub the subset 428 * @param sup the superset 429 * @return {@code true} if {@code env(sub) ⊆ env(sup)}, {@code false} 430 * otherwise 431 */ 432 public static boolean isEnvSubsetEnv(SetVar sub, SetVar sup) { 433 if (sub.getEnvelopeSize() > sup.getEnvelopeSize()) { 434 return false; 435 } 436 for (int i = sub.getEnvelopeFirst(); i != SetVar.END; i = sub.getEnvelopeNext()) { 437 if (!sup.envelopeContains(i)) { 438 return false; 439 } 440 } 441 return true; 442 } 443 444 /** 445 * Checks if a set's envelope is contained entirely in the set's kernel. 446 * 447 * @param sub the subset 448 * @param sup the superset 449 * @return {@code true} if {@code env(sub) ⊆ ker(sup)}, {@code false} 450 * otherwise 451 */ 452 public static boolean isEnvSubsetKer(SetVar sub, SetVar sup) { 453 if (sub.getEnvelopeSize() > sup.getKernelSize()) { 454 return false; 455 } 456 for (int i = sub.getEnvelopeFirst(); i != SetVar.END; i = sub.getEnvelopeNext()) { 457 if (!sup.kernelContains(i)) { 458 return false; 459 } 460 } 461 return true; 462 } 463 464 /** 465 * Checks if a set's kernel is contained entirely in the integer's domain. 466 * 467 * @param sub the subset 468 * @param sup the superset 469 * @return {@code true} if {@code ker(sub) ⊆ dom(sup)}, {@code false} 470 * otherwise 471 */ 472 public static boolean isKerSubsetDom(SetVar sub, IntVar sup) { 473 for (int i = sub.getKernelFirst(); i != SetVar.END; i = sub.getKernelNext()) { 474 if (!sup.contains(i)) { 475 return false; 476 } 477 } 478 return true; 479 } 480 481 /** 482 * Checks if a set's kernel is contained entirely in the set's envelope. 483 * 484 * @param sub the subset 485 * @param sup the superset 486 * @return {@code true} if {@code ker(sub) ⊆ env(sup)}, {@code false} 487 * otherwise 488 */ 489 public static boolean isKerSubsetEnv(SetVar sub, SetVar sup) { 490 for (int i = sub.getKernelFirst(); i != SetVar.END; i = sub.getKernelNext()) { 491 if (!sup.envelopeContains(i)) { 492 return false; 493 } 494 } 495 return true; 496 } 497 498 /** 499 * Checks if a set's kernel is contained entirely in the other set's kernel. 500 * 501 * @param sub the subset 502 * @param sup the superset 503 * @return {@code true} if {@code ker(sub) ⊆ ker(sup)}, {@code false} 504 * otherwise 505 */ 506 public static boolean isKerSubsetKer(SetVar sub, SetVar sup) { 507 508 for (int i = sub.getKernelFirst(); i != SetVar.END; i = sub.getKernelNext()) { 509 if (!sup.kernelContains(i)) { 510 return false; 511 } 512 } 513 return true; 514 } 515 516 /** 517 * Removes every element in an integer's domain that is not in the set. 518 * 519 * @param sub the subset 520 * @param sup the superset 521 * @param propagator the propagator 522 * @throws ContradictionException 523 * @return {@code true} if a variable has been changed, {@code false} 524 * otherwise 525 */ 526 public static boolean domSubsetSet(IntVar sub, TIntSet sup, ICause propagator) throws ContradictionException { 527 boolean changed = false; 528 int left = Integer.MIN_VALUE; 529 int right = left; 530 int ub = sub.getUB(); 531 for (int val = sub.getLB(); val <= ub; val = sub.nextValue(val)) { 532 if (!sup.contains(val)) { 533 if (val == right + 1) { 534 right = val; 535 } else { 536 changed |= sub.removeInterval(left, right, propagator); 537 left = val; 538 right = val; 539 } 540 } 541 } 542 changed |= sub.removeInterval(left, right, propagator); 543 return changed; 544 } 545 546 /** 547 * Removes every element in an integer's domain that is not in the other 548 * integer's domain. 549 * 550 * @param sub the subset 551 * @param sup the superset 552 * @param propagator the propagator 553 * @throws ContradictionException 554 * @return {@code true} if a variable has been changed, {@code false} 555 * otherwise 556 */ 557 public static boolean domSubsetDom(IntVar sub, IntVar sup, ICause propagator) throws ContradictionException { 558 boolean changed = false; 559 changed |= sub.updateLowerBound(sup.getLB(), propagator); 560 changed |= sub.updateUpperBound(sup.getUB(), propagator); 561 int left = Integer.MIN_VALUE; 562 int right = left; 563 int ub = sub.getUB(); 564 for (int val = sub.getLB(); val <= ub; val = sub.nextValue(val)) { 565 if (!sup.contains(val)) { 566 if (val == right + 1) { 567 right = val; 568 } else { 569 changed |= sub.removeInterval(left, right, propagator); 570 left = val; 571 right = val; 572 } 573 } 574 } 575 changed |= sub.removeInterval(left, right, propagator); 576 return changed; 577 } 578 579 /** 580 * Removes every element in an integer's domain that is not in the set's 581 * envelope. 582 * 583 * @param sub the subset 584 * @param sup the superset 585 * @param propagator the propagator 586 * @throws ContradictionException 587 * @return {@code true} if a variable has been changed, {@code false} 588 * otherwise 589 */ 590 public static boolean domSubsetEnv(IntVar sub, SetVar sup, ICause propagator) throws ContradictionException { 591 boolean changed = false; 592 int left = Integer.MIN_VALUE; 593 int right = left; 594 int ub = sub.getUB(); 595 for (int val = sub.getLB(); val <= ub; val = sub.nextValue(val)) { 596 if (!sup.envelopeContains(val)) { 597 if (val == right + 1) { 598 right = val; 599 } else { 600 changed |= sub.removeInterval(left, right, propagator); 601 left = val; 602 right = val; 603 } 604 } 605 } 606 changed |= sub.removeInterval(left, right, propagator); 607 return changed; 608 } 609 610 /** 611 * Removes every element in an integer's domain that is not in the set's 612 * kernel. 613 * 614 * @param sub the subset 615 * @param sup the superset 616 * @param propagator the propagator 617 * @throws ContradictionException 618 * @return {@code true} if a variable has been changed, {@code false} 619 * otherwise 620 */ 621 public static boolean domSubsetKer(IntVar sub, SetVar sup, ICause propagator) throws ContradictionException { 622 boolean changed = false; 623 int left = Integer.MIN_VALUE; 624 int right = left; 625 int ub = sub.getUB(); 626 for (int val = sub.getLB(); val <= ub; val = sub.nextValue(val)) { 627 if (!sup.kernelContains(val)) { 628 if (val == right + 1) { 629 right = val; 630 } else { 631 changed |= sub.removeInterval(left, right, propagator); 632 left = val; 633 right = val; 634 } 635 } 636 } 637 changed |= sub.removeInterval(left, right, propagator); 638 return changed; 639 } 640 641 /** 642 * Removes every element in a set's envelope that is not in the set. 643 * 644 * @param sub the subset 645 * @param sup the superset 646 * @param propagator the propagator 647 * @throws ContradictionException 648 * @return {@code true} if a variable has been changed, {@code false} 649 * otherwise 650 */ 651 public static boolean envSubsetSet(SetVar sub, TIntSet sup, ICause propagator) throws ContradictionException { 652 boolean changed = false; 653 for (int val = sub.getEnvelopeFirst(); val != SetVar.END; val = sub.getEnvelopeNext()) { 654 if (!sup.contains(val)) { 655 changed |= sub.removeFromEnvelope(val, propagator); 656 } 657 } 658 return changed; 659 } 660 661 /** 662 * Removes every element in a set's envelope that is not in the integer's 663 * domain. 664 * 665 * @param sub the subset 666 * @param sup the superset 667 * @param propagator the propagator 668 * @throws ContradictionException 669 * @return {@code true} if a variable has been changed, {@code false} 670 * otherwise 671 */ 672 public static boolean envSubsetDom(SetVar sub, IntVar sup, ICause propagator) throws ContradictionException { 673 boolean changed = false; 674 for (int val = sub.getEnvelopeFirst(); val != SetVar.END; val = sub.getEnvelopeNext()) { 675 if (!sup.contains(val)) { 676 changed |= sub.removeFromEnvelope(val, propagator); 677 } 678 } 679 return changed; 680 } 681 682 /** 683 * Removes every element in a set's envelope that is not in the other set's 684 * envelope. 685 * 686 * @param sub the subset 687 * @param sup the superset 688 * @param propagator the propagator 689 * @throws ContradictionException 690 * @return {@code true} if a variable has been changed, {@code false} 691 * otherwise 692 */ 693 public static boolean envSubsetEnv(SetVar sub, SetVar sup, ICause propagator) throws ContradictionException { 694 boolean changed = false; 695 for (int i = sub.getEnvelopeFirst(); i != SetVar.END; i = sub.getEnvelopeNext()) { 696 if (!sup.envelopeContains(i)) { 697 changed |= sub.removeFromEnvelope(i, propagator); 698 } 699 } 700 return changed; 701 } 702 703 /** 704 * Removes every element in a set's envelope that is not in the set's 705 * kernel. 706 * 707 * @param sub the subset 708 * @param sup the superset 709 * @param propagator the propagator 710 * @throws ContradictionException 711 * @return {@code true} if a variable has been changed, {@code false} 712 * otherwise 713 */ 714 public static boolean envSubsetKer(SetVar sub, SetVar sup, ICause propagator) throws ContradictionException { 715 boolean changed = false; 716 for (int i = sub.getEnvelopeFirst(); i != SetVar.END; i = sub.getEnvelopeNext()) { 717 if (!sup.kernelContains(i)) { 718 changed |= sub.removeFromEnvelope(i, propagator); 719 } 720 } 721 return changed; 722 } 723 724 /** 725 * Adds every element in a set's kernel to the other set's kernel. 726 * 727 * @param sub the subset 728 * @param sup the superset 729 * @param propagator the propagator 730 * @throws ContradictionException 731 * @return {@code true} if a variable has been changed, {@code false} 732 * otherwise 733 */ 734 public static boolean kerSubsetKer(SetVar sub, SetVar sup, ICause propagator) throws ContradictionException { 735 boolean changed = false; 736 for (int i = sub.getKernelFirst(); i != SetVar.END; i = sub.getKernelNext()) { 737 changed |= sup.addToKernel(i, propagator); 738 } 739 return changed; 740 } 741}