23 #include "absl/container/flat_hash_set.h" 24 #include "absl/strings/str_format.h" 35 ABSL_FLAG(
int, cp_impact_divider, 10,
"Divider for continuous update.");
41 const int kDefaultNumberOfSplits = 100;
42 const int kDefaultHeuristicPeriod = 100;
43 const int kDefaultHeuristicNumFailuresLimit = 30;
44 const 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_;
90 class 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_;
153 class 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_;
247 class 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_;
360 class 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; }
689 class 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_;
833 class 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,
DecisionBuilder *const phase
Selects the min value of the selected variable.
Selects the first possible value which is the closest to the center of the domain of the selected var...
std::string DefaultPhaseStatString(DecisionBuilder *db)
IntVarIterator *const iterator_
Randomly select one of the remaining unbound variables.
#define DCHECK_GT(val1, val2)
static const int kLogCacheSize
A DecisionBuilder is responsible for creating the search tree.
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
static const double kPerfectImpact
ConstraintSolverParameters parameters() const
Stored Parameters.
static const double kFailureImpact
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
static const char kVariableGroupExtension[]
DecisionBuilder * MakeDefaultPhase(const std::vector< IntVar * > &vars)
bool ContainsKey(const Collection &collection, const Key &key)
void STLDeleteElements(T *container)
Selects the max value of the selected variable.
IntValueStrategy
This enum describes the strategy used to select the next variable value to set.
ABSL_FLAG(int, cp_impact_divider, 10, "Divider for continuous update.")
static const char kVarsArgument[]
const std::vector< IntVar * > vars_
IntVarStrategy
This enum describes the strategy used to select the next branching variable at each node during the s...
T * RevAlloc(T *object)
Registers the given object as being reversible.
Select the first unbound variable.
static const double kInitFailureImpact
Collection of objects used to extend the Constraint Solver library.
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)
static const int kUninitializedVarIndex
Selects randomly one of the possible values of the selected variable.
#define CHECK_NE(val1, val2)
static const double kSmallSearchSpaceLimit
#define DCHECK_LT(val1, val2)
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
This struct holds all parameters for the default search.