00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <string.h>
00017 #include <algorithm>
00018 #include "base/hash.h"
00019 #include <string>
00020 #include <vector>
00021
00022 #include "base/commandlineflags.h"
00023 #include "base/integral_types.h"
00024 #include "base/logging.h"
00025 #include "base/scoped_ptr.h"
00026 #include "base/stringprintf.h"
00027 #include "base/concise_iterator.h"
00028 #include "base/map-util.h"
00029 #include "constraint_solver/constraint_solver.h"
00030 #include "constraint_solver/constraint_solveri.h"
00031 #include "util/bitset.h"
00032 #include "util/tuple_set.h"
00033
00034 DEFINE_bool(cp_use_compact_table, true,
00035 "Use compact table constraint when possible.");
00036 DEFINE_bool(cp_use_small_table, true,
00037 "Use small compact table constraint when possible.");
00038
00039 namespace operations_research {
00040 namespace {
00041
00042
00043
00044 static const int kBitsInUint64 = 64;
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 class BasePositiveTableConstraint : public Constraint {
00060 public:
00061 BasePositiveTableConstraint(Solver* const s,
00062 const std::vector<IntVar*> & vars,
00063 const IntTupleSet& tuples)
00064 : Constraint(s),
00065 tuple_count_(tuples.NumTuples()),
00066 arity_(vars.size()),
00067 vars_(new IntVar*[arity_]),
00068 tuples_(tuples),
00069 holes_(new IntVarIterator*[arity_]),
00070 iterators_(new IntVarIterator*[arity_]) {
00071
00072 memcpy(vars_.get(), vars.data(), arity_ * sizeof(*vars.data()));
00073
00074 for (int i = 0; i < arity_; ++i) {
00075 holes_[i] = vars_[i]->MakeHoleIterator(true);
00076 iterators_[i] = vars_[i]->MakeDomainIterator(true);
00077 }
00078 }
00079
00080 virtual ~BasePositiveTableConstraint() {}
00081
00082 virtual string DebugString() const {
00083 return StringPrintf("AllowedAssignments(arity = %d, tuple_count = %d",
00084 arity_,
00085 tuple_count_);
00086 }
00087
00088 virtual void Accept(ModelVisitor* const visitor) const {
00089 visitor->BeginVisitConstraint(ModelVisitor::kAllowedAssignments, this);
00090 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
00091 vars_.get(),
00092 arity_);
00093 visitor->VisitIntegerMatrixArgument(ModelVisitor::kTuplesArgument,
00094 tuples_);
00095 visitor->EndVisitConstraint(ModelVisitor::kAllowedAssignments, this);
00096 }
00097
00098 protected:
00099 const int tuple_count_;
00100 const int arity_;
00101 const scoped_array<IntVar*> vars_;
00102
00103 const IntTupleSet tuples_;
00104 scoped_array<IntVarIterator*> holes_;
00105 scoped_array<IntVarIterator*> iterators_;
00106 std::vector<int64> to_remove_;
00107 };
00108
00109 class PositiveTableConstraint : public BasePositiveTableConstraint {
00110 public:
00111 typedef hash_map<int, uint64*> ValueBitset;
00112
00113 PositiveTableConstraint(Solver* const s,
00114 const std::vector<IntVar*> & vars,
00115 const IntTupleSet& tuples)
00116 : BasePositiveTableConstraint(s, vars, tuples),
00117 length_(BitLength64(tuples.NumTuples())),
00118 active_tuples_(new uint64[length_]),
00119 stamps_(new uint64[length_]) {
00120 masks_.clear();
00121 masks_.resize(arity_);
00122 for (int i = 0; i < tuple_count_; ++i) {
00123 InitializeMask(i);
00124 }
00125 }
00126
00127 virtual ~PositiveTableConstraint() {
00128 for (int var_index = 0; var_index < arity_; ++var_index) {
00129 for (ConstIter<ValueBitset> it(masks_[var_index]); !it.at_end(); ++it) {
00130 delete [] it->second;
00131 }
00132 }
00133 }
00134
00135 virtual void Post() {
00136 Demon* d = MakeDelayedConstraintDemon0(solver(),
00137 this,
00138 &PositiveTableConstraint::Propagate,
00139 "Propagate");
00140 for (int i = 0; i < arity_; ++i) {
00141 vars_[i]->WhenDomain(d);
00142 Demon* u = MakeConstraintDemon1(solver(),
00143 this,
00144 &PositiveTableConstraint::Update,
00145 "Update",
00146 i);
00147 vars_[i]->WhenDomain(u);
00148 }
00149 for (int i = 0; i < length_; ++i) {
00150 stamps_[i] = 0;
00151 active_tuples_[i] = ~GG_ULONGLONG(0);
00152 }
00153 }
00154
00155 virtual void InitialPropagate() {
00156
00157 for (int var_index = 0; var_index < arity_; ++var_index) {
00158 for (ConstIter<ValueBitset> it(masks_[var_index]); !it.at_end(); ++it) {
00159 if (!vars_[var_index]->Contains(it->first)) {
00160 for (int i = 0; i < length_; ++i) {
00161 active_tuples_[i] &= ~it->second[i];
00162 }
00163 }
00164 }
00165 }
00166 bool found_one = false;
00167 for (int i = 0; i < length_; ++i) {
00168 if (active_tuples_[i] != 0) {
00169 found_one = true;
00170 break;
00171 }
00172 }
00173 if (!found_one) {
00174 solver()->Fail();
00175 }
00176
00177 for (int var_index = 0; var_index < arity_; ++var_index) {
00178 const ValueBitset& mask = masks_[var_index];
00179 IntVar* const var = vars_[var_index];
00180 to_remove_.clear();
00181 IntVarIterator* const it = iterators_[var_index];
00182 for (it->Init(); it->Ok(); it->Next()) {
00183 const int64 value = it->Value();
00184 if (!ContainsKey(mask, value)) {
00185 to_remove_.push_back(value);
00186 }
00187 }
00188 if (to_remove_.size() > 0) {
00189 var->RemoveValues(to_remove_);
00190 }
00191 }
00192 }
00193
00194 void Propagate() {
00195 for (int var_index = 0; var_index < arity_; ++var_index) {
00196 IntVar* const var = vars_[var_index];
00197 to_remove_.clear();
00198 IntVarIterator* const it = iterators_[var_index];
00199 for (it->Init(); it->Ok(); it->Next()) {
00200 const int64 value = it->Value();
00201 if (!Supported(var_index, value)) {
00202 to_remove_.push_back(value);
00203 }
00204 }
00205 if (to_remove_.size() > 0) {
00206 var->RemoveValues(to_remove_);
00207 }
00208 }
00209 }
00210
00211 void Update(int index) {
00212 const ValueBitset& mask = masks_[index];
00213 IntVar* const var = vars_[index];
00214 const int64 oldmax = var->OldMax();
00215 const int64 vmin = var->Min();
00216 const int64 vmax = var->Max();
00217 for (int64 value = var->OldMin(); value < vmin; ++value) {
00218 BlankActives(FindPtrOrNull(mask, value));
00219 }
00220 for (holes_[index]->Init(); holes_[index]->Ok(); holes_[index]->Next()) {
00221 BlankActives(FindPtrOrNull(mask, holes_[index]->Value()));
00222 }
00223 for (int64 value = vmax + 1; value <= oldmax; ++value) {
00224 BlankActives(FindPtrOrNull(mask, value));
00225 }
00226 }
00227
00228 void BlankActives(uint64* const mask) {
00229 if (mask != NULL) {
00230 bool empty = true;
00231 for (int offset = 0; offset < length_; ++offset) {
00232 if ((mask[offset] & active_tuples_[offset]) != 0) {
00233 AndActiveTuples(offset, ~mask[offset]);
00234 }
00235 if (active_tuples_[offset] != 0) {
00236 empty = false;
00237 }
00238 }
00239 if (empty) {
00240 solver()->Fail();
00241 }
00242 }
00243 }
00244
00245 bool Supported(int var_index, int64 value) {
00246 DCHECK_GE(var_index, 0);
00247 DCHECK_LT(var_index, arity_);
00248 DCHECK(ContainsKey(masks_[var_index], value));
00249 uint64* const mask = masks_[var_index][value];
00250 for (int offset = 0; offset < length_; ++offset) {
00251 if ((mask[offset] & active_tuples_[offset]) != 0LL) {
00252 return true;
00253 }
00254 }
00255 return false;
00256 }
00257
00258 virtual string DebugString() const { return "PositiveTableConstraint"; }
00259
00260 protected:
00261 void InitializeMask(int tuple_index) {
00262 for (int var_index = 0; var_index < arity_; ++var_index) {
00263 const int64 value = tuples_.Value(tuple_index, var_index);
00264 uint64* mask = FindPtrOrNull(masks_[var_index], value);
00265 if (mask == NULL) {
00266 mask = new uint64[length_];
00267 memset(mask, 0, length_ * sizeof(*mask));
00268 masks_[var_index][value] = mask;
00269 }
00270 SetBit64(mask, tuple_index);
00271 }
00272 }
00273
00274 void AndActiveTuples(int offset, uint64 mask) {
00275 const uint64 current_stamp = solver()->stamp();
00276 if (stamps_[offset] < current_stamp) {
00277 stamps_[offset] = current_stamp;
00278 solver()->SaveValue(&active_tuples_[offset]);
00279 }
00280 active_tuples_[offset] &= mask;
00281 }
00282
00283 const int length_;
00284
00285 scoped_array<uint64> active_tuples_;
00286 scoped_array<uint64> stamps_;
00287 std::vector<ValueBitset> masks_;
00288 };
00289
00290
00291
00292 class CompactPositiveTableConstraint : public BasePositiveTableConstraint {
00293 public:
00294 CompactPositiveTableConstraint(Solver* const s,
00295 const std::vector<IntVar*> & vars,
00296 const IntTupleSet& tuples)
00297 : BasePositiveTableConstraint(s, vars, tuples),
00298 length_(BitLength64(tuples.NumTuples())),
00299 active_tuples_(new uint64[length_]),
00300 stamps_(new uint64[length_]),
00301 original_min_(new int64[arity_]),
00302 temp_mask_(new uint64[length_]),
00303 demon_(NULL) {
00304 }
00305
00306 virtual ~CompactPositiveTableConstraint() {}
00307
00308 virtual void Post() {
00309 demon_ = solver()->RegisterDemon(MakeDelayedConstraintDemon0(
00310 solver(),
00311 this,
00312 &CompactPositiveTableConstraint::Propagate,
00313 "Propagate"));
00314 for (int i = 0; i < arity_; ++i) {
00315
00316 Demon* u = MakeConstraintDemon1(solver(),
00317 this,
00318 &CompactPositiveTableConstraint::Update,
00319 "Update",
00320 i);
00321 vars_[i]->WhenDomain(u);
00322 }
00323 for (int i = 0; i < length_; ++i) {
00324 stamps_[i] = 0;
00325 active_tuples_[i] = 0;
00326 }
00327 }
00328
00329 bool IsTupleSupported(int tuple_index) {
00330 for (int var_index = 0; var_index < arity_; ++var_index) {
00331 const int64 value = tuples_.Value(tuple_index, var_index);
00332 if (!vars_[var_index]->Contains(value)) {
00333 return false;
00334 }
00335 }
00336 return true;
00337 }
00338
00339 void BuildStructures() {
00340
00341 bool found_one = false;
00342 for (int tuple_index = 0; tuple_index < tuple_count_; ++tuple_index) {
00343 if (IsTupleSupported(tuple_index)) {
00344 SetBit64(active_tuples_.get(), tuple_index);
00345 found_one = true;
00346 }
00347 }
00348 if (!found_one) {
00349 solver()->Fail();
00350 }
00351 }
00352
00353 void BuildMasks() {
00354
00355 masks_.clear();
00356 masks_.resize(arity_);
00357 for (int i = 0; i < arity_; ++i) {
00358 original_min_[i] = vars_[i]->Min();
00359 const int64 span = vars_[i]->Max() - original_min_[i] + 1;
00360 masks_[i].resize(span);
00361 for (int j = 0; j < span; ++j) {
00362 masks_[i][j] = NULL;
00363 }
00364 }
00365 }
00366
00367 void FillMasks() {
00368 for (int tuple_index = 0; tuple_index < tuple_count_; ++tuple_index) {
00369 if (IsBitSet64(active_tuples_.get(), tuple_index)) {
00370 for (int var_index = 0; var_index < arity_; ++var_index) {
00371 const int64 value_index =
00372 tuples_.Value(tuple_index, var_index) - original_min_[var_index];
00373 DCHECK_GE(value_index, 0);
00374 DCHECK_LT(value_index, masks_[var_index].size());
00375 uint64* mask = masks_[var_index][value_index];
00376 if (!mask) {
00377 mask = solver()->RevAllocArray(new uint64[length_]);
00378 memset(mask, 0, length_ * sizeof(*mask));
00379 masks_[var_index][value_index] = mask;
00380 }
00381 SetBit64(mask, tuple_index);
00382 }
00383 }
00384 }
00385 }
00386
00387 void ComputeMasksBoundaries() {
00388
00389 starts_.clear();
00390 starts_.resize(arity_);
00391 ends_.clear();
00392 ends_.resize(arity_);
00393 supports_.clear();
00394 supports_.resize(arity_);
00395 for (int var_index = 0; var_index < arity_; ++var_index) {
00396 const int64 span = vars_[var_index]->Max() - original_min_[var_index] + 1;
00397 starts_[var_index].resize(span);
00398 ends_[var_index].resize(span);
00399 supports_[var_index].resize(span);
00400 for (int value_index = 0; value_index < span; ++value_index) {
00401 const uint64* const mask = masks_[var_index][value_index];
00402 if (mask != NULL) {
00403 starts_[var_index][value_index] = 0;
00404 while (!mask[starts_[var_index][value_index]]) {
00405 starts_[var_index][value_index]++;
00406 }
00407 supports_[var_index][value_index] = starts_[var_index][value_index];
00408 ends_[var_index][value_index] = length_ - 1;
00409 while (!mask[ends_[var_index][value_index]]) {
00410 ends_[var_index][value_index]--;
00411 }
00412 }
00413 }
00414 }
00415 }
00416
00417 void RemoveUnsupportedValues() {
00418
00419 for (int var_index = 0; var_index < arity_; ++var_index) {
00420 IntVar* const var = vars_[var_index];
00421 to_remove_.clear();
00422 IntVarIterator* const it = iterators_[var_index];
00423 for (it->Init(); it->Ok(); it->Next()) {
00424 const int64 value = it->Value();
00425 if (!masks_[var_index][value - original_min_[var_index]]) {
00426 to_remove_.push_back(value);
00427 }
00428 }
00429 if (to_remove_.size() > 0) {
00430 var->RemoveValues(to_remove_);
00431 }
00432 }
00433 }
00434
00435 virtual void InitialPropagate() {
00436 BuildStructures();
00437 BuildMasks();
00438 FillMasks();
00439 ComputeMasksBoundaries();
00440 RemoveUnsupportedValues();
00441 }
00442
00443 bool Supported(int var_index, int64 value_index) {
00444 DCHECK_GE(var_index, 0);
00445 DCHECK_LT(var_index, arity_);
00446 DCHECK_GE(value_index, 0);
00447 DCHECK(masks_[var_index][value_index]);
00448 const uint64* const mask = masks_[var_index][value_index];
00449 const int support = supports_[var_index][value_index];
00450 if ((mask[support] & active_tuples_[support]) != 0) {
00451 return true;
00452 }
00453 const int loop_end = ends_[var_index][value_index];
00454 for (int offset = starts_[var_index][value_index];
00455 offset <= loop_end;
00456 ++offset) {
00457 if ((mask[offset] & active_tuples_[offset]) != 0) {
00458 supports_[var_index][value_index] = offset;
00459 return true;
00460 }
00461 }
00462 return false;
00463 }
00464
00465 void Propagate() {
00466
00467
00468
00469
00470 memset(temp_mask_.get(), 0, length_ * sizeof(*temp_mask_.get()));
00471 for (int var_index = 0; var_index < arity_; ++var_index) {
00472 to_remove_.clear();
00473 IntVarIterator* const it = iterators_[var_index];
00474 for (it->Init(); it->Ok(); it->Next()) {
00475 const int64 value_index = it->Value() - original_min_[var_index];
00476 if (!Supported(var_index, value_index)) {
00477 to_remove_.push_back(it->Value());
00478 }
00479 }
00480 if (to_remove_.size() > 0) {
00481 vars_[var_index]->RemoveValues(to_remove_);
00482
00483 for (int offset = 0; offset < length_; ++offset) {
00484 temp_mask_[offset] = 0;
00485 }
00486 for (ConstIter<std::vector<int64> > it(to_remove_); !it.at_end(); ++it) {
00487 const int64 value_index = (*it) - original_min_[var_index];
00488 const uint64* const mask = masks_[var_index][value_index];
00489 DCHECK(mask);
00490 UpdateTempMask(mask,
00491 starts_[var_index][value_index],
00492 ends_[var_index][value_index]);
00493 }
00494 for (int offset = 0; offset < length_; ++offset) {
00495 if ((temp_mask_[offset] & active_tuples_[offset]) != 0) {
00496 AndActiveTuples(offset, ~temp_mask_[offset]);
00497 }
00498 }
00499 }
00500 }
00501 for (int offset = 0; offset < length_; ++offset) {
00502 if (active_tuples_[offset]) {
00503 return;
00504 }
00505 }
00506 solver()->Fail();
00507 }
00508
00509 void UpdateTempMask(const uint64* const mask, int start, int end) {
00510 for (int offset = start; offset <= end; ++offset) {
00511 temp_mask_[offset] |= mask[offset];
00512 }
00513 }
00514
00515 void Update(int var_index) {
00516
00517
00518
00519
00520 IntVar* const var = vars_[var_index];
00521 const int64 omin = original_min_[var_index];
00522 bool changed = false;
00523 memset(temp_mask_.get(), 0, length_ * sizeof(*temp_mask_.get()));
00524 const int64 oldmax = var->OldMax();
00525 const int64 vmin = var->Min();
00526 const int64 vmax = var->Max();
00527 for (int64 value = var->OldMin(); value < vmin; ++value) {
00528 const int64 value_index = value - omin;
00529 const uint64* const mask = masks_[var_index][value_index];
00530 if (mask) {
00531 UpdateTempMask(mask,
00532 starts_[var_index][value_index],
00533 ends_[var_index][value_index]);
00534 }
00535 }
00536 IntVarIterator* const hole = holes_[var_index];
00537 for (hole->Init(); hole->Ok(); hole->Next()) {
00538 const int64 value_index = hole->Value() - omin;
00539 const uint64* const mask = masks_[var_index][value_index];
00540 if (mask) {
00541 UpdateTempMask(mask,
00542 starts_[var_index][value_index],
00543 ends_[var_index][value_index]);
00544 }
00545 }
00546 for (int64 value = vmax + 1; value <= oldmax; ++value) {
00547 const int64 value_index = value - omin;
00548 const uint64* const mask = masks_[var_index][value_index];
00549 if (mask) {
00550 UpdateTempMask(mask,
00551 starts_[var_index][value_index],
00552 ends_[var_index][value_index]);
00553 }
00554 }
00555
00556 for (int offset = 0; offset < length_; ++offset) {
00557 if ((temp_mask_[offset] & active_tuples_[offset]) != 0) {
00558 AndActiveTuples(offset, ~temp_mask_[offset]);
00559 changed = true;
00560 }
00561 }
00562
00563 for (int offset = 0; offset < length_; ++offset) {
00564 if (active_tuples_[offset]) {
00565
00566 if (changed) {
00567 Enqueue(demon_);
00568 }
00569 return;
00570 }
00571 }
00572 solver()->Fail();
00573 }
00574
00575 private:
00576 void AndActiveTuples(int offset, uint64 mask) {
00577 const uint64 current_stamp = solver()->stamp();
00578 if (stamps_[offset] < current_stamp) {
00579 stamps_[offset] = current_stamp;
00580 solver()->SaveValue(&active_tuples_[offset]);
00581 }
00582 active_tuples_[offset] &= mask;
00583 }
00584
00585
00586 const int length_;
00587
00588 scoped_array<uint64> active_tuples_;
00589
00590 scoped_array<uint64> stamps_;
00591
00592 std::vector<std::vector<uint64*> > masks_;
00593
00594 scoped_array<int64> original_min_;
00595
00596 std::vector<std::vector<int> > starts_;
00597
00598 std::vector<std::vector<int> > ends_;
00599
00600 scoped_array<uint64> temp_mask_;
00601
00602 std::vector<std::vector<int> > supports_;
00603 Demon* demon_;
00604 };
00605
00606
00607
00608
00609
00610 class SmallCompactPositiveTableConstraint : public BasePositiveTableConstraint {
00611 public:
00612 SmallCompactPositiveTableConstraint(Solver* const s,
00613 const std::vector<IntVar*> & vars,
00614 const IntTupleSet& tuples)
00615 : BasePositiveTableConstraint(s, vars, tuples),
00616 active_tuples_(0),
00617 stamp_(0),
00618 masks_(new uint64*[arity_]),
00619 original_min_(new int64[arity_]),
00620 demon_(NULL) {
00621 CHECK_GE(tuple_count_, 0);
00622 CHECK_GE(arity_, 0);
00623 CHECK_LE(tuples.NumTuples(), kBitsInUint64);
00624
00625 memset(masks_.get(), 0, arity_ * sizeof(*masks_.get()));
00626 }
00627
00628 virtual ~SmallCompactPositiveTableConstraint() {
00629 for (int i = 0; i < arity_; ++i) {
00630 delete [] masks_[i];
00631 masks_[i] = NULL;
00632 }
00633 }
00634
00635 virtual void Post() {
00636 demon_ = solver()->RegisterDemon(MakeDelayedConstraintDemon0(
00637 solver(),
00638 this,
00639 &SmallCompactPositiveTableConstraint::Propagate,
00640 "Propagate"));
00641 for (int i = 0; i < arity_; ++i) {
00642 if (!vars_[i]->Bound()) {
00643 Demon* const update_demon = MakeConstraintDemon1(
00644 solver(),
00645 this,
00646 &SmallCompactPositiveTableConstraint::Update,
00647 "Update",
00648 i);
00649 vars_[i]->WhenDomain(update_demon);
00650 }
00651 }
00652 stamp_ = 0;
00653 }
00654
00655 void InitMasks() {
00656
00657 for (int i = 0; i < arity_; ++i) {
00658 original_min_[i] = vars_[i]->Min();
00659 const int64 span = vars_[i]->Max() - original_min_[i] + 1;
00660 masks_[i] = new uint64[span];
00661 memset(masks_[i], 0, span * sizeof(*masks_[i]));
00662 }
00663 }
00664
00665 bool IsTupleSupported(int tuple_index) {
00666 for (int var_index = 0; var_index < arity_; ++var_index) {
00667 const int64 value = tuples_.Value(tuple_index, var_index);
00668 if (!vars_[var_index]->Contains(value)) {
00669 return false;
00670 }
00671 }
00672 return true;
00673 }
00674
00675 void ComputeActiveTuples() {
00676 active_tuples_ = 0;
00677
00678 for (int tuple_index = 0; tuple_index < tuple_count_; ++tuple_index) {
00679 if (IsTupleSupported(tuple_index)) {
00680 const uint64 local_mask = OneBit64(tuple_index);
00681 active_tuples_ |= local_mask;
00682 for (int var_index = 0; var_index < arity_; ++var_index) {
00683 const int64 value_index =
00684 tuples_.Value(tuple_index, var_index) - original_min_[var_index];
00685 masks_[var_index][value_index] |= local_mask;
00686 }
00687 }
00688 }
00689 if (!active_tuples_) {
00690 solver()->Fail();
00691 }
00692 }
00693
00694 void RemoveUnsupportedValues() {
00695
00696 for (int var_index = 0; var_index < arity_; ++var_index) {
00697 IntVar* const var = vars_[var_index];
00698 const int64 original_min = original_min_[var_index];
00699 to_remove_.clear();
00700 IntVarIterator* const it = iterators_[var_index];
00701 for (it->Init(); it->Ok(); it->Next()) {
00702 const int64 value = it->Value();
00703 if (masks_[var_index][value - original_min] == 0) {
00704 to_remove_.push_back(value);
00705 }
00706 }
00707 if (to_remove_.size() > 0) {
00708 var->RemoveValues(to_remove_);
00709 }
00710 }
00711 }
00712
00713 virtual void InitialPropagate() {
00714 InitMasks();
00715 ComputeActiveTuples();
00716 RemoveUnsupportedValues();
00717 }
00718
00719 void Propagate() {
00720
00721
00722
00723
00724
00725
00726 const uint64 actives = active_tuples_;
00727
00728
00729 for (int var_index = 0; var_index < arity_; ++var_index) {
00730 const uint64* const var_mask = masks_[var_index];
00731 const int64 original_min = original_min_[var_index];
00732 IntVar* const var = vars_[var_index];
00733 if (var->Bound()) {
00734 if ((var_mask[var->Min() - original_min] & actives) == 0) {
00735 solver()->Fail();
00736 }
00737 } else {
00738 to_remove_.clear();
00739 IntVarIterator* const it = iterators_[var_index];
00740 for (it->Init(); it->Ok(); it->Next()) {
00741 const int64 value = it->Value();
00742 if ((var_mask[value - original_min] & actives) == 0) {
00743 to_remove_.push_back(value);
00744 }
00745 }
00746 if (to_remove_.size() == var->Size()) {
00747 solver()->Fail();
00748 } else if (to_remove_.size() > 0) {
00749 vars_[var_index]->RemoveValues(to_remove_);
00750 }
00751 }
00752 }
00753 }
00754
00755 void Update(int var_index) {
00756
00757
00758
00759
00760 IntVar* const var = vars_[var_index];
00761 const int64 original_min = original_min_[var_index];
00762 uint64 temp_mask = 0;
00763 const uint64* const var_mask = masks_[var_index];
00764 const int64 oldmax = var->OldMax();
00765 const int64 vmin = var->Min();
00766 const int64 vmax = var->Max();
00767
00768 for (int64 value = var->OldMin(); value < vmin; ++value) {
00769 temp_mask |= var_mask[value - original_min];
00770 }
00771 IntVarIterator* const hole = holes_[var_index];
00772 for (hole->Init(); hole->Ok(); hole->Next()) {
00773 temp_mask |= var_mask[hole->Value() - original_min];
00774 }
00775 for (int64 value = vmax + 1; value <= oldmax; ++value) {
00776 temp_mask |= var_mask[value - original_min];
00777 }
00778
00779 if (temp_mask & active_tuples_) {
00780 AndActiveTuples(~temp_mask);
00781 if (active_tuples_) {
00782 Enqueue(demon_);
00783 } else {
00784 solver()->Fail();
00785 }
00786 }
00787 }
00788
00789 private:
00790 void AndActiveTuples(uint64 mask) {
00791 const uint64 current_stamp = solver()->stamp();
00792 if (stamp_ < current_stamp) {
00793 stamp_ = current_stamp;
00794 solver()->SaveValue(&active_tuples_);
00795 }
00796 active_tuples_ &= mask;
00797 }
00798
00799
00800 uint64 active_tuples_;
00801
00802 uint64 stamp_;
00803
00804 scoped_array<uint64*> masks_;
00805
00806 scoped_array<int64> original_min_;
00807 Demon* demon_;
00808 };
00809
00810
00811 bool HasCompactDomains(const IntVar* const * vars, int arity) {
00812 int64 sum_of_spans = 0LL;
00813 int64 sum_of_sizes = 0LL;
00814 for (int i = 0; i < arity; ++i) {
00815 const int64 vmin = vars[i]->Min();
00816 const int64 vmax = vars[i]->Max();
00817 sum_of_sizes += vars[i]->Size();
00818 sum_of_spans += vmax - vmin + 1;
00819 }
00820 return sum_of_spans < 4 * sum_of_sizes;
00821 }
00822 }
00823
00824 Constraint* Solver::MakeAllowedAssignments(
00825 const std::vector<IntVar*>& vars,
00826 const IntTupleSet& tuples) {
00827 if (FLAGS_cp_use_compact_table
00828 && HasCompactDomains(vars.data(), vars.size())) {
00829 if (tuples.NumTuples() < kBitsInUint64 && FLAGS_cp_use_small_table) {
00830 return RevAlloc(
00831 new SmallCompactPositiveTableConstraint(this, vars, tuples));
00832 } else {
00833 return RevAlloc(new CompactPositiveTableConstraint(this, vars, tuples));
00834 }
00835 }
00836 return RevAlloc(new PositiveTableConstraint(this, vars, tuples));
00837 }
00838
00839 namespace {
00840
00841
00842
00843
00844
00845
00846
00847 class TransitionConstraint : public Constraint {
00848 public:
00849 static const int kStatePosition;
00850 static const int kNextStatePosition;
00851 static const int kTransitionTupleSize;
00852 TransitionConstraint(Solver* const s,
00853 const std::vector<IntVar*>& vars,
00854 const IntTupleSet& transition_table,
00855 int64 initial_state,
00856 const std::vector<int64>& final_states)
00857 : Constraint(s),
00858 vars_(vars),
00859 transition_table_(transition_table),
00860 initial_state_(initial_state),
00861 final_states_(final_states) {}
00862
00863 TransitionConstraint(Solver* const s,
00864 const std::vector<IntVar*>& vars,
00865 const IntTupleSet& transition_table,
00866 int64 initial_state,
00867 const std::vector<int>& final_states)
00868 : Constraint(s),
00869 vars_(vars),
00870 transition_table_(transition_table),
00871 initial_state_(initial_state),
00872 final_states_(final_states.size()) {
00873 for (int i = 0; i < final_states.size(); ++i) {
00874 final_states_[i] = final_states[i];
00875 }
00876 }
00877
00878 virtual ~TransitionConstraint() {}
00879
00880 virtual void Post() {
00881 Solver* const s = solver();
00882 int64 state_min = kint64max;
00883 int64 state_max = kint64min;
00884 const int nb_vars = vars_.size();
00885 for (int i = 0; i < transition_table_.NumTuples(); ++i) {
00886 state_max = std::max(state_max,
00887 transition_table_.Value(i, kStatePosition));
00888 state_max = std::max(state_max,
00889 transition_table_.Value(i, kNextStatePosition));
00890 state_min = std::min(state_min,
00891 transition_table_.Value(i, kStatePosition));
00892 state_min = std::min(state_min,
00893 transition_table_.Value(i, kNextStatePosition));
00894 }
00895
00896 std::vector<IntVar*> states;
00897 states.push_back(s->MakeIntConst(initial_state_));
00898 for (int var_index = 1; var_index < nb_vars; ++var_index) {
00899 states.push_back(s->MakeIntVar(state_min, state_max));
00900 }
00901 states.push_back(s->MakeIntVar(final_states_));
00902 CHECK_EQ(nb_vars + 1, states.size());
00903
00904 for (int var_index = 0; var_index < nb_vars; ++var_index) {
00905 std::vector<IntVar*> tmp_vars;
00906 tmp_vars.push_back(states[var_index]);
00907 tmp_vars.push_back(vars_[var_index]);
00908 tmp_vars.push_back(states[var_index + 1]);
00909 s->AddConstraint(
00910 s->MakeAllowedAssignments(tmp_vars, transition_table_));
00911 }
00912 }
00913
00914 virtual void InitialPropagate() {}
00915
00916 virtual void Accept(ModelVisitor* const visitor) const {
00917 visitor->BeginVisitConstraint(ModelVisitor::kTransition, this);
00918 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
00919 vars_.data(),
00920 vars_.size());
00921 visitor->VisitIntegerArgument(ModelVisitor::kInitialState,
00922 initial_state_);
00923 visitor->VisitIntegerArrayArgument(ModelVisitor::kFinalStatesArgument,
00924 final_states_.data(),
00925 final_states_.size());
00926 visitor->VisitIntegerMatrixArgument(ModelVisitor::kTuplesArgument,
00927 transition_table_);
00928 visitor->EndVisitConstraint(ModelVisitor::kTransition, this);
00929 }
00930
00931
00932 private:
00933
00934 const std::vector<IntVar*> vars_;
00935
00936 const IntTupleSet transition_table_;
00937
00938 const int64 initial_state_;
00939
00940 std::vector<int64> final_states_;
00941 };
00942
00943 const int TransitionConstraint::kStatePosition = 0;
00944 const int TransitionConstraint::kNextStatePosition = 2;
00945 const int TransitionConstraint::kTransitionTupleSize = 3;
00946 }
00947
00948 Constraint* Solver::MakeTransitionConstraint(
00949 const std::vector<IntVar*>& vars,
00950 const IntTupleSet& transition_table,
00951 int64 initial_state,
00952 const std::vector<int64>& final_states) {
00953 return RevAlloc(new TransitionConstraint(this,
00954 vars,
00955 transition_table,
00956 initial_state,
00957 final_states));
00958 }
00959
00960 Constraint* Solver::MakeTransitionConstraint(
00961 const std::vector<IntVar*>& vars,
00962 const IntTupleSet& transition_table,
00963 int64 initial_state,
00964 const std::vector<int>& final_states) {
00965 return RevAlloc(new TransitionConstraint(this,
00966 vars,
00967 transition_table,
00968 initial_state,
00969 final_states));
00970 }
00971
00972 }