24#include "absl/container/flat_hash_set.h"
25#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);
73 DomainWatcher(
const DomainWatcher&) =
delete;
74 DomainWatcher& operator=(
const DomainWatcher&) =
delete;
76 double LogSearchSpaceSize() {
79 result += cached_log_.Log2(vars_[
index]->Size());
84 double Log2(int64_t
size)
const {
return cached_log_.Log2(
size); }
87 std::vector<IntVar*>
vars_;
88 CachedLog cached_log_;
93class FindVar :
public DecisionVisitor {
95 enum Operation { NONE, ASSIGN, SPLIT_LOW, SPLIT_HIGH };
97 FindVar() : var_(nullptr), value_(0), operation_(NONE) {}
99 ~FindVar()
override {}
101 void VisitSetVariableValue(IntVar*
var, int64_t
value)
override {
107 void VisitSplitVariableDomain(IntVar*
var, int64_t
value,
108 bool start_with_lower_half)
override {
111 operation_ = start_with_lower_half ? SPLIT_LOW : SPLIT_HIGH;
114 void VisitScheduleOrPostpone(IntervalVar*
const var, int64_t est)
override {
118 virtual void VisitTryRankFirst(SequenceVar*
const sequence,
int index) {
122 virtual void VisitTryRankLast(SequenceVar*
const sequence,
int index) {
126 void VisitUnknownDecision()
override { operation_ = NONE; }
129 IntVar*
var()
const {
130 CHECK_NE(operation_, NONE);
135 int64_t
value()
const {
136 CHECK_NE(operation_, NONE);
140 Operation operation()
const {
return operation_; }
142 std::string DebugString()
const override {
143 return "FindVar decision visitor";
149 Operation operation_;
156class InitVarImpacts :
public DecisionBuilder {
161 update_impact_callback_(nullptr),
165 update_impact_closure_([this]() { UpdateImpacts(); }),
166 updater_(update_impact_closure_) {
167 CHECK(update_impact_closure_ !=
nullptr);
170 ~InitVarImpacts()
override {}
172 void UpdateImpacts() {
174 update_impact_callback_(var_index_, var_->Min());
177 void Init(IntVar*
const var, IntVarIterator*
const iterator,
int var_index) {
179 iterator_ = iterator;
185 Decision*
Next(Solver*
const solver)
override {
186 CHECK(var_ !=
nullptr);
187 CHECK(iterator_ !=
nullptr);
189 active_values_.clear();
190 for (
const int64_t
value : InitAndGetValues(iterator_)) {
191 active_values_.push_back(
value);
195 if (value_index_ == active_values_.size()) {
198 updater_.var_ = var_;
199 updater_.value_ = active_values_[value_index_];
204 void set_update_impact_callback(std::function<
void(
int, int64_t)>
callback) {
205 update_impact_callback_ = std::move(
callback);
210 class AssignCallFail :
public Decision {
212 explicit AssignCallFail(
const std::function<
void()>& update_impact_closure)
215 update_impact_closure_(update_impact_closure) {
216 CHECK(update_impact_closure_ !=
nullptr);
220 AssignCallFail(
const AssignCallFail&) =
delete;
221 AssignCallFail& operator=(
const AssignCallFail&) =
delete;
222 ~AssignCallFail()
override {}
223 void Apply(Solver*
const solver)
override {
224 CHECK(var_ !=
nullptr);
225 var_->SetValue(value_);
227 update_impact_closure_();
230 void Refute(Solver*
const solver)
override {}
236 const std::function<void()>& update_impact_closure_;
240 std::function<void(
int, int64_t)> update_impact_callback_;
242 IntVarIterator* iterator_;
244 std::vector<int64_t> active_values_;
246 std::function<void()> update_impact_closure_;
247 AssignCallFail updater_;
253class InitVarImpactsWithSplits :
public DecisionBuilder {
256 class AssignIntervalCallFail :
public Decision {
258 explicit AssignIntervalCallFail(
259 const std::function<
void()>& update_impact_closure)
263 update_impact_closure_(update_impact_closure) {
264 CHECK(update_impact_closure_ !=
nullptr);
268 AssignIntervalCallFail(
const AssignIntervalCallFail&) =
delete;
269 AssignIntervalCallFail& operator=(
const AssignIntervalCallFail&) =
delete;
270 ~AssignIntervalCallFail()
override {}
271 void Apply(Solver*
const solver)
override {
272 CHECK(var_ !=
nullptr);
273 var_->SetRange(value_min_, value_max_);
275 update_impact_closure_();
278 void Refute(Solver*
const solver)
override {}
286 const std::function<void()>& update_impact_closure_;
291 explicit InitVarImpactsWithSplits(
int split_size)
293 update_impact_callback_(nullptr),
298 split_size_(split_size),
300 update_impact_closure_([this]() { UpdateImpacts(); }),
301 updater_(update_impact_closure_) {
302 CHECK(update_impact_closure_ !=
nullptr);
305 ~InitVarImpactsWithSplits()
override {}
307 void UpdateImpacts() {
308 for (
const int64_t
value : InitAndGetValues(iterator_)) {
309 update_impact_callback_(var_index_,
value);
313 void Init(IntVar*
const var, IntVarIterator*
const iterator,
int var_index) {
315 iterator_ = iterator;
321 int64_t IntervalStart(
int index)
const {
322 const int64_t length = max_value_ - min_value_ + 1;
323 return (min_value_ + length *
index / split_size_);
326 Decision*
Next(Solver*
const solver)
override {
328 min_value_ = var_->Min();
329 max_value_ = var_->Max();
332 if (split_index_ == split_size_) {
335 updater_.var_ = var_;
336 updater_.value_min_ = IntervalStart(split_index_);
338 if (split_index_ == split_size_) {
339 updater_.value_max_ = max_value_;
341 updater_.value_max_ = IntervalStart(split_index_) - 1;
346 void set_update_impact_callback(std::function<
void(
int, int64_t)>
callback) {
347 update_impact_callback_ = std::move(
callback);
352 std::function<void(
int, int64_t)> update_impact_callback_;
354 IntVarIterator* iterator_;
358 const int split_size_;
360 std::function<void()> update_impact_closure_;
361 AssignIntervalCallFail updater_;
369class ImpactRecorder :
public SearchMonitor {
377 ImpactRecorder(Solver*
const solver, DomainWatcher*
const domain_watcher,
378 const std::vector<IntVar*>& vars,
380 : SearchMonitor(solver),
381 domain_watcher_(domain_watcher),
384 current_log_space_(0.0),
386 original_min_(size_, 0LL),
387 domain_iterators_(new IntVarIterator*[size_]),
388 display_level_(display_level),
392 for (
int i = 0; i < size_; ++i) {
393 domain_iterators_[i] =
vars_[i]->MakeDomainIterator(
true);
394 var_map_[
vars_[i]] = i;
399 ImpactRecorder(
const ImpactRecorder&) =
delete;
400 ImpactRecorder& operator=(
const ImpactRecorder&) =
delete;
402 void ApplyDecision(Decision*
const d)
override {
406 d->Accept(&find_var_);
407 if (find_var_.operation() == FindVar::ASSIGN &&
408 var_map_.contains(find_var_.var())) {
409 current_var_ = var_map_[find_var_.var()];
410 current_value_ = find_var_.value();
411 current_log_space_ = domain_watcher_->LogSearchSpaceSize();
418 void AfterDecision(Decision*
const d,
bool apply)
override {
419 if (init_done_ && current_var_ != kUninitializedVarIndex) {
420 if (current_log_space_ > 0.0) {
421 const double log_space = domain_watcher_->LogSearchSpaceSize();
423 const double impact =
kPerfectImpact - log_space / current_log_space_;
424 UpdateImpact(current_var_, current_value_, impact);
428 current_log_space_ = log_space;
433 void BeginFail()
override {
434 if (init_done_ && current_var_ != kUninitializedVarIndex) {
435 UpdateImpact(current_var_, current_value_, kFailureImpact);
441 void ResetAllImpacts() {
442 for (
int i = 0;
i < size_; ++
i) {
443 original_min_[
i] =
vars_[
i]->Min();
447 impacts_[
i].resize(vars_[i]->Max() - vars_[i]->Min() + 1,
451 for (
int i = 0;
i < size_; ++
i) {
452 for (
int j = 0; j < impacts_[
i].size(); ++j) {
460 const double current_impact = impacts_[
var_index][value_index];
461 const double new_impact =
462 (current_impact * (absl::GetFlag(FLAGS_cp_impact_divider) - 1) +
464 absl::GetFlag(FLAGS_cp_impact_divider);
465 impacts_[
var_index][value_index] = new_impact;
469 const double log_space = domain_watcher_->LogSearchSpaceSize();
470 const double impact =
kPerfectImpact - log_space / current_log_space_;
474 impacts_[
var_index][value_index] = impact;
478 void FirstRun(int64_t splits) {
479 Solver*
const s = solver();
480 current_log_space_ = domain_watcher_->LogSearchSpaceSize();
482 LOG(INFO) <<
" - initial log2(SearchSpace) = " << current_log_space_;
484 const int64_t init_time = s->wall_time();
486 int64_t removed_counter = 0;
487 FirstRunVariableContainers* container =
488 s->RevAlloc(
new FirstRunVariableContainers(
this, splits));
495 IntVarIterator*
const iterator = domain_iterators_[
var_index];
496 DecisionBuilder* init_decision_builder =
nullptr;
497 const bool no_split =
var->Size() < splits;
500 container->without_split()->set_update_impact_callback(
501 container->update_impact_callback());
502 container->without_split()->Init(
var, iterator,
var_index);
503 init_decision_builder = container->without_split();
507 container->with_splits()->set_update_impact_callback(
508 container->update_impact_callback());
509 container->with_splits()->Init(
var, iterator,
var_index);
510 init_decision_builder = container->with_splits();
515 s->Solve(init_decision_builder);
520 if (init_count_ !=
var->Size() && no_split) {
521 container->ClearRemovedValues();
522 for (
const int64_t
value : InitAndGetValues(iterator)) {
524 if (impacts_[
var_index][value_index] == kInitFailureImpact) {
525 container->PushBackRemovedValue(
value);
528 CHECK(container->HasRemovedValues()) <<
var->DebugString();
529 removed_counter += container->NumRemovedValues();
530 const double old_log = domain_watcher_->Log2(
var->Size());
531 var->RemoveValues(container->removed_values());
532 current_log_space_ += domain_watcher_->Log2(
var->Size()) - old_log;
536 if (removed_counter) {
537 LOG(INFO) <<
" - init done, time = " << s->wall_time() - init_time
538 <<
" ms, " << removed_counter
539 <<
" values removed, log2(SearchSpace) = "
540 << current_log_space_;
542 LOG(INFO) <<
" - init done, time = " << s->wall_time() - init_time
546 s->SaveAndSetValue(&init_done_,
true);
552 void ScanVarImpacts(
int var_index, int64_t*
const best_impact_value,
553 double*
const var_impacts,
556 CHECK(best_impact_value !=
nullptr);
557 CHECK(var_impacts !=
nullptr);
558 double max_impact = -std::numeric_limits<double>::max();
559 double min_impact = std::numeric_limits<double>::max();
560 double sum_var_impact = 0.0;
561 int64_t min_impact_value = -1;
562 int64_t max_impact_value = -1;
563 for (
const int64_t
value : InitAndGetValues(domain_iterators_[
var_index])) {
567 const double current_impact = impacts_[
var_index][value_index];
568 sum_var_impact += current_impact;
569 if (current_impact > max_impact) {
570 max_impact = current_impact;
571 max_impact_value =
value;
573 if (current_impact < min_impact) {
574 min_impact = current_impact;
575 min_impact_value =
value;
579 switch (var_select) {
585 *var_impacts = max_impact;
589 *var_impacts = sum_var_impact;
594 switch (value_select) {
596 *best_impact_value = min_impact_value;
600 *best_impact_value = max_impact_value;
606 std::string DebugString()
const override {
return "ImpactRecorder"; }
611 class FirstRunVariableContainers :
public BaseObject {
613 FirstRunVariableContainers(ImpactRecorder* impact_recorder, int64_t splits)
614 : update_impact_callback_(
620 with_splits_(splits) {}
621 std::function<void(
int, int64_t)> update_impact_callback()
const {
622 return update_impact_callback_;
624 void PushBackRemovedValue(int64_t
value) {
625 removed_values_.push_back(
value);
627 bool HasRemovedValues()
const {
return !removed_values_.empty(); }
628 void ClearRemovedValues() { removed_values_.clear(); }
629 size_t NumRemovedValues()
const {
return removed_values_.size(); }
630 const std::vector<int64_t>& removed_values()
const {
631 return removed_values_;
633 InitVarImpacts* without_split() {
return &without_splits_; }
634 InitVarImpactsWithSplits* with_splits() {
return &with_splits_; }
636 std::string DebugString()
const override {
637 return "FirstRunVariableContainers";
641 const std::function<void(
int, int64_t)> update_impact_callback_;
642 std::vector<int64_t> removed_values_;
643 InitVarImpacts without_splits_;
644 InitVarImpactsWithSplits with_splits_;
647 DomainWatcher*
const domain_watcher_;
648 std::vector<IntVar*>
vars_;
650 double current_log_space_;
653 std::vector<std::vector<double> > impacts_;
654 std::vector<int64_t> original_min_;
655 std::unique_ptr<IntVarIterator*[]> domain_iterators_;
659 int64_t current_value_;
661 absl::flat_hash_map<const IntVar*, int> var_map_;
665const int ImpactRecorder::kLogCacheSize = 1000;
666const double ImpactRecorder::kPerfectImpact = 1.0;
667const double ImpactRecorder::kFailureImpact = 1.0;
668const double ImpactRecorder::kInitFailureImpact = 2.0;
669const int ImpactRecorder::kUninitializedVarIndex = -1;
674 ChoiceInfo() : value_(0), var_(nullptr), left_(
false) {}
676 ChoiceInfo(IntVar*
const var, int64_t
value,
bool left)
677 : value_(
value), var_(
var), left_(left) {}
679 std::string DebugString()
const {
680 return absl::StrFormat(
"%s %s %d", var_->name(), (left_ ?
"==" :
"!="),
684 IntVar*
var()
const {
return var_; }
686 bool left()
const {
return left_; }
688 int64_t
value()
const {
return value_; }
690 void set_left(
bool left) { left_ = left; }
700class RunHeuristicsAsDives :
public Decision {
702 RunHeuristicsAsDives(Solver*
const solver,
const std::vector<IntVar*>& vars,
704 bool run_all_heuristics,
int random_seed,
705 int heuristic_period,
int heuristic_num_failures_limit)
706 : heuristic_limit_(nullptr),
707 display_level_(level),
708 run_all_heuristics_(run_all_heuristics),
709 random_(random_seed),
710 heuristic_period_(heuristic_period),
711 heuristic_branch_count_(0),
713 Init(solver, vars, heuristic_num_failures_limit);
718 void Apply(Solver*
const solver)
override {
719 if (!RunAllHeuristics(solver)) {
724 void Refute(Solver*
const solver)
override {}
727 if (heuristic_period_ <= 0) {
730 ++heuristic_branch_count_;
731 return heuristic_branch_count_ % heuristic_period_ == 0;
734 bool RunOneHeuristic(Solver*
const solver,
int index) {
735 HeuristicWrapper*
const wrapper = heuristics_[
index];
739 solver->SolveAndCommit(wrapper->phase, heuristic_limit_);
741 LOG(INFO) <<
" --- solution found by heuristic " << wrapper->name
747 bool RunAllHeuristics(Solver*
const solver) {
748 if (run_all_heuristics_) {
750 for (
int run = 0; run < heuristics_[
index]->runs; ++run) {
751 if (RunOneHeuristic(solver,
index)) {
758 DCHECK_GT(heuristics_.size(), 0);
759 const int index = absl::Uniform<int>(random_, 0, heuristics_.size());
760 return RunOneHeuristic(solver,
index);
764 int Rand32(
int size) {
766 return absl::Uniform<int>(random_, 0,
size);
769 void Init(Solver*
const solver,
const std::vector<IntVar*>& vars,
770 int heuristic_num_failures_limit) {
771 const int kRunOnce = 1;
772 const int kRunMore = 2;
773 const int kRunALot = 3;
775 heuristics_.push_back(
new HeuristicWrapper(
779 heuristics_.push_back(
new HeuristicWrapper(
783 heuristics_.push_back(
786 "AssignCenterValueToMinDomainSize", kRunOnce));
788 heuristics_.push_back(
new HeuristicWrapper(
790 "AssignRandomValueToFirstUnbound", kRunALot));
792 heuristics_.push_back(
new HeuristicWrapper(
794 "AssignMinValueToRandomVariable", kRunMore));
796 heuristics_.push_back(
new HeuristicWrapper(
798 "AssignMaxValueToRandomVariable", kRunMore));
800 heuristics_.push_back(
new HeuristicWrapper(
802 "AssignRandomValueToRandomVariable", kRunMore));
804 heuristic_limit_ = solver->MakeFailuresLimit(heuristic_num_failures_limit);
807 int heuristic_runs()
const {
return heuristic_runs_; }
812 struct HeuristicWrapper {
813 HeuristicWrapper(Solver*
const solver,
const std::vector<IntVar*>& vars,
816 const std::string& heuristic_name,
int heuristic_runs)
817 :
phase(solver->MakePhase(vars, var_strategy, value_strategy)),
818 name(heuristic_name),
819 runs(heuristic_runs) {}
831 std::vector<HeuristicWrapper*> heuristics_;
832 SearchMonitor* heuristic_limit_;
834 bool run_all_heuristics_;
835 std::mt19937 random_;
836 const int heuristic_period_;
837 int heuristic_branch_count_;
844class DefaultIntegerSearch :
public DecisionBuilder {
848 DefaultIntegerSearch(Solver*
const solver,
const std::vector<IntVar*>& vars,
853 impact_recorder_(solver, &domain_watcher_, vars,
855 heuristics_(solver,
vars_, parameters_.display_level,
856 parameters_.run_all_heuristics, parameters_.random_seed,
857 parameters_.heuristic_period,
858 parameters_.heuristic_num_failures_limit),
860 last_int_var_(nullptr),
862 last_operation_(FindVar::NONE),
863 last_conflict_count_(0),
866 ~DefaultIntegerSearch()
override {}
868 Decision*
Next(Solver*
const solver)
override {
871 if (heuristics_.ShouldRun()) {
875 Decision*
const decision = parameters_.decision_builder !=
nullptr
876 ? parameters_.decision_builder->Next(solver)
877 : ImpactNext(solver);
880 if (decision ==
nullptr) {
888 decision->Accept(&find_var_);
889 IntVar*
const decision_var =
890 find_var_.operation() != FindVar::NONE ? find_var_.var() :
nullptr;
900 if (parameters_.use_last_conflict && last_int_var_ !=
nullptr &&
901 !last_int_var_->Bound() &&
902 (decision_var ==
nullptr || decision_var != last_int_var_)) {
903 switch (last_operation_) {
904 case FindVar::ASSIGN: {
905 if (last_int_var_->Contains(last_int_value_)) {
907 solver->MakeAssignVariableValue(last_int_var_, last_int_value_);
909 last_conflict_count_++;
914 case FindVar::SPLIT_LOW: {
915 if (last_int_var_->Max() > last_int_value_ &&
916 last_int_var_->Min() <= last_int_value_) {
917 Decision*
const split = solver->MakeVariableLessOrEqualValue(
918 last_int_var_, last_int_value_);
920 last_conflict_count_++;
925 case FindVar::SPLIT_HIGH: {
926 if (last_int_var_->Min() < last_int_value_ &&
927 last_int_var_->Max() >= last_int_value_) {
928 Decision*
const split = solver->MakeVariableGreaterOrEqualValue(
929 last_int_var_, last_int_value_);
931 last_conflict_count_++;
942 if (parameters_.use_last_conflict) {
944 decision->Accept(&find_var_);
945 if (find_var_.operation() != FindVar::NONE) {
946 last_int_var_ = find_var_.var();
947 last_int_value_ = find_var_.value();
948 last_operation_ = find_var_.operation();
955 void ClearLastDecision() {
956 last_int_var_ =
nullptr;
958 last_operation_ = FindVar::NONE;
961 void AppendMonitors(Solver*
const solver,
962 std::vector<SearchMonitor*>*
const extras)
override {
963 CHECK(solver !=
nullptr);
964 CHECK(extras !=
nullptr);
965 if (parameters_.decision_builder ==
nullptr) {
966 extras->push_back(&impact_recorder_);
970 void Accept(ModelVisitor*
const visitor)
const override {
977 std::string DebugString()
const override {
978 std::string out =
"DefaultIntegerSearch(";
980 if (parameters_.decision_builder ==
nullptr) {
981 out.append(
"Impact Based Search, ");
983 out.append(parameters_.decision_builder->DebugString());
991 std::string StatString()
const {
992 const int runs = heuristics_.heuristic_runs();
995 if (!result.empty()) {
999 result.append(
"1 heuristic run");
1001 absl::StrAppendFormat(&result,
"%d heuristic runs",
runs);
1004 if (last_conflict_count_ > 0) {
1005 if (!result.empty()) {
1006 result.append(
", ");
1008 if (last_conflict_count_ == 1) {
1009 result.append(
"1 last conflict hint");
1011 absl::StrAppendFormat(&result,
"%d last conflict hints",
1012 last_conflict_count_);
1019 void CheckInit(Solver*
const solver) {
1023 if (parameters_.decision_builder ==
nullptr) {
1025 for (
int i = 0;
i <
vars_.size(); ++
i) {
1026 if (vars_[i]->Max() - vars_[i]->Min() > 0xFFFFFF) {
1028 LOG(INFO) <<
"Domains are too large, switching to simple "
1032 reinterpret_cast<void**
>(¶meters_.decision_builder));
1033 parameters_.decision_builder =
1036 solver->SaveAndSetValue(&init_done_,
true);
1041 if (domain_watcher_.LogSearchSpaceSize() < kSmallSearchSpaceLimit) {
1043 LOG(INFO) <<
"Search space is too small, switching to simple "
1047 reinterpret_cast<void**
>(¶meters_.decision_builder));
1048 parameters_.decision_builder = solver->MakePhase(
1050 solver->SaveAndSetValue(&init_done_,
true);
1055 LOG(INFO) <<
"Init impact based search phase on " <<
vars_.size()
1056 <<
" variables, initialization splits = "
1057 << parameters_.initialization_splits
1058 <<
", heuristic_period = " << parameters_.heuristic_period
1059 <<
", run_all_heuristics = "
1060 << parameters_.run_all_heuristics;
1063 impact_recorder_.FirstRun(parameters_.initialization_splits);
1065 if (parameters_.persistent_impact) {
1068 solver->SaveAndSetValue(&init_done_,
true);
1076 Decision* ImpactNext(Solver*
const solver) {
1077 IntVar*
var =
nullptr;
1079 double best_var_impact = -std::numeric_limits<double>::max();
1080 for (
int i = 0;
i <
vars_.size(); ++
i) {
1081 if (!vars_[i]->Bound()) {
1082 int64_t current_value = 0;
1083 double current_var_impact = 0.0;
1084 impact_recorder_.ScanVarImpacts(i, ¤t_value, ¤t_var_impact,
1085 parameters_.var_selection_schema,
1086 parameters_.value_selection_schema);
1087 if (current_var_impact > best_var_impact) {
1089 value = current_value;
1090 best_var_impact = current_var_impact;
1094 if (
var ==
nullptr) {
1097 return solver->MakeAssignVariableValue(
var,
value);
1103 std::vector<IntVar*>
vars_;
1104 DefaultPhaseParameters parameters_;
1105 DomainWatcher domain_watcher_;
1106 ImpactRecorder impact_recorder_;
1107 RunHeuristicsAsDives heuristics_;
1109 IntVar* last_int_var_;
1110 int64_t last_int_value_;
1111 FindVar::Operation last_operation_;
1112 int last_conflict_count_;
1116const double DefaultIntegerSearch::kSmallSearchSpaceLimit = 10.0;
1122 DefaultIntegerSearch*
const dis =
dynamic_cast<DefaultIntegerSearch*
>(db);
1123 return dis !=
nullptr ? dis->StatString() :
"";
1132 const std::vector<IntVar*>& vars,
const std::vector< IntVar * > vars_
static const char kVariableGroupExtension[]
static const char kVarsArgument[]
@ CHOOSE_MIN_SIZE_LOWEST_MIN
@ CHOOSE_RANDOM
Randomly select one of the remaining unbound variables.
@ CHOOSE_MIN_SIZE_HIGHEST_MAX
DecisionBuilder * MakeDefaultPhase(const std::vector< IntVar * > &vars)
ConstraintSolverParameters parameters() const
Stored Parameters.
@ ASSIGN_MAX_VALUE
Selects the max value of the selected variable.
@ 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.
static const double kSmallSearchSpaceLimit
static const int kUninitializedVarIndex
static const double kFailureImpact
static const int kLogCacheSize
const std::string name
A name for logging purposes.
static const double kInitFailureImpact
ABSL_FLAG(int, cp_impact_divider, 10, "Divider for continuous update.")
DecisionBuilder *const phase
The decision builder we are going to use in this dive.
static const double kPerfectImpact
void STLDeleteElements(T *container)
For infeasible and unbounded see Not checked if options check_solutions_if_inf_or_unbounded and the If options first_solution_only is false
problem is infeasible or unbounded (default).
In SWIG mode, we don't want anything besides these top-level includes.
std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)
Join v[i]->DebugString().
std::string DefaultPhaseStatString(DecisionBuilder *db)
-------— API -------—
Select next search node to expand Select next item_i to assign(using primary propagator) - Generate a new search node where item_i is in the knapsack - Check validity of this new partial solution(using propagators) - If valid
@ CHOOSE_MAX_VALUE_IMPACT
@ CHOOSE_MAX_AVERAGE_IMPACT