23#include "absl/container/flat_hash_set.h"
24#include "absl/strings/str_format.h"
35ABSL_FLAG(
int, cp_impact_divider, 10,
"Divider for continuous update.");
41const int kDefaultNumberOfSplits = 100;
42const int kDefaultHeuristicPeriod = 100;
43const int kDefaultHeuristicNumFailuresLimit = 30;
44const bool kDefaultUseLastConflict =
true;
50 initialization_splits(kDefaultNumberOfSplits),
51 run_all_heuristics(true),
52 heuristic_period(kDefaultHeuristicPeriod),
53 heuristic_num_failures_limit(kDefaultHeuristicNumFailuresLimit),
54 persistent_impact(true),
57 use_last_conflict(kDefaultUseLastConflict),
58 decision_builder(nullptr) {}
67 DomainWatcher(
const std::vector<IntVar*>& vars,
int cache_size)
69 cached_log_.Init(cache_size);
72 double LogSearchSpaceSize() {
75 result += cached_log_.Log2(vars_[
index]->Size());
80 double Log2(int64_t size)
const {
return cached_log_.Log2(size); }
83 std::vector<IntVar*>
vars_;
84 CachedLog cached_log_;
90class FindVar :
public DecisionVisitor {
92 enum Operation { NONE, ASSIGN, SPLIT_LOW, SPLIT_HIGH };
94 FindVar() : var_(nullptr), value_(0), operation_(NONE) {}
96 ~FindVar()
override {}
98 void VisitSetVariableValue(IntVar*
const var, int64_t
value)
override {
104 void VisitSplitVariableDomain(IntVar*
const var, int64_t
value,
105 bool start_with_lower_half)
override {
108 operation_ = start_with_lower_half ? SPLIT_LOW : SPLIT_HIGH;
111 void VisitScheduleOrPostpone(IntervalVar*
const var, int64_t est)
override {
115 virtual void VisitTryRankFirst(SequenceVar*
const sequence,
int index) {
119 virtual void VisitTryRankLast(SequenceVar*
const sequence,
int index) {
123 void VisitUnknownDecision()
override { operation_ = NONE; }
126 IntVar*
const var()
const {
132 int64_t
value()
const {
137 Operation operation()
const {
return operation_; }
139 std::string DebugString()
const override {
140 return "FindVar decision visitor";
146 Operation operation_;
153class InitVarImpacts :
public DecisionBuilder {
158 update_impact_callback_(nullptr),
162 update_impact_closure_([this]() { UpdateImpacts(); }),
163 updater_(update_impact_closure_) {
164 CHECK(update_impact_closure_ !=
nullptr);
167 ~InitVarImpacts()
override {}
169 void UpdateImpacts() {
171 update_impact_callback_(var_index_, var_->Min());
174 void Init(IntVar*
const var, IntVarIterator*
const iterator,
int var_index) {
177 var_index_ = var_index;
182 Decision* Next(Solver*
const solver)
override {
183 CHECK(var_ !=
nullptr);
186 active_values_.clear();
188 active_values_.push_back(
value);
192 if (value_index_ == active_values_.size()) {
195 updater_.var_ = var_;
196 updater_.value_ = active_values_[value_index_];
201 void set_update_impact_callback(std::function<
void(
int, int64_t)>
callback) {
202 update_impact_callback_ = std::move(
callback);
207 class AssignCallFail :
public Decision {
209 explicit AssignCallFail(
const std::function<
void()>& update_impact_closure)
212 update_impact_closure_(update_impact_closure) {
213 CHECK(update_impact_closure_ !=
nullptr);
215 ~AssignCallFail()
override {}
216 void Apply(Solver*
const solver)
override {
217 CHECK(var_ !=
nullptr);
218 var_->SetValue(value_);
220 update_impact_closure_();
223 void Refute(Solver*
const solver)
override {}
229 const std::function<void()>& update_impact_closure_;
234 std::function<void(
int, int64_t)> update_impact_callback_;
238 std::vector<int64_t> active_values_;
240 std::function<void()> update_impact_closure_;
241 AssignCallFail updater_;
247class InitVarImpactsWithSplits :
public DecisionBuilder {
250 class AssignIntervalCallFail :
public Decision {
252 explicit AssignIntervalCallFail(
253 const std::function<
void()>& update_impact_closure)
257 update_impact_closure_(update_impact_closure) {
258 CHECK(update_impact_closure_ !=
nullptr);
260 ~AssignIntervalCallFail()
override {}
261 void Apply(Solver*
const solver)
override {
262 CHECK(var_ !=
nullptr);
265 update_impact_closure_();
268 void Refute(Solver*
const solver)
override {}
276 const std::function<void()>& update_impact_closure_;
282 explicit InitVarImpactsWithSplits(
int split_size)
284 update_impact_callback_(nullptr),
289 split_size_(split_size),
291 update_impact_closure_([this]() { UpdateImpacts(); }),
292 updater_(update_impact_closure_) {
293 CHECK(update_impact_closure_ !=
nullptr);
296 ~InitVarImpactsWithSplits()
override {}
298 void UpdateImpacts() {
300 update_impact_callback_(var_index_,
value);
304 void Init(IntVar*
const var, IntVarIterator*
const iterator,
int var_index) {
307 var_index_ = var_index;
312 int64_t IntervalStart(
int index)
const {
313 const int64_t length = max_value_ - min_value_ + 1;
314 return (min_value_ + length *
index / split_size_);
317 Decision* Next(Solver*
const solver)
override {
319 min_value_ = var_->Min();
320 max_value_ = var_->Max();
323 if (split_index_ == split_size_) {
326 updater_.var_ = var_;
327 updater_.value_min_ = IntervalStart(split_index_);
329 if (split_index_ == split_size_) {
330 updater_.value_max_ = max_value_;
332 updater_.value_max_ = IntervalStart(split_index_) - 1;
337 void set_update_impact_callback(std::function<
void(
int, int64_t)>
callback) {
338 update_impact_callback_ = std::move(
callback);
343 std::function<void(
int, int64_t)> update_impact_callback_;
349 const int split_size_;
351 std::function<void()> update_impact_closure_;
352 AssignIntervalCallFail updater_;
360class ImpactRecorder :
public SearchMonitor {
368 ImpactRecorder(Solver*
const solver, DomainWatcher*
const domain_watcher,
369 const std::vector<IntVar*>& vars,
371 : SearchMonitor(solver),
372 domain_watcher_(domain_watcher),
375 current_log_space_(0.0),
377 original_min_(size_, 0LL),
378 domain_iterators_(new IntVarIterator*[size_]),
379 display_level_(display_level),
383 for (
int i = 0; i < size_; ++i) {
384 domain_iterators_[i] =
vars_[i]->MakeDomainIterator(
true);
385 var_map_[
vars_[i]] = i;
389 void ApplyDecision(Decision*
const d)
override {
393 d->Accept(&find_var_);
394 if (find_var_.operation() == FindVar::ASSIGN &&
396 current_var_ = var_map_[find_var_.var()];
397 current_value_ = find_var_.value();
398 current_log_space_ = domain_watcher_->LogSearchSpaceSize();
405 void AfterDecision(Decision*
const d,
bool apply)
override {
407 if (current_log_space_ > 0.0) {
408 const double log_space = domain_watcher_->LogSearchSpaceSize();
410 const double impact =
kPerfectImpact - log_space / current_log_space_;
411 UpdateImpact(current_var_, current_value_, impact);
415 current_log_space_ = log_space;
420 void BeginFail()
override {
428 void ResetAllImpacts() {
429 for (
int i = 0; i < size_; ++i) {
430 original_min_[i] =
vars_[i]->Min();
434 impacts_[i].resize(vars_[i]->Max() - vars_[i]->Min() + 1,
438 for (
int i = 0; i < size_; ++i) {
439 for (
int j = 0; j < impacts_[i].size(); ++j) {
445 void UpdateImpact(
int var_index, int64_t
value,
double impact) {
446 const int64_t value_index =
value - original_min_[var_index];
447 const double current_impact = impacts_[var_index][value_index];
448 const double new_impact =
449 (current_impact * (absl::GetFlag(FLAGS_cp_impact_divider) - 1) +
451 absl::GetFlag(FLAGS_cp_impact_divider);
452 impacts_[var_index][value_index] = new_impact;
455 void InitImpact(
int var_index, int64_t
value) {
456 const double log_space = domain_watcher_->LogSearchSpaceSize();
457 const double impact =
kPerfectImpact - log_space / current_log_space_;
458 const int64_t value_index =
value - original_min_[var_index];
460 DCHECK_LT(value_index, impacts_[var_index].size());
461 impacts_[var_index][value_index] = impact;
465 void FirstRun(int64_t splits) {
466 Solver*
const s = solver();
467 current_log_space_ = domain_watcher_->LogSearchSpaceSize();
469 LOG(
INFO) <<
" - initial log2(SearchSpace) = " << current_log_space_;
471 const int64_t init_time = s->wall_time();
473 int64_t removed_counter = 0;
474 FirstRunVariableContainers* container =
475 s->RevAlloc(
new FirstRunVariableContainers(
this, splits));
477 for (
int var_index = 0; var_index < size_; ++var_index) {
478 IntVar*
const var =
vars_[var_index];
482 IntVarIterator*
const iterator = domain_iterators_[var_index];
483 DecisionBuilder* init_decision_builder =
nullptr;
484 const bool no_split =
var->Size() < splits;
487 container->without_split()->set_update_impact_callback(
488 container->update_impact_callback());
489 container->without_split()->Init(
var, iterator, var_index);
490 init_decision_builder = container->without_split();
494 container->with_splits()->set_update_impact_callback(
495 container->update_impact_callback());
496 container->with_splits()->Init(
var, iterator, var_index);
497 init_decision_builder = container->with_splits();
502 s->Solve(init_decision_builder);
507 if (init_count_ !=
var->Size() && no_split) {
508 container->ClearRemovedValues();
509 for (
const int64_t
value : InitAndGetValues(iterator)) {
510 const int64_t value_index =
value - original_min_[var_index];
512 container->PushBackRemovedValue(
value);
515 CHECK(container->HasRemovedValues()) <<
var->DebugString();
516 removed_counter += container->NumRemovedValues();
517 const double old_log = domain_watcher_->Log2(
var->Size());
518 var->RemoveValues(container->removed_values());
519 current_log_space_ += domain_watcher_->Log2(
var->Size()) - old_log;
523 if (removed_counter) {
524 LOG(
INFO) <<
" - init done, time = " << s->wall_time() - init_time
525 <<
" ms, " << removed_counter
526 <<
" values removed, log2(SearchSpace) = "
527 << current_log_space_;
529 LOG(
INFO) <<
" - init done, time = " << s->wall_time() - init_time
533 s->SaveAndSetValue(&init_done_,
true);
539 void ScanVarImpacts(
int var_index, int64_t*
const best_impact_value,
540 double*
const var_impacts,
543 CHECK(best_impact_value !=
nullptr);
544 CHECK(var_impacts !=
nullptr);
547 double sum_var_impact = 0.0;
548 int64_t min_impact_value = -1;
549 int64_t max_impact_value = -1;
550 for (
const int64_t
value : InitAndGetValues(domain_iterators_[var_index])) {
551 const int64_t value_index =
value - original_min_[var_index];
553 DCHECK_LT(value_index, impacts_[var_index].size());
554 const double current_impact = impacts_[var_index][value_index];
555 sum_var_impact += current_impact;
556 if (current_impact > max_impact) {
557 max_impact = current_impact;
558 max_impact_value =
value;
560 if (current_impact < min_impact) {
561 min_impact = current_impact;
562 min_impact_value =
value;
566 switch (var_select) {
568 *var_impacts = sum_var_impact /
vars_[var_index]->Size();
572 *var_impacts = max_impact;
576 *var_impacts = sum_var_impact;
581 switch (value_select) {
583 *best_impact_value = min_impact_value;
587 *best_impact_value = max_impact_value;
593 std::string DebugString()
const override {
return "ImpactRecorder"; }
598 class FirstRunVariableContainers :
public BaseObject {
600 FirstRunVariableContainers(ImpactRecorder* impact_recorder, int64_t splits)
601 : update_impact_callback_(
602 [impact_recorder](int var_index, int64_t
value) {
603 impact_recorder->InitImpact(var_index,
value);
607 with_splits_(splits) {}
608 std::function<void(
int, int64_t)> update_impact_callback()
const {
609 return update_impact_callback_;
611 void PushBackRemovedValue(int64_t
value) {
612 removed_values_.push_back(
value);
614 bool HasRemovedValues()
const {
return !removed_values_.empty(); }
615 void ClearRemovedValues() { removed_values_.clear(); }
616 size_t NumRemovedValues()
const {
return removed_values_.size(); }
617 const std::vector<int64_t>& removed_values()
const {
618 return removed_values_;
620 InitVarImpacts* without_split() {
return &without_splits_; }
621 InitVarImpactsWithSplits* with_splits() {
return &with_splits_; }
623 std::string DebugString()
const override {
624 return "FirstRunVariableContainers";
628 const std::function<void(
int, int64_t)> update_impact_callback_;
629 std::vector<int64_t> removed_values_;
630 InitVarImpacts without_splits_;
631 InitVarImpactsWithSplits with_splits_;
634 DomainWatcher*
const domain_watcher_;
635 std::vector<IntVar*>
vars_;
637 double current_log_space_;
640 std::vector<std::vector<double> > impacts_;
641 std::vector<int64_t> original_min_;
642 std::unique_ptr<IntVarIterator*[]> domain_iterators_;
646 int64_t current_value_;
648 absl::flat_hash_map<const IntVar*, int> var_map_;
663 ChoiceInfo() : value_(0), var_(nullptr), left_(false) {}
665 ChoiceInfo(IntVar*
const var, int64_t
value,
bool left)
666 : value_(
value), var_(
var), left_(left) {}
668 std::string DebugString()
const {
669 return absl::StrFormat(
"%s %s %d", var_->name(), (left_ ?
"==" :
"!="),
673 IntVar*
var()
const {
return var_; }
675 bool left()
const {
return left_; }
677 int64_t
value()
const {
return value_; }
679 void set_left(
bool left) { left_ = left; }
689class RunHeuristicsAsDives :
public Decision {
691 RunHeuristicsAsDives(Solver*
const solver,
const std::vector<IntVar*>& vars,
693 bool run_all_heuristics,
int random_seed,
694 int heuristic_period,
int heuristic_num_failures_limit)
695 : heuristic_limit_(nullptr),
696 display_level_(level),
697 run_all_heuristics_(run_all_heuristics),
698 random_(random_seed),
699 heuristic_period_(heuristic_period),
700 heuristic_branch_count_(0),
702 Init(solver, vars, heuristic_num_failures_limit);
707 void Apply(Solver*
const solver)
override {
708 if (!RunAllHeuristics(solver)) {
713 void Refute(Solver*
const solver)
override {}
716 if (heuristic_period_ <= 0) {
719 ++heuristic_branch_count_;
720 return heuristic_branch_count_ % heuristic_period_ == 0;
723 bool RunOneHeuristic(Solver*
const solver,
int index) {
724 HeuristicWrapper*
const wrapper = heuristics_[
index];
728 solver->SolveAndCommit(wrapper->phase, heuristic_limit_);
730 LOG(
INFO) <<
" --- solution found by heuristic " << wrapper->name
736 bool RunAllHeuristics(Solver*
const solver) {
737 if (run_all_heuristics_) {
739 for (
int run = 0; run < heuristics_[
index]->runs; ++run) {
740 if (RunOneHeuristic(solver,
index)) {
748 const int index = absl::Uniform<int>(random_, 0, heuristics_.size());
749 return RunOneHeuristic(solver,
index);
753 int Rand32(
int size) {
755 return absl::Uniform<int>(random_, 0, size);
758 void Init(Solver*
const solver,
const std::vector<IntVar*>& vars,
759 int heuristic_num_failures_limit) {
760 const int kRunOnce = 1;
761 const int kRunMore = 2;
762 const int kRunALot = 3;
764 heuristics_.push_back(
new HeuristicWrapper(
768 heuristics_.push_back(
new HeuristicWrapper(
772 heuristics_.push_back(
775 "AssignCenterValueToMinDomainSize", kRunOnce));
777 heuristics_.push_back(
new HeuristicWrapper(
779 "AssignRandomValueToFirstUnbound", kRunALot));
781 heuristics_.push_back(
new HeuristicWrapper(
783 "AssignMinValueToRandomVariable", kRunMore));
785 heuristics_.push_back(
new HeuristicWrapper(
787 "AssignMaxValueToRandomVariable", kRunMore));
789 heuristics_.push_back(
new HeuristicWrapper(
791 "AssignRandomValueToRandomVariable", kRunMore));
793 heuristic_limit_ = solver->MakeFailuresLimit(heuristic_num_failures_limit);
796 int heuristic_runs()
const {
return heuristic_runs_; }
801 struct HeuristicWrapper {
802 HeuristicWrapper(Solver*
const solver,
const std::vector<IntVar*>& vars,
805 const std::string& heuristic_name,
int heuristic_runs)
806 :
phase(solver->MakePhase(vars, var_strategy, value_strategy)),
807 name(heuristic_name),
808 runs(heuristic_runs) {}
820 std::vector<HeuristicWrapper*> heuristics_;
821 SearchMonitor* heuristic_limit_;
823 bool run_all_heuristics_;
824 std::mt19937 random_;
825 const int heuristic_period_;
826 int heuristic_branch_count_;
833class DefaultIntegerSearch :
public DecisionBuilder {
837 DefaultIntegerSearch(Solver*
const solver,
const std::vector<IntVar*>& vars,
842 impact_recorder_(solver, &domain_watcher_, vars,
844 heuristics_(solver,
vars_, parameters_.display_level,
845 parameters_.run_all_heuristics, parameters_.random_seed,
846 parameters_.heuristic_period,
847 parameters_.heuristic_num_failures_limit),
849 last_int_var_(nullptr),
851 last_operation_(FindVar::NONE),
852 last_conflict_count_(0),
855 ~DefaultIntegerSearch()
override {}
857 Decision* Next(Solver*
const solver)
override {
860 if (heuristics_.ShouldRun()) {
864 Decision*
const decision = parameters_.decision_builder !=
nullptr
865 ? parameters_.decision_builder->Next(solver)
866 : ImpactNext(solver);
869 if (decision ==
nullptr) {
877 decision->Accept(&find_var_);
878 IntVar*
const decision_var =
879 find_var_.operation() != FindVar::NONE ? find_var_.var() :
nullptr;
889 if (parameters_.use_last_conflict && last_int_var_ !=
nullptr &&
890 !last_int_var_->Bound() &&
891 (decision_var ==
nullptr || decision_var != last_int_var_)) {
892 switch (last_operation_) {
893 case FindVar::ASSIGN: {
894 if (last_int_var_->Contains(last_int_value_)) {
895 Decision*
const assign =
896 solver->MakeAssignVariableValue(last_int_var_, last_int_value_);
898 last_conflict_count_++;
903 case FindVar::SPLIT_LOW: {
904 if (last_int_var_->Max() > last_int_value_ &&
905 last_int_var_->Min() <= last_int_value_) {
906 Decision*
const split = solver->MakeVariableLessOrEqualValue(
907 last_int_var_, last_int_value_);
909 last_conflict_count_++;
914 case FindVar::SPLIT_HIGH: {
915 if (last_int_var_->Min() < last_int_value_ &&
916 last_int_var_->Max() >= last_int_value_) {
917 Decision*
const split = solver->MakeVariableGreaterOrEqualValue(
918 last_int_var_, last_int_value_);
920 last_conflict_count_++;
931 if (parameters_.use_last_conflict) {
933 decision->Accept(&find_var_);
934 if (find_var_.operation() != FindVar::NONE) {
935 last_int_var_ = find_var_.var();
936 last_int_value_ = find_var_.value();
937 last_operation_ = find_var_.operation();
944 void ClearLastDecision() {
945 last_int_var_ =
nullptr;
947 last_operation_ = FindVar::NONE;
950 void AppendMonitors(Solver*
const solver,
951 std::vector<SearchMonitor*>*
const extras)
override {
952 CHECK(solver !=
nullptr);
953 CHECK(extras !=
nullptr);
954 if (parameters_.decision_builder ==
nullptr) {
955 extras->push_back(&impact_recorder_);
959 void Accept(ModelVisitor*
const visitor)
const override {
966 std::string DebugString()
const override {
967 std::string out =
"DefaultIntegerSearch(";
969 if (parameters_.decision_builder ==
nullptr) {
970 out.append(
"Impact Based Search, ");
972 out.append(parameters_.decision_builder->DebugString());
980 std::string StatString()
const {
981 const int runs = heuristics_.heuristic_runs();
984 if (!result.empty()) {
988 result.append(
"1 heuristic run");
990 absl::StrAppendFormat(&result,
"%d heuristic runs",
runs);
993 if (last_conflict_count_ > 0) {
994 if (!result.empty()) {
997 if (last_conflict_count_ == 1) {
998 result.append(
"1 last conflict hint");
1000 absl::StrAppendFormat(&result,
"%d last conflict hints",
1001 last_conflict_count_);
1008 void CheckInit(Solver*
const solver) {
1012 if (parameters_.decision_builder ==
nullptr) {
1014 for (
int i = 0; i <
vars_.size(); ++i) {
1015 if (vars_[i]->Max() - vars_[i]->Min() > 0xFFFFFF) {
1017 LOG(
INFO) <<
"Domains are too large, switching to simple "
1021 reinterpret_cast<void**
>(¶meters_.decision_builder));
1022 parameters_.decision_builder =
1025 solver->SaveAndSetValue(&init_done_,
true);
1032 LOG(
INFO) <<
"Search space is too small, switching to simple "
1036 reinterpret_cast<void**
>(¶meters_.decision_builder));
1037 parameters_.decision_builder = solver->MakePhase(
1039 solver->SaveAndSetValue(&init_done_,
true);
1044 LOG(
INFO) <<
"Init impact based search phase on " <<
vars_.size()
1045 <<
" variables, initialization splits = "
1046 << parameters_.initialization_splits
1047 <<
", heuristic_period = " << parameters_.heuristic_period
1048 <<
", run_all_heuristics = "
1049 << parameters_.run_all_heuristics;
1052 impact_recorder_.FirstRun(parameters_.initialization_splits);
1054 if (parameters_.persistent_impact) {
1057 solver->SaveAndSetValue(&init_done_,
true);
1065 Decision* ImpactNext(Solver*
const solver) {
1066 IntVar*
var =
nullptr;
1069 for (
int i = 0; i <
vars_.size(); ++i) {
1070 if (!vars_[i]->Bound()) {
1071 int64_t current_value = 0;
1072 double current_var_impact = 0.0;
1073 impact_recorder_.ScanVarImpacts(i, ¤t_value, ¤t_var_impact,
1074 parameters_.var_selection_schema,
1075 parameters_.value_selection_schema);
1076 if (current_var_impact > best_var_impact) {
1078 value = current_value;
1079 best_var_impact = current_var_impact;
1083 if (
var ==
nullptr) {
1086 return solver->MakeAssignVariableValue(
var,
value);
1092 std::vector<IntVar*>
vars_;
1093 DefaultPhaseParameters parameters_;
1094 DomainWatcher domain_watcher_;
1095 ImpactRecorder impact_recorder_;
1096 RunHeuristicsAsDives heuristics_;
1098 IntVar* last_int_var_;
1099 int64_t last_int_value_;
1100 FindVar::Operation last_operation_;
1101 int last_conflict_count_;
1111 DefaultIntegerSearch*
const dis =
dynamic_cast<DefaultIntegerSearch*
>(db);
1112 return dis !=
nullptr ? dis->StatString() :
"";
1121 const std::vector<IntVar*>& vars,
const std::vector< IntVar * > vars_
#define CHECK_NE(val1, val2)
#define DCHECK_GT(val1, val2)
#define DCHECK_LT(val1, val2)
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.
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)
T * RevAlloc(T *object)
Registers the given object as being reversible.
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)
bool ContainsKey(const Collection &collection, const Key &key)
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