this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2/* 3 * Main authors: 4 * Linnea Ingmar <linnea.ingmar@hotmail.com> 5 * Christian Schulte <schulte@gecode.org> 6 * 7 * Copyright: 8 * Linnea Ingmar, 2017 9 * Christian Schulte, 2017 10 * 11 * This file is part of Gecode, the generic constraint 12 * development environment: 13 * http://www.gecode.org 14 * 15 * Permission is hereby granted, free of charge, to any person obtaining 16 * a copy of this software and associated documentation files (the 17 * "Software"), to deal in the Software without restriction, including 18 * without limitation the rights to use, copy, modify, merge, publish, 19 * distribute, sublicense, and/or sell copies of the Software, and to 20 * permit persons to whom the Software is furnished to do so, subject to 21 * the following conditions: 22 * 23 * The above copyright notice and this permission notice shall be 24 * included in all copies or substantial portions of the Software. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 30 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 31 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 32 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 * 34 */ 35 36#include <algorithm> 37#include <type_traits> 38 39namespace Gecode { namespace Int { namespace Extensional { 40 41 /* 42 * Advisor 43 * 44 */ 45 template<class View, bool pos> 46 forceinline void 47 Compact<View,pos>::CTAdvisor::adjust(void) { 48 if (pos) { 49 { 50 int n = view().min(); 51 assert((_fst->min <= n) && (n <= _lst->max)); 52 while (n > _fst->max) 53 _fst++; 54 assert((_fst->min <= n) && (n <= _lst->max)); 55 } 56 { 57 int n = view().max(); 58 assert((_fst->min <= n) && (n <= _lst->max)); 59 while (n < _lst->min) 60 _lst--; 61 assert((_fst->min <= n) && (n <= _lst->max)); 62 } 63 } else { 64 { 65 int n = view().min(); 66 while ((_fst <= _lst) && (n > _fst->max)) 67 _fst++; 68 } 69 { 70 int n = view().max(); 71 while ((_fst <= _lst) && (n < _lst->min)) 72 _lst--; 73 } 74 } 75 } 76 77 template<class View, bool pos> 78 forceinline 79 Compact<View,pos>::CTAdvisor::CTAdvisor 80 (Space& home, Propagator& p, 81 Council<CTAdvisor>& c, const TupleSet& ts, View x0, int i) 82 : ViewAdvisor<View>(home,p,c,x0), _fst(ts.fst(i)), _lst(ts.lst(i)) { 83 adjust(); 84 } 85 86 template<class View, bool pos> 87 forceinline 88 Compact<View,pos>::CTAdvisor::CTAdvisor(Space& home, CTAdvisor& a) 89 : ViewAdvisor<View>(home,a), _fst(a._fst), _lst(a._lst) {} 90 91 template<class View, bool pos> 92 forceinline const typename Compact<View,pos>::Range* 93 Compact<View,pos>::CTAdvisor::fst(void) const { 94 return _fst; 95 } 96 97 template<class View, bool pos> 98 forceinline const typename Compact<View,pos>::Range* 99 Compact<View,pos>::CTAdvisor::lst(void) const { 100 return _lst; 101 } 102 103 template<class View, bool pos> 104 forceinline void 105 Compact<View,pos>::CTAdvisor::dispose(Space& home, Council<CTAdvisor>& c) { 106 (void) ViewAdvisor<View>::dispose(home,c); 107 } 108 109 110 /* 111 * The propagator base class 112 * 113 */ 114 template<class View, bool pos> 115 const typename Compact<View,pos>::Range* 116 Compact<View,pos>::range(CTAdvisor& a, int n) { 117 assert((n > a.fst()->max) && (n < a.lst()->min)); 118 119 const Range* f=a.fst()+1; 120 const Range* l=a.lst()-1; 121 122 assert(!pos || (f<=l)); 123 124 while (f < l) { 125 const Range* m = f + ((l-f) >> 1); 126 if (n < m->min) { 127 l=m-1; 128 } else if (n > m->max) { 129 f=m+1; 130 } else { 131 f=m; break; 132 } 133 } 134 135 if (pos) { 136 assert((f->min <= n) && (n <= f->max)); 137 return f; 138 } else { 139 if ((f <= l) && (f->min <= n) && (n <= f->max)) 140 return f; 141 else 142 return nullptr; 143 } 144 } 145 146 template<class View, bool pos> 147 forceinline const BitSetData* 148 Compact<View,pos>::supports(CTAdvisor& a, int n) { 149 const Range* fnd; 150 const Range* fst=a.fst(); 151 const Range* lst=a.lst(); 152 if (pos) { 153 if (n <= fst->max) { 154 fnd=fst; 155 } else if (n >= lst->min) { 156 fnd=lst; 157 } else { 158 fnd=range(a,n); 159 } 160 } else { 161 if ((n < fst->min) || (n > lst->max)) 162 return nullptr; 163 if (n <= fst->max) { 164 fnd=fst; 165 } else if (n >= lst->min) { 166 fnd=lst; 167 } else { 168 fnd=range(a,n); 169 if (!fnd) 170 return nullptr; 171 } 172 } 173 assert((fnd->min <= n) && (n <= fnd->max)); 174 return fnd->supports(n_words,n); 175 } 176 177 template<class View, bool pos> 178 forceinline void 179 Compact<View,pos>::ValidSupports::find(void) { 180 assert(!pos); 181 assert(n <= max); 182 while (true) { 183 while (xr() && (n > xr.max())) 184 ++xr; 185 if (!xr()) { 186 n = max+1; return; 187 } 188 assert(n <= xr.max()); 189 n = std::max(n,xr.min()); 190 191 while ((sr <= lst) && (n > sr->max)) 192 sr++; 193 if (sr > lst) { 194 n = max+1; return; 195 } 196 assert(n <= sr->max); 197 n = std::max(n,sr->min); 198 199 if ((xr.min() <= n) && (n <= xr.max())) { 200 s = sr->supports(n_words,n); 201 return; 202 } 203 } 204 GECODE_NEVER; 205 } 206 207 template<class View, bool pos> 208 forceinline 209 Compact<View,pos>::ValidSupports::ValidSupports(const Compact<View,pos>& p, 210 CTAdvisor& a) 211 : n_words(p.n_words), max(a.view().max()), 212 xr(a.view()), sr(a.fst()), lst(a.lst()), n(xr.min()) { 213 if (pos) { 214 while (n > sr->max) 215 sr++; 216 s = sr->supports(n_words,n); 217 } else { 218 s = nullptr; // To avoid warnings 219 find(); 220 } 221 } 222 template<class View, bool pos> 223 forceinline 224 Compact<View,pos>::ValidSupports::ValidSupports(const TupleSet& ts, 225 int i, View x) 226 : n_words(ts.words()), max(x.max()), 227 xr(x), sr(ts.fst(i)), lst(ts.lst(i)), n(xr.min()) { 228 if (pos) { 229 while (n > sr->max) 230 sr++; 231 s = sr->supports(n_words,n); 232 } else { 233 s = nullptr; // To avoid warnings 234 find(); 235 } 236 } 237 template<class View, bool pos> 238 forceinline void 239 Compact<View,pos>::ValidSupports::operator ++(void) { 240 n++; 241 if (pos) { 242 if (n <= xr.max()) { 243 assert(n <= sr->max); 244 s += n_words; 245 } else if (n <= max) { 246 while (n > xr.max()) 247 ++xr; 248 n = xr.min(); 249 while (n > sr->max) 250 sr++; 251 s = sr->supports(n_words,n); 252 assert((xr.min() <= n) && (n <= xr.max())); 253 assert((sr->min <= n) && (n <= sr->max)); 254 assert(sr->min <= xr.min()); 255 } 256 } else { 257 if ((n <= sr->max) && (n <= xr.max())) { 258 s += n_words; 259 } else if (n <= max) { 260 find(); 261 } 262 } 263 } 264 template<class View, bool pos> 265 forceinline bool 266 Compact<View,pos>::ValidSupports::operator ()(void) const { 267 return n <= max; 268 } 269 template<class View, bool pos> 270 forceinline const BitSetData* 271 Compact<View,pos>::ValidSupports::supports(void) const { 272 assert(s == sr->supports(n_words,n)); 273 return s; 274 } 275 template<class View, bool pos> 276 forceinline int 277 Compact<View,pos>::ValidSupports::val(void) const { 278 return n; 279 } 280 281 /* 282 * Lost supports iterator 283 * 284 */ 285 template<class View, bool pos> 286 forceinline 287 Compact<View,pos>::LostSupports::LostSupports 288 (const Compact<View,pos>& p, CTAdvisor& a, int l0, int h0) 289 : n_words(p.n_words), r(a.fst()), l(l0), h(h0) { 290 assert(pos); 291 // Move to first value for which there is support 292 while (l > r->max) 293 r++; 294 l = std::max(l,r->min); 295 s = r->supports(n_words,l); 296 } 297 template<class View, bool pos> 298 forceinline void 299 Compact<View,pos>::LostSupports::operator ++(void) { 300 l++; s += n_words; 301 while ((l <= h) && (l > r->max)) { 302 r++; l=r->min; s=r->s; 303 } 304 } 305 template<class View, bool pos> 306 forceinline bool 307 Compact<View,pos>::LostSupports::operator ()(void) const { 308 return l<=h; 309 } 310 template<class View, bool pos> 311 forceinline const TupleSet::BitSetData* 312 Compact<View,pos>::LostSupports::supports(void) const { 313 assert((l >= r->min) && (l <= r->max)); 314 assert(s == r->supports(n_words,l)); 315 return s; 316 } 317 318 template<class View, bool pos> 319 forceinline bool 320 Compact<View,pos>::all(void) const { 321 Advisors<CTAdvisor> as(c); 322 return !as(); 323 } 324 template<class View, bool pos> 325 forceinline bool 326 Compact<View,pos>::atmostone(void) const { 327 Advisors<CTAdvisor> as(c); 328 if (!as()) return true; 329 ++as; 330 return !as(); 331 } 332 333 template<class View, bool pos> 334 forceinline 335 Compact<View,pos>::Compact(Space& home, Compact& p) 336 : Propagator(home,p), n_words(p.n_words), ts(p.ts) { 337 c.update(home,p.c); 338 } 339 340 template<class View, bool pos> 341 forceinline 342 Compact<View,pos>::Compact(Home home, const TupleSet& ts0) 343 : Propagator(home), n_words(ts0.words()), ts(ts0), c(home) { 344 home.notice(*this, AP_DISPOSE); 345 } 346 347 template<class View, bool pos> 348 template<class Table> 349 void 350 Compact<View,pos>::setup(Space& home, Table& table, ViewArray<View>& x) { 351 // For scheduling the propagator 352 ModEvent me = ME_INT_BND; 353 Region r; 354 BitSetData* mask = r.alloc<BitSetData>(table.size()); 355 // Invalidate tuples 356 for (int i=0; i<x.size(); i++) { 357 table.clear_mask(mask); 358 for (ValidSupports vs(ts,i,x[i]); vs(); ++vs) 359 table.add_to_mask(vs.supports(),mask); 360 table.template intersect_with_mask<false>(mask); 361 // The propagator must be scheduled for subsumption 362 if (table.empty()) 363 goto schedule; 364 } 365 // Post advisors 366 for (int i=0; i<x.size(); i++) 367 if (!x[i].assigned()) 368 (void) new (home) CTAdvisor(home,*this,c,ts,x[i],i); 369 else 370 me = ME_INT_VAL; 371 // Schedule propagator 372 schedule: 373 View::schedule(home,*this,me); 374 } 375 376 template<class View, bool pos> 377 template<class Table> 378 forceinline bool 379 Compact<View,pos>::full(const Table& table) const { 380 unsigned long long int s = 1U; 381 for (Advisors<CTAdvisor> as(c); as(); ++as) { 382 s *= static_cast<unsigned long long int>(as.advisor().view().size()); 383 if (s > table.bits()) 384 return false; 385 } 386 return s == table.ones(); 387 } 388 389 template<class View, bool pos> 390 PropCost 391 Compact<View,pos>::cost(const Space&, const ModEventDelta&) const { 392 // Computing this is crucial in case there are many propagators! 393 int n = 0; 394 // The value of 3 is cheating from the Gecode kernel... 395 for (Advisors<CTAdvisor> as(c); as() && (n <= 3); ++as) 396 n++; 397 return PropCost::quadratic(PropCost::HI,n); 398 } 399 400 template<class View, bool pos> 401 forceinline size_t 402 Compact<View,pos>::dispose(Space& home) { 403 home.ignore(*this,AP_DISPOSE); 404 c.dispose(home); 405 ts.~TupleSet(); 406 (void) Propagator::dispose(home); 407 return sizeof(*this); 408 } 409 410 411 /* 412 * Status for the positive propagator 413 * 414 */ 415 template<class View, class Table> 416 forceinline 417 PosCompact<View,Table>::Status::Status(StatusType t) 418 : s(t) {} 419 template<class View, class Table> 420 forceinline 421 PosCompact<View,Table>::Status::Status(const Status& s) 422 : s(s.s) {} 423 template<class View, class Table> 424 forceinline typename PosCompact<View,Table>::StatusType 425 PosCompact<View,Table>::Status::type(void) const { 426 return static_cast<StatusType>(s & 3); 427 } 428 template<class View, class Table> 429 forceinline bool 430 PosCompact<View,Table>::Status::single(CTAdvisor& a) const { 431 if (type() != SINGLE) 432 return false; 433 assert(type() == 0); 434 return reinterpret_cast<CTAdvisor*>(s) == &a; 435 } 436 template<class View, class Table> 437 forceinline void 438 PosCompact<View,Table>::Status::touched(CTAdvisor& a) { 439 if (!single(a)) 440 s = MULTIPLE; 441 } 442 template<class View, class Table> 443 forceinline void 444 PosCompact<View,Table>::Status::none(void) { 445 s = NONE; 446 } 447 template<class View, class Table> 448 forceinline void 449 PosCompact<View,Table>::Status::propagating(void) { 450 s = PROPAGATING; 451 } 452 453 /* 454 * The propagator proper 455 * 456 */ 457 template<class View, class Table> 458 template<class TableProp> 459 forceinline 460 PosCompact<View,Table>::PosCompact(Space& home, TableProp& p) 461 : Compact<View,true>(home,p), status(NONE), table(home,p.table) { 462 assert(!table.empty()); 463 } 464 465 template<class View, class Table> 466 Actor* 467 PosCompact<View,Table>::copy(Space& home) { 468 assert((table.words() > 0U) && (table.width() >= table.words())); 469 if (table.words() <= 4U) { 470 switch (table.width()) { 471 case 0U: 472 GECODE_NEVER; break; 473 case 1U: 474 return new (home) PosCompact<View,TinyBitSet<1U>>(home,*this); 475 case 2U: 476 return new (home) PosCompact<View,TinyBitSet<2U>>(home,*this); 477 case 3U: 478 return new (home) PosCompact<View,TinyBitSet<3U>>(home,*this); 479 case 4U: 480 return new (home) PosCompact<View,TinyBitSet<4U>>(home,*this); 481 default: 482 break; 483 } 484 } 485 if (std::is_same<Table,BitSet<unsigned char>>::value) { 486 goto copy_char; 487 } else if (std::is_same<Table,BitSet<unsigned short int>>::value) { 488 switch (Gecode::Support::u_type(table.width())) { 489 case Gecode::Support::IT_CHAR: goto copy_char; 490 case Gecode::Support::IT_SHRT: goto copy_short; 491 case Gecode::Support::IT_INT: GECODE_NEVER; 492 default: GECODE_NEVER; 493 } 494 } else { 495 switch (Gecode::Support::u_type(table.width())) { 496 case Gecode::Support::IT_CHAR: goto copy_char; 497 case Gecode::Support::IT_SHRT: goto copy_short; 498 case Gecode::Support::IT_INT: goto copy_int; 499 default: GECODE_NEVER; 500 } 501 GECODE_NEVER; 502 return nullptr; 503 } 504 copy_char: 505 return new (home) PosCompact<View,BitSet<unsigned char>>(home,*this); 506 copy_short: 507 return new (home) PosCompact<View,BitSet<unsigned short int>>(home,*this); 508 copy_int: 509 return new (home) PosCompact<View,BitSet<unsigned int>>(home,*this); 510 } 511 512 template<class View, class Table> 513 forceinline 514 PosCompact<View,Table>::PosCompact(Home home, ViewArray<View>& x, 515 const TupleSet& ts) 516 : Compact<View,true>(home,ts), status(MULTIPLE), table(home,ts.words()) { 517 setup(home,table,x); 518 } 519 520 template<class View, class Table> 521 forceinline ExecStatus 522 PosCompact<View,Table>::post(Home home, ViewArray<View>& x, 523 const TupleSet& ts) { 524 auto ct = new (home) PosCompact(home,x,ts); 525 assert((x.size() > 1) && (ts.tuples() > 1)); 526 return ct->table.empty() ? ES_FAILED : ES_OK; 527 } 528 529 template<class View, class Table> 530 forceinline size_t 531 PosCompact<View,Table>::dispose(Space& home) { 532 (void) Compact<View,true>::dispose(home); 533 return sizeof(*this); 534 } 535 536 template<class View, class Table> 537 void 538 PosCompact<View,Table>::reschedule(Space& home) { 539 // Modified variable, subsumption, or failure 540 if ((status.type() != StatusType::NONE) || 541 all() || table.empty()) 542 View::schedule(home,*this,ME_INT_DOM); 543 } 544 545 template<class View, class Table> 546 ExecStatus 547 PosCompact<View,Table>::propagate(Space& home, const ModEventDelta&) { 548 if (table.empty()) 549 return ES_FAILED; 550 if (all()) 551 return home.ES_SUBSUMED(*this); 552 553 Status touched(status); 554 // Mark as performing propagation 555 status.propagating(); 556 557 Region r; 558 // Scan all values of all unassigned variables to see if they 559 // are still supported. 560 for (Advisors<CTAdvisor> as(c); as(); ++as) { 561 CTAdvisor& a = as.advisor(); 562 View x = a.view(); 563 564 // No point filtering variable if it was the only modified variable 565 if (touched.single(a) || x.assigned()) 566 continue; 567 568 if (x.size() == 2) { // Consider min and max values only 569 if (!table.intersects(supports(a,x.min()))) 570 GECODE_ME_CHECK(x.eq(home,x.max())); 571 else if (!table.intersects(supports(a,x.max()))) 572 GECODE_ME_CHECK(x.eq(home,x.min())); 573 if (!x.assigned()) 574 a.adjust(); 575 } else { // x.size() > 2 576 // How many values to remove 577 int* nq = r.alloc<int>(x.size()); 578 unsigned int n_nq = 0; 579 // The initialization is here just to avoid warnings... 580 int last_support = 0; 581 for (ValidSupports vs(*this,a); vs(); ++vs) 582 if (!table.intersects(vs.supports())) 583 nq[n_nq++] = vs.val(); 584 else 585 last_support = vs.val(); 586 // Remove collected values 587 if (n_nq > 0U) { 588 if (n_nq == 1U) { 589 GECODE_ME_CHECK(x.nq(home,nq[0])); 590 } else if (n_nq == x.size() - 1U) { 591 GECODE_ME_CHECK(x.eq(home,last_support)); 592 goto noadjust; 593 } else { 594 Iter::Values::Array rnq(nq,n_nq); 595 GECODE_ASSUME(n_nq >= 2U); 596 GECODE_ME_CHECK(x.minus_v(home,rnq,false)); 597 } 598 a.adjust(); 599 noadjust: ; 600 } 601 r.free(); 602 } 603 } 604 605 // Mark as no touched variable 606 status.none(); 607 // Should not be in a failed state 608 assert(!table.empty()); 609 // Subsume if there is at most one non-assigned variable 610 return atmostone() ? home.ES_SUBSUMED(*this) : ES_FIX; 611 } 612 613 template<class View, class Table> 614 ExecStatus 615 PosCompact<View,Table>::advise(Space& home, Advisor& a0, const Delta& d) { 616 CTAdvisor& a = static_cast<CTAdvisor&>(a0); 617 618 // Do not fail a disabled propagator 619 if (table.empty()) 620 return Compact<View,true>::disabled() ? 621 home.ES_NOFIX_DISPOSE(c,a) : ES_FAILED; 622 623 View x = a.view(); 624 625 /* 626 * Do not schedule if propagator is performing propagation, 627 * and dispose if assigned. 628 */ 629 if (status.type() == StatusType::PROPAGATING) 630 return x.assigned() ? home.ES_FIX_DISPOSE(c,a) : ES_FIX; 631 632 // Update status 633 status.touched(a); 634 635 if (x.assigned()) { 636 // Variable is assigned -- intersect with its value 637 table.template intersect_with_mask<true>(supports(a,x.val())); 638 return home.ES_NOFIX_DISPOSE(c,a); 639 } 640 641 if (!x.any(d) && (x.min(d) == x.max(d))) { 642 table.nand_with_mask(supports(a,x.min(d))); 643 a.adjust(); 644 } else if (!x.any(d) && (x.width(d) <= x.size())) { 645 // Incremental update, using the removed values 646 for (LostSupports ls(*this,a,x.min(d),x.max(d)); ls(); ++ls) { 647 table.nand_with_mask(ls.supports()); 648 if (table.empty()) 649 return Compact<View,true>::disabled() ? 650 home.ES_NOFIX_DISPOSE(c,a) : ES_FAILED; 651 } 652 a.adjust(); 653 } else { 654 a.adjust(); 655 // Reset-based update, using the values that are left 656 if (x.size() == 2) { 657 table.intersect_with_masks(supports(a,x.min()), 658 supports(a,x.max())); 659 } else { 660 Region r; 661 BitSetData* mask = r.alloc<BitSetData>(table.size()); 662 // Collect all tuples to be kept in a temporary mask 663 table.clear_mask(mask); 664 for (ValidSupports vs(*this,a); vs(); ++vs) 665 table.add_to_mask(vs.supports(),mask); 666 table.template intersect_with_mask<false>(mask); 667 } 668 } 669 670 // Do not fail a disabled propagator 671 if (table.empty()) 672 return Compact<View,true>::disabled() ? 673 home.ES_NOFIX_DISPOSE(c,a) : ES_FAILED; 674 675 // Schedule propagator 676 return ES_NOFIX; 677 } 678 679 680 /* 681 * Post function 682 */ 683 template<class View> 684 ExecStatus 685 postposcompact(Home home, ViewArray<View>& x, const TupleSet& ts) { 686 if (ts.tuples() == 0) 687 return (x.size() == 0) ? ES_OK : ES_FAILED; 688 689 // All variables pruned to correct domain 690 for (int i=0; i<x.size(); i++) { 691 TupleSet::Ranges r(ts,i); 692 GECODE_ME_CHECK(x[i].inter_r(home, r, false)); 693 } 694 695 if ((x.size() <= 1) || (ts.tuples() <= 1)) 696 return ES_OK; 697 698 // Choose the right bit set implementation 699 switch (ts.words()) { 700 case 0U: 701 GECODE_NEVER; return ES_OK; 702 case 1U: 703 return PosCompact<View,TinyBitSet<1U>>::post(home,x,ts); 704 case 2U: 705 return PosCompact<View,TinyBitSet<2U>>::post(home,x,ts); 706 case 3U: 707 return PosCompact<View,TinyBitSet<3U>>::post(home,x,ts); 708 case 4U: 709 return PosCompact<View,TinyBitSet<4U>>::post(home,x,ts); 710 default: 711 switch (Gecode::Support::u_type(ts.words())) { 712 case Gecode::Support::IT_CHAR: 713 return PosCompact<View,BitSet<unsigned char>> 714 ::post(home,x,ts); 715 case Gecode::Support::IT_SHRT: 716 return PosCompact<View,BitSet<unsigned short int>> 717 ::post(home,x,ts); 718 case Gecode::Support::IT_INT: 719 return PosCompact<View,BitSet<unsigned int>> 720 ::post(home,x,ts); 721 default: GECODE_NEVER; 722 } 723 } 724 GECODE_NEVER; 725 return ES_OK; 726 } 727 728 729 /* 730 * The negative propagator 731 * 732 */ 733 template<class View, class Table> 734 template<class TableProp> 735 forceinline 736 NegCompact<View,Table>::NegCompact(Space& home, TableProp& p) 737 : Compact<View,false>(home,p), table(home,p.table) { 738 assert(!table.empty()); 739 } 740 741 template<class View, class Table> 742 Actor* 743 NegCompact<View,Table>::copy(Space& home) { 744 assert((table.words() > 0U) && (table.width() >= table.words())); 745 if (table.words() <= 4U) { 746 switch (table.width()) { 747 case 0U: 748 GECODE_NEVER; break; 749 case 1U: 750 return new (home) NegCompact<View,TinyBitSet<1U>>(home,*this); 751 case 2U: 752 return new (home) NegCompact<View,TinyBitSet<2U>>(home,*this); 753 case 3U: 754 return new (home) NegCompact<View,TinyBitSet<3U>>(home,*this); 755 case 4U: 756 return new (home) NegCompact<View,TinyBitSet<4U>>(home,*this); 757 default: 758 break; 759 } 760 } 761 if (std::is_same<Table,BitSet<unsigned char>>::value) { 762 goto copy_char; 763 } else if (std::is_same<Table,BitSet<unsigned short int>>::value) { 764 switch (Gecode::Support::u_type(table.width())) { 765 case Gecode::Support::IT_CHAR: goto copy_char; 766 case Gecode::Support::IT_SHRT: goto copy_short; 767 case Gecode::Support::IT_INT: GECODE_NEVER; 768 default: GECODE_NEVER; 769 } 770 } else { 771 switch (Gecode::Support::u_type(table.width())) { 772 case Gecode::Support::IT_CHAR: goto copy_char; 773 case Gecode::Support::IT_SHRT: goto copy_short; 774 case Gecode::Support::IT_INT: goto copy_int; 775 default: GECODE_NEVER; 776 } 777 GECODE_NEVER; 778 return nullptr; 779 } 780 copy_char: 781 return new (home) NegCompact<View,BitSet<unsigned char>>(home,*this); 782 copy_short: 783 return new (home) NegCompact<View,BitSet<unsigned short int>>(home,*this); 784 copy_int: 785 return new (home) NegCompact<View,BitSet<unsigned int>>(home,*this); 786 } 787 788 template<class View, class Table> 789 forceinline 790 NegCompact<View,Table>::NegCompact(Home home, ViewArray<View>& x, 791 const TupleSet& ts) 792 : Compact<View,false>(home,ts), table(home,ts.words()) { 793 setup(home,table,x); 794 } 795 796 template<class View, class Table> 797 forceinline ExecStatus 798 NegCompact<View,Table>::post(Home home, ViewArray<View>& x, 799 const TupleSet& ts) { 800 auto ct = new (home) NegCompact(home,x,ts); 801 return ct->full(ct->table) ? ES_FAILED : ES_OK; 802 } 803 804 template<class View, class Table> 805 forceinline size_t 806 NegCompact<View,Table>::dispose(Space& home) { 807 (void) Compact<View,false>::dispose(home); 808 return sizeof(*this); 809 } 810 811 template<class View, class Table> 812 void 813 NegCompact<View,Table>::reschedule(Space& home) { 814 View::schedule(home,*this,ME_INT_DOM); 815 } 816 817 template<class View, class Table> 818 ExecStatus 819 NegCompact<View,Table>::propagate(Space& home, const ModEventDelta&) { 820#ifndef NDEBUG 821 if (!table.empty()) { 822 // Check that all views have at least one value with support 823 for (Advisors<CTAdvisor> as(c); as(); ++as) { 824 ValidSupports vs(*this,as.advisor()); 825 assert(vs()); 826 } 827 } 828#endif 829 830 if (table.empty()) 831 return home.ES_SUBSUMED(*this); 832 833 // Estimate whether any pruning will be possible 834 unsigned long long int x_size = 1U; 835 unsigned long long int x_max = 1U; 836 /* The size of the Cartesian product will be x_size times x_max, 837 * where x_max is the size of the largest variable domain. 838 */ 839 for (Advisors<CTAdvisor> as(c); as(); ++as) { 840 unsigned long long int n = as.advisor().view().size(); 841 if (n > x_max) { 842 x_size *= x_max; x_max = n; 843 } else { 844 x_size *= n; 845 } 846 if (x_size > table.bits()) 847 return ES_FIX; 848 } 849 if (x_size > table.ones()) 850 return ES_FIX; 851 852 { 853 // Adjust to size of the Cartesian product 854 x_size *= x_max; 855 856 Region r; 857 858 for (Advisors<CTAdvisor> as(c); as(); ++as) { 859 assert(!table.empty()); 860 CTAdvisor& a = as.advisor(); 861 View x = a.view(); 862 863 // Adjust for the current variable domain 864 x_size /= static_cast<unsigned long long int>(x.size()); 865 866 if ((x_size <= table.bits()) && (x_size <= table.ones())) { 867 // How many values to remove 868 int* nq = r.alloc<int>(x.size()); 869 unsigned int n_nq = 0U; 870 871 for (ValidSupports vs(*this,a); vs(); ++vs) 872 if (x_size == table.ones(vs.supports())) 873 nq[n_nq++] = vs.val(); 874 875 // Remove collected values 876 if (n_nq > 0U) { 877 if (n_nq == 1U) { 878 GECODE_ME_CHECK(x.nq(home,nq[0])); 879 } else { 880 Iter::Values::Array rnq(nq,n_nq); 881 GECODE_ASSUME(n_nq >= 2U); 882 GECODE_ME_CHECK(x.minus_v(home,rnq,false)); 883 } 884 if (table.empty()) 885 return home.ES_SUBSUMED(*this); 886 a.adjust(); 887 } 888 r.free(); 889 } 890 // Re-adjust size 891 x_size *= static_cast<unsigned long long int>(x.size()); 892 } 893 } 894 895 if (table.ones() == x_size) 896 return ES_FAILED; 897 if (table.empty() || atmostone()) 898 return home.ES_SUBSUMED(*this); 899 return ES_FIX; 900 } 901 902 template<class View, class Table> 903 ExecStatus 904 NegCompact<View,Table>::advise(Space& home, Advisor& a0, const Delta&) { 905 CTAdvisor& a = static_cast<CTAdvisor&>(a0); 906 907 // We are subsumed 908 if (table.empty()) 909 return home.ES_NOFIX_DISPOSE(c,a); 910 911 View x = a.view(); 912 913 a.adjust(); 914 915 if (x.assigned()) { 916 // Variable is assigned -- intersect with its value 917 if (const BitSetData* s = supports(a,x.val())) 918 table.template intersect_with_mask<true>(s); 919 else 920 table.flush(); // Mark as subsumed 921 return home.ES_NOFIX_DISPOSE(c,a); 922 } 923 924 { 925 ValidSupports vs(*this,a); 926 if (!vs()) { 927 table.flush(); // Mark as subsumed 928 return home.ES_NOFIX_DISPOSE(c,a); 929 } 930 931 Region r; 932 BitSetData* mask = r.alloc<BitSetData>(table.size()); 933 // Collect all tuples to be kept in a temporary mask 934 table.clear_mask(mask); 935 do { 936 table.add_to_mask(vs.supports(),mask); 937 ++vs; 938 } while (vs()); 939 table.template intersect_with_mask<false>(mask); 940 } 941 942 if (table.empty()) 943 return home.ES_NOFIX_DISPOSE(c,a); 944 945 // Schedule propagator 946 return ES_NOFIX; 947 } 948 949 950 /* 951 * Post function 952 */ 953 template<class View> 954 ExecStatus 955 postnegcompact(Home home, ViewArray<View>& x, const TupleSet& ts) { 956 if (ts.tuples() == 0) 957 return ES_OK; 958 959 // Check whether a variable does not overlap with supported values 960 for (int i=0; i<x.size(); i++) { 961 TupleSet::Ranges rs(ts,i); 962 ViewRanges<View> rx(x[i]); 963 if (Iter::Ranges::disjoint(rs,rx)) 964 return ES_OK; 965 } 966 967 // Choose the right bit set implementation 968 switch (ts.words()) { 969 case 0U: 970 GECODE_NEVER; return ES_OK; 971 case 1U: 972 return NegCompact<View,TinyBitSet<1U>>::post(home,x,ts); 973 case 2U: 974 return NegCompact<View,TinyBitSet<2U>>::post(home,x,ts); 975 case 3U: 976 return NegCompact<View,TinyBitSet<3U>>::post(home,x,ts); 977 case 4U: 978 return NegCompact<View,TinyBitSet<4U>>::post(home,x,ts); 979 default: 980 switch (Gecode::Support::u_type(ts.words())) { 981 case Gecode::Support::IT_CHAR: 982 return NegCompact<View,BitSet<unsigned char>> 983 ::post(home,x,ts); 984 case Gecode::Support::IT_SHRT: 985 return NegCompact<View,BitSet<unsigned short int>> 986 ::post(home,x,ts); 987 case Gecode::Support::IT_INT: 988 return NegCompact<View,BitSet<unsigned int>> 989 ::post(home,x,ts); 990 default: GECODE_NEVER; 991 } 992 } 993 GECODE_NEVER; 994 return ES_OK; 995 } 996 997 998 /* 999 * The reified propagator 1000 * 1001 */ 1002 template<class View, class Table, class CtrlView, ReifyMode rm> 1003 template<class TableProp> 1004 forceinline 1005 ReCompact<View,Table,CtrlView,rm>::ReCompact(Space& home, TableProp& p) 1006 : Compact<View,false>(home,p), table(home,p.table) { 1007 b.update(home,p.b); 1008 y.update(home,p.y); 1009 assert(!table.empty()); 1010 } 1011 1012 template<class View, class Table, class CtrlView, ReifyMode rm> 1013 Actor* 1014 ReCompact<View,Table,CtrlView,rm>::copy(Space& home) { 1015 assert((table.words() > 0U) && (table.width() >= table.words())); 1016 if (table.words() <= 4U) { 1017 switch (table.width()) { 1018 case 0U: 1019 GECODE_NEVER; break; 1020 case 1U: 1021 return new (home) ReCompact<View,TinyBitSet<1U>,CtrlView,rm> 1022 (home,*this); 1023 case 2U: 1024 return new (home) ReCompact<View,TinyBitSet<2U>,CtrlView,rm> 1025 (home,*this); 1026 case 3U: 1027 return new (home) ReCompact<View,TinyBitSet<3U>,CtrlView,rm> 1028 (home,*this); 1029 case 4U: 1030 return new (home) ReCompact<View,TinyBitSet<4U>,CtrlView,rm> 1031 (home,*this); 1032 default: 1033 break; 1034 } 1035 } 1036 if (std::is_same<Table,BitSet<unsigned char>>::value) { 1037 goto copy_char; 1038 } else if (std::is_same<Table,BitSet<unsigned short int>>::value) { 1039 switch (Gecode::Support::u_type(table.width())) { 1040 case Gecode::Support::IT_CHAR: goto copy_char; 1041 case Gecode::Support::IT_SHRT: goto copy_short; 1042 case Gecode::Support::IT_INT: GECODE_NEVER; 1043 default: GECODE_NEVER; 1044 } 1045 } else { 1046 switch (Gecode::Support::u_type(table.width())) { 1047 case Gecode::Support::IT_CHAR: goto copy_char; 1048 case Gecode::Support::IT_SHRT: goto copy_short; 1049 case Gecode::Support::IT_INT: goto copy_int; 1050 default: GECODE_NEVER; 1051 } 1052 GECODE_NEVER; 1053 return nullptr; 1054 } 1055 copy_char: 1056 return new (home) ReCompact<View,BitSet<unsigned char>,CtrlView,rm> 1057 (home,*this); 1058 copy_short: 1059 return new (home) ReCompact<View,BitSet<unsigned short int>,CtrlView,rm> 1060 (home,*this); 1061 copy_int: 1062 return new (home) ReCompact<View,BitSet<unsigned int>,CtrlView,rm> 1063 (home,*this); 1064 } 1065 1066 template<class View, class Table, class CtrlView, ReifyMode rm> 1067 forceinline 1068 ReCompact<View,Table,CtrlView,rm>::ReCompact(Home home, ViewArray<View>& x, 1069 const TupleSet& ts, CtrlView b0) 1070 : Compact<View,false>(home,ts), table(home,ts.words()), b(b0), y(x) { 1071 b.subscribe(home,*this,PC_BOOL_VAL); 1072 setup(home,table,x); 1073 } 1074 1075 template<class View, class Table, class CtrlView, ReifyMode rm> 1076 forceinline ExecStatus 1077 ReCompact<View,Table,CtrlView,rm>::post(Home home, ViewArray<View>& x, 1078 const TupleSet& ts, CtrlView b) { 1079 if (b.one()) { 1080 if (rm == RM_PMI) 1081 return ES_OK; 1082 return postposcompact(home,x,ts); 1083 } 1084 if (b.zero()) { 1085 if (rm == RM_IMP) 1086 return ES_OK; 1087 return postnegcompact(home,x,ts); 1088 } 1089 (void) new (home) ReCompact(home,x,ts,b); 1090 return ES_OK; 1091 } 1092 1093 template<class View, class Table, class CtrlView, ReifyMode rm> 1094 forceinline size_t 1095 ReCompact<View,Table,CtrlView,rm>::dispose(Space& home) { 1096 b.cancel(home,*this,PC_BOOL_VAL); 1097 (void) Compact<View,false>::dispose(home); 1098 return sizeof(*this); 1099 } 1100 1101 template<class View, class Table, class CtrlView, ReifyMode rm> 1102 void 1103 ReCompact<View,Table,CtrlView,rm>::reschedule(Space& home) { 1104 View::schedule(home,*this,ME_INT_DOM); 1105 } 1106 1107 template<class View, class Table, class CtrlView, ReifyMode rm> 1108 ExecStatus 1109 ReCompact<View,Table,CtrlView,rm>::propagate(Space& home, 1110 const ModEventDelta&) { 1111 if (b.one()) { 1112 if (rm == RM_PMI) 1113 return home.ES_SUBSUMED(*this); 1114 TupleSet keep(ts); 1115 GECODE_REWRITE(*this,postposcompact(home(*this),y,keep)); 1116 } 1117 if (b.zero()) { 1118 if (rm == RM_IMP) 1119 return home.ES_SUBSUMED(*this); 1120 TupleSet keep(ts); 1121 GECODE_REWRITE(*this,postnegcompact(home(*this),y,keep)); 1122 } 1123 1124 if (table.empty()) { 1125 if (rm != RM_PMI) 1126 GECODE_ME_CHECK(b.zero_none(home)); 1127 return home.ES_SUBSUMED(*this); 1128 } 1129 if (full(table)) { 1130 if (rm != RM_IMP) 1131 GECODE_ME_CHECK(b.one_none(home)); 1132 return home.ES_SUBSUMED(*this); 1133 } 1134 1135 return ES_FIX; 1136 } 1137 1138 template<class View, class Table, class CtrlView, ReifyMode rm> 1139 ExecStatus 1140 ReCompact<View,Table,CtrlView,rm>::advise(Space& home, 1141 Advisor& a0, const Delta&) { 1142 CTAdvisor& a = static_cast<CTAdvisor&>(a0); 1143 1144 // We are subsumed 1145 if (table.empty() || b.assigned()) 1146 return home.ES_NOFIX_DISPOSE(c,a); 1147 1148 View x = a.view(); 1149 1150 a.adjust(); 1151 1152 if (x.assigned()) { 1153 // Variable is assigned -- intersect with its value 1154 if (const BitSetData* s = supports(a,x.val())) 1155 table.template intersect_with_mask<true>(s); 1156 else 1157 table.flush(); // Mark as failed 1158 return home.ES_NOFIX_DISPOSE(c,a); 1159 } 1160 1161 { 1162 ValidSupports vs(*this,a); 1163 if (!vs()) { 1164 table.flush(); // Mark as failed 1165 return home.ES_NOFIX_DISPOSE(c,a); 1166 } 1167 1168 Region r; 1169 BitSetData* mask = r.alloc<BitSetData>(table.size()); 1170 // Collect all tuples to be kept in a temporary mask 1171 table.clear_mask(mask); 1172 do { 1173 table.add_to_mask(vs.supports(),mask); 1174 ++vs; 1175 } while (vs()); 1176 table.template intersect_with_mask<false>(mask); 1177 } 1178 1179 if (table.empty()) 1180 return home.ES_NOFIX_DISPOSE(c,a); 1181 1182 // Schedule propagator 1183 return ES_NOFIX; 1184 } 1185 1186 1187 /* 1188 * Post function 1189 */ 1190 template<class View, class CtrlView, ReifyMode rm> 1191 ExecStatus 1192 postrecompact(Home home, ViewArray<View>& x, const TupleSet& ts, 1193 CtrlView b) { 1194 // Enforce invariant that there is at least one tuple... 1195 if (ts.tuples() == 0) { 1196 if (x.size() != 0) { 1197 if (rm != RM_PMI) 1198 GECODE_ME_CHECK(b.zero(home)); 1199 } else { 1200 if (rm != RM_IMP) 1201 GECODE_ME_CHECK(b.one(home)); 1202 } 1203 return ES_OK; 1204 } 1205 // Check whether a variable does not overlap with supported values 1206 for (int i=0; i<x.size(); i++) { 1207 TupleSet::Ranges rs(ts,i); 1208 ViewRanges<View> rx(x[i]); 1209 if (Iter::Ranges::disjoint(rs,rx)) { 1210 if (rm != RM_PMI) 1211 GECODE_ME_CHECK(b.zero(home)); 1212 return ES_OK; 1213 } 1214 } 1215 // Choose the right bit set implementation 1216 switch (ts.words()) { 1217 case 0U: 1218 GECODE_NEVER; return ES_OK; 1219 case 1U: 1220 return ReCompact<View,TinyBitSet<1U>,CtrlView,rm>::post(home,x,ts,b); 1221 case 2U: 1222 return ReCompact<View,TinyBitSet<2U>,CtrlView,rm>::post(home,x,ts,b); 1223 case 3U: 1224 return ReCompact<View,TinyBitSet<3U>,CtrlView,rm>::post(home,x,ts,b); 1225 case 4U: 1226 return ReCompact<View,TinyBitSet<4U>,CtrlView,rm>::post(home,x,ts,b); 1227 default: 1228 switch (Gecode::Support::u_type(ts.words())) { 1229 case Gecode::Support::IT_CHAR: 1230 return ReCompact<View,BitSet<unsigned char>,CtrlView,rm> 1231 ::post(home,x,ts,b); 1232 case Gecode::Support::IT_SHRT: 1233 return ReCompact<View,BitSet<unsigned short int>,CtrlView,rm> 1234 ::post(home,x,ts,b); 1235 case Gecode::Support::IT_INT: 1236 return ReCompact<View,BitSet<unsigned int>,CtrlView,rm> 1237 ::post(home,x,ts,b); 1238 default: GECODE_NEVER; 1239 } 1240 } 1241 GECODE_NEVER; 1242 return ES_OK; 1243 } 1244 1245}}} 1246 1247// STATISTICS: int-prop