ongoing work on table constraint

This commit is contained in:
lperron@google.com
2013-07-29 23:57:50 +00:00
parent ff82466aaf
commit e8fac8d546
2 changed files with 192 additions and 73 deletions

View File

@@ -305,7 +305,8 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint {
original_min_(new int64[arity_]),
temp_mask_(new uint64[length_]),
demon_(NULL),
touched_var_(-1) {
touched_var_(-1),
var_sizes_(arity_, 0) {
}
virtual ~CompactPositiveTableConstraint() {}
@@ -329,6 +330,9 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint {
stamps_[i] = 0;
active_tuples_[i] = 0;
}
for (int i = 0; i < arity_; ++i) {
var_sizes_.SetValue(solver(), i, vars_[i]->Size());
}
}
bool IsTupleSupported(int tuple_index) {
@@ -477,6 +481,7 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint {
if (var_index == touched_var_) {
continue;
}
IntVar* const var = vars_[var_index];
to_remove_.clear();
int64 new_min = kint64max;
int64 new_max = kint64min;
@@ -494,9 +499,9 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint {
}
}
if (!to_remove_.empty()) {
vars_[var_index]->SetRange(new_min, new_max);
var->SetRange(new_min, new_max);
if (new_min != new_max) {
vars_[var_index]->RemoveValues(to_remove_);
var->RemoveValues(to_remove_);
}
}
}
@@ -526,49 +531,9 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint {
IntVar* const var = vars_[var_index];
const int64 omin = original_min_[var_index];
bool changed = false;
ClearTempMask();
const int64 oldmin = var->OldMin();
const int64 oldmax = var->OldMax();
const int64 vmin = var->Min();
const int64 vmax = 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_index = 0; value_index < vmin - omin; ++value_index) {
count += masks_[var_index][value_index] != nullptr;
}
IntVarIterator* const hole = holes_[var_index];
for (hole->Init(); hole->Ok(); hole->Next()) {
count++;
}
for (int64 value = vmax + 1; value <= oldmax; ++value) {
count += masks_[var_index][value - omin] != nullptr;
}
if (count < var->Size()) {
for (int64 value = oldmin; value < vmin; ++value) {
UpdateTempMask(var_index, value - omin);
}
IntVarIterator* const hole = holes_[var_index];
for (hole->Init(); hole->Ok(); hole->Next()) {
UpdateTempMask(var_index, hole->Value() - omin);
}
for (int64 value = vmax + 1; value <= oldmax; ++value) {
UpdateTempMask(var_index, value - omin);
}
// Then we apply this mask to active_tuples_.
for (int offset = 0; offset < length_; ++offset) {
if ((temp_mask_[offset] & active_tuples_[offset]) != 0) {
AndActiveTuples(offset, ~temp_mask_[offset]);
changed = true;
}
}
} else {
IntVarIterator* it = iterators_[var_index];
for (it->Init(); it->Ok(); it->Next()) {
const int64 value = it->Value();
UpdateTempMask(var_index, value - omin);
}
if (var->Bound()) { // Fast path for bound variables.
ClearTempMask();
UpdateTempMask(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) {
@@ -576,23 +541,62 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint {
changed = true;
}
}
} else {
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) {
UpdateTempMask(var_index, value - omin);
}
IntVarIterator* const hole = holes_[var_index];
for (hole->Init(); hole->Ok(); hole->Next()) {
UpdateTempMask(var_index, hole->Value() - omin);
}
for (int64 value = vmax + 1; value <= oldmax; ++value) {
UpdateTempMask(var_index, value - omin);
}
// Then we apply this mask to active_tuples_.
for (int offset = 0; offset < length_; ++offset) {
if ((temp_mask_[offset] & active_tuples_[offset]) != 0) {
AndActiveTuples(offset, ~temp_mask_[offset]);
changed = true;
}
}
} else {
IntVarIterator* it = iterators_[var_index];
for (it->Init(); it->Ok(); it->Next()) {
const int64 value = it->Value();
UpdateTempMask(var_index, value - omin);
}
// Then we apply this mask to active_tuples_.
for (int offset = 0; offset < length_; ++offset) {
if ((~temp_mask_[offset] & active_tuples_[offset]) != 0) {
AndActiveTuples(offset, temp_mask_[offset]);
changed = true;
}
}
}
}
// And check active_tuples_ is still not empty, we fail otherwise.
for (int offset = 0; offset < length_; ++offset) {
if (active_tuples_[offset]) {
// We push the propagate method only if something has changed.
if (changed) {
if (changed) {
for (int offset = 0; offset < length_; ++offset) {
if (active_tuples_[offset]) {
// We push the propagate method only if something has changed.
if (touched_var_ == -1) {
touched_var_ = var_index;
} else {
touched_var_ = -2; // more than one var.
}
EnqueueDelayedDemon(demon_);
return;
}
return;
}
solver()->Fail();
}
solver()->Fail();
}
private:
@@ -625,6 +629,7 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint {
std::vector<std::vector<int> > supports_;
Demon* demon_;
int touched_var_;
RevArray<int64> var_sizes_;
};
// ----- Small Compact Table. -----
@@ -769,8 +774,10 @@ class SmallCompactPositiveTableConstraint : public BasePositiveTableConstraint {
}
if (to_remove_.size() == var->Size()) {
solver()->Fail();
} else if (to_remove_.size() == 1) {
var->RemoveValue(to_remove_.back());
} else if (to_remove_.size() > 0) {
vars_[var_index]->RemoveValues(to_remove_);
var->RemoveValues(to_remove_);
}
}
}
@@ -780,34 +787,80 @@ class SmallCompactPositiveTableConstraint : public BasePositiveTableConstraint {
// This method updates the set of active tuples by masking out all
// tuples attached to values of the variables that have been removed.
// We first collect the complete set of tuples to blank out in temp_mask.
IntVar* const var = vars_[var_index];
if (var->Bound()) { // Fast path for bound variables.
const uint64 temp_mask =
masks_[var_index][var->Min() - original_min_[var_index]];
if ((~temp_mask & active_tuples_) != 0) {
AndActiveTuples(temp_mask);
if (active_tuples_ != 0) {
EnqueueDelayedDemon(demon_);
return;
} else {
solver()->Fail();
}
}
}
// 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();
for (int64 value = var->OldMin(); value < vmin; ++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) {
temp_mask |= var_mask[value - original_min];
}
// Then we apply this mask to active_tuples_.
if (temp_mask & active_tuples_) {
AndActiveTuples(~temp_mask);
if (active_tuples_) {
EnqueueDelayedDemon(demon_);
} else {
solver()->Fail();
// // 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) {
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) {
temp_mask |= var_mask[value - original_min];
}
// Then we apply this mask to active_tuples_.
if (temp_mask & active_tuples_) {
AndActiveTuples(~temp_mask);
if (active_tuples_) {
EnqueueDelayedDemon(demon_);
} else {
solver()->Fail();
}
}
// } else {
// IntVarIterator* it = iterators_[var_index];
// for (it->Init(); it->Ok(); it->Next()) {
// const int64 value = it->Value();
// temp_mask |= var_mask[value - original_min];
// }
// // Then we apply this mask to active_tuples_.
// if ((~temp_mask & active_tuples_) != 0) {
// AndActiveTuples(temp_mask);
// if (active_tuples_) {
// EnqueueDelayedDemon(demon_);
// } else {
// solver()->Fail();
// }
// }
// }
}
private:

View File

@@ -563,7 +563,8 @@ void ParserState::SortConstraints(NodeSet* const candidates,
FZLOG << " - defines only : " << defines_only.size() << std::endl;
FZLOG << " - no defines : " << no_defines.size() << std::endl;
FZLOG << " - defines and require : " << defines_and_require.size() << std::endl;
FZLOG << " - defines and require : " << defines_and_require.size()
<< std::endl;
FZLOG << " - nullified constraints : " << nullified << std::endl;
const int size = constraints_.size();
@@ -1625,6 +1626,71 @@ bool ParserState::PresolveOneConstraint(CtSpec* const spec) {
}
}
}
if (id == "regular") {
if (spec->Arg(1)->getInt() == 1) {
// One state, this is a constant table.
AstArray* const array_variables = spec->Arg(0)->getArray();
const int size = array_variables->a.size();
const int64 num_states = spec->Arg(1)->getInt();
const int64 num_values = spec->Arg(2)->getInt();
const AstArray* const array_transitions = spec->Arg(3)->getArray();
const int64 initial_state = spec->Arg(4)->getInt();
// Find the value that is stable w.r.t. the transitions.
int count = 0;
bool value_defined = false;
int64 value = 0;
for (int q = 1; q <= num_states; ++q) {
for (int s = 1; s <= num_values; ++s) {
const int64 next = array_transitions->a[count++]->getInt();
if (next == initial_state && q == initial_state) {
if (value_defined) {
// Many value are stables. We abort.
return false;
} else {
value = s;
value_defined = true;
}
}
}
}
if (!value_defined) {
return false;
}
AstSetLit* const final_set = spec->Arg(5)->getSet();
std::vector<int64> final_states;
if (final_set->interval) {
for (int v = final_set->imin; v <= final_set->imax; ++v) {
final_states.push_back(v);
}
} else {
final_states.insert(
final_states.end(), final_set->s.begin(), final_set->s.end());
}
if (final_states.size() == 1 && final_states.back() == initial_state) {
VLOG(2) << " - presolve: regular, one state and one stable value: "
<< value << " for " << spec->DebugString();
// All variables should be set to the stable value w.r.t transisions.
bool all_succeed = true;
for (int i = 0; i < size; ++i) {
AstNode* var_node = array_variables->a[i];
if (var_node->isIntVar()) {
IntVarSpec* const var_spec = int_variables_[var_node->getIntVar()];
VLOG(2) << " assign " << var_spec->DebugString()
<< " to " << value;
if (!var_spec->MergeBounds(value, value)) {
all_succeed = false;
}
} else if (!var_node->isInt() || var_node->getInt() != value) {
all_succeed = false;
}
}
if (all_succeed) {
spec->Nullify();
}
}
}
}
return false;
}