speed up table constraint; some fixed in scheduling when used with unperformed activities

This commit is contained in:
lperron@google.com
2013-07-30 21:41:29 +00:00
parent abbdba5fcb
commit 99cc91bb94
5 changed files with 246 additions and 221 deletions

View File

@@ -1836,7 +1836,7 @@ class Solver {
std::vector<IntervalVar*>* const array);
// Creates an fixed and performed interval.
// Creates a fixed and performed interval.
IntervalVar* MakeFixedInterval(int64 start,
int64 duration,
const string& name);

View File

@@ -287,7 +287,7 @@ void SequenceVarLocalSearchOperator::Start(const Assignment* assignment) {
element = &(container.Element(vars_[i]));
}
const std::vector<int>& 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;

View File

@@ -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);

View File

@@ -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<int>* const possible_firsts,
std::vector<int>* const possible_lasts) {
possible_firsts->clear();
possible_lasts->clear();
hash_set<int> 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<int>& 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<int> all_candidates;
std::vector<std::vector<int> > all_possible_firsts;
std::vector<SequenceVar*> all_candidates;
std::vector<std::vector<int>> 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;
}

View File

@@ -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<IntVar*> & vars,
BasePositiveTableConstraint(Solver* const s, const std::vector<IntVar*>& 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<int, uint64*> ValueBitset;
PositiveTableConstraint(Solver* const s,
const std::vector<IntVar*> & vars,
PositiveTableConstraint(Solver* const s, const std::vector<IntVar*>& 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<ValueBitset> 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<IntVar*> & vars,
CompactPositiveTableConstraint(Solver* const s, const std::vector<IntVar*>& 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<IntVar*> & vars,
const std::vector<IntVar*>& 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<IntVar*>& vars,
const IntTupleSet& transition_table,
int64 initial_state,
TransitionConstraint(Solver* const s, const std::vector<IntVar*>& vars,
const IntTupleSet& transition_table, int64 initial_state,
const std::vector<int64>& 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<IntVar*>& vars,
const IntTupleSet& transition_table,
int64 initial_state,
TransitionConstraint(Solver* const s, const std::vector<IntVar*>& vars,
const IntTupleSet& transition_table, int64 initial_state,
const std::vector<int>& 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<IntVar*> 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<IntVar*>& vars);
Constraint* Solver::MakeAllowedAssignments(
const std::vector<IntVar*>& 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<IntVar*>& 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<IntVar*>& vars,
const IntTupleSet& transition_table,
int64 initial_state,
const std::vector<int64>& final_states) {
return RevAlloc(new TransitionConstraint(this,
vars,
transition_table,
initial_state,
final_states));
const std::vector<IntVar*>& vars, const IntTupleSet& transition_table,
int64 initial_state, const std::vector<int64>& final_states) {
return RevAlloc(new TransitionConstraint(this, vars, transition_table,
initial_state, final_states));
}
Constraint* Solver::MakeTransitionConstraint(
const std::vector<IntVar*>& vars,
const IntTupleSet& transition_table,
int64 initial_state,
const std::vector<int>& final_states) {
return RevAlloc(new TransitionConstraint(this,
vars,
transition_table,
initial_state,
final_states));
const std::vector<IntVar*>& vars, const IntTupleSet& transition_table,
int64 initial_state, const std::vector<int>& final_states) {
return RevAlloc(new TransitionConstraint(this, vars, transition_table,
initial_state, final_states));
}
} // namespace operations_research