00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <stddef.h>
00015 #include <string.h>
00016 #include "base/hash.h"
00017 #include <limits>
00018 #include <string>
00019 #include <vector>
00020
00021 #include "base/callback.h"
00022 #include "base/commandlineflags.h"
00023 #include "base/integral_types.h"
00024 #include "base/logging.h"
00025 #include "base/macros.h"
00026 #include "base/scoped_ptr.h"
00027 #include "base/stl_util.h"
00028 #include "constraint_solver/constraint_solver.h"
00029 #include "constraint_solver/constraint_solveri.h"
00030 #include "util/cached_log.h"
00031 #include "base/random.h"
00032
00033 DEFINE_int32(cp_impact_divider, 10, "Divider for continuous update.");
00034
00035 namespace operations_research {
00036
00037
00038 const int DefaultPhaseParameters::kDefaultNumberOfSplits = 100;
00039 const int DefaultPhaseParameters::kDefaultHeuristicPeriod = 100;
00040 const int DefaultPhaseParameters::kDefaultHeuristicNumFailuresLimit = 30;
00041 const int DefaultPhaseParameters::kDefaultSeed = 0;
00042 const double DefaultPhaseParameters::kDefaultRestartLogSize = -1.0;
00043 const bool DefaultPhaseParameters::kDefaultUseNoGoods = true;
00044
00045 namespace {
00046
00047
00048
00049
00050 class DomainWatcher {
00051 public:
00052 DomainWatcher(const IntVar* const * vars, int size, int cache_size)
00053 : vars_(NULL), size_(size) {
00054 if (size_ > 0) {
00055 vars_.reset(new IntVar*[size_]);
00056 memcpy(vars_.get(), vars, size_ * sizeof(*vars));
00057 }
00058 cached_log_.Init(cache_size);
00059 }
00060
00061 double LogSearchSpaceSize() {
00062 double result = 0.0;
00063 for (int index = 0; index < size_; ++index) {
00064 result += cached_log_.Log2(vars_[index]->Size());
00065 }
00066 return result;
00067 }
00068
00069 double Log2(int64 size) const {
00070 return cached_log_.Log2(size);
00071 }
00072
00073 private:
00074 scoped_array<IntVar*> vars_;
00075 const int size_;
00076 CachedLog cached_log_;
00077 DISALLOW_COPY_AND_ASSIGN(DomainWatcher);
00078 };
00079
00080
00081
00082
00083
00084 class InitVarImpacts : public DecisionBuilder {
00085 public:
00086
00087 InitVarImpacts()
00088 : var_(NULL),
00089 update_impact_callback_(NULL),
00090 new_start_(false),
00091 var_index_(0),
00092 value_index_(-1),
00093 update_impact_closure_(
00094 NewPermanentCallback(this, &InitVarImpacts::UpdateImpacts)),
00095 updater_(update_impact_closure_.get()) {
00096 CHECK_NOTNULL(update_impact_closure_);
00097 }
00098
00099 virtual ~InitVarImpacts() {}
00100
00101 void UpdateImpacts() {
00102
00103 update_impact_callback_->Run(var_index_, var_->Min());
00104 }
00105
00106 void Init(IntVar* const var,
00107 IntVarIterator* const iterator,
00108 int var_index) {
00109 var_ = var;
00110 iterator_ = iterator;
00111 var_index_ = var_index;
00112 new_start_ = true;
00113 value_index_ = 0;
00114 }
00115
00116 virtual Decision* Next(Solver* const solver) {
00117 CHECK_NOTNULL(var_);
00118 CHECK_NOTNULL(iterator_);
00119 if (new_start_) {
00120 active_values_.clear();
00121 for (iterator_->Init(); iterator_->Ok(); iterator_->Next()) {
00122 active_values_.push_back(iterator_->Value());
00123 }
00124 new_start_ = false;
00125 }
00126 if (value_index_ == active_values_.size()) {
00127 return NULL;
00128 }
00129 updater_.var_ = var_;
00130 updater_.value_ = active_values_[value_index_];
00131 value_index_++;
00132 return &updater_;
00133 }
00134
00135 void set_update_impact_callback(Callback2<int, int64>* const callback) {
00136 update_impact_callback_ = callback;
00137 }
00138
00139 private:
00140
00141 class AssignCallFail : public Decision {
00142 public:
00143 explicit AssignCallFail(Closure* const update_impact_closure)
00144 : var_(NULL),
00145 value_(0),
00146 update_impact_closure_(update_impact_closure) {
00147 CHECK_NOTNULL(update_impact_closure_);
00148 }
00149 virtual ~AssignCallFail() {}
00150 virtual void Apply(Solver* const solver) {
00151 CHECK_NOTNULL(var_);
00152 var_->SetValue(value_);
00153
00154 update_impact_closure_->Run();
00155 solver->Fail();
00156 }
00157 virtual void Refute(Solver* const solver) {}
00158
00159 IntVar* var_;
00160 int64 value_;
00161
00162 private:
00163 Closure* const update_impact_closure_;
00164 DISALLOW_COPY_AND_ASSIGN(AssignCallFail);
00165 };
00166
00167 IntVar* var_;
00168 Callback2<int, int64>* update_impact_callback_;
00169 bool new_start_;
00170 IntVarIterator* iterator_;
00171 int var_index_;
00172 std::vector<int64> active_values_;
00173 int value_index_;
00174 const scoped_ptr<Closure> update_impact_closure_;
00175 AssignCallFail updater_;
00176 };
00177
00178
00179
00180
00181 class InitVarImpactsWithSplits : public DecisionBuilder {
00182 public:
00183
00184 class AssignIntervalCallFail : public Decision {
00185 public:
00186 explicit AssignIntervalCallFail(Closure* const update_impact_closure)
00187 : var_(NULL),
00188 value_min_(0),
00189 value_max_(0),
00190 update_impact_closure_(update_impact_closure) {
00191 CHECK_NOTNULL(update_impact_closure_);
00192 }
00193 virtual ~AssignIntervalCallFail() {}
00194 virtual void Apply(Solver* const solver) {
00195 CHECK_NOTNULL(var_);
00196 var_->SetRange(value_min_, value_max_);
00197
00198 update_impact_closure_->Run();
00199 solver->Fail();
00200 }
00201 virtual void Refute(Solver* const solver) {}
00202
00203
00204 IntVar* var_;
00205 int64 value_min_;
00206 int64 value_max_;
00207
00208 private:
00209 Closure* const update_impact_closure_;
00210 DISALLOW_COPY_AND_ASSIGN(AssignIntervalCallFail);
00211 };
00212
00213
00214
00215 explicit InitVarImpactsWithSplits(int split_size)
00216 : var_(NULL),
00217 update_impact_callback_(NULL),
00218 new_start_(false),
00219 var_index_(0),
00220 min_value_(0),
00221 max_value_(0),
00222 split_size_(split_size),
00223 split_index_(-1),
00224 update_impact_closure_(NewPermanentCallback(
00225 this, &InitVarImpactsWithSplits::UpdateImpacts)),
00226 updater_(update_impact_closure_.get()) {
00227 CHECK_NOTNULL(update_impact_closure_);
00228 }
00229
00230 virtual ~InitVarImpactsWithSplits() {}
00231
00232 void UpdateImpacts() {
00233 for (iterator_->Init(); iterator_->Ok(); iterator_->Next()) {
00234 update_impact_callback_->Run(var_index_, iterator_->Value());
00235 }
00236 }
00237
00238 void Init(IntVar* const var,
00239 IntVarIterator* const iterator,
00240 int var_index) {
00241 var_ = var;
00242 iterator_ = iterator;
00243 var_index_ = var_index;
00244 new_start_ = true;
00245 split_index_ = 0;
00246 }
00247
00248 int64 IntervalStart(int index) const {
00249 const int64 length = max_value_ - min_value_ + 1;
00250 return (min_value_ + length * index / split_size_);
00251 }
00252
00253 virtual Decision* Next(Solver* const solver) {
00254 if (new_start_) {
00255 min_value_ = var_->Min();
00256 max_value_ = var_->Max();
00257 new_start_ = false;
00258 }
00259 if (split_index_ == split_size_) {
00260 return NULL;
00261 }
00262 updater_.var_ = var_;
00263 updater_.value_min_ = IntervalStart(split_index_);
00264 split_index_++;
00265 if (split_index_ == split_size_) {
00266 updater_.value_max_ = max_value_;
00267 } else {
00268 updater_.value_max_ = IntervalStart(split_index_) - 1;
00269 }
00270 return &updater_;
00271 }
00272
00273 void set_update_impact_callback(Callback2<int, int64>* const callback) {
00274 update_impact_callback_ = callback;
00275 }
00276
00277 private:
00278 IntVar* var_;
00279 Callback2<int, int64>* update_impact_callback_;
00280 bool new_start_;
00281 IntVarIterator* iterator_;
00282 int var_index_;
00283 int64 min_value_;
00284 int64 max_value_;
00285 const int split_size_;
00286 int split_index_;
00287 scoped_ptr<Closure> update_impact_closure_;
00288 AssignIntervalCallFail updater_;
00289 };
00290
00291
00292
00293
00294
00295
00296 class ImpactRecorder {
00297 public:
00298 static const int kLogCacheSize;
00299 static const double kPerfectImpact;
00300 static const double kFailureImpact;
00301 static const double kInitFailureImpact;
00302
00303 ImpactRecorder(const IntVar* const * vars,
00304 int size,
00305 DefaultPhaseParameters::DisplayLevel display_level)
00306 : domain_watcher_(vars, size, kLogCacheSize),
00307 size_(size),
00308 current_log_space_(0.0),
00309 impacts_(size_),
00310 original_min_(size_, 0LL),
00311 domain_iterators_(new IntVarIterator*[size_]),
00312 display_level_(display_level) {
00313 CHECK_GE(size_, 0);
00314 if (size_ > 0) {
00315 vars_.reset(new IntVar*[size_]);
00316 memcpy(vars_.get(), vars, size_ * sizeof(*vars));
00317 }
00318 for (int i = 0; i < size_; ++i) {
00319 domain_iterators_[i] = vars_[i]->MakeDomainIterator(true);
00320 original_min_[i] = vars_[i]->Min();
00321
00322
00323
00324 impacts_[i].resize(vars_[i]->Max() - vars_[i]->Min() + 1,
00325 kInitFailureImpact);
00326 }
00327 }
00328
00329 void ResetImpacts() {
00330 for (int i = 0; i < size_; ++i) {
00331 for (int j = 0; j < impacts_[i].size(); ++j) {
00332 impacts_[i][j] = kInitFailureImpact;
00333 }
00334 }
00335 }
00336
00337 void RecordLogSearchSpace() {
00338 current_log_space_ = domain_watcher_.LogSearchSpaceSize();
00339 }
00340
00341 double LogSearchSpaceSize() const {
00342 return current_log_space_;
00343 }
00344
00345 void UpdateImpact(int var_index, int64 value, double impact) {
00346 const int64 value_index = value - original_min_[var_index];
00347 const double current_impact = impacts_[var_index][value_index];
00348 const double new_impact =
00349 (current_impact * (FLAGS_cp_impact_divider - 1) + impact) /
00350 FLAGS_cp_impact_divider;
00351 impacts_[var_index][value_index] = new_impact;
00352 }
00353
00354 void InitImpact(int var_index, int64 value) {
00355 const double log_space = domain_watcher_.LogSearchSpaceSize();
00356 const double impact = kPerfectImpact - log_space / current_log_space_;
00357 const int64 value_index = value - original_min_[var_index];
00358 DCHECK_LT(var_index, size_);
00359 DCHECK_LT(value_index, impacts_[var_index].size());
00360 impacts_[var_index][value_index] = impact;
00361 init_count_++;
00362 }
00363
00364 void FirstRun(Solver* const solver, int64 splits) {
00365 current_log_space_ = domain_watcher_.LogSearchSpaceSize();
00366 if (display_level_ != DefaultPhaseParameters::NONE) {
00367 LOG(INFO) << " - initial log2(SearchSpace) = " << current_log_space_;
00368 }
00369 const int64 init_time = solver->wall_time();
00370 int64 removed_counter = 0;
00371 FirstRunVariableContainers* container = solver->RevAlloc(
00372 new FirstRunVariableContainers(this, splits));
00373
00374 for (int var_index = 0; var_index < size_; ++var_index) {
00375 IntVar* const var = vars_[var_index];
00376 if (var->Bound()) {
00377 continue;
00378 }
00379 IntVarIterator* const iterator = domain_iterators_[var_index];
00380 DecisionBuilder* init_decision_builder = NULL;
00381 if (var->Max() - var->Min() < splits) {
00382
00383 container->without_split()->set_update_impact_callback(
00384 container->update_impact_callback());
00385 container->without_split()->Init(var, iterator, var_index);
00386 init_decision_builder = container->without_split();
00387 } else {
00388
00389
00390 container->with_splits()->set_update_impact_callback(
00391 container->update_impact_callback());
00392 container->with_splits()->Init(var, iterator, var_index);
00393 init_decision_builder = container->with_splits();
00394 }
00395
00396 init_count_ = 0;
00397
00398 solver->NestedSolve(init_decision_builder, true);
00399
00400
00401
00402
00403 if (init_count_ != var->Size()) {
00404 container->ClearRemovedValues();
00405 for (iterator->Init(); iterator->Ok(); iterator->Next()) {
00406 const int64 value = iterator->Value();
00407 const int64 value_index = value - original_min_[var_index];
00408 if (impacts_[var_index][value_index] == kInitFailureImpact) {
00409 container->PushBackRemovedValue(value);
00410 }
00411 }
00412 CHECK(container->HasRemovedValues()) << var->DebugString();
00413 removed_counter += container->NumRemovedValues();
00414 const double old_log = domain_watcher_.Log2(var->Size());
00415 var->RemoveValues(container->removed_values());
00416 current_log_space_ += domain_watcher_.Log2(var->Size()) - old_log;
00417 }
00418 }
00419 if (display_level_ != DefaultPhaseParameters::NONE) {
00420 if (removed_counter) {
00421 LOG(INFO) << " - init done, time = "
00422 << solver->wall_time() - init_time
00423 << " ms, " << removed_counter
00424 << " values removed, log2(SearchSpace) = "
00425 << current_log_space_;
00426 } else {
00427 LOG(INFO) << " - init done, time = "
00428 << solver->wall_time() - init_time << " ms";
00429 }
00430 }
00431 }
00432
00433 void UpdateAfterAssignment(int var_index, int64 value) {
00434 CHECK_GT(current_log_space_, 0.0);
00435 const double log_space = domain_watcher_.LogSearchSpaceSize();
00436 const double impact = kPerfectImpact - log_space / current_log_space_;
00437 UpdateImpact(var_index, value, impact);
00438 current_log_space_ = log_space;
00439 }
00440
00441 void UpdateAfterFailure(int var_index, int64 value) {
00442 UpdateImpact(var_index, value, kFailureImpact);
00443 current_log_space_ = domain_watcher_.LogSearchSpaceSize();
00444 }
00445
00446
00447
00448
00449 void ScanVarImpacts(int var_index,
00450 int64* const best_impact_value,
00451 double* const var_impacts,
00452 DefaultPhaseParameters::VariableSelection var_select,
00453 DefaultPhaseParameters::ValueSelection value_select) {
00454 CHECK_NOTNULL(best_impact_value);
00455 CHECK_NOTNULL(var_impacts);
00456 double max_impact = -std::numeric_limits<double>::max();
00457 double min_impact = std::numeric_limits<double>::max();
00458 double sum_var_impact = 0.0;
00459 int64 min_impact_value = -1;
00460 int64 max_impact_value = -1;
00461 IntVarIterator* const it = domain_iterators_[var_index];
00462 for (it->Init(); it->Ok(); it->Next()) {
00463 const int64 value = it->Value();
00464 const int64 value_index = value - original_min_[var_index];
00465 DCHECK_LT(var_index, size_);
00466 DCHECK_LT(value_index, impacts_[var_index].size());
00467 const double current_impact = impacts_[var_index][value_index];
00468 sum_var_impact += current_impact;
00469 if (current_impact > max_impact) {
00470 max_impact = current_impact;
00471 max_impact_value = value;
00472 }
00473 if (current_impact < min_impact) {
00474 min_impact = current_impact;
00475 min_impact_value = value;
00476 }
00477 }
00478
00479 switch (var_select) {
00480 case DefaultPhaseParameters::CHOOSE_MAX_AVERAGE_IMPACT: {
00481 *var_impacts = sum_var_impact / vars_[var_index]->Size();
00482 break;
00483 }
00484 case DefaultPhaseParameters::CHOOSE_MAX_VALUE_IMPACT: {
00485 *var_impacts = max_impact;
00486 break;
00487 }
00488 default: {
00489 *var_impacts = sum_var_impact;
00490 break;
00491 }
00492 }
00493
00494 switch (value_select) {
00495 case DefaultPhaseParameters::SELECT_MIN_IMPACT: {
00496 *best_impact_value = min_impact_value;
00497 break;
00498 }
00499 case DefaultPhaseParameters::SELECT_MAX_IMPACT: {
00500 *best_impact_value = max_impact_value;
00501 break;
00502 }
00503 }
00504 }
00505
00506 private:
00507
00508
00509 class FirstRunVariableContainers : public BaseObject {
00510 public:
00511 FirstRunVariableContainers(ImpactRecorder* impact_recorder, int64 splits)
00512 : update_impact_callback_(
00513 NewPermanentCallback(impact_recorder,
00514 &ImpactRecorder::InitImpact)),
00515 removed_values_(),
00516 without_splits_(),
00517 with_splits_(splits) {}
00518 Callback2<int, int64>* update_impact_callback() {
00519 return update_impact_callback_.get();
00520 }
00521 void PushBackRemovedValue(int64 value) { removed_values_.push_back(value); }
00522 bool HasRemovedValues() const { return !removed_values_.empty(); }
00523 void ClearRemovedValues() { removed_values_.clear(); }
00524 size_t NumRemovedValues() const { return removed_values_.size(); }
00525 const std::vector<int64>& removed_values() const { return removed_values_; }
00526 InitVarImpacts* without_split() { return &without_splits_; }
00527 InitVarImpactsWithSplits* with_splits() { return &with_splits_; }
00528
00529 private:
00530 scoped_ptr<Callback2<int, int64> > update_impact_callback_;
00531 std::vector<int64> removed_values_;
00532 InitVarImpacts without_splits_;
00533 InitVarImpactsWithSplits with_splits_;
00534 };
00535
00536 DomainWatcher domain_watcher_;
00537 scoped_array<IntVar*> vars_;
00538 const int size_;
00539 double current_log_space_;
00540
00541
00542 std::vector<std::vector<double> > impacts_;
00543 std::vector<int64> original_min_;
00544 scoped_array<IntVarIterator*> domain_iterators_;
00545 int64 init_count_;
00546 const DefaultPhaseParameters::DisplayLevel display_level_;
00547
00548 DISALLOW_COPY_AND_ASSIGN(ImpactRecorder);
00549 };
00550
00551 const int ImpactRecorder::kLogCacheSize = 1000;
00552 const double ImpactRecorder::kPerfectImpact = 1.0;
00553 const double ImpactRecorder::kFailureImpact = 1.0;
00554 const double ImpactRecorder::kInitFailureImpact = 2.0;
00555
00556
00557
00558
00559 int64 ComputeBranchRestart(int64 log) {
00560 if (log <= 0 || log > 63) {
00561 return kint64max;
00562 }
00563 return GG_ULONGLONG(1) << log;
00564 }
00565
00566
00567 class ImpactDecisionBuilder : public DecisionBuilder {
00568 public:
00569 static const int kUninitializedVarIndex;
00570 static const uint64 kUninitializedFailStamp;
00571
00572
00573 class ChoiceInfo {
00574 public:
00575 ChoiceInfo() : value_(0), index_(kUninitializedVarIndex), left_(false) {}
00576
00577 ChoiceInfo(int index, int64 value, bool left)
00578 : value_(value), index_(index), left_(left) {}
00579
00580 string DebugString() const {
00581 return StringPrintf("var(%d) %s %lld",
00582 index_,
00583 (left_ ? "==" : "!="),
00584 value_);
00585 }
00586
00587 int index() const { return index_; }
00588
00589 bool left() const { return left_; }
00590
00591 int64 value() const { return value_; }
00592
00593 private:
00594 int64 value_;
00595 int index_;
00596 bool left_;
00597 };
00598
00599 ImpactDecisionBuilder(Solver* const solver,
00600 const IntVar* const* vars,
00601 int size,
00602 const DefaultPhaseParameters& parameters)
00603 : impact_recorder_(vars, size, parameters.display_level),
00604 size_(size),
00605 parameters_(parameters),
00606 init_done_(false),
00607 fail_stamp_(kUninitializedFailStamp),
00608 current_var_index_(kUninitializedVarIndex),
00609 current_value_(0),
00610 heuristic_limit_(NULL),
00611 random_(parameters_.random_seed),
00612 runner_(NewPermanentCallback(this,
00613 &ImpactDecisionBuilder::RunHeuristics)),
00614 heuristic_branch_count_(0),
00615 min_log_search_space_(std::numeric_limits<double>::infinity()),
00616 no_good_manager_(NULL),
00617 branches_between_restarts_(0),
00618 min_restart_period_(ComputeBranchRestart(parameters_.restart_log_size)),
00619 maximum_restart_depth_(kint64max) {
00620 CHECK_GE(size_, 0);
00621 if (size_ > 0) {
00622 vars_.reset(new IntVar*[size_]);
00623 memcpy(vars_.get(), vars, size_ * sizeof(*vars));
00624 }
00625 InitHeuristics(solver);
00626 }
00627
00628 virtual ~ImpactDecisionBuilder() {
00629 STLDeleteElements(&heuristics_);
00630 }
00631
00632 virtual Decision* Next(Solver* const solver) {
00633 if (parameters_.use_impacts) {
00634 if (!init_done_) {
00635 if (parameters_.display_level != DefaultPhaseParameters::NONE) {
00636 LOG(INFO) << "Init impact based search phase on " << size_
00637 << " variables, initialization splits = "
00638 << parameters_.initialization_splits
00639 << ", heuristic_period = " << parameters_.heuristic_period
00640 << ", run_all_heuristics = "
00641 << parameters_.run_all_heuristics
00642 << ", restart_log_size = " << parameters_.restart_log_size;
00643 }
00644
00645
00646 impact_recorder_.ResetImpacts();
00647 impact_recorder_.FirstRun(solver, parameters_.initialization_splits);
00648 if (parameters_.persistent_impact) {
00649 init_done_ = true;
00650 } else {
00651 solver->SaveAndSetValue(&init_done_, true);
00652 }
00653 }
00654
00655 if (current_var_index_.Value() == kUninitializedVarIndex &&
00656 fail_stamp_ != kUninitializedFailStamp) {
00657
00658 impact_recorder_.RecordLogSearchSpace();
00659 } else {
00660 if (fail_stamp_ != kUninitializedFailStamp) {
00661 if (solver->fail_stamp() == fail_stamp_) {
00662 impact_recorder_.UpdateAfterAssignment(current_var_index_.Value(),
00663 current_value_.Value());
00664 } else {
00665 const ChoiceInfo* const info = choices_.Last();
00666 if (info != NULL) {
00667 DCHECK_EQ(info->index(), current_var_index_.Value());
00668 DCHECK_EQ(info->value(), current_value_.Value());
00669 choices_.SetLastValue(
00670 ChoiceInfo(info->index(), info->value(), false));
00671 }
00672 impact_recorder_.UpdateAfterFailure(current_var_index_.Value(),
00673 current_value_.Value());
00674 }
00675 }
00676 }
00677 fail_stamp_ = solver->fail_stamp();
00678
00679 ++heuristic_branch_count_;
00680 if (heuristic_branch_count_ % parameters_.heuristic_period == 0) {
00681 current_var_index_.SetValue(solver, kUninitializedVarIndex);
00682 return &runner_;
00683 }
00684 int var_index = kUninitializedVarIndex;
00685 int64 value = 0;
00686 if (FindVarValue(&var_index, &value)) {
00687 current_var_index_.SetValue(solver, var_index);
00688 current_value_.SetValue(solver, value);
00689 choices_.Push(solver, ChoiceInfo(var_index, value, true));
00690 return solver->MakeAssignVariableValue(
00691 vars_[current_var_index_.Value()], current_value_.Value());
00692 } else {
00693 if (parameters_.display_level == DefaultPhaseParameters::VERBOSE) {
00694 LOG(INFO) << "Found a solution after the following decisions:";
00695 for (SimpleRevFIFO<ChoiceInfo>::Iterator it(&choices_);
00696 it.ok();
00697 ++it) {
00698 LOG(INFO) << " " << (*it).DebugString();
00699 }
00700 }
00701 return NULL;
00702 }
00703 } else {
00704 if (solver->fail_stamp() != fail_stamp_) {
00705 const ChoiceInfo* const info = choices_.Last();
00706 if (info != NULL) {
00707 DCHECK_EQ(info->index(), current_var_index_.Value());
00708 DCHECK_EQ(info->value(), current_value_.Value());
00709 choices_.SetLastValue(
00710 ChoiceInfo(info->index(), info->value(), false));
00711 }
00712 }
00713 fail_stamp_ = solver->fail_stamp();
00714 int var_index = kUninitializedVarIndex;
00715 int64 value = 0;
00716 if (FindVarValueNoImpact(&var_index, &value)) {
00717 current_var_index_.SetValue(solver, var_index);
00718 current_value_.SetValue(solver, value);
00719 choices_.Push(solver, ChoiceInfo(var_index, value, true));
00720 return solver->MakeAssignVariableValue(
00721 vars_[current_var_index_.Value()], current_value_.Value());
00722 }
00723 return NULL;
00724 }
00725 }
00726
00727 virtual void AppendMonitors(Solver* const solver,
00728 std::vector<SearchMonitor*>* const extras) {
00729 CHECK_NOTNULL(solver);
00730 CHECK_NOTNULL(extras);
00731 extras->push_back(solver->RevAlloc(new RestartMonitor(solver, this)));
00732
00733 if (parameters_.restart_log_size >= 0 && parameters_.use_no_goods) {
00734 no_good_manager_ = solver->MakeNoGoodManager();
00735 extras->push_back(no_good_manager_);
00736 }
00737 }
00738
00739 void VisitBranch() {
00740 branches_between_restarts_++;
00741 }
00742
00743 void ExitSearch() {
00744 if (parameters_.display_level != DefaultPhaseParameters::NONE &&
00745 no_good_manager_ != NULL) {
00746 LOG(INFO) << "Default search has generated "
00747 << no_good_manager_->NoGoodCount() << " no goods";
00748 }
00749 }
00750
00751 virtual void Accept(ModelVisitor* const visitor) const {
00752 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
00753 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
00754 vars_.get(),
00755 size_);
00756 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
00757 }
00758
00759 private:
00760
00761 class RestartMonitor : public SearchMonitor {
00762 public:
00763 RestartMonitor(Solver* const solver, ImpactDecisionBuilder* const db)
00764 : SearchMonitor(solver), db_(db) {}
00765
00766 virtual ~RestartMonitor() {}
00767
00768 virtual void ApplyDecision(Decision* const d) {
00769 db_->VisitBranch();
00770 }
00771
00772 virtual void RefuteDecision(Decision* const d) {
00773 CHECK_NOTNULL(d);
00774 Solver* const s = solver();
00775 db_->VisitBranch();
00776 if (db_->CheckRestartOnRefute(s)) {
00777 db_->DoRestartAndAddNoGood(s);
00778 RestartCurrentSearch();
00779 s->Fail();
00780 }
00781 }
00782
00783 virtual void ExitSearch() {
00784 db_->ExitSearch();
00785 }
00786
00787 private:
00788 ImpactDecisionBuilder* const db_;
00789 };
00790
00791
00792
00793 struct HeuristicWrapper {
00794 HeuristicWrapper(Solver* const solver,
00795 IntVar* const* vars,
00796 int size,
00797 Solver::IntVarStrategy var_strategy,
00798 Solver::IntValueStrategy value_strategy,
00799 const string& heuristic_name,
00800 int heuristic_runs)
00801 : phase(solver->MakePhase(vars, size, var_strategy, value_strategy)),
00802 name(heuristic_name),
00803 runs(heuristic_runs) {}
00804
00805
00806 DecisionBuilder* const phase;
00807
00808 const string name;
00809
00810
00811
00812 const int runs;
00813 };
00814
00815
00816
00817 class RunHeuristic : public Decision {
00818 public:
00819 explicit RunHeuristic(ResultCallback1<bool, Solver*>* call_heuristics)
00820 : call_heuristics_(call_heuristics) {
00821 CHECK_NOTNULL(call_heuristics);
00822 }
00823 virtual ~RunHeuristic() {}
00824
00825 virtual void Apply(Solver* const solver) {
00826 if (!call_heuristics_->Run(solver)) {
00827 solver->Fail();
00828 }
00829 }
00830
00831 virtual void Refute(Solver* const solver) {}
00832
00833 private:
00834 scoped_ptr<ResultCallback1<bool, Solver*> > call_heuristics_;
00835 };
00836
00837 void InitHeuristics(Solver* const solver) {
00838 const int kRunOnce = 1;
00839 const int kRunMore = 2;
00840 const int kRunALot = 3;
00841
00842 heuristics_.push_back(
00843 new HeuristicWrapper(solver,
00844 vars_.get(),
00845 size_,
00846 Solver::CHOOSE_MIN_SIZE_LOWEST_MIN,
00847 Solver::ASSIGN_MIN_VALUE,
00848 "AssignMinValueToMinDomainSize",
00849 kRunOnce));
00850
00851 heuristics_.push_back(
00852 new HeuristicWrapper(solver,
00853 vars_.get(),
00854 size_,
00855 Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX,
00856 Solver::ASSIGN_MAX_VALUE,
00857 "AssignMaxValueToMinDomainSize",
00858 kRunOnce));
00859
00860 heuristics_.push_back(
00861 new HeuristicWrapper(solver,
00862 vars_.get(),
00863 size_,
00864 Solver::CHOOSE_MIN_SIZE_LOWEST_MIN,
00865 Solver::ASSIGN_CENTER_VALUE,
00866 "AssignCenterValueToMinDomainSize",
00867 kRunOnce));
00868
00869 heuristics_.push_back(
00870 new HeuristicWrapper(solver,
00871 vars_.get(),
00872 size_,
00873 Solver::CHOOSE_FIRST_UNBOUND,
00874 Solver::ASSIGN_RANDOM_VALUE,
00875 "AssignRandomValueToFirstUnbound",
00876 kRunALot));
00877
00878 heuristics_.push_back(
00879 new HeuristicWrapper(solver,
00880 vars_.get(),
00881 size_,
00882 Solver::CHOOSE_RANDOM,
00883 Solver::ASSIGN_MIN_VALUE,
00884 "AssignMinValueToRandomVariable",
00885 kRunMore));
00886
00887 heuristics_.push_back(
00888 new HeuristicWrapper(solver,
00889 vars_.get(),
00890 size_,
00891 Solver::CHOOSE_RANDOM,
00892 Solver::ASSIGN_MAX_VALUE,
00893 "AssignMaxValueToRandomVariable",
00894 kRunMore));
00895
00896 heuristics_.push_back(
00897 new HeuristicWrapper(solver,
00898 vars_.get(),
00899 size_,
00900 Solver::CHOOSE_RANDOM,
00901 Solver::ASSIGN_RANDOM_VALUE,
00902 "AssignRandomValueToRandomVariable",
00903 kRunMore));
00904
00905 heuristic_limit_ =
00906 solver->MakeLimit(kint64max,
00907 kint64max,
00908 parameters_.heuristic_num_failures_limit,
00909 kint64max);
00910 }
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928 bool CheckRestartOnRefute(Solver* const solver) {
00929
00930 if (parameters_.restart_log_size >= 0) {
00931 const int search_depth = solver->SearchDepth();
00932 impact_recorder_.RecordLogSearchSpace();
00933 const double log_search_space_size =
00934 impact_recorder_.LogSearchSpaceSize();
00935 if (min_log_search_space_ > log_search_space_size) {
00936 min_log_search_space_ = log_search_space_size;
00937 }
00938
00939
00940 if (parameters_.display_level == DefaultPhaseParameters::VERBOSE) {
00941 LOG(INFO) << "search_depth = " << search_depth
00942 << ", branches between restarts = "
00943 << branches_between_restarts_
00944 << ", log_search_space_size = " << log_search_space_size
00945 << ", min_log_search_space = " << min_log_search_space_;
00946 }
00947 if (search_depth > maximum_restart_depth_) {
00948
00949
00950 return false;
00951 }
00952
00953
00954 if (min_log_search_space_ + parameters_.restart_log_size <
00955 log_search_space_size ||
00956 (search_depth <= maximum_restart_depth_ &&
00957 maximum_restart_depth_ != kint64max)) {
00958
00959
00960
00961 if (branches_between_restarts_ < min_restart_period_) {
00962 maximum_restart_depth_ = search_depth - 1;
00963 if (parameters_.display_level == DefaultPhaseParameters::VERBOSE) {
00964 LOG(INFO) << "Postpone restarting until depth <= "
00965 << maximum_restart_depth_ << ", visited nodes = "
00966 << branches_between_restarts_
00967 << " / " << min_restart_period_;
00968 }
00969 return false;
00970 }
00971 return true;
00972 }
00973 }
00974 return false;
00975 }
00976
00977
00978
00979 void DoRestartAndAddNoGood(Solver* const solver) {
00980 const int search_depth = solver->SearchDepth();
00981 if (parameters_.display_level == DefaultPhaseParameters::VERBOSE) {
00982 LOG(INFO) << "Restarting at depth " << search_depth;
00983 }
00984 min_log_search_space_ = std::numeric_limits<double>::infinity();
00985 branches_between_restarts_ = 0;
00986 maximum_restart_depth_ = kint64max;
00987
00988 if (parameters_.use_no_goods) {
00989 DCHECK(no_good_manager_ != NULL);
00990 NoGood* const nogood = no_good_manager_->MakeNoGood();
00991
00992
00993 hash_set<int> positive_variable_indices;
00994 for (SimpleRevFIFO<ChoiceInfo>::Iterator it(&choices_);
00995 it.ok();
00996 ++it) {
00997 const ChoiceInfo& choice = *it;
00998 if (choice.left()) {
00999 positive_variable_indices.insert(choice.index());
01000 }
01001 }
01002
01003 for (SimpleRevFIFO<ChoiceInfo>::Iterator it(&choices_);
01004 it.ok();
01005 ++it) {
01006 const ChoiceInfo& choice = *it;
01007 IntVar* const var = vars_[choice.index()];
01008 const int64 value = choice.value();
01009 if (choice.left()) {
01010 nogood->AddIntegerVariableEqualValueTerm(var, value);
01011 } else if (!ContainsKey(positive_variable_indices, choice.index())) {
01012 nogood->AddIntegerVariableNotEqualValueTerm(var, value);
01013 }
01014 }
01015 if (parameters_.display_level == DefaultPhaseParameters::VERBOSE) {
01016 LOG(INFO) << "Adding no good no " << no_good_manager_->NoGoodCount()
01017 << ": " << nogood->DebugString();
01018 }
01019
01020 no_good_manager_->AddNoGood(nogood);
01021 }
01022 }
01023
01024
01025
01026
01027
01028 bool FindVarValue(int* const var_index, int64* const value) {
01029 CHECK_NOTNULL(var_index);
01030 CHECK_NOTNULL(value);
01031 *var_index = -1;
01032 *value = 0;
01033 double best_var_impact = -std::numeric_limits<double>::max();
01034 for (int i = 0; i < size_; ++i) {
01035 if (!vars_[i]->Bound()) {
01036 int64 current_value = 0;
01037 double current_var_impact = 0.0;
01038 impact_recorder_.ScanVarImpacts(i,
01039 ¤t_value,
01040 ¤t_var_impact,
01041 parameters_.var_selection_schema,
01042 parameters_.value_selection_schema);
01043 if (current_var_impact > best_var_impact) {
01044 *var_index = i;
01045 *value = current_value;
01046 best_var_impact = current_var_impact;
01047 }
01048 }
01049 }
01050 return (*var_index != -1);
01051 }
01052
01053 bool FindVarValueNoImpact(int* const var_index, int64* const value) {
01054 CHECK_NOTNULL(var_index);
01055 CHECK_NOTNULL(value);
01056 *var_index = -1;
01057 *value = 0;
01058 for (int i = 0; i < size_; ++i) {
01059 if (!vars_[i]->Bound()) {
01060 *var_index = i;
01061 *value = vars_[i]->Min();
01062 return true;
01063 }
01064 }
01065 return false;
01066 }
01067
01068 bool RunOneHeuristic(Solver* const solver, int index) {
01069 HeuristicWrapper* const wrapper = heuristics_[index];
01070
01071 const bool result =
01072 solver->NestedSolve(wrapper->phase, false, heuristic_limit_);
01073 if (result && parameters_.display_level != DefaultPhaseParameters::NONE) {
01074 LOG(INFO) << "Solution found by heuristic " << wrapper->name;
01075 }
01076 return result;
01077 }
01078
01079 bool RunHeuristics(Solver* const solver) {
01080 if (parameters_.run_all_heuristics) {
01081 for (int index = 0; index < heuristics_.size(); ++index) {
01082 for (int run = 0; run < heuristics_[index]->runs; ++run) {
01083 if (RunOneHeuristic(solver, index)) {
01084 return true;
01085 }
01086 }
01087 }
01088 return false;
01089 } else {
01090 const int index = random_.Uniform(heuristics_.size());
01091 return RunOneHeuristic(solver, index);
01092 }
01093 }
01094
01095
01096
01097 ImpactRecorder impact_recorder_;
01098 scoped_array<IntVar*> vars_;
01099 const int size_;
01100 DefaultPhaseParameters parameters_;
01101 bool init_done_;
01102 uint64 fail_stamp_;
01103 Rev<int> current_var_index_;
01104 Rev<int64> current_value_;
01105 std::vector<HeuristicWrapper*> heuristics_;
01106 SearchMonitor* heuristic_limit_;
01107 ACMRandom random_;
01108 RunHeuristic runner_;
01109 int heuristic_branch_count_;
01110 double min_log_search_space_;
01111 SimpleRevFIFO<ChoiceInfo> choices_;
01112 NoGoodManager* no_good_manager_;
01113 int64 branches_between_restarts_;
01114 const int64 min_restart_period_;
01115 int64 maximum_restart_depth_;
01116 };
01117
01118 const int ImpactDecisionBuilder::kUninitializedVarIndex = -1;
01119 const uint64 ImpactDecisionBuilder::kUninitializedFailStamp = 0;
01120
01121 }
01122
01123
01124
01125 DecisionBuilder* Solver::MakeDefaultPhase(const std::vector<IntVar*>& vars) {
01126 DefaultPhaseParameters parameters;
01127 return MakeDefaultPhase(vars.data(), vars.size(), parameters);
01128 }
01129
01130 DecisionBuilder* Solver::MakeDefaultPhase(
01131 const std::vector<IntVar*>& vars,
01132 const DefaultPhaseParameters& parameters) {
01133 return MakeDefaultPhase(vars.data(), vars.size(), parameters);
01134 }
01135
01136 DecisionBuilder* Solver::MakeDefaultPhase(
01137 const IntVar* const* vars,
01138 int size,
01139 const DefaultPhaseParameters& parameters) {
01140 return RevAlloc(new ImpactDecisionBuilder(this,
01141 vars,
01142 size,
01143 parameters));
01144 }
01145
01146 DecisionBuilder* Solver::MakeDefaultPhase(const IntVar* const* vars, int size) {
01147 DefaultPhaseParameters parameters;
01148 return MakeDefaultPhase(vars, size, parameters);
01149 }
01150 }