remove NestedSolve(), Solve() is available even when nested, added SOlveAndCommit() available when nested, NewSearch() is also possible when nested

This commit is contained in:
lperron@google.com
2012-05-17 15:43:34 +00:00
parent 5b27efe9ee
commit 0297f8e2e2
9 changed files with 142 additions and 144 deletions

View File

@@ -861,7 +861,8 @@ class Search {
decision_builder_(NULL), created_by_solve_(false),
selector_(NULL), search_depth_(0), left_search_depth_(0),
should_restart_(false), should_finish_(false),
sentinel_pushed_(0), jmpbuf_filled_(false) {}
sentinel_pushed_(0), jmpbuf_filled_(false),
restore_(true) {}
// Constructor for a dummy search. The only difference between a dummy search
// and a regular one is that the search depth and left search depth is
@@ -871,7 +872,8 @@ class Search {
decision_builder_(NULL), created_by_solve_(false),
selector_(NULL), search_depth_(-1), left_search_depth_(-1),
should_restart_(false), should_finish_(false),
sentinel_pushed_(0), jmpbuf_filled_(false) {}
sentinel_pushed_(0), jmpbuf_filled_(false),
restore_(true) {}
~Search() {
STLDeleteElements(&marker_stack_);
@@ -918,6 +920,8 @@ class Search {
void RightMove() {
search_depth_++;
}
bool restore() const { return restore_; }
void set_restore(bool restore) { restore_ = restore; }
int search_depth() const { return search_depth_; }
void set_search_depth(int d) { search_depth_ = d; }
int left_search_depth() const { return left_search_depth_; }
@@ -954,6 +958,7 @@ class Search {
bool should_finish_;
int sentinel_pushed_;
bool jmpbuf_filled_;
bool restore_;
};
// Backtrack is implemented using 3 primitives:
@@ -1090,6 +1095,7 @@ void Search::Clear() {
search_depth_ = 0;
left_search_depth_ = 0;
selector_.reset(NULL);
restore_ = true;
}
void Search::EnterSearch() {
@@ -1885,18 +1891,31 @@ void Solver::NewSearch(DecisionBuilder* const db,
int size) {
// TODO(user) : reset statistics
// ----- gets or creates the search object -----
CHECK_NOTNULL(db);
DCHECK_GE(size, 0);
const bool nested = state_ == IN_SEARCH;
if (state_ == IN_SEARCH || state_ == IN_ROOT_NODE) {
LOG(FATAL) << "Use NestedSolve() inside search";
if (state_ == IN_ROOT_NODE) {
LOG(FATAL) << "Cannot start new searches here.";
}
// Check state and go to OUTSIDE_SEARCH.
Search* const search = searches_.back();
Search* const search = nested ? new Search(this) : searches_.back();
search->set_created_by_solve(false); // default behavior.
BacktrackToSentinel(INITIAL_SEARCH_SENTINEL);
state_ = OUTSIDE_SEARCH;
// ----- jumps to correct state -----
if (nested) {
DCHECK_GE(searches_.size(), 2);
searches_.push_back(search);
} else {
DCHECK_EQ(2, searches_.size());
BacktrackToSentinel(INITIAL_SEARCH_SENTINEL);
state_ = OUTSIDE_SEARCH;
}
// ----- manages all monitors -----
// Always install the main propagation monitor.
propagation_monitor_->Install();
@@ -1921,22 +1940,25 @@ void Solver::NewSearch(DecisionBuilder* const db,
// Install the print trace if needed.
// The print_trace needs to be last to detect propagation from the objective.
if (FLAGS_cp_trace_propagation) {
print_trace_ = BuildPrintTrace(this);
if (!nested) { // Build trace objet at top level.
print_trace_ = BuildPrintTrace(this);
}
print_trace_->Install();
} else {
// This is useful to trace the exact behavior of the search.
// The '######## ' prefix is the same as the progagation trace.
if (FLAGS_cp_trace_search) {
if (FLAGS_cp_trace_search && !nested) {
SearchMonitor* const trace = MakeSearchTrace("######## ");
trace->Install();
}
print_trace_ = NULL;
}
// ----- enters search -----
search->EnterSearch();
// Push sentinel and set decision builder.
DCHECK_EQ(2, searches_.size());
PushSentinel(INITIAL_SEARCH_SENTINEL);
search->set_decision_builder(db);
}
@@ -2281,22 +2303,33 @@ bool Solver::NextSolution() {
}
void Solver::EndSearch() {
CHECK_EQ(2, searches_.size());
Search* const search = searches_.back();
BacktrackToSentinel(INITIAL_SEARCH_SENTINEL);
if (search->restore()) {
BacktrackToSentinel(INITIAL_SEARCH_SENTINEL);
} else {
CHECK_GT(searches_.size(), 2);
if (search->sentinel_pushed_ > 0) {
JumpToSentinelWhenNested();
}
}
search->ExitSearch();
search->Clear();
state_ = OUTSIDE_SEARCH;
if (!FLAGS_cp_profile_file.empty()) {
LOG(INFO) << "Exporting profile to " << FLAGS_cp_profile_file;
ExportProfilingOverview(FLAGS_cp_profile_file);
if (2 == searches_.size()) { // Post top level search actions.
state_ = OUTSIDE_SEARCH;
if (!FLAGS_cp_profile_file.empty()) {
LOG(INFO) << "Exporting profile to " << FLAGS_cp_profile_file;
ExportProfilingOverview(FLAGS_cp_profile_file);
}
} else { // We clean the nested Search.
delete search;
searches_.pop_back();
}
}
bool Solver::CheckAssignment(Assignment* const solution) {
CHECK(solution);
if (state_ == IN_SEARCH || state_ == IN_ROOT_NODE) {
LOG(FATAL) << "Use NestedSolve() inside search";
LOG(FATAL) << "CheckAssignment is only available at the top level.";
}
// Check state and go to OUTSIDE_SEARCH.
Search* const search = searches_.back();
@@ -2373,93 +2406,52 @@ bool Solver::CheckConstraint(Constraint* const ct) {
return Solve(MakeConstraintAdder(ct));
}
bool Solver::NestedSolve(DecisionBuilder* const db,
bool restore,
const std::vector<SearchMonitor*>& monitors) {
return NestedSolve(db, restore, monitors.data(), monitors.size());
bool Solver::SolveAndCommit(DecisionBuilder* const db,
const std::vector<SearchMonitor*>& monitors) {
return SolveAndCommit(db, monitors.data(), monitors.size());
}
bool Solver::NestedSolve(DecisionBuilder* const db,
bool restore,
SearchMonitor* const m1) {
bool Solver::SolveAndCommit(DecisionBuilder* const db,
SearchMonitor* const m1) {
std::vector<SearchMonitor*> monitors;
monitors.push_back(m1);
return NestedSolve(db, restore, monitors.data(), monitors.size());
return SolveAndCommit(db, monitors.data(), monitors.size());
}
bool Solver::NestedSolve(DecisionBuilder* const db, bool restore) {
return NestedSolve(db, restore, NULL, Zero());
bool Solver::SolveAndCommit(DecisionBuilder* const db) {
return SolveAndCommit(db, NULL, Zero());
}
bool Solver::NestedSolve(DecisionBuilder* const db,
bool restore,
SearchMonitor* const m1,
SearchMonitor* const m2) {
bool Solver::SolveAndCommit(DecisionBuilder* const db,
SearchMonitor* const m1,
SearchMonitor* const m2) {
std::vector<SearchMonitor*> monitors;
monitors.push_back(m1);
monitors.push_back(m2);
return NestedSolve(db, restore, monitors.data(), monitors.size());
return SolveAndCommit(db, monitors.data(), monitors.size());
}
bool Solver::NestedSolve(DecisionBuilder* const db,
bool restore,
SearchMonitor* const m1,
SearchMonitor* const m2,
SearchMonitor* const m3) {
bool Solver::SolveAndCommit(DecisionBuilder* const db,
SearchMonitor* const m1,
SearchMonitor* const m2,
SearchMonitor* const m3) {
std::vector<SearchMonitor*> monitors;
monitors.push_back(m1);
monitors.push_back(m2);
monitors.push_back(m3);
return NestedSolve(db, restore, monitors.data(), monitors.size());
return SolveAndCommit(db, monitors.data(), monitors.size());
}
bool Solver::NestedSolve(DecisionBuilder* const db,
bool restore,
SearchMonitor* const * monitors,
int size) {
Search new_search(this);
searches_.push_back(&new_search);
// Always install the main propagation monitor.
propagation_monitor_->Install();
// Install the demon monitor if needed.
if (demon_profiler_ != NULL) {
InstallDemonProfiler(demon_profiler_);
}
for (int i = 0; i < size; ++i) {
if (monitors[i] != NULL) {
monitors[i]->Install();
}
}
std::vector<SearchMonitor*> extras;
db->AppendMonitors(this, &extras);
for (ConstIter<std::vector<SearchMonitor*> > it(extras); !it.at_end(); ++it) {
SearchMonitor* const monitor = *it;
if (monitor != NULL) {
monitor->Install();
}
}
// Install the print trace if needed.
if (print_trace_ != NULL) {
print_trace_->Install();
}
bool Solver::SolveAndCommit(DecisionBuilder* const db,
SearchMonitor* const * monitors,
int size) {
NewSearch(db, monitors, size);
searches_.back()->set_created_by_solve(true); // Overwrites default.
new_search.EnterSearch();
PushSentinel(INITIAL_SEARCH_SENTINEL);
new_search.set_decision_builder(db);
bool res = NextSolution();
if (res) {
if (restore) {
BacktrackToSentinel(INITIAL_SEARCH_SENTINEL);
} else {
JumpToSentinelWhenNested();
}
}
new_search.ExitSearch();
new_search.Clear();
searches_.pop_back();
return res;
searches_.back()->set_restore(false);
NextSolution();
const bool solution_found = searches_.back()->solution_counter() > 0;
EndSearch();
return solution_found;
}
void Solver::Fail() {

View File

@@ -908,8 +908,8 @@ class Solver {
// assigning any variable to any value is a solution, unless the root node
// propagation discovers that the model is infeasible.
//
// These function must be called from outside of search, meaning that
// <tt>state() == OUTSIDE_SEARCH</tt>.
// These function must be called from either from outside of search,
// or withing the Next() method of a decion builder.
//
// Solve will terminate whenever any of the following event arise:
// * A search monitor asks the solver to terminate the search by calling
@@ -951,13 +951,14 @@ class Solver {
// @}
// @{
// Decomposed top level search.
// The code should look like
// Decomposed search.
// The code for a top level search should look like
// solver->NewSearch(db);
// while (solver->NextSolution()) {
// //.. use the current solution
// }
// solver()->EndSearch();
void NewSearch(DecisionBuilder* const db,
const std::vector<SearchMonitor*>& monitors);
void NewSearch(DecisionBuilder* const db,
@@ -982,37 +983,34 @@ class Solver {
void EndSearch();
// @}
// Nested solve using a decision builder and up to three
// SolveAndCommit using a decision builder and up to three
// search monitors, usually one for the objective, one for the limits
// and one to collect solutions.
// The restore parameter indicates if the search should backtrack completely
// after completion, even in case of success.
bool NestedSolve(DecisionBuilder* const db,
bool restore,
const std::vector<SearchMonitor*>& monitors);
bool NestedSolve(DecisionBuilder* const db,
bool restore,
SearchMonitor* const * monitors,
int size);
bool NestedSolve(DecisionBuilder* const db, bool restore);
bool NestedSolve(DecisionBuilder* const db,
bool restore,
SearchMonitor* const m1);
bool NestedSolve(DecisionBuilder* const db,
bool restore,
SearchMonitor* const m1, SearchMonitor* const m2);
bool NestedSolve(DecisionBuilder* const db,
bool restore,
SearchMonitor* const m1,
SearchMonitor* const m2,
SearchMonitor* const m3);
//
// The difference between a SolveAndCommit() and a Solve() method
// call is the fact that SolveAndCommit will not backtrack all
// modifications at the end of the search. This method is only
// usable during the Next() method of a decision builder.
bool SolveAndCommit(DecisionBuilder* const db,
const std::vector<SearchMonitor*>& monitors);
bool SolveAndCommit(DecisionBuilder* const db,
SearchMonitor* const * monitors,
int size);
bool SolveAndCommit(DecisionBuilder* const db);
bool SolveAndCommit(DecisionBuilder* const db,
SearchMonitor* const m1);
bool SolveAndCommit(DecisionBuilder* const db,
SearchMonitor* const m1, SearchMonitor* const m2);
bool SolveAndCommit(DecisionBuilder* const db,
SearchMonitor* const m1,
SearchMonitor* const m2,
SearchMonitor* const m3);
// Checks whether the given assignment satisfies all the relevant constraints.
bool CheckAssignment(Assignment* const assignment);
// Checks whether adding this constraint will lead to an immediate
// failure. It will return true if the model is already
// failure. It will return false if the model is already
// inconsistent, or if adding the constraint makes it inconsistent.
bool CheckConstraint(Constraint* const constraint);
@@ -1513,9 +1511,7 @@ class Solver {
// |{i | v[i] == value}| == count
Constraint* MakeCount(const std::vector<IntVar*>& v,
int64 value,
int64 count);
Constraint* MakeCount(const std::vector<IntVar*>& v, int64 value, int64 count);
// |{i | v[i] == value}| == count
Constraint* MakeCount(const std::vector<IntVar*>& v, int64 value,
IntVar* const count);
@@ -2765,8 +2761,7 @@ class Solver {
int SearchLeftDepth() const;
// Gets the number of nested searches. It returns 0 outside search,
// 1 during the top level search, 2 if one level of NestedSolve() is
// used, and more if more solves are nested.
// 1 during the top level search, 2 or more in case of nested searched.
int SolveDepth() const;
// Sets the given branch selector on the current active search.

View File

@@ -924,7 +924,6 @@ static void SetPythonFlags(bool trace_propagation,
PhaseStrategy str);
%ignore Solver::Solve(DecisionBuilder* const db,
SearchMonitor* const * monitors, int size);
%ignore Solver::NestedSolve;
%ignore Solver::Compose(DecisionBuilder* const db1,
DecisionBuilder* const db2);
%ignore Solver::Compose(DecisionBuilder* const db1,

View File

@@ -394,8 +394,8 @@ class ImpactRecorder {
}
// Reset the number of impacts initialized.
init_count_ = 0;
// Use NestedSolve() to scan all values of one variable.
solver->NestedSolve(init_decision_builder, true);
// Use Solve() to scan all values of one variable.
solver->Solve(init_decision_builder);
// If we have not initialized all values, then they can be removed.
// As the iterator is not stable w.r.t. deletion, we need to store
@@ -1069,7 +1069,7 @@ class ImpactDecisionBuilder : public DecisionBuilder {
HeuristicWrapper* const wrapper = heuristics_[index];
const bool result =
solver->NestedSolve(wrapper->phase, false, heuristic_limit_);
solver->SolveAndCommit(wrapper->phase, heuristic_limit_);
if (result && parameters_.display_level != DefaultPhaseParameters::NONE) {
LOG(INFO) << "Solution found by heuristic " << wrapper->name;
}

View File

@@ -4377,6 +4377,7 @@ IntVar* Solver::MakeIntConst(int64 val) {
namespace {
string IndexedName(const string& prefix, int index, int max_index) {
#if 0
#if defined(_MSC_VER)
const int digits = max_index > 0 ?
static_cast<int>(log(1.0L * max_index) / log(10.0L)) + 1 :
@@ -4385,6 +4386,9 @@ string IndexedName(const string& prefix, int index, int max_index) {
const int digits = max_index > 0 ? static_cast<int>(log10(max_index)) + 1: 1;
#endif
return StringPrintf("%s%0*d", prefix.c_str(), digits, index);
#else
return StringPrintf("%s%d", prefix.c_str(), index);
#endif
}
} // namespace

View File

@@ -108,13 +108,13 @@ class GccConstraint : public Constraint {
for (i = 2; i < count + 2; i++) {
sum_[i + 1] = sum_[i] + elements[i - 2];
}
sum_[i + 1] = sum_[i] + 1;
sum_[i + 2] = sum_[i + 1] + 1;
sum_[count + 3] = sum_[i] + 1;
sum_[count + 4] = sum_[i + 1] + 1;
i = count + 3;
j = i;
while (i > 0) {
while (sum_[i] == sum_[i-1]) {
while (sum_[i] == sum_[i - 1]) {
ds_[i--] = j;
}
ds_[j] = i--;
@@ -144,10 +144,10 @@ class GccConstraint : public Constraint {
int64 Sum(int64 from, int64 to) const {
if (from <= to) {
DCHECK((offset_ <= from) && (to <= last_value_));
return sum_[to - offset_] - sum_[from - offset_ - 1];
return sum_[to - offset_] - sum_[from -1 - offset_];
} else {
DCHECK((offset_ <= to) && (from <= last_value_));
return sum_[to - offset_ - 1] - sum_[from - offset_];
return sum_[to - 1 - offset_] - sum_[from - offset_];
}
}
@@ -418,30 +418,30 @@ class GccConstraint : public Constraint {
bounds_[0] = last;
// merge sorted_by_min_[] and sorted_by_max_[] into bounds_[]
int64 i = 0;
int64 j = 0;
int64 min_index = 0;
int64 max_index = 0;
int64 active_index = 0;
for (;;) {
// make sure sorted_by_min_ exhausted first
if (i < size_ && min <= max) {
if (min_index < size_ && min <= max) {
if (min != last) {
bounds_[++active_index] = min;
last = min;
}
sorted_by_min_[i]->min_rank = active_index;
if (++i < size_) {
min = sorted_by_min_[i]->min_value;
sorted_by_min_[min_index]->min_rank = active_index;
if (++min_index < size_) {
min = sorted_by_min_[min_index]->min_value;
}
} else {
if (max != last) {
bounds_[++active_index] = max;
last = max;
}
sorted_by_max_[j]->max_rank = active_index;
if (++j == size_) {
sorted_by_max_[max_index]->max_rank = active_index;
if (++max_index == size_) {
break;
}
max = sorted_by_max_[j]->max_value + 1;
max = sorted_by_max_[max_index]->max_value + 1;
}
}
active_size_ = active_index;
@@ -477,7 +477,7 @@ class GccConstraint : public Constraint {
solver()->Fail();
}
if (hall_[x] > x) {
int64 w = PathMax(hall_, hall_[x]);
const int64 w = PathMax(hall_, hall_[x]);
sorted_by_max_[i]->min_value = bounds_[w];
PathSet(&hall_, x, w, w);
changed = true;

View File

@@ -2870,7 +2870,7 @@ Decision* FindOneNeighbor::Next(Solver* const solver) {
solver->filtered_neighbors_ += 1;
assignment_copy->Copy(reference_assignment_.get());
assignment_copy->Copy(delta);
if (solver->NestedSolve(restore, false)) {
if (solver->SolveAndCommit(restore)) {
solver->accepted_neighbors_ += 1;
assignment_->Store();
neighbor_found_ = true;
@@ -3081,11 +3081,18 @@ NestedSolveDecision::NestedSolveDecision(DecisionBuilder* const db,
void NestedSolveDecision::Apply(Solver* const solver) {
CHECK(NULL != solver);
if (solver->NestedSolve(db_, restore_,
monitors_.data(), monitors_.size())) {
solver->SaveAndSetValue(&state_, static_cast<int>(DECISION_FOUND));
if (restore_) {
if (solver->Solve(db_, monitors_.data(), monitors_.size())) {
solver->SaveAndSetValue(&state_, static_cast<int>(DECISION_FOUND));
} else {
solver->SaveAndSetValue(&state_, static_cast<int>(DECISION_FAILED));
}
} else {
solver->SaveAndSetValue(&state_, static_cast<int>(DECISION_FAILED));
if (solver->SolveAndCommit(db_, monitors_.data(), monitors_.size())) {
solver->SaveAndSetValue(&state_, static_cast<int>(DECISION_FOUND));
} else {
solver->SaveAndSetValue(&state_, static_cast<int>(DECISION_FAILED));
}
}
}

View File

@@ -133,6 +133,7 @@ class MtSolveSupport : public ParallelSolveSupport {
void LockMutex();
// Unlocks the internal mutex.
void UnlockMutex();
private:
bool CheckTermination();
void Reset();

View File

@@ -4138,7 +4138,7 @@ class SolveOnce : public DecisionBuilder {
virtual ~SolveOnce() {}
virtual Decision* Next(Solver* s) {
bool res = s->NestedSolve(db_, false, monitors_);
bool res = s->SolveAndCommit(db_, monitors_);
if (!res) {
s->Fail();
}
@@ -4255,7 +4255,7 @@ class NestedOptimize : public DecisionBuilder {
}
virtual Decision* Next(Solver* solver) {
solver->NestedSolve(db_, true, monitors_);
solver->Solve(db_, monitors_);
if (collector_->solution_count() == 0) {
solver->Fail();
}