diff --git a/src/constraint_solver/constraint_solver.h b/src/constraint_solver/constraint_solver.h index cb84f8a2e5..3538ba910e 100644 --- a/src/constraint_solver/constraint_solver.h +++ b/src/constraint_solver/constraint_solver.h @@ -1836,7 +1836,7 @@ class Solver { std::vector* const array); - // Creates an fixed and performed interval. + // Creates a fixed and performed interval. IntervalVar* MakeFixedInterval(int64 start, int64 duration, const string& name); diff --git a/src/constraint_solver/local_search.cc b/src/constraint_solver/local_search.cc index dd63190358..af466c9bcf 100644 --- a/src/constraint_solver/local_search.cc +++ b/src/constraint_solver/local_search.cc @@ -287,7 +287,7 @@ void SequenceVarLocalSearchOperator::Start(const Assignment* assignment) { element = &(container.Element(vars_[i])); } const std::vector& value = element->ForwardSequence(); - CHECK_EQ(vars_[i]->size(), value.size()); + CHECK_GE(vars_[i]->size(), value.size()); values_[i] = value; backward_values_[i].clear(); old_values_[i] = value; diff --git a/src/constraint_solver/resource.cc b/src/constraint_solver/resource.cc index cb44e39a9c..872156bee8 100644 --- a/src/constraint_solver/resource.cc +++ b/src/constraint_solver/resource.cc @@ -796,11 +796,13 @@ class RankedPropagator : public Constraint { int first = 0; int counter = 0; while (nexts_[first]->Bound()) { + DCHECK_NE(first, nexts_[first]->Min()); first = nexts_[first]->Min(); if (first == sentinel) { return; } if (++counter > ranked_first) { + DCHECK(intervals_[first - 1]->MayBePerformed()); partial_sequence_.RankFirst(s, first - 1); VLOG(1) << "RankFirst " << first - 1 << " -> " << partial_sequence_.DebugString(); @@ -824,7 +826,7 @@ class RankedPropagator : public Constraint { << " -> " << partial_sequence_.DebugString(); } } - VLOG(1) << "PropagateNext(" + VLOG(1) << "PropagateNexts(" << DebugStringArray(nexts_.get(), size_ + 1, ", ") << ", " << partial_sequence_.DebugString() << ")"; } @@ -930,8 +932,11 @@ class RankedPropagator : public Constraint { } virtual string DebugString() const { - return StringPrintf("RankedPropagator([%s])", - partial_sequence_.DebugString().c_str()); + return StringPrintf( + "RankedPropagator([%s], nexts = [%s], intervals = [%s])", + partial_sequence_.DebugString().c_str(), + DebugStringArray(nexts_.get(), size_ + 1, ", ").c_str(), + DebugStringArray(intervals_.get(), size_, ", ").c_str()); } void Accept(ModelVisitor* const visitor) const { @@ -1039,7 +1044,9 @@ class FullDisjunctiveConstraint : public DisjunctiveConstraint { actives_.resize(num_nodes); for (int i = 0; i < size_; ++i) { - actives_[i + 1] = intervals_[i]->PerformedExpr()->Var(); + actives_[i + 1] = s->MakeIsDifferentCstVar(nexts_[i + 1], i + 1); + s->AddConstraint( + s->MakeEquality(actives_[i + 1], intervals_[i]->PerformedExpr())); } // TODO(user): Only if at least one activity is always performed. actives_[0] = s->MakeIntConst(1); diff --git a/src/constraint_solver/sched_search.cc b/src/constraint_solver/sched_search.cc index 351e34e7dd..b204d84485 100644 --- a/src/constraint_solver/sched_search.cc +++ b/src/constraint_solver/sched_search.cc @@ -77,14 +77,15 @@ string SequenceVar::DebugString() const { "d..%" GG_LL_FORMAT "d, duration = %" GG_LL_FORMAT "d..%" GG_LL_FORMAT - "d, not ranked = %d, ranked = %d)", + "d, not ranked = %d, ranked = %d, nexts = [%s])", name().c_str(), hmin, hmax, dmin, dmax, not_ranked, - ranked); + ranked, + DebugStringArray(nexts_.get(), next_size_, ", ").c_str()); } void SequenceVar::Accept(ModelVisitor* const visitor) const { @@ -182,13 +183,15 @@ void SequenceVar::ComputeStatistics(int* const ranked, last = previous_[last]; (*ranked)++; } + } else { // We counted the sentinel. + (*ranked)--; } *not_ranked = size_ - *ranked - *unperformed; } int SequenceVar::ComputeForwardFrontier() { int first = 0; - while (nexts_[first]->Bound() && first != next_size_) { + while (first != next_size_ && nexts_[first]->Bound()) { first = nexts_[first]->Min(); } return first; @@ -206,6 +209,8 @@ int SequenceVar::ComputeBackwardFrontier() { void SequenceVar::ComputePossibleFirstsAndLasts( std::vector* const possible_firsts, std::vector* const possible_lasts) { + possible_firsts->clear(); + possible_lasts->clear(); hash_set to_check; for (int i = 0; i < size_; ++i) { if (intervals_[i]->MayBePerformed()) { @@ -215,10 +220,10 @@ void SequenceVar::ComputePossibleFirstsAndLasts( int first = 0; while (nexts_[first]->Bound()) { first = nexts_[first]->Min(); - to_check.erase(ValueToIndex(first)); if (first == next_size_) { return; } + to_check.erase(ValueToIndex(first)); } IntVar* const forward_var = nexts_[first]; @@ -311,7 +316,14 @@ void SequenceVar::RankSequence(const std::vector& rank_first, void SequenceVar::RankFirst(int index) { solver()->GetPropagationMonitor()->RankFirst(this, index); intervals_[index]->SetPerformed(true); - const int forward_frontier = ComputeForwardFrontier(); + int forward_frontier = 0; + while (forward_frontier != next_size_ && nexts_[forward_frontier]->Bound()) { + forward_frontier = nexts_[forward_frontier]->Min(); + if (forward_frontier == IndexToValue(index)) { + return; + } + } + DCHECK_LT(forward_frontier, next_size_); nexts_[forward_frontier]->SetValue(IndexToValue(index)); } @@ -320,15 +332,21 @@ void SequenceVar::RankNotFirst(int index) { const int forward_frontier = ComputeForwardFrontier(); if (forward_frontier < next_size_) { nexts_[forward_frontier]->RemoveValue(IndexToValue(index)); - } else { - solver()->Fail(); } } void SequenceVar::RankLast(int index) { solver()->GetPropagationMonitor()->RankLast(this, index); intervals_[index]->SetPerformed(true); - const int backward_frontier = ComputeBackwardFrontier(); + UpdatePrevious(); + int backward_frontier = next_size_; + while (previous_[backward_frontier] != -1) { + backward_frontier = previous_[backward_frontier]; + if (backward_frontier == IndexToValue(index)) { + return; + } + } + DCHECK_NE(backward_frontier, 0); nexts_[IndexToValue(index)]->SetValue(backward_frontier); } @@ -695,8 +713,8 @@ class RankFirstIntervalVars : public DecisionBuilder { bool FindSequenceVarRandomly(Solver* const s, SequenceVar** const best_sequence) { - std::vector all_candidates; - std::vector > all_possible_firsts; + std::vector all_candidates; + std::vector> all_possible_firsts; for (int i = 0; i < size_; ++i) { SequenceVar* const candidate_sequence = sequences_[i]; int ranked = 0; @@ -722,7 +740,7 @@ class RankFirstIntervalVars : public DecisionBuilder { return true; } - all_candidates.push_back(i); + all_candidates.push_back(candidate_sequence); all_possible_firsts.push_back(candidate_possible_firsts_); } } @@ -730,7 +748,7 @@ class RankFirstIntervalVars : public DecisionBuilder { return false; } const int chosen = s->Rand32(all_candidates.size()); - *best_sequence = sequences_[all_candidates[chosen]]; + *best_sequence = all_candidates[chosen]; best_possible_firsts_ = all_possible_firsts[chosen]; return true; } diff --git a/src/constraint_solver/table.cc b/src/constraint_solver/table.cc index 3baef4fe78..89fda1c3a4 100644 --- a/src/constraint_solver/table.cc +++ b/src/constraint_solver/table.cc @@ -62,16 +62,15 @@ static const int kBitsInUint64 = 64; // tuple that supports it. class BasePositiveTableConstraint : public Constraint { public: - BasePositiveTableConstraint(Solver* const s, - const std::vector & vars, + BasePositiveTableConstraint(Solver* const s, const std::vector& vars, const IntTupleSet& tuples) : Constraint(s), tuple_count_(tuples.NumTuples()), arity_(vars.size()), - vars_(new IntVar*[arity_]), + vars_(new IntVar* [arity_]), tuples_(tuples), - holes_(new IntVarIterator*[arity_]), - iterators_(new IntVarIterator*[arity_]) { + holes_(new IntVarIterator* [arity_]), + iterators_(new IntVarIterator* [arity_]) { // Copy vars. memcpy(vars_.get(), vars.data(), arity_ * sizeof(*vars.data())); // Create hole iterators @@ -85,17 +84,14 @@ class BasePositiveTableConstraint : public Constraint { virtual string DebugString() const { return StringPrintf("AllowedAssignments(arity = %d, tuple_count = %d)", - arity_, - tuple_count_); + arity_, tuple_count_); } virtual void Accept(ModelVisitor* const visitor) const { visitor->BeginVisitConstraint(ModelVisitor::kAllowedAssignments, this); visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument, - vars_.get(), - arity_); - visitor->VisitIntegerMatrixArgument(ModelVisitor::kTuplesArgument, - tuples_); + vars_.get(), arity_); + visitor->VisitIntegerMatrixArgument(ModelVisitor::kTuplesArgument, tuples_); visitor->EndVisitConstraint(ModelVisitor::kAllowedAssignments, this); } @@ -114,8 +110,7 @@ class PositiveTableConstraint : public BasePositiveTableConstraint { public: typedef hash_map ValueBitset; - PositiveTableConstraint(Solver* const s, - const std::vector & vars, + PositiveTableConstraint(Solver* const s, const std::vector& vars, const IntTupleSet& tuples) : BasePositiveTableConstraint(s, vars, tuples), length_(BitLength64(tuples.NumTuples())), @@ -131,23 +126,18 @@ class PositiveTableConstraint : public BasePositiveTableConstraint { virtual ~PositiveTableConstraint() { for (int var_index = 0; var_index < arity_; ++var_index) { for (ConstIter it(masks_[var_index]); !it.at_end(); ++it) { - delete [] it->second; + delete[] it->second; } } } virtual void Post() { - Demon* d = MakeDelayedConstraintDemon0(solver(), - this, - &PositiveTableConstraint::Propagate, - "Propagate"); + Demon* d = MakeDelayedConstraintDemon0( + solver(), this, &PositiveTableConstraint::Propagate, "Propagate"); for (int i = 0; i < arity_; ++i) { vars_[i]->WhenDomain(d); - Demon* u = MakeConstraintDemon1(solver(), - this, - &PositiveTableConstraint::Update, - "Update", - i); + Demon* u = MakeConstraintDemon1( + solver(), this, &PositiveTableConstraint::Update, "Update", i); vars_[i]->WhenDomain(u); } for (int i = 0; i < length_; ++i) { @@ -215,7 +205,7 @@ class PositiveTableConstraint : public BasePositiveTableConstraint { void Update(int index) { const ValueBitset& mask = masks_[index]; IntVar* const var = vars_[index]; - const int64 oldmax = var->OldMax(); + const int64 old_max = var->OldMax(); const int64 vmin = var->Min(); const int64 vmax = var->Max(); for (int64 value = var->OldMin(); value < vmin; ++value) { @@ -224,7 +214,7 @@ class PositiveTableConstraint : public BasePositiveTableConstraint { for (holes_[index]->Init(); holes_[index]->Ok(); holes_[index]->Next()) { BlankActives(FindPtrOrNull(mask, holes_[index]->Value())); } - for (int64 value = vmax + 1; value <= oldmax; ++value) { + for (int64 value = vmax + 1; value <= old_max; ++value) { BlankActives(FindPtrOrNull(mask, value)); } } @@ -295,8 +285,7 @@ class PositiveTableConstraint : public BasePositiveTableConstraint { class CompactPositiveTableConstraint : public BasePositiveTableConstraint { public: - CompactPositiveTableConstraint(Solver* const s, - const std::vector & vars, + CompactPositiveTableConstraint(Solver* const s, const std::vector& vars, const IntTupleSet& tuples) : BasePositiveTableConstraint(s, vars, tuples), length_(BitLength64(tuples.NumTuples())), @@ -306,24 +295,17 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint { temp_mask_(new uint64[length_]), demon_(NULL), touched_var_(-1), - var_sizes_(arity_, 0) { - } + var_sizes_(arity_, 0) {} virtual ~CompactPositiveTableConstraint() {} virtual void Post() { demon_ = solver()->RegisterDemon(MakeDelayedConstraintDemon0( - solver(), - this, - &CompactPositiveTableConstraint::Propagate, + solver(), this, &CompactPositiveTableConstraint::Propagate, "Propagate")); for (int i = 0; i < arity_; ++i) { Demon* const u = MakeConstraintDemon1( - solver(), - this, - &CompactPositiveTableConstraint::Update, - "Update", - i); + solver(), this, &CompactPositiveTableConstraint::Update, "Update", i); vars_[i]->WhenDomain(u); } for (int i = 0; i < length_; ++i) { @@ -449,34 +431,11 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint { RemoveUnsupportedValues(); } - bool Supported(int var_index, int64 value_index) { - DCHECK_GE(var_index, 0); - DCHECK_LT(var_index, arity_); - DCHECK_GE(value_index, 0); - DCHECK(masks_[var_index][value_index]); - const uint64* const mask = masks_[var_index][value_index]; - const int support = supports_[var_index][value_index]; - if ((mask[support] & active_tuples_[support]) != 0) { - return true; - } - const int loop_end = ends_[var_index][value_index]; - for (int offset = starts_[var_index][value_index]; - offset <= loop_end; - ++offset) { - if ((mask[offset] & active_tuples_[offset]) != 0) { - supports_[var_index][value_index] = offset; - return true; - } - } - return false; - } - void Propagate() { // This methods scans all values of all variables to see if they // are still supported. // This method is not attached to any particular variable, but is pushed // at a delayed priority after Update(var_index) is called. - ClearTempMask(); for (int var_index = 0; var_index < arity_; ++var_index) { if (var_index == touched_var_) { continue; @@ -508,25 +467,52 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint { } default: { to_remove_.clear(); + const int64 var_min = var->Min(); + const int64 var_max = var->Max(); int64 new_min = kint64max; int64 new_max = kint64min; - IntVarIterator* const it = iterators_[var_index]; - for (it->Init(); it->Ok(); it->Next()) { - const int64 value = it->Value(); - const int64 value_index = value - original_min_[var_index]; - if (!Supported(var_index, value_index)) { - to_remove_.push_back(value); - } else { - if (new_min == kint64max) { - new_min = value; + if (var_max - var_min + 1 == var->Size()) { + // Continous case, a simple loop is enough. + for (int64 value = var_min; value <= var_max; ++value) { + if (!Supported(var_index, value - original_min)) { + to_remove_.push_back(value); + } else { + if (new_min == kint64max) { + new_min = value; + // This will be covered by the SetRange. + to_remove_.clear(); + } + new_max = value; + } + } + } else { + IntVarIterator* const it = iterators_[var_index]; + for (it->Init(); it->Ok(); it->Next()) { + const int64 value = it->Value(); + if (!Supported(var_index, value - original_min)) { + to_remove_.push_back(value); + } else { + if (new_min == kint64max) { + new_min = value; + // This will be covered by the SetRange. + to_remove_.clear(); + } + new_max = value; } - new_max = value; } } - if (!to_remove_.empty()) { - var->SetRange(new_min, new_max); - if (new_min != new_max) { - var->RemoveValues(to_remove_); + var->SetRange(new_min, new_max); + switch (to_remove_.size()) { + case 0: { break; } + case 1: { + var->RemoveValue(to_remove_.back()); + break; + } + default: { + if (new_min != new_max) { + var->RemoveValues(to_remove_); + } + break; } } } @@ -535,21 +521,6 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint { touched_var_ = -1; } - void OrTempMask(int var_index, int64 value_index) { - const uint64* const mask = masks_[var_index][value_index]; - const int start = starts_[var_index][value_index]; - const int end = ends_[var_index][value_index]; - if (mask) { - for (int offset = start; offset <= end; ++offset) { - temp_mask_[offset] |= mask[offset]; - } - } - } - - void ClearTempMask() { - memset(temp_mask_.get(), 0, length_ * sizeof(*temp_mask_.get())); - } - void Update(int var_index) { // This method will update the set of active tuples by masking out all // tuples attached to values of the variables that have been removed. @@ -558,10 +529,11 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint { IntVar* const var = vars_[var_index]; bool changed = false; const int64 omin = original_min_[var_index]; - switch (var->Size()) { + const int64 var_size = var->Size(); + + switch (var_size) { case 1: { - ClearTempMask(); - OrTempMask(var_index, var->Min() - omin); + SetTempMask(var_index, var->Min() - omin); // Then we apply this mask to active_tuples_. for (int offset = 0; offset < length_; ++offset) { if ((~temp_mask_[offset] & active_tuples_[offset]) != 0) { @@ -572,8 +544,7 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint { break; } case 2: { - ClearTempMask(); - OrTempMask(var_index, var->Min() - omin); + SetTempMask(var_index, var->Min() - omin); OrTempMask(var_index, var->Max() - omin); // Then we apply this mask to active_tuples_. for (int offset = 0; offset < length_; ++offset) { @@ -586,20 +557,22 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint { } default: { ClearTempMask(); - const int64 count = var_sizes_.Value(var_index) - var->Size(); - if (count < 2 * var->Size()) { - const int64 oldmin = var->OldMin(); - const int64 oldmax = var->OldMax(); - const int64 vmin = var->Min(); - const int64 vmax = var->Max(); - for (int64 value = oldmin; value < vmin; ++value) { + const int64 count = var_sizes_.Value(var_index) - var_size; + // Rough estimation of the number of operation if we scan + // deltas in the domain of the variable. + const int64 old_min = var->OldMin(); + const int64 old_max = var->OldMax(); + const int64 var_min = var->Min(); + const int64 var_max = var->Max(); + if (count + var_min - old_min + old_max - var_max < var->Size()) { + for (int64 value = old_min; value < var_min; ++value) { OrTempMask(var_index, value - omin); } IntVarIterator* const hole = holes_[var_index]; for (hole->Init(); hole->Ok(); hole->Next()) { OrTempMask(var_index, hole->Value() - omin); } - for (int64 value = vmax + 1; value <= oldmax; ++value) { + for (int64 value = var_max + 1; value <= old_max; ++value) { OrTempMask(var_index, value - omin); } // Then we apply this mask to active_tuples_. @@ -610,10 +583,16 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint { } } } else { - IntVarIterator* it = iterators_[var_index]; - for (it->Init(); it->Ok(); it->Next()) { - const int64 value = it->Value(); - OrTempMask(var_index, value - omin); + if (var_max - var_min + 1 == var_size) { + for (int64 value = var_min; value <= var_max; ++value) { + OrTempMask(var_index, value - omin); + } + } else { + IntVarIterator* const it = iterators_[var_index]; + for (it->Init(); it->Ok(); it->Next()) { + const int64 value = it->Value(); + OrTempMask(var_index, value - omin); + } } // Then we apply this mask to active_tuples_. for (int offset = 0; offset < length_; ++offset) { @@ -623,6 +602,7 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint { } } } + var_sizes_.SetValue(solver(), var_index, var_size); } } // And check active_tuples_ is still not empty, we fail otherwise. @@ -644,6 +624,47 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint { } private: + bool Supported(int var_index, int64 value_index) { + DCHECK_GE(var_index, 0); + DCHECK_LT(var_index, arity_); + DCHECK_GE(value_index, 0); + DCHECK(masks_[var_index][value_index]); + const uint64* const mask = masks_[var_index][value_index]; + const int support = supports_[var_index][value_index]; + if ((mask[support] & active_tuples_[support]) != 0) { + return true; + } + const int loop_end = ends_[var_index][value_index]; + for (int offset = starts_[var_index][value_index]; offset <= loop_end; + ++offset) { + if ((mask[offset] & active_tuples_[offset]) != 0) { + supports_[var_index][value_index] = offset; + return true; + } + } + return false; + } + + void OrTempMask(int var_index, int64 value_index) { + const uint64* const mask = masks_[var_index][value_index]; + if (mask) { + const int start = starts_[var_index][value_index]; + const int end = ends_[var_index][value_index]; + for (int offset = start; offset <= end; ++offset) { + temp_mask_[offset] |= mask[offset]; + } + } + } + + void SetTempMask(int var_index, int64 value_index) { + memcpy(temp_mask_.get(), masks_[var_index][value_index], + length_ * sizeof(*temp_mask_.get())); + } + + void ClearTempMask() { + memset(temp_mask_.get(), 0, length_ * sizeof(*temp_mask_.get())); + } + void AndActiveTuples(int offset, uint64 mask) { const uint64 current_stamp = solver()->stamp(); if (stamps_[offset] < current_stamp) { @@ -683,12 +704,12 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint { class SmallCompactPositiveTableConstraint : public BasePositiveTableConstraint { public: SmallCompactPositiveTableConstraint(Solver* const s, - const std::vector & vars, + const std::vector& vars, const IntTupleSet& tuples) : BasePositiveTableConstraint(s, vars, tuples), active_tuples_(0), stamp_(0), - masks_(new uint64*[arity_]), + masks_(new uint64* [arity_]), original_min_(new int64[arity_]), demon_(NULL), touched_var_(-1) { @@ -701,25 +722,20 @@ class SmallCompactPositiveTableConstraint : public BasePositiveTableConstraint { virtual ~SmallCompactPositiveTableConstraint() { for (int i = 0; i < arity_; ++i) { - delete [] masks_[i]; + delete[] masks_[i]; masks_[i] = NULL; } } virtual void Post() { demon_ = solver()->RegisterDemon(MakeDelayedConstraintDemon0( - solver(), - this, - &SmallCompactPositiveTableConstraint::Propagate, + solver(), this, &SmallCompactPositiveTableConstraint::Propagate, "Propagate")); for (int i = 0; i < arity_; ++i) { if (!vars_[i]->Bound()) { Demon* const update_demon = MakeConstraintDemon1( - solver(), - this, - &SmallCompactPositiveTableConstraint::Update, - "Update", - i); + solver(), this, &SmallCompactPositiveTableConstraint::Update, + "Update", i); vars_[i]->WhenDomain(update_demon); } } @@ -835,11 +851,22 @@ class SmallCompactPositiveTableConstraint : public BasePositiveTableConstraint { } default: { to_remove_.clear(); - IntVarIterator* const it = iterators_[var_index]; - for (it->Init(); it->Ok(); it->Next()) { - const int64 value = it->Value(); - if ((var_mask[value - original_min] & actives) == 0) { - to_remove_.push_back(value); + const int64 var_min = var->Min(); + const int64 var_max = var->Max(); + if (var_max - var_min + 1 == var->Size()) { + // Continous case, a simple loop is enough. + for (int64 value = var_min; value <= var_max; ++value) { + if ((var_mask[value - original_min] & actives) == 0) { + to_remove_.push_back(value); + } + } + } else { + IntVarIterator* const it = iterators_[var_index]; + for (it->Init(); it->Ok(); it->Next()) { + const int64 value = it->Value(); + if ((var_mask[value - original_min] & actives) == 0) { + to_remove_.push_back(value); + } } } if (to_remove_.size() == var->Size()) { @@ -860,10 +887,10 @@ class SmallCompactPositiveTableConstraint : public BasePositiveTableConstraint { // tuples attached to values of the variables that have been removed. IntVar* const var = vars_[var_index]; + const int64 original_min = original_min_[var_index]; switch (var->Size()) { case 1: { - const uint64 temp_mask = - masks_[var_index][var->Min() - original_min_[var_index]]; + const uint64 temp_mask = masks_[var_index][var->Min() - original_min]; if ((~temp_mask & active_tuples_) != 0) { AndActiveTuples(temp_mask); if (active_tuples_ != 0) { @@ -877,9 +904,8 @@ class SmallCompactPositiveTableConstraint : public BasePositiveTableConstraint { break; } case 2: { - const uint64 temp_mask = - masks_[var_index][var->Min() - original_min_[var_index]] | - masks_[var_index][var->Max() - original_min_[var_index]]; + const uint64 temp_mask = masks_[var_index][var->Min() - original_min] | + masks_[var_index][var->Max() - original_min]; if ((~temp_mask & active_tuples_) != 0) { AndActiveTuples(temp_mask); if (active_tuples_ != 0) { @@ -895,37 +921,29 @@ class SmallCompactPositiveTableConstraint : public BasePositiveTableConstraint { default: { // We first collect the complete set of tuples to blank out in // temp_mask. - const int64 original_min = original_min_[var_index]; uint64 temp_mask = 0; const uint64* const var_mask = masks_[var_index]; - const int64 oldmin = var->OldMin(); - const int64 oldmax = var->OldMax(); - const int64 vmin = var->Min(); - const int64 vmax = var->Max(); + const int64 old_min = var->OldMin(); + const int64 old_max = var->OldMax(); + const int64 var_min = var->Min(); + const int64 var_max = var->Max(); // Count the number of masks to collect to compare the deduction // vs the construction of the new active bitset. int count = 0; - for (int64 value = oldmin; value < vmin; ++value) { - count += var_mask[value - original_min] != 0; - } IntVarIterator* const hole = holes_[var_index]; for (hole->Init(); hole->Ok(); hole->Next()) { count++; } - for (int64 value = vmax + 1; value <= oldmax; ++value) { - count += var_mask[value - original_min] != 0; - } - - if (count < var->Size()) { - for (int64 value = var->OldMin(); value < vmin; ++value) { + if (count + var_min - old_min + old_max - var_max < var->Size()) { + for (int64 value = old_min; value < var_min; ++value) { temp_mask |= var_mask[value - original_min]; } IntVarIterator* const hole = holes_[var_index]; for (hole->Init(); hole->Ok(); hole->Next()) { temp_mask |= var_mask[hole->Value() - original_min]; } - for (int64 value = vmax + 1; value <= oldmax; ++value) { + for (int64 value = var_max + 1; value <= old_max; ++value) { temp_mask |= var_mask[value - original_min]; } // Then we apply this mask to active_tuples_. @@ -940,7 +958,7 @@ class SmallCompactPositiveTableConstraint : public BasePositiveTableConstraint { } } } else { - IntVarIterator* it = iterators_[var_index]; + IntVarIterator* const it = iterators_[var_index]; for (it->Init(); it->Ok(); it->Next()) { const int64 value = it->Value(); temp_mask |= var_mask[value - original_min]; @@ -970,9 +988,7 @@ class SmallCompactPositiveTableConstraint : public BasePositiveTableConstraint { } } - void ClearTouchedVar() { - touched_var_ = -1; - } + void ClearTouchedVar() { touched_var_ = -1; } void AndActiveTuples(uint64 mask) { const uint64 current_stamp = solver()->stamp(); @@ -995,15 +1011,14 @@ class SmallCompactPositiveTableConstraint : public BasePositiveTableConstraint { int touched_var_; }; - -bool HasCompactDomains(const IntVar* const * vars, int arity) { +bool HasCompactDomains(const IntVar* const* vars, int arity) { int64 sum_of_spans = 0LL; int64 sum_of_sizes = 0LL; for (int i = 0; i < arity; ++i) { - const int64 vmin = vars[i]->Min(); - const int64 vmax = vars[i]->Max(); + const int64 var_min = vars[i]->Min(); + const int64 var_max = vars[i]->Max(); sum_of_sizes += vars[i]->Size(); - sum_of_spans += vmax - vmin + 1; + sum_of_spans += var_max - var_min + 1; } return sum_of_spans < 4 * sum_of_sizes; } @@ -1020,10 +1035,8 @@ class TransitionConstraint : public Constraint { static const int kStatePosition; static const int kNextStatePosition; static const int kTransitionTupleSize; - TransitionConstraint(Solver* const s, - const std::vector& vars, - const IntTupleSet& transition_table, - int64 initial_state, + TransitionConstraint(Solver* const s, const std::vector& vars, + const IntTupleSet& transition_table, int64 initial_state, const std::vector& final_states) : Constraint(s), vars_(vars), @@ -1031,10 +1044,8 @@ class TransitionConstraint : public Constraint { initial_state_(initial_state), final_states_(final_states) {} - TransitionConstraint(Solver* const s, - const std::vector& vars, - const IntTupleSet& transition_table, - int64 initial_state, + TransitionConstraint(Solver* const s, const std::vector& vars, + const IntTupleSet& transition_table, int64 initial_state, const std::vector& final_states) : Constraint(s), vars_(vars), @@ -1054,14 +1065,14 @@ class TransitionConstraint : public Constraint { int64 state_max = kint64min; const int nb_vars = vars_.size(); for (int i = 0; i < transition_table_.NumTuples(); ++i) { - state_max = std::max(state_max, - transition_table_.Value(i, kStatePosition)); - state_max = std::max(state_max, - transition_table_.Value(i, kNextStatePosition)); - state_min = std::min(state_min, - transition_table_.Value(i, kStatePosition)); - state_min = std::min(state_min, - transition_table_.Value(i, kNextStatePosition)); + state_max = + std::max(state_max, transition_table_.Value(i, kStatePosition)); + state_max = + std::max(state_max, transition_table_.Value(i, kNextStatePosition)); + state_min = + std::min(state_min, transition_table_.Value(i, kStatePosition)); + state_min = + std::min(state_min, transition_table_.Value(i, kNextStatePosition)); } std::vector states; @@ -1077,6 +1088,7 @@ class TransitionConstraint : public Constraint { tmp_vars.push_back(states[var_index]); tmp_vars.push_back(vars_[var_index]); tmp_vars.push_back(states[var_index + 1]); + // We always build the compact versions of the tables. if (transition_table_.NumTuples() < kBitsInUint64) { s->AddConstraint(s->RevAlloc(new SmallCompactPositiveTableConstraint( s, tmp_vars, transition_table_))); @@ -1092,10 +1104,8 @@ class TransitionConstraint : public Constraint { virtual void Accept(ModelVisitor* const visitor) const { visitor->BeginVisitConstraint(ModelVisitor::kTransition, this); visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument, - vars_.data(), - vars_.size()); - visitor->VisitIntegerArgument(ModelVisitor::kInitialState, - initial_state_); + vars_.data(), vars_.size()); + visitor->VisitIntegerArgument(ModelVisitor::kInitialState, initial_state_); visitor->VisitIntegerArrayArgument(ModelVisitor::kFinalStatesArgument, final_states_.data(), final_states_.size()); @@ -1105,11 +1115,11 @@ class TransitionConstraint : public Constraint { } virtual string DebugString() const { - return StringPrintf("TransitionConstraint([%s], %d transitions, initial = %" - GG_LL_FORMAT "d, final = [%s])", - DebugStringVector(vars_, ", ").c_str(), - transition_table_.NumTuples(), initial_state_, - Int64VectorToString(final_states_, ", ").c_str()); + return StringPrintf( + "TransitionConstraint([%s], %d transitions, initial = %" GG_LL_FORMAT + "d, final = [%s])", + DebugStringVector(vars_, ", ").c_str(), transition_table_.NumTuples(), + initial_state_, Int64VectorToString(final_states_, ", ").c_str()); } private: @@ -1134,14 +1144,10 @@ Constraint* BuildAc4TableConstraint(Solver* const solver, const IntTupleSet& tuples, const std::vector& vars); -Constraint* Solver::MakeAllowedAssignments( - const std::vector& vars, - const IntTupleSet& tuples) { - if (tuples.NumTuples() > FLAGS_cp_ac4r_table_threshold) { - return BuildAc4TableConstraint(this, tuples, vars); - } - if (FLAGS_cp_use_compact_table - && HasCompactDomains(vars.data(), vars.size())) { +Constraint* Solver::MakeAllowedAssignments(const std::vector& vars, + const IntTupleSet& tuples) { + if (FLAGS_cp_use_compact_table && + HasCompactDomains(vars.data(), vars.size())) { if (tuples.NumTuples() < kBitsInUint64 && FLAGS_cp_use_small_table) { return RevAlloc( new SmallCompactPositiveTableConstraint(this, vars, tuples)); @@ -1149,31 +1155,25 @@ Constraint* Solver::MakeAllowedAssignments( return RevAlloc(new CompactPositiveTableConstraint(this, vars, tuples)); } } - return RevAlloc(new PositiveTableConstraint(this, vars, tuples)); + if (tuples.NumTuples() > FLAGS_cp_ac4r_table_threshold) { + return BuildAc4TableConstraint(this, tuples, vars); + } else { + return RevAlloc(new PositiveTableConstraint(this, vars, tuples)); + } } Constraint* Solver::MakeTransitionConstraint( - const std::vector& vars, - const IntTupleSet& transition_table, - int64 initial_state, - const std::vector& final_states) { - return RevAlloc(new TransitionConstraint(this, - vars, - transition_table, - initial_state, - final_states)); + const std::vector& vars, const IntTupleSet& transition_table, + int64 initial_state, const std::vector& final_states) { + return RevAlloc(new TransitionConstraint(this, vars, transition_table, + initial_state, final_states)); } Constraint* Solver::MakeTransitionConstraint( - const std::vector& vars, - const IntTupleSet& transition_table, - int64 initial_state, - const std::vector& final_states) { - return RevAlloc(new TransitionConstraint(this, - vars, - transition_table, - initial_state, - final_states)); + const std::vector& vars, const IntTupleSet& transition_table, + int64 initial_state, const std::vector& final_states) { + return RevAlloc(new TransitionConstraint(this, vars, transition_table, + initial_state, final_states)); } } // namespace operations_research