24 #include "absl/container/flat_hash_set.h"
25 #include "absl/strings/str_format.h"
36 ABSL_FLAG(
int, cp_impact_divider, 10,
"Divider for continuous update.");
42 const int kDefaultNumberOfSplits = 100;
43 const int kDefaultHeuristicPeriod = 100;
44 const int kDefaultHeuristicNumFailuresLimit = 30;
45 const bool kDefaultUseLastConflict =
true;
51 initialization_splits(kDefaultNumberOfSplits),
52 run_all_heuristics(true),
53 heuristic_period(kDefaultHeuristicPeriod),
54 heuristic_num_failures_limit(kDefaultHeuristicNumFailuresLimit),
55 persistent_impact(true),
58 use_last_conflict(kDefaultUseLastConflict),
59 decision_builder(nullptr) {}
68 DomainWatcher(
const std::vector<IntVar*>& vars,
int cache_size)
70 cached_log_.Init(cache_size);
73 double LogSearchSpaceSize() {
76 result += cached_log_.Log2(vars_[
index]->Size());
81 double Log2(int64_t size)
const {
return cached_log_.Log2(size); }
84 std::vector<IntVar*>
vars_;
85 CachedLog cached_log_;
91 class FindVar :
public DecisionVisitor {
93 enum Operation { NONE, ASSIGN, SPLIT_LOW, SPLIT_HIGH };
95 FindVar() : var_(nullptr), value_(0), operation_(NONE) {}
97 ~FindVar()
override {}
99 void VisitSetVariableValue(IntVar*
const var, int64_t
value)
override {
105 void VisitSplitVariableDomain(IntVar*
const var, int64_t
value,
106 bool start_with_lower_half)
override {
109 operation_ = start_with_lower_half ? SPLIT_LOW : SPLIT_HIGH;
112 void VisitScheduleOrPostpone(IntervalVar*
const var, int64_t est)
override {
116 virtual void VisitTryRankFirst(SequenceVar*
const sequence,
int index) {
120 virtual void VisitTryRankLast(SequenceVar*
const sequence,
int index) {
124 void VisitUnknownDecision()
override { operation_ = NONE; }
127 IntVar*
const var()
const {
128 CHECK_NE(operation_, NONE);
133 int64_t
value()
const {
134 CHECK_NE(operation_, NONE);
138 Operation operation()
const {
return operation_; }
140 std::string DebugString()
const override {
141 return "FindVar decision visitor";
147 Operation operation_;
154 class InitVarImpacts :
public DecisionBuilder {
159 update_impact_callback_(nullptr),
163 update_impact_closure_([this]() { UpdateImpacts(); }),
164 updater_(update_impact_closure_) {
165 CHECK(update_impact_closure_ !=
nullptr);
168 ~InitVarImpacts()
override {}
170 void UpdateImpacts() {
172 update_impact_callback_(var_index_, var_->Min());
175 void Init(IntVar*
const var, IntVarIterator*
const iterator,
int var_index) {
178 var_index_ = var_index;
183 Decision* Next(Solver*
const solver)
override {
184 CHECK(var_ !=
nullptr);
187 active_values_.clear();
189 active_values_.push_back(
value);
193 if (value_index_ == active_values_.size()) {
196 updater_.var_ = var_;
197 updater_.value_ = active_values_[value_index_];
202 void set_update_impact_callback(std::function<
void(
int, int64_t)>
callback) {
203 update_impact_callback_ = std::move(
callback);
208 class AssignCallFail :
public Decision {
210 explicit AssignCallFail(
const std::function<
void()>& update_impact_closure)
213 update_impact_closure_(update_impact_closure) {
214 CHECK(update_impact_closure_ !=
nullptr);
216 ~AssignCallFail()
override {}
217 void Apply(Solver*
const solver)
override {
218 CHECK(var_ !=
nullptr);
219 var_->SetValue(value_);
221 update_impact_closure_();
224 void Refute(Solver*
const solver)
override {}
230 const std::function<void()>& update_impact_closure_;
235 std::function<void(
int, int64_t)> update_impact_callback_;
239 std::vector<int64_t> active_values_;
241 std::function<void()> update_impact_closure_;
242 AssignCallFail updater_;
248 class InitVarImpactsWithSplits :
public DecisionBuilder {
251 class AssignIntervalCallFail :
public Decision {
253 explicit AssignIntervalCallFail(
254 const std::function<
void()>& update_impact_closure)
258 update_impact_closure_(update_impact_closure) {
259 CHECK(update_impact_closure_ !=
nullptr);
261 ~AssignIntervalCallFail()
override {}
262 void Apply(Solver*
const solver)
override {
263 CHECK(var_ !=
nullptr);
266 update_impact_closure_();
269 void Refute(Solver*
const solver)
override {}
277 const std::function<void()>& update_impact_closure_;
283 explicit InitVarImpactsWithSplits(
int split_size)
285 update_impact_callback_(nullptr),
290 split_size_(split_size),
292 update_impact_closure_([this]() { UpdateImpacts(); }),
293 updater_(update_impact_closure_) {
294 CHECK(update_impact_closure_ !=
nullptr);
297 ~InitVarImpactsWithSplits()
override {}
299 void UpdateImpacts() {
301 update_impact_callback_(var_index_,
value);
305 void Init(IntVar*
const var, IntVarIterator*
const iterator,
int var_index) {
308 var_index_ = var_index;
313 int64_t IntervalStart(
int index)
const {
314 const int64_t length = max_value_ - min_value_ + 1;
315 return (min_value_ + length *
index / split_size_);
318 Decision* Next(Solver*
const solver)
override {
320 min_value_ = var_->Min();
321 max_value_ = var_->Max();
324 if (split_index_ == split_size_) {
327 updater_.var_ = var_;
328 updater_.value_min_ = IntervalStart(split_index_);
330 if (split_index_ == split_size_) {
331 updater_.value_max_ = max_value_;
333 updater_.value_max_ = IntervalStart(split_index_) - 1;
338 void set_update_impact_callback(std::function<
void(
int, int64_t)>
callback) {
339 update_impact_callback_ = std::move(
callback);
344 std::function<void(
int, int64_t)> update_impact_callback_;
350 const int split_size_;
352 std::function<void()> update_impact_closure_;
353 AssignIntervalCallFail updater_;
361 class ImpactRecorder :
public SearchMonitor {
369 ImpactRecorder(Solver*
const solver, DomainWatcher*
const domain_watcher,
370 const std::vector<IntVar*>& vars,
372 : SearchMonitor(solver),
373 domain_watcher_(domain_watcher),
376 current_log_space_(0.0),
378 original_min_(size_, 0LL),
379 domain_iterators_(new IntVarIterator*[size_]),
380 display_level_(display_level),
384 for (
int i = 0; i < size_; ++i) {
385 domain_iterators_[i] =
vars_[i]->MakeDomainIterator(
true);
386 var_map_[
vars_[i]] = i;
390 void ApplyDecision(Decision*
const d)
override {
394 d->Accept(&find_var_);
395 if (find_var_.operation() == FindVar::ASSIGN &&
396 var_map_.contains(find_var_.var())) {
397 current_var_ = var_map_[find_var_.var()];
398 current_value_ = find_var_.value();
399 current_log_space_ = domain_watcher_->LogSearchSpaceSize();
406 void AfterDecision(Decision*
const d,
bool apply)
override {
408 if (current_log_space_ > 0.0) {
409 const double log_space = domain_watcher_->LogSearchSpaceSize();
411 const double impact =
kPerfectImpact - log_space / current_log_space_;
412 UpdateImpact(current_var_, current_value_, impact);
416 current_log_space_ = log_space;
421 void BeginFail()
override {
429 void ResetAllImpacts() {
430 for (
int i = 0; i < size_; ++i) {
431 original_min_[i] =
vars_[i]->Min();
435 impacts_[i].resize(vars_[i]->Max() - vars_[i]->Min() + 1,
439 for (
int i = 0; i < size_; ++i) {
440 for (
int j = 0; j < impacts_[i].size(); ++j) {
446 void UpdateImpact(
int var_index, int64_t
value,
double impact) {
447 const int64_t value_index =
value - original_min_[var_index];
448 const double current_impact = impacts_[var_index][value_index];
449 const double new_impact =
450 (current_impact * (absl::GetFlag(FLAGS_cp_impact_divider) - 1) +
452 absl::GetFlag(FLAGS_cp_impact_divider);
453 impacts_[var_index][value_index] = new_impact;
456 void InitImpact(
int var_index, int64_t
value) {
457 const double log_space = domain_watcher_->LogSearchSpaceSize();
458 const double impact =
kPerfectImpact - log_space / current_log_space_;
459 const int64_t value_index =
value - original_min_[var_index];
460 DCHECK_LT(var_index, size_);
461 DCHECK_LT(value_index, impacts_[var_index].size());
462 impacts_[var_index][value_index] = impact;
466 void FirstRun(int64_t splits) {
467 Solver*
const s = solver();
468 current_log_space_ = domain_watcher_->LogSearchSpaceSize();
470 LOG(INFO) <<
" - initial log2(SearchSpace) = " << current_log_space_;
472 const int64_t init_time = s->wall_time();
474 int64_t removed_counter = 0;
475 FirstRunVariableContainers* container =
476 s->RevAlloc(
new FirstRunVariableContainers(
this, splits));
478 for (
int var_index = 0; var_index < size_; ++var_index) {
479 IntVar*
const var =
vars_[var_index];
483 IntVarIterator*
const iterator = domain_iterators_[var_index];
484 DecisionBuilder* init_decision_builder =
nullptr;
485 const bool no_split =
var->Size() < splits;
488 container->without_split()->set_update_impact_callback(
489 container->update_impact_callback());
490 container->without_split()->Init(
var, iterator, var_index);
491 init_decision_builder = container->without_split();
495 container->with_splits()->set_update_impact_callback(
496 container->update_impact_callback());
497 container->with_splits()->Init(
var, iterator, var_index);
498 init_decision_builder = container->with_splits();
503 s->Solve(init_decision_builder);
508 if (init_count_ !=
var->Size() && no_split) {
509 container->ClearRemovedValues();
510 for (
const int64_t
value : InitAndGetValues(iterator)) {
511 const int64_t value_index =
value - original_min_[var_index];
513 container->PushBackRemovedValue(
value);
516 CHECK(container->HasRemovedValues()) <<
var->DebugString();
517 removed_counter += container->NumRemovedValues();
518 const double old_log = domain_watcher_->Log2(
var->Size());
519 var->RemoveValues(container->removed_values());
520 current_log_space_ += domain_watcher_->Log2(
var->Size()) - old_log;
524 if (removed_counter) {
525 LOG(INFO) <<
" - init done, time = " << s->wall_time() - init_time
526 <<
" ms, " << removed_counter
527 <<
" values removed, log2(SearchSpace) = "
528 << current_log_space_;
530 LOG(INFO) <<
" - init done, time = " << s->wall_time() - init_time
534 s->SaveAndSetValue(&init_done_,
true);
540 void ScanVarImpacts(
int var_index, int64_t*
const best_impact_value,
541 double*
const var_impacts,
544 CHECK(best_impact_value !=
nullptr);
545 CHECK(var_impacts !=
nullptr);
548 double sum_var_impact = 0.0;
549 int64_t min_impact_value = -1;
550 int64_t max_impact_value = -1;
551 for (
const int64_t
value : InitAndGetValues(domain_iterators_[var_index])) {
552 const int64_t value_index =
value - original_min_[var_index];
553 DCHECK_LT(var_index, size_);
554 DCHECK_LT(value_index, impacts_[var_index].size());
555 const double current_impact = impacts_[var_index][value_index];
556 sum_var_impact += current_impact;
557 if (current_impact > max_impact) {
558 max_impact = current_impact;
559 max_impact_value =
value;
561 if (current_impact < min_impact) {
562 min_impact = current_impact;
563 min_impact_value =
value;
567 switch (var_select) {
569 *var_impacts = sum_var_impact /
vars_[var_index]->Size();
573 *var_impacts = max_impact;
577 *var_impacts = sum_var_impact;
582 switch (value_select) {
584 *best_impact_value = min_impact_value;
588 *best_impact_value = max_impact_value;
594 std::string DebugString()
const override {
return "ImpactRecorder"; }
599 class FirstRunVariableContainers :
public BaseObject {
601 FirstRunVariableContainers(ImpactRecorder* impact_recorder, int64_t splits)
602 : update_impact_callback_(
603 [impact_recorder](int var_index, int64_t
value) {
604 impact_recorder->InitImpact(var_index,
value);
608 with_splits_(splits) {}
609 std::function<void(
int, int64_t)> update_impact_callback()
const {
610 return update_impact_callback_;
612 void PushBackRemovedValue(int64_t
value) {
613 removed_values_.push_back(
value);
615 bool HasRemovedValues()
const {
return !removed_values_.empty(); }
616 void ClearRemovedValues() { removed_values_.clear(); }
617 size_t NumRemovedValues()
const {
return removed_values_.size(); }
618 const std::vector<int64_t>& removed_values()
const {
619 return removed_values_;
621 InitVarImpacts* without_split() {
return &without_splits_; }
622 InitVarImpactsWithSplits* with_splits() {
return &with_splits_; }
624 std::string DebugString()
const override {
625 return "FirstRunVariableContainers";
629 const std::function<void(
int, int64_t)> update_impact_callback_;
630 std::vector<int64_t> removed_values_;
631 InitVarImpacts without_splits_;
632 InitVarImpactsWithSplits with_splits_;
635 DomainWatcher*
const domain_watcher_;
636 std::vector<IntVar*>
vars_;
638 double current_log_space_;
641 std::vector<std::vector<double> > impacts_;
642 std::vector<int64_t> original_min_;
643 std::unique_ptr<IntVarIterator*[]> domain_iterators_;
647 int64_t current_value_;
649 absl::flat_hash_map<const IntVar*, int> var_map_;
664 ChoiceInfo() : value_(0), var_(nullptr), left_(false) {}
666 ChoiceInfo(IntVar*
const var, int64_t
value,
bool left)
667 : value_(
value), var_(
var), left_(left) {}
669 std::string DebugString()
const {
670 return absl::StrFormat(
"%s %s %d", var_->name(), (left_ ?
"==" :
"!="),
674 IntVar*
var()
const {
return var_; }
676 bool left()
const {
return left_; }
678 int64_t
value()
const {
return value_; }
680 void set_left(
bool left) { left_ = left; }
690 class RunHeuristicsAsDives :
public Decision {
692 RunHeuristicsAsDives(Solver*
const solver,
const std::vector<IntVar*>& vars,
694 bool run_all_heuristics,
int random_seed,
695 int heuristic_period,
int heuristic_num_failures_limit)
696 : heuristic_limit_(nullptr),
697 display_level_(level),
698 run_all_heuristics_(run_all_heuristics),
699 random_(random_seed),
700 heuristic_period_(heuristic_period),
701 heuristic_branch_count_(0),
703 Init(solver, vars, heuristic_num_failures_limit);
708 void Apply(Solver*
const solver)
override {
709 if (!RunAllHeuristics(solver)) {
714 void Refute(Solver*
const solver)
override {}
717 if (heuristic_period_ <= 0) {
720 ++heuristic_branch_count_;
721 return heuristic_branch_count_ % heuristic_period_ == 0;
724 bool RunOneHeuristic(Solver*
const solver,
int index) {
725 HeuristicWrapper*
const wrapper = heuristics_[
index];
729 solver->SolveAndCommit(wrapper->phase, heuristic_limit_);
731 LOG(INFO) <<
" --- solution found by heuristic " << wrapper->name
737 bool RunAllHeuristics(Solver*
const solver) {
738 if (run_all_heuristics_) {
740 for (
int run = 0; run < heuristics_[
index]->runs; ++run) {
741 if (RunOneHeuristic(solver,
index)) {
748 DCHECK_GT(heuristics_.size(), 0);
749 const int index = absl::Uniform<int>(random_, 0, heuristics_.size());
750 return RunOneHeuristic(solver,
index);
754 int Rand32(
int size) {
756 return absl::Uniform<int>(random_, 0, size);
759 void Init(Solver*
const solver,
const std::vector<IntVar*>& vars,
760 int heuristic_num_failures_limit) {
761 const int kRunOnce = 1;
762 const int kRunMore = 2;
763 const int kRunALot = 3;
765 heuristics_.push_back(
new HeuristicWrapper(
769 heuristics_.push_back(
new HeuristicWrapper(
773 heuristics_.push_back(
776 "AssignCenterValueToMinDomainSize", kRunOnce));
778 heuristics_.push_back(
new HeuristicWrapper(
780 "AssignRandomValueToFirstUnbound", kRunALot));
782 heuristics_.push_back(
new HeuristicWrapper(
784 "AssignMinValueToRandomVariable", kRunMore));
786 heuristics_.push_back(
new HeuristicWrapper(
788 "AssignMaxValueToRandomVariable", kRunMore));
790 heuristics_.push_back(
new HeuristicWrapper(
792 "AssignRandomValueToRandomVariable", kRunMore));
794 heuristic_limit_ = solver->MakeFailuresLimit(heuristic_num_failures_limit);
797 int heuristic_runs()
const {
return heuristic_runs_; }
802 struct HeuristicWrapper {
803 HeuristicWrapper(Solver*
const solver,
const std::vector<IntVar*>& vars,
806 const std::string& heuristic_name,
int heuristic_runs)
807 :
phase(solver->MakePhase(vars, var_strategy, value_strategy)),
808 name(heuristic_name),
809 runs(heuristic_runs) {}
821 std::vector<HeuristicWrapper*> heuristics_;
822 SearchMonitor* heuristic_limit_;
824 bool run_all_heuristics_;
825 std::mt19937 random_;
826 const int heuristic_period_;
827 int heuristic_branch_count_;
834 class DefaultIntegerSearch :
public DecisionBuilder {
838 DefaultIntegerSearch(Solver*
const solver,
const std::vector<IntVar*>& vars,
843 impact_recorder_(solver, &domain_watcher_, vars,
845 heuristics_(solver,
vars_, parameters_.display_level,
846 parameters_.run_all_heuristics, parameters_.random_seed,
847 parameters_.heuristic_period,
848 parameters_.heuristic_num_failures_limit),
850 last_int_var_(nullptr),
852 last_operation_(FindVar::NONE),
853 last_conflict_count_(0),
856 ~DefaultIntegerSearch()
override {}
858 Decision* Next(Solver*
const solver)
override {
861 if (heuristics_.ShouldRun()) {
865 Decision*
const decision = parameters_.decision_builder !=
nullptr
866 ? parameters_.decision_builder->Next(solver)
867 : ImpactNext(solver);
870 if (decision ==
nullptr) {
878 decision->Accept(&find_var_);
879 IntVar*
const decision_var =
880 find_var_.operation() != FindVar::NONE ? find_var_.var() :
nullptr;
890 if (parameters_.use_last_conflict && last_int_var_ !=
nullptr &&
891 !last_int_var_->Bound() &&
892 (decision_var ==
nullptr || decision_var != last_int_var_)) {
893 switch (last_operation_) {
894 case FindVar::ASSIGN: {
895 if (last_int_var_->Contains(last_int_value_)) {
896 Decision*
const assign =
897 solver->MakeAssignVariableValue(last_int_var_, last_int_value_);
899 last_conflict_count_++;
904 case FindVar::SPLIT_LOW: {
905 if (last_int_var_->Max() > last_int_value_ &&
906 last_int_var_->Min() <= last_int_value_) {
907 Decision*
const split = solver->MakeVariableLessOrEqualValue(
908 last_int_var_, last_int_value_);
910 last_conflict_count_++;
915 case FindVar::SPLIT_HIGH: {
916 if (last_int_var_->Min() < last_int_value_ &&
917 last_int_var_->Max() >= last_int_value_) {
918 Decision*
const split = solver->MakeVariableGreaterOrEqualValue(
919 last_int_var_, last_int_value_);
921 last_conflict_count_++;
932 if (parameters_.use_last_conflict) {
934 decision->Accept(&find_var_);
935 if (find_var_.operation() != FindVar::NONE) {
936 last_int_var_ = find_var_.var();
937 last_int_value_ = find_var_.value();
938 last_operation_ = find_var_.operation();
945 void ClearLastDecision() {
946 last_int_var_ =
nullptr;
948 last_operation_ = FindVar::NONE;
951 void AppendMonitors(Solver*
const solver,
952 std::vector<SearchMonitor*>*
const extras)
override {
953 CHECK(solver !=
nullptr);
954 CHECK(extras !=
nullptr);
955 if (parameters_.decision_builder ==
nullptr) {
956 extras->push_back(&impact_recorder_);
960 void Accept(ModelVisitor*
const visitor)
const override {
967 std::string DebugString()
const override {
968 std::string out =
"DefaultIntegerSearch(";
970 if (parameters_.decision_builder ==
nullptr) {
971 out.append(
"Impact Based Search, ");
973 out.append(parameters_.decision_builder->DebugString());
981 std::string StatString()
const {
982 const int runs = heuristics_.heuristic_runs();
985 if (!result.empty()) {
989 result.append(
"1 heuristic run");
991 absl::StrAppendFormat(&result,
"%d heuristic runs",
runs);
994 if (last_conflict_count_ > 0) {
995 if (!result.empty()) {
998 if (last_conflict_count_ == 1) {
999 result.append(
"1 last conflict hint");
1001 absl::StrAppendFormat(&result,
"%d last conflict hints",
1002 last_conflict_count_);
1009 void CheckInit(Solver*
const solver) {
1013 if (parameters_.decision_builder ==
nullptr) {
1015 for (
int i = 0; i <
vars_.size(); ++i) {
1016 if (vars_[i]->Max() - vars_[i]->Min() > 0xFFFFFF) {
1018 LOG(INFO) <<
"Domains are too large, switching to simple "
1022 reinterpret_cast<void**
>(¶meters_.decision_builder));
1023 parameters_.decision_builder =
1026 solver->SaveAndSetValue(&init_done_,
true);
1033 LOG(INFO) <<
"Search space is too small, switching to simple "
1037 reinterpret_cast<void**
>(¶meters_.decision_builder));
1038 parameters_.decision_builder = solver->MakePhase(
1040 solver->SaveAndSetValue(&init_done_,
true);
1045 LOG(INFO) <<
"Init impact based search phase on " <<
vars_.size()
1046 <<
" variables, initialization splits = "
1047 << parameters_.initialization_splits
1048 <<
", heuristic_period = " << parameters_.heuristic_period
1049 <<
", run_all_heuristics = "
1050 << parameters_.run_all_heuristics;
1053 impact_recorder_.FirstRun(parameters_.initialization_splits);
1055 if (parameters_.persistent_impact) {
1058 solver->SaveAndSetValue(&init_done_,
true);
1066 Decision* ImpactNext(Solver*
const solver) {
1067 IntVar*
var =
nullptr;
1070 for (
int i = 0; i <
vars_.size(); ++i) {
1071 if (!vars_[i]->Bound()) {
1072 int64_t current_value = 0;
1073 double current_var_impact = 0.0;
1074 impact_recorder_.ScanVarImpacts(i, ¤t_value, ¤t_var_impact,
1075 parameters_.var_selection_schema,
1076 parameters_.value_selection_schema);
1077 if (current_var_impact > best_var_impact) {
1079 value = current_value;
1080 best_var_impact = current_var_impact;
1084 if (
var ==
nullptr) {
1087 return solver->MakeAssignVariableValue(
var,
value);
1093 std::vector<IntVar*>
vars_;
1094 DefaultPhaseParameters parameters_;
1095 DomainWatcher domain_watcher_;
1096 ImpactRecorder impact_recorder_;
1097 RunHeuristicsAsDives heuristics_;
1099 IntVar* last_int_var_;
1100 int64_t last_int_value_;
1101 FindVar::Operation last_operation_;
1102 int last_conflict_count_;
1112 DefaultIntegerSearch*
const dis =
dynamic_cast<DefaultIntegerSearch*
>(db);
1113 return dis !=
nullptr ? dis->StatString() :
"";
1122 const std::vector<IntVar*>& vars,
const std::vector< IntVar * > vars_
A DecisionBuilder is responsible for creating the search tree.
static const char kVarsArgument[]
static const char kVariableGroupExtension[]
ConstraintSolverParameters parameters() const
Stored Parameters.
IntValueStrategy
This enum describes the strategy used to select the next variable value to set.
@ ASSIGN_CENTER_VALUE
Selects the first possible value which is the closest to the center of the domain of the selected var...
@ ASSIGN_MIN_VALUE
Selects the min value of the selected variable.
@ ASSIGN_RANDOM_VALUE
Selects randomly one of the possible values of the selected variable.
@ ASSIGN_MAX_VALUE
Selects the max value of the selected variable.
T * RevAlloc(T *object)
Registers the given object as being reversible.
IntVarStrategy
This enum describes the strategy used to select the next branching variable at each node during the s...
@ CHOOSE_RANDOM
Randomly select one of the remaining unbound variables.
@ CHOOSE_FIRST_UNBOUND
Select the first unbound variable.
@ CHOOSE_MIN_SIZE_LOWEST_MIN
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ CHOOSE_MIN_SIZE_HIGHEST_MAX
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
DecisionBuilder * MakeDefaultPhase(const std::vector< IntVar * > &vars)
static const double kSmallSearchSpaceLimit
static const int kUninitializedVarIndex
static const double kFailureImpact
static const int kLogCacheSize
static const double kInitFailureImpact
ABSL_FLAG(int, cp_impact_divider, 10, "Divider for continuous update.")
DecisionBuilder *const phase
static const double kPerfectImpact
IntVarIterator *const iterator_
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
void STLDeleteElements(T *container)
Collection of objects used to extend the Constraint Solver library.
std::string DefaultPhaseStatString(DecisionBuilder *db)
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)
This struct holds all parameters for the default search.
@ CHOOSE_MAX_VALUE_IMPACT
@ CHOOSE_MAX_AVERAGE_IMPACT