22 #include "absl/container/flat_hash_set.h"
23 #include "absl/strings/str_format.h"
34 DEFINE_int32(cp_impact_divider, 10,
"Divider for continuous update.");
40 const int kDefaultNumberOfSplits = 100;
41 const int kDefaultHeuristicPeriod = 100;
42 const int kDefaultHeuristicNumFailuresLimit = 30;
43 const bool kDefaultUseLastConflict =
true;
46 DefaultPhaseParameters::DefaultPhaseParameters()
47 : var_selection_schema(DefaultPhaseParameters::CHOOSE_MAX_SUM_IMPACT),
48 value_selection_schema(DefaultPhaseParameters::SELECT_MIN_IMPACT),
49 initialization_splits(kDefaultNumberOfSplits),
50 run_all_heuristics(true),
51 heuristic_period(kDefaultHeuristicPeriod),
52 heuristic_num_failures_limit(kDefaultHeuristicNumFailuresLimit),
53 persistent_impact(true),
54 random_seed(CpRandomSeed()),
55 display_level(DefaultPhaseParameters::NORMAL),
56 use_last_conflict(kDefaultUseLastConflict),
57 decision_builder(nullptr) {}
66 DomainWatcher(
const std::vector<IntVar*>& vars,
int cache_size)
68 cached_log_.Init(cache_size);
71 double LogSearchSpaceSize() {
74 result += cached_log_.Log2(vars_[
index]->Size());
79 double Log2(
int64 size)
const {
return cached_log_.Log2(size); }
82 std::vector<IntVar*>
vars_;
83 CachedLog cached_log_;
89 class FindVar :
public DecisionVisitor {
91 enum Operation { NONE, ASSIGN, SPLIT_LOW, SPLIT_HIGH };
93 FindVar() : var_(nullptr), value_(0), operation_(NONE) {}
95 ~FindVar()
override {}
97 void VisitSetVariableValue(IntVar*
const var,
int64 value)
override {
103 void VisitSplitVariableDomain(IntVar*
const var,
int64 value,
104 bool start_with_lower_half)
override {
107 operation_ = start_with_lower_half ? SPLIT_LOW : SPLIT_HIGH;
110 void VisitScheduleOrPostpone(IntervalVar*
const var,
int64 est)
override {
114 virtual void VisitTryRankFirst(SequenceVar*
const sequence,
int index) {
118 virtual void VisitTryRankLast(SequenceVar*
const sequence,
int index) {
122 void VisitUnknownDecision()
override { operation_ = NONE; }
125 IntVar*
const var()
const {
126 CHECK_NE(operation_, NONE);
132 CHECK_NE(operation_, NONE);
136 Operation operation()
const {
return operation_; }
138 std::string DebugString()
const override {
139 return "FindVar decision visitor";
145 Operation operation_;
152 class InitVarImpacts :
public DecisionBuilder {
157 update_impact_callback_(nullptr),
161 update_impact_closure_([this]() { UpdateImpacts(); }),
162 updater_(update_impact_closure_) {
163 CHECK(update_impact_closure_ !=
nullptr);
166 ~InitVarImpacts()
override {}
168 void UpdateImpacts() {
170 update_impact_callback_(var_index_, var_->Min());
173 void Init(IntVar*
const var, IntVarIterator*
const iterator,
int var_index) {
176 var_index_ = var_index;
181 Decision* Next(Solver*
const solver)
override {
182 CHECK(var_ !=
nullptr);
185 active_values_.clear();
187 active_values_.push_back(
value);
191 if (value_index_ == active_values_.size()) {
194 updater_.var_ = var_;
195 updater_.value_ = active_values_[value_index_];
200 void set_update_impact_callback(std::function<
void(
int,
int64)>
callback) {
201 update_impact_callback_ = std::move(
callback);
206 class AssignCallFail :
public Decision {
208 explicit AssignCallFail(
const std::function<
void()>& update_impact_closure)
211 update_impact_closure_(update_impact_closure) {
212 CHECK(update_impact_closure_ !=
nullptr);
214 ~AssignCallFail()
override {}
215 void Apply(Solver*
const solver)
override {
216 CHECK(var_ !=
nullptr);
217 var_->SetValue(value_);
219 update_impact_closure_();
222 void Refute(Solver*
const solver)
override {}
228 const std::function<void()>& update_impact_closure_;
233 std::function<void(
int,
int64)> update_impact_callback_;
237 std::vector<int64> active_values_;
239 std::function<void()> update_impact_closure_;
240 AssignCallFail updater_;
246 class InitVarImpactsWithSplits :
public DecisionBuilder {
249 class AssignIntervalCallFail :
public Decision {
251 explicit AssignIntervalCallFail(
252 const std::function<
void()>& update_impact_closure)
256 update_impact_closure_(update_impact_closure) {
257 CHECK(update_impact_closure_ !=
nullptr);
259 ~AssignIntervalCallFail()
override {}
260 void Apply(Solver*
const solver)
override {
261 CHECK(var_ !=
nullptr);
264 update_impact_closure_();
267 void Refute(Solver*
const solver)
override {}
275 const std::function<void()>& update_impact_closure_;
281 explicit InitVarImpactsWithSplits(
int split_size)
283 update_impact_callback_(nullptr),
288 split_size_(split_size),
290 update_impact_closure_([this]() { UpdateImpacts(); }),
291 updater_(update_impact_closure_) {
292 CHECK(update_impact_closure_ !=
nullptr);
295 ~InitVarImpactsWithSplits()
override {}
297 void UpdateImpacts() {
299 update_impact_callback_(var_index_,
value);
303 void Init(IntVar*
const var, IntVarIterator*
const iterator,
int var_index) {
306 var_index_ = var_index;
312 const int64 length = max_value_ - min_value_ + 1;
313 return (min_value_ + length *
index / split_size_);
316 Decision* Next(Solver*
const solver)
override {
318 min_value_ = var_->Min();
319 max_value_ = var_->Max();
322 if (split_index_ == split_size_) {
325 updater_.var_ = var_;
326 updater_.value_min_ = IntervalStart(split_index_);
328 if (split_index_ == split_size_) {
329 updater_.value_max_ = max_value_;
331 updater_.value_max_ = IntervalStart(split_index_) - 1;
336 void set_update_impact_callback(std::function<
void(
int,
int64)>
callback) {
337 update_impact_callback_ = std::move(
callback);
342 std::function<void(
int,
int64)> update_impact_callback_;
348 const int split_size_;
350 std::function<void()> update_impact_closure_;
351 AssignIntervalCallFail updater_;
359 class ImpactRecorder :
public SearchMonitor {
367 ImpactRecorder(Solver*
const solver, DomainWatcher*
const domain_watcher,
368 const std::vector<IntVar*>& vars,
369 DefaultPhaseParameters::DisplayLevel display_level)
370 : SearchMonitor(solver),
371 domain_watcher_(domain_watcher),
374 current_log_space_(0.0),
376 original_min_(size_, 0LL),
377 domain_iterators_(new IntVarIterator*[size_]),
378 display_level_(display_level),
382 for (
int i = 0; i < size_; ++i) {
383 domain_iterators_[i] =
vars_[i]->MakeDomainIterator(
true);
384 var_map_[
vars_[i]] = i;
388 void ApplyDecision(Decision*
const d)
override {
392 d->Accept(&find_var_);
393 if (find_var_.operation() == FindVar::ASSIGN &&
395 current_var_ = var_map_[find_var_.var()];
396 current_value_ = find_var_.value();
397 current_log_space_ = domain_watcher_->LogSearchSpaceSize();
404 void AfterDecision(Decision*
const d,
bool apply)
override {
406 if (current_log_space_ > 0.0) {
407 const double log_space = domain_watcher_->LogSearchSpaceSize();
409 const double impact =
kPerfectImpact - log_space / current_log_space_;
410 UpdateImpact(current_var_, current_value_, impact);
414 current_log_space_ = log_space;
419 void BeginFail()
override {
427 void ResetAllImpacts() {
428 for (
int i = 0; i < size_; ++i) {
429 original_min_[i] =
vars_[i]->Min();
433 impacts_[i].resize(vars_[i]->Max() - vars_[i]->Min() + 1,
437 for (
int i = 0; i < size_; ++i) {
438 for (
int j = 0; j < impacts_[i].size(); ++j) {
444 void UpdateImpact(
int var_index,
int64 value,
double impact) {
445 const int64 value_index =
value - original_min_[var_index];
446 const double current_impact = impacts_[var_index][value_index];
447 const double new_impact =
448 (current_impact * (FLAGS_cp_impact_divider - 1) + impact) /
449 FLAGS_cp_impact_divider;
450 impacts_[var_index][value_index] = new_impact;
454 const double log_space = domain_watcher_->LogSearchSpaceSize();
455 const double impact =
kPerfectImpact - log_space / current_log_space_;
456 const int64 value_index =
value - original_min_[var_index];
457 DCHECK_LT(var_index, size_);
458 DCHECK_LT(value_index, impacts_[var_index].size());
459 impacts_[var_index][value_index] = impact;
463 void FirstRun(
int64 splits) {
464 Solver*
const s = solver();
465 current_log_space_ = domain_watcher_->LogSearchSpaceSize();
466 if (display_level_ != DefaultPhaseParameters::NONE) {
467 LOG(INFO) <<
" - initial log2(SearchSpace) = " << current_log_space_;
469 const int64 init_time = s->wall_time();
471 int64 removed_counter = 0;
472 FirstRunVariableContainers* container =
473 s->RevAlloc(
new FirstRunVariableContainers(
this, splits));
475 for (
int var_index = 0; var_index < size_; ++var_index) {
476 IntVar*
const var =
vars_[var_index];
480 IntVarIterator*
const iterator = domain_iterators_[var_index];
481 DecisionBuilder* init_decision_builder =
nullptr;
482 const bool no_split =
var->Size() < splits;
485 container->without_split()->set_update_impact_callback(
486 container->update_impact_callback());
487 container->without_split()->Init(
var, iterator, var_index);
488 init_decision_builder = container->without_split();
492 container->with_splits()->set_update_impact_callback(
493 container->update_impact_callback());
494 container->with_splits()->Init(
var, iterator, var_index);
495 init_decision_builder = container->with_splits();
500 s->Solve(init_decision_builder);
505 if (init_count_ !=
var->Size() && no_split) {
506 container->ClearRemovedValues();
507 for (
const int64 value : InitAndGetValues(iterator)) {
508 const int64 value_index =
value - original_min_[var_index];
510 container->PushBackRemovedValue(
value);
513 CHECK(container->HasRemovedValues()) <<
var->DebugString();
514 removed_counter += container->NumRemovedValues();
515 const double old_log = domain_watcher_->Log2(
var->Size());
516 var->RemoveValues(container->removed_values());
517 current_log_space_ += domain_watcher_->Log2(
var->Size()) - old_log;
520 if (display_level_ != DefaultPhaseParameters::NONE) {
521 if (removed_counter) {
522 LOG(INFO) <<
" - init done, time = " << s->wall_time() - init_time
523 <<
" ms, " << removed_counter
524 <<
" values removed, log2(SearchSpace) = "
525 << current_log_space_;
527 LOG(INFO) <<
" - init done, time = " << s->wall_time() - init_time
531 s->SaveAndSetValue(&init_done_,
true);
537 void ScanVarImpacts(
int var_index,
int64*
const best_impact_value,
538 double*
const var_impacts,
539 DefaultPhaseParameters::VariableSelection var_select,
540 DefaultPhaseParameters::ValueSelection value_select) {
541 CHECK(best_impact_value !=
nullptr);
542 CHECK(var_impacts !=
nullptr);
545 double sum_var_impact = 0.0;
546 int64 min_impact_value = -1;
547 int64 max_impact_value = -1;
548 for (
const int64 value : InitAndGetValues(domain_iterators_[var_index])) {
549 const int64 value_index =
value - original_min_[var_index];
550 DCHECK_LT(var_index, size_);
551 DCHECK_LT(value_index, impacts_[var_index].size());
552 const double current_impact = impacts_[var_index][value_index];
553 sum_var_impact += current_impact;
554 if (current_impact > max_impact) {
555 max_impact = current_impact;
556 max_impact_value =
value;
558 if (current_impact < min_impact) {
559 min_impact = current_impact;
560 min_impact_value =
value;
564 switch (var_select) {
565 case DefaultPhaseParameters::CHOOSE_MAX_AVERAGE_IMPACT: {
566 *var_impacts = sum_var_impact /
vars_[var_index]->Size();
569 case DefaultPhaseParameters::CHOOSE_MAX_VALUE_IMPACT: {
570 *var_impacts = max_impact;
574 *var_impacts = sum_var_impact;
579 switch (value_select) {
580 case DefaultPhaseParameters::SELECT_MIN_IMPACT: {
581 *best_impact_value = min_impact_value;
584 case DefaultPhaseParameters::SELECT_MAX_IMPACT: {
585 *best_impact_value = max_impact_value;
591 std::string DebugString()
const override {
return "ImpactRecorder"; }
596 class FirstRunVariableContainers :
public BaseObject {
598 FirstRunVariableContainers(ImpactRecorder* impact_recorder,
int64 splits)
599 : update_impact_callback_(
600 [impact_recorder](int var_index,
int64 value) {
601 impact_recorder->InitImpact(var_index,
value);
605 with_splits_(splits) {}
606 std::function<void(
int,
int64)> update_impact_callback()
const {
607 return update_impact_callback_;
609 void PushBackRemovedValue(
int64 value) { removed_values_.push_back(
value); }
610 bool HasRemovedValues()
const {
return !removed_values_.empty(); }
611 void ClearRemovedValues() { removed_values_.clear(); }
612 size_t NumRemovedValues()
const {
return removed_values_.size(); }
613 const std::vector<int64>& removed_values()
const {
return removed_values_; }
614 InitVarImpacts* without_split() {
return &without_splits_; }
615 InitVarImpactsWithSplits* with_splits() {
return &with_splits_; }
617 std::string DebugString()
const override {
618 return "FirstRunVariableContainers";
622 const std::function<void(
int,
int64)> update_impact_callback_;
623 std::vector<int64> removed_values_;
624 InitVarImpacts without_splits_;
625 InitVarImpactsWithSplits with_splits_;
628 DomainWatcher*
const domain_watcher_;
629 std::vector<IntVar*>
vars_;
631 double current_log_space_;
634 std::vector<std::vector<double> > impacts_;
635 std::vector<int64> original_min_;
636 std::unique_ptr<IntVarIterator*[]> domain_iterators_;
638 const DefaultPhaseParameters::DisplayLevel display_level_;
640 int64 current_value_;
642 absl::flat_hash_map<const IntVar*, int> var_map_;
657 ChoiceInfo() : value_(0), var_(nullptr), left_(false) {}
660 : value_(
value), var_(
var), left_(left) {}
662 std::string DebugString()
const {
663 return absl::StrFormat(
"%s %s %d", var_->name(), (left_ ?
"==" :
"!="),
667 IntVar*
var()
const {
return var_; }
669 bool left()
const {
return left_; }
673 void set_left(
bool left) { left_ = left; }
683 class RunHeuristicsAsDives :
public Decision {
685 RunHeuristicsAsDives(Solver*
const solver,
const std::vector<IntVar*>& vars,
686 DefaultPhaseParameters::DisplayLevel level,
687 bool run_all_heuristics,
int random_seed,
688 int heuristic_period,
int heuristic_num_failures_limit)
689 : heuristic_limit_(nullptr),
690 display_level_(level),
691 run_all_heuristics_(run_all_heuristics),
692 random_(random_seed),
693 heuristic_period_(heuristic_period),
694 heuristic_branch_count_(0),
696 Init(solver, vars, heuristic_num_failures_limit);
701 void Apply(Solver*
const solver)
override {
702 if (!RunAllHeuristics(solver)) {
707 void Refute(Solver*
const solver)
override {}
710 if (heuristic_period_ <= 0) {
713 ++heuristic_branch_count_;
714 return heuristic_branch_count_ % heuristic_period_ == 0;
717 bool RunOneHeuristic(Solver*
const solver,
int index) {
718 HeuristicWrapper*
const wrapper = heuristics_[
index];
722 solver->SolveAndCommit(wrapper->phase, heuristic_limit_);
723 if (result && display_level_ != DefaultPhaseParameters::NONE) {
724 LOG(INFO) <<
" --- solution found by heuristic " << wrapper->name
730 bool RunAllHeuristics(Solver*
const solver) {
731 if (run_all_heuristics_) {
733 for (
int run = 0; run < heuristics_[
index]->runs; ++run) {
734 if (RunOneHeuristic(solver,
index)) {
741 DCHECK_GT(heuristics_.size(), 0);
742 const int index = absl::Uniform<int>(random_, 0, heuristics_.size());
743 return RunOneHeuristic(solver,
index);
747 int Rand32(
int size) {
749 return absl::Uniform<int>(random_, 0, size);
752 void Init(Solver*
const solver,
const std::vector<IntVar*>& vars,
753 int heuristic_num_failures_limit) {
754 const int kRunOnce = 1;
755 const int kRunMore = 2;
756 const int kRunALot = 3;
758 heuristics_.push_back(
new HeuristicWrapper(
759 solver, vars, Solver::CHOOSE_MIN_SIZE_LOWEST_MIN,
760 Solver::ASSIGN_MIN_VALUE,
"AssignMinValueToMinDomainSize", kRunOnce));
762 heuristics_.push_back(
new HeuristicWrapper(
763 solver, vars, Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX,
764 Solver::ASSIGN_MAX_VALUE,
"AssignMaxValueToMinDomainSize", kRunOnce));
766 heuristics_.push_back(
767 new HeuristicWrapper(solver, vars, Solver::CHOOSE_MIN_SIZE_LOWEST_MIN,
768 Solver::ASSIGN_CENTER_VALUE,
769 "AssignCenterValueToMinDomainSize", kRunOnce));
771 heuristics_.push_back(
new HeuristicWrapper(
772 solver, vars, Solver::CHOOSE_FIRST_UNBOUND, Solver::ASSIGN_RANDOM_VALUE,
773 "AssignRandomValueToFirstUnbound", kRunALot));
775 heuristics_.push_back(
new HeuristicWrapper(
776 solver, vars, Solver::CHOOSE_RANDOM, Solver::ASSIGN_MIN_VALUE,
777 "AssignMinValueToRandomVariable", kRunMore));
779 heuristics_.push_back(
new HeuristicWrapper(
780 solver, vars, Solver::CHOOSE_RANDOM, Solver::ASSIGN_MAX_VALUE,
781 "AssignMaxValueToRandomVariable", kRunMore));
783 heuristics_.push_back(
new HeuristicWrapper(
784 solver, vars, Solver::CHOOSE_RANDOM, Solver::ASSIGN_RANDOM_VALUE,
785 "AssignRandomValueToRandomVariable", kRunMore));
787 heuristic_limit_ = solver->MakeFailuresLimit(heuristic_num_failures_limit);
790 int heuristic_runs()
const {
return heuristic_runs_; }
795 struct HeuristicWrapper {
796 HeuristicWrapper(Solver*
const solver,
const std::vector<IntVar*>& vars,
797 Solver::IntVarStrategy var_strategy,
798 Solver::IntValueStrategy value_strategy,
799 const std::string& heuristic_name,
int heuristic_runs)
800 :
phase(solver->MakePhase(vars, var_strategy, value_strategy)),
801 name(heuristic_name),
802 runs(heuristic_runs) {}
814 std::vector<HeuristicWrapper*> heuristics_;
815 SearchMonitor* heuristic_limit_;
816 DefaultPhaseParameters::DisplayLevel display_level_;
817 bool run_all_heuristics_;
818 std::mt19937 random_;
819 const int heuristic_period_;
820 int heuristic_branch_count_;
827 class DefaultIntegerSearch :
public DecisionBuilder {
831 DefaultIntegerSearch(Solver*
const solver,
const std::vector<IntVar*>& vars,
836 impact_recorder_(solver, &domain_watcher_, vars,
838 heuristics_(solver,
vars_, parameters_.display_level,
839 parameters_.run_all_heuristics, parameters_.random_seed,
840 parameters_.heuristic_period,
841 parameters_.heuristic_num_failures_limit),
843 last_int_var_(nullptr),
845 last_operation_(FindVar::NONE),
846 last_conflict_count_(0),
849 ~DefaultIntegerSearch()
override {}
851 Decision* Next(Solver*
const solver)
override {
854 if (heuristics_.ShouldRun()) {
858 Decision*
const decision = parameters_.decision_builder !=
nullptr
859 ? parameters_.decision_builder->Next(solver)
860 : ImpactNext(solver);
863 if (decision ==
nullptr) {
871 decision->Accept(&find_var_);
872 IntVar*
const decision_var =
873 find_var_.operation() != FindVar::NONE ? find_var_.var() :
nullptr;
883 if (parameters_.use_last_conflict && last_int_var_ !=
nullptr &&
884 !last_int_var_->Bound() &&
885 (decision_var ==
nullptr || decision_var != last_int_var_)) {
886 switch (last_operation_) {
887 case FindVar::ASSIGN: {
888 if (last_int_var_->Contains(last_int_value_)) {
889 Decision*
const assign =
890 solver->MakeAssignVariableValue(last_int_var_, last_int_value_);
892 last_conflict_count_++;
897 case FindVar::SPLIT_LOW: {
898 if (last_int_var_->Max() > last_int_value_ &&
899 last_int_var_->Min() <= last_int_value_) {
900 Decision*
const split = solver->MakeVariableLessOrEqualValue(
901 last_int_var_, last_int_value_);
903 last_conflict_count_++;
908 case FindVar::SPLIT_HIGH: {
909 if (last_int_var_->Min() < last_int_value_ &&
910 last_int_var_->Max() >= last_int_value_) {
911 Decision*
const split = solver->MakeVariableGreaterOrEqualValue(
912 last_int_var_, last_int_value_);
914 last_conflict_count_++;
925 if (parameters_.use_last_conflict) {
927 decision->Accept(&find_var_);
928 if (find_var_.operation() != FindVar::NONE) {
929 last_int_var_ = find_var_.var();
930 last_int_value_ = find_var_.value();
931 last_operation_ = find_var_.operation();
938 void ClearLastDecision() {
939 last_int_var_ =
nullptr;
941 last_operation_ = FindVar::NONE;
944 void AppendMonitors(Solver*
const solver,
945 std::vector<SearchMonitor*>*
const extras)
override {
946 CHECK(solver !=
nullptr);
947 CHECK(extras !=
nullptr);
948 if (parameters_.decision_builder ==
nullptr) {
949 extras->push_back(&impact_recorder_);
953 void Accept(ModelVisitor*
const visitor)
const override {
954 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
955 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
957 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
960 std::string DebugString()
const override {
961 std::string out =
"DefaultIntegerSearch(";
963 if (parameters_.decision_builder ==
nullptr) {
964 out.append(
"Impact Based Search, ");
966 out.append(parameters_.decision_builder->DebugString());
974 std::string StatString()
const {
975 const int runs = heuristics_.heuristic_runs();
978 if (!result.empty()) {
982 result.append(
"1 heuristic run");
984 absl::StrAppendFormat(&result,
"%d heuristic runs",
runs);
987 if (last_conflict_count_ > 0) {
988 if (!result.empty()) {
991 if (last_conflict_count_ == 1) {
992 result.append(
"1 last conflict hint");
994 absl::StrAppendFormat(&result,
"%d last conflict hints",
995 last_conflict_count_);
1002 void CheckInit(Solver*
const solver) {
1006 if (parameters_.decision_builder ==
nullptr) {
1008 for (
int i = 0; i <
vars_.size(); ++i) {
1009 if (vars_[i]->Max() - vars_[i]->Min() > 0xFFFFFF) {
1010 if (parameters_.display_level == DefaultPhaseParameters::VERBOSE) {
1011 LOG(INFO) <<
"Domains are too large, switching to simple "
1015 reinterpret_cast<void**
>(¶meters_.decision_builder));
1016 parameters_.decision_builder =
1017 solver->MakePhase(vars_, Solver::CHOOSE_MIN_SIZE_LOWEST_MIN,
1018 Solver::ASSIGN_MIN_VALUE);
1019 solver->SaveAndSetValue(&init_done_,
true);
1025 if (parameters_.display_level == DefaultPhaseParameters::VERBOSE) {
1026 LOG(INFO) <<
"Search space is too small, switching to simple "
1030 reinterpret_cast<void**
>(¶meters_.decision_builder));
1031 parameters_.decision_builder = solver->MakePhase(
1032 vars_, Solver::CHOOSE_FIRST_UNBOUND, Solver::ASSIGN_MIN_VALUE);
1033 solver->SaveAndSetValue(&init_done_,
true);
1037 if (parameters_.display_level != DefaultPhaseParameters::NONE) {
1038 LOG(INFO) <<
"Init impact based search phase on " <<
vars_.size()
1039 <<
" variables, initialization splits = "
1040 << parameters_.initialization_splits
1041 <<
", heuristic_period = " << parameters_.heuristic_period
1042 <<
", run_all_heuristics = "
1043 << parameters_.run_all_heuristics;
1046 impact_recorder_.FirstRun(parameters_.initialization_splits);
1048 if (parameters_.persistent_impact) {
1051 solver->SaveAndSetValue(&init_done_,
true);
1059 Decision* ImpactNext(Solver*
const solver) {
1060 IntVar*
var =
nullptr;
1063 for (
int i = 0; i <
vars_.size(); ++i) {
1064 if (!vars_[i]->Bound()) {
1065 int64 current_value = 0;
1066 double current_var_impact = 0.0;
1067 impact_recorder_.ScanVarImpacts(i, ¤t_value, ¤t_var_impact,
1068 parameters_.var_selection_schema,
1069 parameters_.value_selection_schema);
1070 if (current_var_impact > best_var_impact) {
1072 value = current_value;
1073 best_var_impact = current_var_impact;
1077 if (
var ==
nullptr) {
1080 return solver->MakeAssignVariableValue(
var,
value);
1086 std::vector<IntVar*>
vars_;
1087 DefaultPhaseParameters parameters_;
1088 DomainWatcher domain_watcher_;
1089 ImpactRecorder impact_recorder_;
1090 RunHeuristicsAsDives heuristics_;
1092 IntVar* last_int_var_;
1093 int64 last_int_value_;
1094 FindVar::Operation last_operation_;
1095 int last_conflict_count_;
1105 DefaultIntegerSearch*
const dis =
dynamic_cast<DefaultIntegerSearch*
>(db);
1106 return dis !=
nullptr ? dis->StatString() :
"";
1109 DecisionBuilder* Solver::MakeDefaultPhase(
const std::vector<IntVar*>& vars) {
1114 DecisionBuilder* Solver::MakeDefaultPhase(
1115 const std::vector<IntVar*>& vars,
1117 return RevAlloc(
new DefaultIntegerSearch(
this, vars,
parameters));