Google OR-Tools: ortools/constraint_solver/search.cc Source File
27#include "absl/container/flat_hash_map.h"
28#include "absl/flags/flag.h"
31#include "absl/log/vlog_is_on.h"
32#include "absl/random/distributions.h"
33#include "absl/strings/str_cat.h"
34#include "absl/strings/str_format.h"
35#include "absl/strings/str_join.h"
36#include "absl/strings/string_view.h"
38#include "absl/types/span.h"
51ABSL_FLAG(bool, cp_use_sparse_gls_penalties, false,
52 "Use sparse implementation to store Guided Local Search penalties");
54 "Whether search related logging should be "
56ABSL_FLAG(int64_t, cp_large_domain_no_splitting_limit, 0xFFFFF,
57 "Size limit to allow holes in variables from the strategy.");
63 std::string vars_name, std::vector<double> scaling_factors,
64 std::vector<double> offsets,
65 std::function<std::string()> display_callback,
66 bool display_on_new_solutions_only, int period)
70 vars_(std::move(vars)),
71 vars_name_(std::move(vars_name)),
72 scaling_factors_(std::move(scaling_factors)),
73 offsets_(std::move(offsets)),
74 display_callback_(std::move(display_callback)),
75 display_on_new_solutions_only_(display_on_new_solutions_only),
77 objective_min_(vars_.size(), std::numeric_limits<int64_t>::max()),
78 objective_max_(vars_.size(), std::numeric_limits<int64_t>::min()),
79 min_right_depth_(std::numeric_limits<int32_t>::max()),
90 (!display_on_new_solutions_only_ && display_callback_ != nullptr)
91 ? absl::StrFormat("Start search (%s, %s)", MemoryUsage(),
93 : absl::StrFormat("Start search (%s)", MemoryUsage());
96 min_right_depth_ = std::numeric_limits<int32_t>::max();
99 last_objective_value_.clear();
105 int64_t ms = absl::ToInt64Milliseconds(timer_->GetDuration());
109 const std::string buffer = absl::StrFormat(
110 "End search (time = %d ms, branches = %d, failures = %d, %s, speed = %d "
112 ms, branches, solver()->failures(), MemoryUsage(), branches * 1000 / ms);
120 std::vector<int64_t> current;
121 bool objective_updated = false;
122 const auto scaled_str = [this](absl::Span<const int64_t> values) {
123 std::vector<std::string> value_strings(values.size());
124 for (int i = 0; i < values.size(); ++i) {
125 if (scaling_factors_[i] != 1.0 || offsets_[i] != 0.0) {
127 absl::StrFormat("%d (%.8lf)", values[i],
128 scaling_factors_[i] * (values[i] + offsets_[i]));
130 value_strings[i] = absl::StrCat(values[i]);
133 return absl::StrJoin(value_strings, ", ");
135 bool all_vars_bound = !vars_.empty();
136 for (IntVar* var : vars_) {
137 all_vars_bound &= var->Bound();
140 for (IntVar* var : vars_) {
141 current.push_back(var->Value());
145 vars_name_.empty() ? "" : absl::StrCat(vars_name_, " = "),
146 scaled_str(current), ", ");
148 current.push_back(solver()->GetOrCreateLocalSearchState()->ObjectiveMin());
149 absl::StrAppend(&obj_str, "objective = ", scaled_str(current), ", ");
152 const absl::Duration now = timer_->GetDuration();
154 if (!last_objective_value_.empty()) {
155 const int64_t elapsed_ms =
156 absl::ToInt64Milliseconds(now - last_objective_timestamp_);
157 for (int i = 0; i < current.size(); ++i) {
158 const double improvement_rate =
159 100.0 * 1000.0 * (current[i] - last_objective_value_[i]) /
160 std::max<int64_t>(1, last_objective_value_[i] * elapsed_ms);
161 absl::StrAppend(&obj_str, "improvement rate = ", improvement_rate,
163 last_objective_value_[i] = current[i];
166 last_objective_value_ = current;
168 last_objective_timestamp_ = now;
169 if (!objective_min_.empty() &&
170 std::lexicographical_compare(objective_min_.begin(),
171 objective_min_.end(), current.begin(),
174 vars_name_.empty() ? "" : absl::StrCat(vars_name_, " "),
175 "minimum = ", scaled_str(objective_min_), ", ");
180 if (!objective_max_.empty() &&
181 std::lexicographical_compare(current.begin(), current.end(),
185 vars_name_.empty() ? "" : absl::StrCat(vars_name_, " "),
186 "maximum = ", scaled_str(objective_max_), ", ");
192 absl::StrAppendFormat(&log,
193 "Solution #%d (%stime = %d ms, branches = %d,"
194 " failures = %d, depth = %d",
195 nsol_++, obj_str, absl::ToInt64Milliseconds(now),
196 solver()->branches(), solver()->failures(), depth);
197 if (!solver()->SearchContext().empty()) {
198 absl::StrAppendFormat(&log, ", %s", solver()->SearchContext());
200 if (solver()->accepted_neighbors() != neighbors_offset_) {
201 absl::StrAppendFormat(&log,
202 ", neighbors = %d, filtered neighbors = %d,"
203 " accepted neighbors = %d",
204 solver()->neighbors(), solver()->filtered_neighbors(),
205 solver()->accepted_neighbors());
207 absl::StrAppendFormat(&log, ", %s", MemoryUsage());
210 absl::StrAppendFormat(&log, ", limit = %d%%", progress);
213 absl::StrAppendFormat(&log, ", %s", display_callback_());
225 std::string buffer = absl::StrFormat(
226 "Finished search tree (time = %d ms, branches = %d,"
228 absl::ToInt64Milliseconds(timer_->GetDuration()), solver()->branches(),
229 solver()->failures());
230 if (solver()->neighbors() != 0) {
231 absl::StrAppendFormat(&buffer,
232 ", neighbors = %d, filtered neighbors = %d,"
233 " accepted neigbors = %d",
234 solver()->neighbors(), solver()->filtered_neighbors(),
235 solver()->accepted_neighbors());
237 absl::StrAppendFormat(&buffer, ", %s", MemoryUsage());
238 if (!display_on_new_solutions_only_ && display_callback_) {
239 absl::StrAppendFormat(&buffer, ", %s", display_callback_());
254 min_right_depth_ = std::min(min_right_depth_, solver()->SearchDepth());
259 std::string buffer = absl::StrFormat(
260 "%d branches, %d ms, %d failures", solver()->branches(),
261 absl::ToInt64Milliseconds(timer_->GetDuration()), solver()->failures());
262 if (min_right_depth_ != std::numeric_limits<int32_t>::max() &&
265 absl::StrAppendFormat(&buffer, ", tree pos=%d/%d/%d minref=%d max=%d",
266 sliding_min_depth_, depth, sliding_max_depth_,
267 min_right_depth_, max_depth_);
268 sliding_min_depth_ = depth;
269 sliding_max_depth_ = depth;
271 if (!objective_min_.empty() &&
272 objective_min_[0] != std::numeric_limits<int64_t>::max() &&
273 objective_max_[0] != std::numeric_limits<int64_t>::min()) {
275 vars_name_.empty() ? "" : absl::StrCat(" ", vars_name_);
276 absl::StrAppendFormat(&buffer,
279 name, objective_min_[0], name, objective_max_[0]);
283 absl::StrAppendFormat(&buffer, ", limit = %d%%", progress);
290 sliding_min_depth_ = std::min(current_depth, sliding_min_depth_);
291 sliding_max_depth_ = std::max(current_depth, sliding_max_depth_);
298 const int64_t delta = std::max<int64_t>(
299 absl::ToInt64Milliseconds(timer_->GetDuration() - tick_), 0);
300 const std::string buffer = absl::StrFormat(
301 "Root node processed (time = %d ms, constraints = %d, %s)", delta,
314std::string SearchLog::MemoryUsage() {
315 static const int64_t kDisplayThreshold = 2;
316 static const int64_t kKiloByte = 1024;
317 static const int64_t kMegaByte = kKiloByte * kKiloByte;
318 static const int64_t kGigaByte = kMegaByte * kKiloByte;
320 if (memory_usage > kDisplayThreshold * kGigaByte) {
321 return absl::StrFormat("memory used = %.2lf GB",
322 memory_usage * 1.0 / kGigaByte);
323 } else if (memory_usage > kDisplayThreshold * kMegaByte) {
324 return absl::StrFormat("memory used = %.2lf MB",
325 memory_usage * 1.0 / kMegaByte);
326 } else if (memory_usage > kDisplayThreshold * kKiloByte) {
327 return absl::StrFormat("memory used = %2lf KB",
328 memory_usage * 1.0 / kKiloByte);
330 return absl::StrFormat("memory used = %d", memory_usage);
335 return MakeSearchLog(branch_period, std::vector<IntVar*>{}, nullptr);
339 return MakeSearchLog(branch_period, std::vector<IntVar*>{var}, nullptr);
343 int branch_period, std::function<std::string()> display_callback) {
344 return MakeSearchLog(branch_period, std::vector<IntVar*>{},
349 int branch_period, IntVar* var,
350 std::function<std::string()> display_callback) {
351 return MakeSearchLog(branch_period, std::vector<IntVar*>{var},
356 int branch_period, std::vector<IntVar*> vars,
357 std::function<std::string()> display_callback) {
358 return RevAlloc(new SearchLog(this, std::move(vars), "", {1.0}, {0.0},
369 std::function<std::string()> display_callback) {
370 std::vector<IntVar*> vars = opt_var->objective_vars();
371 std::vector<double> scaling_factors(vars.size(), 1.0);
372 std::vector<double> offsets(vars.size(), 0.0);
374 this, std::move(vars), opt_var->Name(), std::move(scaling_factors),
381 << "Either variables are empty or objective is nullptr.";
382 std::vector<IntVar*> vars = parameters.objective != nullptr
383 ? parameters.objective->objective_vars()
385 std::vector<double> scaling_factors = std::move(parameters.scaling_factors);
386 scaling_factors.resize(vars.size(), 1.0);
387 std::vector<double> offsets = std::move(parameters.offsets);
388 offsets.resize(vars.size(), 0.0);
390 this, std::move(vars), "", std::move(scaling_factors), std::move(offsets),
391 std::move(parameters.display_callback),
399 SearchTrace(Solver* const s, const std::string& prefix)
401 ~SearchTrace() override {}
403 void EnterSearch() override {
404 LOG(INFO) << prefix_ << " EnterSearch(" << solver()->SolveDepth() << ")";
406 void RestartSearch() override {
407 LOG(INFO) << prefix_ << " RestartSearch(" << solver()->SolveDepth() << ")";
409 void ExitSearch() override {
410 LOG(INFO) << prefix_ << " ExitSearch(" << solver()->SolveDepth() << ")";
412 void BeginNextDecision(DecisionBuilder* const b) override {
413 LOG(INFO) << prefix_ << " BeginNextDecision(" << b << ") ";
415 void EndNextDecision(DecisionBuilder* const b, Decision* const d) override {
417 LOG(INFO) << prefix_ << " EndNextDecision(" << b << ", " << d << ") ";
419 LOG(INFO) << prefix_ << " EndNextDecision(" << b << ") ";
422 void ApplyDecision(Decision* const d) override {
423 LOG(INFO) << prefix_ << " ApplyDecision(" << d << ") ";
425 void RefuteDecision(Decision* const d) override {
426 LOG(INFO) << prefix_ << " RefuteDecision(" << d << ") ";
428 void AfterDecision(Decision* const d, bool apply) override {
429 LOG(INFO) << prefix_ << " AfterDecision(" << d << ", " << apply << ") ";
431 void BeginFail() override {
432 LOG(INFO) << prefix_ << " BeginFail(" << solver()->SearchDepth() << ")";
435 LOG(INFO) << prefix_ << " EndFail(" << solver()->SearchDepth() << ")";
437 void BeginInitialPropagation() override {
438 LOG(INFO) << prefix_ << " BeginInitialPropagation()";
440 void EndInitialPropagation() override {
441 LOG(INFO) << prefix_ << " EndInitialPropagation()";
443 bool AtSolution() override {
444 LOG(INFO) << prefix_ << " AtSolution()";
447 bool AcceptSolution() override {
448 LOG(INFO) << prefix_ << " AcceptSolution()";
451 void NoMoreSolutions() override {
452 LOG(INFO) << prefix_ << " NoMoreSolutions()";
455 std::string DebugString() const override { return "SearchTrace"; }
458 const std::string prefix_;
463 return RevAlloc(new SearchTrace(this, prefix));
470 AtSolutionCallback(Solver* const solver, std::function<void()> callback)
472 ~AtSolutionCallback() override {}
473 bool AtSolution() override;
477 const std::function<void()> callback_;
480bool AtSolutionCallback::AtSolution() {
485void AtSolutionCallback::Install() {
486 ListenToEvent(Solver::MonitorEvent::kAtSolution);
492 return RevAlloc(new AtSolutionCallback(this, std::move(callback)));
496class EnterSearchCallback : public SearchMonitor {
498 EnterSearchCallback(Solver* const solver, std::function<void()> callback)
500 ~EnterSearchCallback() override {}
501 void EnterSearch() override;
505 const std::function<void()> callback_;
508void EnterSearchCallback::EnterSearch() { callback_(); }
510void EnterSearchCallback::Install() {
511 ListenToEvent(Solver::MonitorEvent::kEnterSearch);
517 return RevAlloc(new EnterSearchCallback(this, std::move(callback)));
523 ExitSearchCallback(Solver* const solver, std::function<void()> callback)
525 ~ExitSearchCallback() override {}
526 void ExitSearch() override;
530 const std::function<void()> callback_;
533void ExitSearchCallback::ExitSearch() { callback_(); }
535void ExitSearchCallback::Install() {
536 ListenToEvent(Solver::MonitorEvent::kExitSearch);
542 return RevAlloc(new ExitSearchCallback(this, std::move(callback)));
550 CompositeDecisionBuilder();
551 explicit CompositeDecisionBuilder(const std::vector<DecisionBuilder*>& dbs);
552 ~CompositeDecisionBuilder() override;
554 void AppendMonitors(Solver* solver,
555 std::vector<SearchMonitor*>* monitors) override;
556 void Accept(ModelVisitor* visitor) const override;
559 std::vector<DecisionBuilder*> builders_;
562CompositeDecisionBuilder::CompositeDecisionBuilder() {}
564CompositeDecisionBuilder::CompositeDecisionBuilder(
565 const std::vector<DecisionBuilder*>& dbs) {
566 for (int i = 0; i < dbs.size(); ++i) {
571CompositeDecisionBuilder::~CompositeDecisionBuilder() {}
573void CompositeDecisionBuilder::Add(DecisionBuilder* const db) {
579void CompositeDecisionBuilder::AppendMonitors(
580 Solver* const solver, std::vector<SearchMonitor*>* const monitors) {
581 for (DecisionBuilder* const db : builders_) {
582 db->AppendMonitors(solver, monitors);
586void CompositeDecisionBuilder::Accept(ModelVisitor* const visitor) const {
587 for (DecisionBuilder* const db : builders_) {
596class ComposeDecisionBuilder : public CompositeDecisionBuilder {
599 explicit ComposeDecisionBuilder(const std::vector<DecisionBuilder*>& dbs);
600 ~ComposeDecisionBuilder() override;
601 Decision* Next(Solver* s) override;
602 std::string DebugString() const override;
608ComposeDecisionBuilder::ComposeDecisionBuilder() : start_index_(0) {}
610ComposeDecisionBuilder::ComposeDecisionBuilder(
611 const std::vector<DecisionBuilder*>& dbs)
612 : CompositeDecisionBuilder(dbs), start_index_(0) {}
614ComposeDecisionBuilder::~ComposeDecisionBuilder() {}
616Decision* ComposeDecisionBuilder::Next(Solver* const s) {
617 const int size = builders_.size();
618 for (int i = start_index_; i < size; ++i) {
619 Decision* d = builders_[i]->Next(s);
621 s->SaveAndSetValue(&start_index_, i);
625 s->SaveAndSetValue(&start_index_, size);
629std::string ComposeDecisionBuilder::DebugString() const {
630 return absl::StrFormat("ComposeDecisionBuilder(%s)",
637 ComposeDecisionBuilder* c = RevAlloc(new ComposeDecisionBuilder());
646 ComposeDecisionBuilder* c = RevAlloc(new ComposeDecisionBuilder());
657 ComposeDecisionBuilder* c = RevAlloc(new ComposeDecisionBuilder());
669 return RevAlloc(new ComposeDecisionBuilder(dbs));
675class ClosureDecision : public Decision {
678 : apply_(std::move(apply)), refute_(std::move(refute)) {}
679 ~ClosureDecision() override {}
681 void Apply(Solver* const s) override { apply_(s); }
683 void Refute(Solver* const s) override { refute_(s); }
685 std::string DebugString() const override { return "ClosureDecision"; }
694 return RevAlloc(new ClosureDecision(std::move(apply), std::move(refute)));
703class TryDecision : public Decision {
705 explicit TryDecision(TryDecisionBuilder* try_builder);
707 void Apply(Solver* solver) override;
708 void Refute(Solver* solver) override;
709 std::string DebugString() const override { return "TryDecision"; }
712 TryDecisionBuilder* const try_builder_;
715class TryDecisionBuilder : public CompositeDecisionBuilder {
718 explicit TryDecisionBuilder(const std::vector<DecisionBuilder*>& dbs);
719 ~TryDecisionBuilder() override;
720 Decision* Next(Solver* solver) override;
721 std::string DebugString() const override;
722 void AdvanceToNextBuilder(Solver* solver);
725 TryDecision try_decision_;
730TryDecision::TryDecision(TryDecisionBuilder* const try_builder)
731 : try_builder_(try_builder) {}
733TryDecision::~TryDecision() {}
735void TryDecision::Apply(Solver* const) {}
737void TryDecision::Refute(Solver* const solver) {
738 try_builder_->AdvanceToNextBuilder(solver);
741TryDecisionBuilder::TryDecisionBuilder()
742 : CompositeDecisionBuilder(),
745 start_new_builder_(true) {}
747TryDecisionBuilder::TryDecisionBuilder(const std::vector<DecisionBuilder*>& dbs)
748 : CompositeDecisionBuilder(dbs),
751 start_new_builder_(true) {}
753TryDecisionBuilder::~TryDecisionBuilder() {}
755Decision* TryDecisionBuilder::Next(Solver* const solver) {
756 if (current_builder_ < 0) {
757 solver->SaveAndSetValue(¤t_builder_, 0);
758 start_new_builder_ = true;
761 start_new_builder_ = false;
764 return builders_[current_builder_]->Next(solver);
768std::string TryDecisionBuilder::DebugString() const {
769 return absl::StrFormat("TryDecisionBuilder(%s)",
773void TryDecisionBuilder::AdvanceToNextBuilder(Solver* const solver) {
775 start_new_builder_ = true;
776 if (current_builder_ >= builders_.size()) {
785 TryDecisionBuilder* try_db = RevAlloc(new TryDecisionBuilder());
794 TryDecisionBuilder* try_db = RevAlloc(new TryDecisionBuilder());
805 TryDecisionBuilder* try_db = RevAlloc(new TryDecisionBuilder());
814 return RevAlloc(new TryDecisionBuilder(dbs));
822class BaseVariableAssignmentSelector : public BaseObject {
824 BaseVariableAssignmentSelector(Solver* solver,
825 const std::vector<IntVar*>& vars)
829 last_unbound_(vars.size() - 1) {}
831 ~BaseVariableAssignmentSelector() override {}
833 virtual int64_t SelectValue(const IntVar* v, int64_t id) = 0;
836 virtual int64_t ChooseVariable() = 0;
838 int64_t ChooseVariableWrapper() {
839 int64_t i;
840 for (i = first_unbound_.Value(); i <= last_unbound_.Value(); ++i) {
845 first_unbound_.SetValue(solver_, i);
846 if (i > last_unbound_.Value()) {
849 for (i = last_unbound_.Value(); i >= first_unbound_.Value(); --i) {
854 last_unbound_.SetValue(solver_, i);
858 void Accept(ModelVisitor* const visitor) const {
859 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
860 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
862 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
865 const std::vector<IntVar*>& vars() const { return vars_; }
869 std::vector<IntVar*> vars_;
870 Rev<int64_t> first_unbound_;
871 Rev<int64_t> last_unbound_;
876int64_t ChooseFirstUnbound(Solver*, const std::vector<IntVar*>& vars,
877 int64_t first_unbound, int64_t last_unbound) {
878 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
880 return i;
888int64_t ChooseMinSizeLowestMin(Solver*, const std::vector<IntVar*>& vars,
889 int64_t first_unbound, int64_t last_unbound) {
890 uint64_t best_size = std::numeric_limits<uint64_t>::max();
891 int64_t best_min = std::numeric_limits<int64_t>::max();
893 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
894 IntVar* const var = vars[i];
896 if (var->Size() < best_size ||
897 (var->Size() == best_size && var->Min() < best_min)) {
900 best_index = i;
909int64_t ChooseMinSizeHighestMin(Solver*, const std::vector<IntVar*>& vars,
910 int64_t first_unbound, int64_t last_unbound) {
911 uint64_t best_size = std::numeric_limits<uint64_t>::max();
912 int64_t best_min = std::numeric_limits<int64_t>::min();
914 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
915 IntVar* const var = vars[i];
917 if (var->Size() < best_size ||
918 (var->Size() == best_size && var->Min() > best_min)) {
921 best_index = i;
930int64_t ChooseMinSizeLowestMax(Solver*, const std::vector<IntVar*>& vars,
931 int64_t first_unbound, int64_t last_unbound) {
932 uint64_t best_size = std::numeric_limits<uint64_t>::max();
933 int64_t best_max = std::numeric_limits<int64_t>::max();
935 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
936 IntVar* const var = vars[i];
938 if (var->Size() < best_size ||
939 (var->Size() == best_size && var->Max() < best_max)) {
942 best_index = i;
951int64_t ChooseMinSizeHighestMax(Solver*, const std::vector<IntVar*>& vars,
952 int64_t first_unbound, int64_t last_unbound) {
953 uint64_t best_size = std::numeric_limits<uint64_t>::max();
954 int64_t best_max = std::numeric_limits<int64_t>::min();
956 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
957 IntVar* const var = vars[i];
959 if (var->Size() < best_size ||
960 (var->Size() == best_size && var->Max() > best_max)) {
963 best_index = i;
972int64_t ChooseLowestMin(Solver*, const std::vector<IntVar*>& vars,
973 int64_t first_unbound, int64_t last_unbound) {
974 int64_t best_min = std::numeric_limits<int64_t>::max();
976 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
977 IntVar* const var = vars[i];
979 if (var->Min() < best_min) {
981 best_index = i;
990int64_t ChooseHighestMax(Solver*, const std::vector<IntVar*>& vars,
991 int64_t first_unbound, int64_t last_unbound) {
992 int64_t best_max = std::numeric_limits<int64_t>::min();
994 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
995 IntVar* const var = vars[i];
997 if (var->Max() > best_max) {
999 best_index = i;
1008int64_t ChooseMinSize(Solver*, const std::vector<IntVar*>& vars,
1009 int64_t first_unbound, int64_t last_unbound) {
1010 uint64_t best_size = std::numeric_limits<uint64_t>::max();
1012 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
1013 IntVar* const var = vars[i];
1015 if (var->Size() < best_size) {
1017 best_index = i;
1026int64_t ChooseMaxSize(Solver*, const std::vector<IntVar*>& vars,
1027 int64_t first_unbound, int64_t last_unbound) {
1030 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
1031 IntVar* const var = vars[i];
1033 if (var->Size() > best_size) {
1035 best_index = i;
1044class HighestRegretSelectorOnMin : public BaseObject {
1046 explicit HighestRegretSelectorOnMin(const std::vector<IntVar*>& vars)
1047 : iterators_(vars.size()) {
1048 for (int64_t i = 0; i < vars.size(); ++i) {
1049 iterators_[i] = vars[i]->MakeDomainIterator(true);
1052 ~HighestRegretSelectorOnMin() override {};
1053 int64_t Choose(Solver* s, const std::vector<IntVar*>& vars,
1054 int64_t first_unbound, int64_t last_unbound);
1055 std::string DebugString() const override { return "MaxRegretSelector"; }
1057 int64_t ComputeRegret(IntVar* var, int64_t index) const {
1059 const int64_t vmin = var->Min();
1060 IntVarIterator* const iterator = iterators_[index];
1063 return iterator->Value() - vmin;
1067 std::vector<IntVarIterator*> iterators_;
1070int64_t HighestRegretSelectorOnMin::Choose(Solver* const,
1071 const std::vector<IntVar*>& vars,
1076 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
1077 IntVar* const var = vars[i];
1079 const int64_t regret = ComputeRegret(var, i);
1080 if (regret > best_regret) {
1082 index = i;
1091int64_t ChooseRandom(Solver* solver, const std::vector<IntVar*>& vars,
1092 int64_t first_unbound, int64_t last_unbound) {
1093 const int64_t span = last_unbound - first_unbound + 1;
1094 const int64_t shift = solver->Rand32(span);
1095 for (int64_t i = 0; i < span; ++i) {
1096 const int64_t index = (i + shift) % span + first_unbound;
1097 if (!vars[index]->Bound()) {
1106class CheapestVarSelector : public BaseObject {
1108 explicit CheapestVarSelector(std::function<int64_t(int64_t)> var_evaluator)
1109 : var_evaluator_(std::move(var_evaluator)) {}
1110 ~CheapestVarSelector() override {};
1111 int64_t Choose(Solver* s, const std::vector<IntVar*>& vars,
1112 int64_t first_unbound, int64_t last_unbound);
1113 std::string DebugString() const override { return "CheapestVarSelector"; }
1116 std::function<int64_t(int64_t)> var_evaluator_;
1119int64_t CheapestVarSelector::Choose(Solver* const,
1120 const std::vector<IntVar*>& vars,
1123 int64_t best_eval = std::numeric_limits<int64_t>::max();
1125 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
1127 const int64_t eval = var_evaluator_(i);
1130 index = i;
1140class PathSelector : public BaseObject {
1142 PathSelector() : first_(std::numeric_limits<int64_t>::max()) {}
1143 ~PathSelector() override {};
1144 int64_t Choose(Solver* s, const std::vector<IntVar*>& vars);
1145 std::string DebugString() const override { return "ChooseNextOnPath"; }
1148 bool UpdateIndex(const std::vector<IntVar*>& vars, int64_t* index) const;
1149 bool FindPathStart(const std::vector<IntVar*>& vars, int64_t* index) const;
1154int64_t PathSelector::Choose(Solver* const s,
1155 const std::vector<IntVar*>& vars) {
1156 int64_t index = first_.Value();
1157 if (!UpdateIndex(vars, &index)) {
1161 while (vars[index]->Bound()) {
1162 index = vars[index]->Value();
1163 if (!UpdateIndex(vars, &index)) {
1167 if (count >= vars.size() &&
1168 !FindPathStart(vars, &index)) {
1172 first_.SetValue(s, index);
1176bool PathSelector::UpdateIndex(const std::vector<IntVar*>& vars,
1178 if (*index >= vars.size()) {
1179 if (!FindPathStart(vars, index)) {
1192bool PathSelector::FindPathStart(const std::vector<IntVar*>& vars,
1195 for (int64_t i = vars.size() - 1; i >= 0; --i) {
1197 const int64_t next = vars[i]->Value();
1198 if (next < vars.size() && !vars[next]->Bound()) {
1205 for (int64_t i = vars.size() - 1; i >= 0; --i) {
1207 bool has_possible_prev = false;
1208 for (int64_t j = 0; j < vars.size(); ++j) {
1209 if (vars[j]->Contains(i)) {
1210 has_possible_prev = true;
1214 if (!has_possible_prev) {
1215 *index = i;
1221 for (int64_t i = 0; i < vars.size(); ++i) {
1223 *index = i;
1232int64_t SelectMinValue(const IntVar* v, int64_t) { return v->Min(); }
1236int64_t SelectMaxValue(const IntVar* v, int64_t) { return v->Max(); }
1240int64_t SelectRandomValue(const IntVar* v, int64_t) {
1241 const uint64_t span = v->Max() - v->Min() + 1;
1242 if (span > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {
1246 const uint64_t size = v->Size();
1247 Solver* const s = v->solver();
1251 const int64_t value = v->Min() + s->Rand64(span);
1252 if (v->Contains(value)) {
1257 int64_t index = s->Rand64(size);
1259 for (int64_t i = v->Min(); i <= v->Max(); ++i) {
1262 return i;
1268 for (int64_t i = v->Max(); i > v->Min(); --i) {
1271 return i;
1283int64_t SelectCenterValue(const IntVar* v, int64_t) {
1284 const int64_t vmin = v->Min();
1285 const int64_t vmax = v->Max();
1286 if (vmax - vmin > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {
1290 const int64_t mid = (vmin + vmax) / 2;
1294 const int64_t diameter = vmax - mid;
1295 for (int64_t i = 1; i <= diameter; ++i) {
1296 if (v->Contains(mid - i)) {
1297 return mid - i;
1299 if (v->Contains(mid + i)) {
1300 return mid + i;
1308int64_t SelectSplitValue(const IntVar* v, int64_t) {
1309 const int64_t vmin = v->Min();
1310 const int64_t vmax = v->Max();
1311 const uint64_t delta = vmax - vmin;
1312 const int64_t mid = vmin + delta / 2;
1318class CheapestValueSelector : public BaseObject {
1320 CheapestValueSelector(std::function<int64_t(int64_t, int64_t)> eval,
1321 std::function<int64_t(int64_t)> tie_breaker)
1322 : eval_(std::move(eval)), tie_breaker_(std::move(tie_breaker)) {}
1323 ~CheapestValueSelector() override {}
1324 int64_t Select(const IntVar* v, int64_t id);
1325 std::string DebugString() const override { return "CheapestValue"; }
1328 std::function<int64_t(int64_t, int64_t)> eval_;
1329 std::function<int64_t(int64_t)> tie_breaker_;
1330 std::vector<int64_t> cache_;
1333int64_t CheapestValueSelector::Select(const IntVar* v, int64_t id) {
1335 int64_t best = std::numeric_limits<int64_t>::max();
1336 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(false));
1337 for (const int64_t i : InitAndGetValues(it.get())) {
1338 int64_t eval = eval_(id, i);
1343 } else if (eval == best) {
1347 DCHECK_GT(cache_.size(), 0);
1348 if (tie_breaker_ == nullptr || cache_.size() == 1) {
1351 return cache_[tie_breaker_(cache_.size())];
1363class BestValueByComparisonSelector : public BaseObject {
1365 explicit BestValueByComparisonSelector(
1366 Solver::VariableValueComparator comparator)
1367 : comparator_(std::move(comparator)) {}
1368 ~BestValueByComparisonSelector() override {}
1369 int64_t Select(const IntVar* v, int64_t id);
1370 std::string DebugString() const override {
1371 return "BestValueByComparisonSelector";
1375 Solver::VariableValueComparator comparator_;
1378int64_t BestValueByComparisonSelector::Select(const IntVar* v, int64_t id) {
1379 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(false));
1382 int64_t best_value = it->Value();
1383 for (it->Next(); it->Ok(); it->Next()) {
1384 const int64_t candidate_value = it->Value();
1385 if (comparator_(id, candidate_value, best_value)) {
1386 best_value = candidate_value;
1394class VariableAssignmentSelector : public BaseVariableAssignmentSelector {
1396 VariableAssignmentSelector(Solver* solver, const std::vector<IntVar*>& vars,
1397 Solver::VariableIndexSelector var_selector,
1398 Solver::VariableValueSelector value_selector,
1400 : BaseVariableAssignmentSelector(solver, vars),
1401 var_selector_(std::move(var_selector)),
1402 value_selector_(std::move(value_selector)),
1404 ~VariableAssignmentSelector() override {}
1405 int64_t SelectValue(const IntVar* var, int64_t id) override {
1406 return value_selector_(var, id);
1408 int64_t ChooseVariable() override {
1409 return var_selector_(solver_, vars_, first_unbound_.Value(),
1412 std::string DebugString() const override;
1415 Solver::VariableIndexSelector var_selector_;
1416 Solver::VariableValueSelector value_selector_;
1420std::string VariableAssignmentSelector::DebugString() const {
1421 return absl::StrFormat("%s(%s)", name_, JoinDebugStringPtr(vars_, ", "));
1426class BaseEvaluatorSelector : public BaseVariableAssignmentSelector {
1428 BaseEvaluatorSelector(Solver* solver, const std::vector<IntVar*>& vars,
1429 std::function<int64_t(int64_t, int64_t)> evaluator);
1430 ~BaseEvaluatorSelector() override {}
1434 Element() : var(0), value(0) {}
1435 Element(int64_t i, int64_t j) : var(i), value(j) {}
1440 std::string DebugStringInternal(absl::string_view name) const {
1441 return absl::StrFormat("%s(%s)", name, JoinDebugStringPtr(vars_, ", "));
1444 std::function<int64_t(int64_t, int64_t)> evaluator_;
1447BaseEvaluatorSelector::BaseEvaluatorSelector(
1448 Solver* solver, const std::vector<IntVar*>& vars,
1449 std::function<int64_t(int64_t, int64_t)> evaluator)
1450 : BaseVariableAssignmentSelector(solver, vars),
1451 evaluator_(std::move(evaluator)) {}
1455class DynamicEvaluatorSelector : public BaseEvaluatorSelector {
1457 DynamicEvaluatorSelector(Solver* solver, const std::vector<IntVar*>& vars,
1458 std::function<int64_t(int64_t, int64_t)> evaluator,
1459 std::function<int64_t(int64_t)> tie_breaker);
1460 ~DynamicEvaluatorSelector() override {}
1461 int64_t SelectValue(const IntVar* var, int64_t id) override;
1462 int64_t ChooseVariable() override;
1463 std::string DebugString() const override;
1467 std::function<int64_t(int64_t)> tie_breaker_;
1468 std::vector<Element> cache_;
1471DynamicEvaluatorSelector::DynamicEvaluatorSelector(
1472 Solver* solver, const std::vector<IntVar*>& vars,
1473 std::function<int64_t(int64_t, int64_t)> evaluator,
1474 std::function<int64_t(int64_t)> tie_breaker)
1475 : BaseEvaluatorSelector(solver, vars, std::move(evaluator)),
1477 tie_breaker_(std::move(tie_breaker)) {}
1479int64_t DynamicEvaluatorSelector::SelectValue(const IntVar*, int64_t) {
1480 return cache_[first_].value;
1483int64_t DynamicEvaluatorSelector::ChooseVariable() {
1484 int64_t best_evaluation = std::numeric_limits<int64_t>::max();
1486 for (int64_t i = 0; i < vars_.size(); ++i) {
1487 const IntVar* const var = vars_[i];
1489 std::unique_ptr<IntVarIterator> it(var->MakeDomainIterator(false));
1490 for (const int64_t j : InitAndGetValues(it.get())) {
1491 const int64_t value = evaluator_(i, j);
1492 if (value < best_evaluation) {
1495 cache_.push_back(Element(i, j));
1496 } else if (value == best_evaluation && tie_breaker_) {
1497 cache_.push_back(Element(i, j));
1507 if (tie_breaker_ == nullptr || cache_.size() == 1) {
1509 return cache_.front().var;
1511 first_ = tie_breaker_(cache_.size());
1512 return cache_[first_].var;
1516std::string DynamicEvaluatorSelector::DebugString() const {
1517 return DebugStringInternal("AssignVariablesOnDynamicEvaluator");
1522class StaticEvaluatorSelector : public BaseEvaluatorSelector {
1525 Solver* solver, const std::vector<IntVar*>& vars,
1526 const std::function<int64_t(int64_t, int64_t)>& evaluator);
1527 ~StaticEvaluatorSelector() override {}
1528 int64_t SelectValue(const IntVar* var, int64_t id) override;
1529 int64_t ChooseVariable() override;
1530 std::string DebugString() const override;
1535 explicit Compare(std::function<int64_t(int64_t, int64_t)> evaluator)
1536 : evaluator_(std::move(evaluator)) {}
1537 bool operator()(const Element& lhs, const Element& rhs) const {
1538 const int64_t value_lhs = Value(lhs);
1539 const int64_t value_rhs = Value(rhs);
1540 return value_lhs < value_rhs ||
1541 (value_lhs == value_rhs &&
1543 (lhs.var == rhs.var && lhs.value < rhs.value)));
1545 int64_t Value(const Element& element) const {
1546 return evaluator_(element.var, element.value);
1550 std::function<int64_t(int64_t, int64_t)> evaluator_;
1554 std::vector<Element> elements_;
1558StaticEvaluatorSelector::StaticEvaluatorSelector(
1559 Solver* solver, const std::vector<IntVar*>& vars,
1560 const std::function<int64_t(int64_t, int64_t)>& evaluator)
1561 : BaseEvaluatorSelector(solver, vars, evaluator),
1565int64_t StaticEvaluatorSelector::SelectValue(const IntVar*, int64_t) {
1566 return elements_[first_].value;
1569int64_t StaticEvaluatorSelector::ChooseVariable() {
1572 int64_t element_size = 0;
1573 for (int64_t i = 0; i < vars_.size(); ++i) {
1574 if (!vars_[i]->Bound()) {
1575 element_size += vars_[i]->Size();
1578 elements_.resize(element_size);
1580 for (int i = 0; i < vars_.size(); ++i) {
1581 const IntVar* const var = vars_[i];
1583 std::unique_ptr<IntVarIterator> it(var->MakeDomainIterator(false));
1584 for (const int64_t value : InitAndGetValues(it.get())) {
1585 elements_[count++] = Element(i, value);
1590 std::sort(elements_.begin(), elements_.end(), comp_);
1591 solver_->SaveAndSetValue<int64_t>(&first_, 0);
1593 for (int64_t i = first_; i < elements_.size(); ++i) {
1594 const Element& element = elements_[i];
1595 IntVar* const var = vars_[element.var];
1596 if (!var->Bound() && var->Contains(element.value)) {
1597 solver_->SaveAndSetValue(&first_, i);
1601 solver_->SaveAndSetValue(&first_, static_cast<int64_t>(elements_.size()));
1605std::string StaticEvaluatorSelector::DebugString() const {
1606 return DebugStringInternal("AssignVariablesOnStaticEvaluator");
1611class AssignOneVariableValue : public Decision {
1613 AssignOneVariableValue(IntVar* v, int64_t val);
1614 ~AssignOneVariableValue() override {}
1615 void Apply(Solver* s) override;
1616 void Refute(Solver* s) override;
1617 std::string DebugString() const override;
1618 void Accept(DecisionVisitor* const visitor) const override {
1619 visitor->VisitSetVariableValue(var_, value_);
1627AssignOneVariableValue::AssignOneVariableValue(IntVar* const v, int64_t val)
1628 : var_(v), value_(val) {}
1630std::string AssignOneVariableValue::DebugString() const {
1631 return absl::StrFormat("[%s == %d] or [%s != %d]", var_->DebugString(),
1635void AssignOneVariableValue::Apply(Solver* const) { var_->SetValue(value_); }
1637void AssignOneVariableValue::Refute(Solver* const) {
1643 return RevAlloc(new AssignOneVariableValue(var, val));
1649class AssignOneVariableValueOrFail : public Decision {
1651 AssignOneVariableValueOrFail(IntVar* v, int64_t value);
1652 ~AssignOneVariableValueOrFail() override {}
1653 void Apply(Solver* s) override;
1654 void Refute(Solver* s) override;
1655 std::string DebugString() const override;
1656 void Accept(DecisionVisitor* const visitor) const override {
1657 visitor->VisitSetVariableValue(var_, value_);
1665AssignOneVariableValueOrFail::AssignOneVariableValueOrFail(IntVar* const v,
1667 : var_(v), value_(value) {}
1669std::string AssignOneVariableValueOrFail::DebugString() const {
1670 return absl::StrFormat("[%s == %d] or fail", var_->DebugString(), value_);
1673void AssignOneVariableValueOrFail::Apply(Solver* const) {
1677void AssignOneVariableValueOrFail::Refute(Solver* const s) { s->Fail(); }
1688class AssignOneVariableValueDoNothing : public Decision {
1690 AssignOneVariableValueDoNothing(IntVar* const v, int64_t value)
1691 : var_(v), value_(value) {}
1692 ~AssignOneVariableValueDoNothing() override {}
1693 void Apply(Solver* const) override { var_->SetValue(value_); }
1694 void Refute(Solver* const) override {}
1695 std::string DebugString() const override {
1696 return absl::StrFormat("[%s == %d] or []", var_->DebugString(), value_);
1698 void Accept(DecisionVisitor* const visitor) const override {
1699 visitor->VisitSetVariableValue(var_, value_);
1717class SplitOneVariable : public Decision {
1719 SplitOneVariable(IntVar* v, int64_t val, bool start_with_lower_half);
1720 ~SplitOneVariable() override {}
1721 void Apply(Solver* s) override;
1722 void Refute(Solver* s) override;
1723 std::string DebugString() const override;
1724 void Accept(DecisionVisitor* const visitor) const override {
1725 visitor->VisitSplitVariableDomain(var_, value_, start_with_lower_half_);
1731 const bool start_with_lower_half_;
1734SplitOneVariable::SplitOneVariable(IntVar* const v, int64_t val,
1735 bool start_with_lower_half)
1736 : var_(v), value_(val), start_with_lower_half_(start_with_lower_half) {}
1738std::string SplitOneVariable::DebugString() const {
1739 if (start_with_lower_half_) {
1740 return absl::StrFormat("[%s <= %d]", var_->DebugString(), value_);
1742 return absl::StrFormat("[%s >= %d]", var_->DebugString(), value_);
1746void SplitOneVariable::Apply(Solver* const) {
1747 if (start_with_lower_half_) {
1748 var_->SetMax(value_);
1750 var_->SetMin(value_ + 1);
1754void SplitOneVariable::Refute(Solver* const) {
1755 if (start_with_lower_half_) {
1756 var_->SetMin(value_ + 1);
1758 var_->SetMax(value_);
1764 bool start_with_lower_half) {
1765 return RevAlloc(new SplitOneVariable(var, val, start_with_lower_half));
1781class AssignVariablesValues : public Decision {
1787 enum class RefutationBehavior { kForbidAssignment, kDoNothing, kFail };
1789 const std::vector<IntVar*>& vars, const std::vector<int64_t>& values,
1790 RefutationBehavior refutation = RefutationBehavior::kForbidAssignment);
1791 ~AssignVariablesValues() override {}
1792 void Apply(Solver* s) override;
1793 void Refute(Solver* s) override;
1794 std::string DebugString() const override;
1795 void Accept(DecisionVisitor* const visitor) const override {
1796 for (int i = 0; i < vars_.size(); ++i) {
1797 visitor->VisitSetVariableValue(vars_[i], values_[i]);
1801 virtual void Accept(ModelVisitor* const visitor) const {
1802 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
1803 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1805 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
1809 const std::vector<IntVar*> vars_;
1810 const std::vector<int64_t> values_;
1811 const RefutationBehavior refutation_;
1814AssignVariablesValues::AssignVariablesValues(const std::vector<IntVar*>& vars,
1815 const std::vector<int64_t>& values,
1816 RefutationBehavior refutation)
1817 : vars_(vars), values_(values), refutation_(refutation) {}
1819std::string AssignVariablesValues::DebugString() const {
1821 if (vars_.empty()) out += "do nothing";
1822 for (int i = 0; i < vars_.size(); ++i) {
1823 absl::StrAppendFormat(&out, "[%s == %d]", vars_[i]->DebugString(),
1827 case RefutationBehavior::kForbidAssignment:
1828 out += " or forbid assignment";
1830 case RefutationBehavior::kDoNothing:
1833 case RefutationBehavior::kFail:
1840void AssignVariablesValues::Apply(Solver* const) {
1841 if (vars_.empty()) return;
1843 for (int i = 0; i < vars_.size(); ++i) {
1844 vars_[i]->SetValue(values_[i]);
1846 vars_[0]->UnfreezeQueue();
1849void AssignVariablesValues::Refute(Solver* const s) {
1851 case RefutationBehavior::kForbidAssignment: {
1852 std::vector<IntVar*> terms;
1853 for (int i = 0; i < vars_.size(); ++i) {
1854 IntVar* term = s->MakeBoolVar();
1855 s->AddConstraint(s->MakeIsDifferentCstCt(vars_[i], values_[i], term));
1858 s->AddConstraint(s->MakeSumGreaterOrEqual(terms, 1));
1861 case RefutationBehavior::kDoNothing: {
1864 case RefutationBehavior::kFail: {
1873 const std::vector<IntVar*>& vars, const std::vector<int64_t>& values) {
1874 CHECK_EQ(vars.size(), values.size());
1875 return RevAlloc(new AssignVariablesValues(
1877 AssignVariablesValues::RefutationBehavior::kForbidAssignment));
1881 const std::vector<IntVar*>& vars, const std::vector<int64_t>& values) {
1882 CHECK_EQ(vars.size(), values.size());
1883 return RevAlloc(new AssignVariablesValues(
1884 vars, values, AssignVariablesValues::RefutationBehavior::kDoNothing));
1888 const std::vector<IntVar*>& vars, const std::vector<int64_t>& values) {
1889 CHECK_EQ(vars.size(), values.size());
1890 return RevAlloc(new AssignVariablesValues(
1891 vars, values, AssignVariablesValues::RefutationBehavior::kFail));
1905 BaseAssignVariables(BaseVariableAssignmentSelector* const selector, Mode mode)
1906 : selector_(selector), mode_(mode) {}
1908 ~BaseAssignVariables() override;
1909 Decision* Next(Solver* s) override;
1910 std::string DebugString() const override;
1911 static BaseAssignVariables* MakePhase(
1912 Solver* s, const std::vector<IntVar*>& vars,
1913 Solver::VariableIndexSelector var_selector,
1914 Solver::VariableValueSelector value_selector,
1915 const std::string& value_selector_name, BaseAssignVariables::Mode mode);
1917 static Solver::VariableIndexSelector MakeVariableSelector(
1918 Solver* const s, const std::vector<IntVar*>& vars,
1919 Solver::IntVarStrategy str) {
1921 case Solver::INT_VAR_DEFAULT:
1922 case Solver::INT_VAR_SIMPLE:
1923 case Solver::CHOOSE_FIRST_UNBOUND:
1924 return ChooseFirstUnbound;
1925 case Solver::CHOOSE_RANDOM:
1927 case Solver::CHOOSE_MIN_SIZE_LOWEST_MIN:
1928 return ChooseMinSizeLowestMin;
1929 case Solver::CHOOSE_MIN_SIZE_HIGHEST_MIN:
1930 return ChooseMinSizeHighestMin;
1931 case Solver::CHOOSE_MIN_SIZE_LOWEST_MAX:
1932 return ChooseMinSizeLowestMax;
1933 case Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX:
1934 return ChooseMinSizeHighestMax;
1935 case Solver::CHOOSE_LOWEST_MIN:
1937 case Solver::CHOOSE_HIGHEST_MAX:
1939 case Solver::CHOOSE_MIN_SIZE:
1941 case Solver::CHOOSE_MAX_SIZE:
1943 case Solver::CHOOSE_MAX_REGRET_ON_MIN: {
1944 HighestRegretSelectorOnMin* const selector =
1945 s->RevAlloc(new HighestRegretSelectorOnMin(vars));
1946 return [selector](Solver* solver, const std::vector<IntVar*>& vars,
1947 int first_unbound, int last_unbound) {
1948 return selector->Choose(solver, vars, first_unbound, last_unbound);
1951 case Solver::CHOOSE_PATH: {
1952 PathSelector* const selector = s->RevAlloc(new PathSelector());
1953 return [selector](Solver* solver, const std::vector<IntVar*>& vars, int,
1954 int) { return selector->Choose(solver, vars); };
1957 LOG(FATAL) << "Unknown int var strategy " << str;
1962 static Solver::VariableValueSelector MakeValueSelector(
1963 Solver* const, Solver::IntValueStrategy val_str) {
1965 case Solver::INT_VALUE_DEFAULT:
1966 case Solver::INT_VALUE_SIMPLE:
1967 case Solver::ASSIGN_MIN_VALUE:
1969 case Solver::ASSIGN_MAX_VALUE:
1971 case Solver::ASSIGN_RANDOM_VALUE:
1972 return SelectRandomValue;
1973 case Solver::ASSIGN_CENTER_VALUE:
1974 return SelectCenterValue;
1975 case Solver::SPLIT_LOWER_HALF:
1977 case Solver::SPLIT_UPPER_HALF:
1980 LOG(FATAL) << "Unknown int value strategy " << val_str;
1985 void Accept(ModelVisitor* const visitor) const override {
1986 selector_->Accept(visitor);
1990 BaseVariableAssignmentSelector* const selector_;
1994BaseAssignVariables::~BaseAssignVariables() {}
1996Decision* BaseAssignVariables::Next(Solver* const s) {
1997 const std::vector<IntVar*>& vars = selector_->vars();
1998 int id = selector_->ChooseVariableWrapper();
1999 if (id >= 0 && id < vars.size()) {
2000 IntVar* const var = vars[id];
2001 const int64_t value = selector_->SelectValue(var, id);
2004 return s->RevAlloc(new AssignOneVariableValue(var, value));
2006 return s->RevAlloc(new SplitOneVariable(var, value, true));
2008 return s->RevAlloc(new SplitOneVariable(var, value, false));
2014std::string BaseAssignVariables::DebugString() const {
2015 return selector_->DebugString();
2018BaseAssignVariables* BaseAssignVariables::MakePhase(
2019 Solver* const s, const std::vector<IntVar*>& vars,
2022 const std::string& value_selector_name, BaseAssignVariables::Mode mode) {
2023 BaseVariableAssignmentSelector* const selector =
2024 s->RevAlloc(new VariableAssignmentSelector(
2025 s, vars, std::move(var_selector), std::move(value_selector),
2027 return s->RevAlloc(new BaseAssignVariables(selector, mode));
2035 return "ChooseFirstUnbound";
2039 return "ChooseMinSizeLowestMin";
2041 return "ChooseMinSizeHighestMin";
2043 return "ChooseMinSizeLowestMax";
2045 return "ChooseMinSizeHighestMax";
2047 return "ChooseLowestMin";
2049 return "ChooseHighestMax";
2055 return "HighestRegretSelectorOnMin";
2059 LOG(FATAL) << "Unknown int var strategy " << var_str;
2073 return "SelectRandomValue";
2075 return "SelectCenterValue";
2077 return "SelectSplitValue";
2079 return "SelectSplitValue";
2081 LOG(FATAL) << "Unknown int value strategy " << val_str;
2088 return ChooseVariableName(var_str) + "_" + SelectValueName(val_str);
2095 std::vector<IntVar*> vars(1);
2097 return MakePhase(vars, var_str, val_str);
2103 std::vector<IntVar*> vars(2);
2106 return MakePhase(vars, var_str, val_str);
2113 std::vector<IntVar*> vars(3);
2117 return MakePhase(vars, var_str, val_str);
2124 std::vector<IntVar*> vars(4);
2129 return MakePhase(vars, var_str, val_str);
2133 BaseAssignVariables::Mode mode = BaseAssignVariables::ASSIGN;
2135 mode = BaseAssignVariables::SPLIT_LOWER;
2145 return BaseAssignVariables::MakePhase(
2147 BaseAssignVariables::MakeVariableSelector(this, vars, var_str),
2148 BaseAssignVariables::MakeValueSelector(this, val_str),
2156 CHECK(var_evaluator != nullptr);
2157 CheapestVarSelector* const var_selector =
2158 RevAlloc(new CheapestVarSelector(std::move(var_evaluator)));
2159 return BaseAssignVariables::MakePhase(
2162 [var_selector](Solver* solver, const std::vector<IntVar*>& vars,
2163 int first_unbound, int last_unbound) {
2164 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2166 BaseAssignVariables::MakeValueSelector(this, val_str),
2167 "ChooseCheapestVariable_" +
2175 CheapestValueSelector* const value_selector =
2176 RevAlloc(new CheapestValueSelector(std::move(value_evaluator), nullptr));
2177 return BaseAssignVariables::MakePhase(
2180 BaseAssignVariables::MakeVariableSelector(this, vars, var_str),
2182 [value_selector](const IntVar* var, int64_t id) {
2183 return value_selector->Select(var, id);
2185 ChooseVariableName(var_str) +
2191 const std::vector<IntVar*>& vars, IntVarStrategy var_str,
2193 BestValueByComparisonSelector* const value_selector = RevAlloc(
2194 new BestValueByComparisonSelector(std::move(var_val1_val2_comparator)));
2195 return BaseAssignVariables::MakePhase(
2197 BaseAssignVariables::MakeVariableSelector(this, vars, var_str),
2199 [value_selector](const IntVar* var, int64_t id) {
2200 return value_selector->Select(var, id);
2208 CheapestVarSelector* const var_selector =
2209 RevAlloc(new CheapestVarSelector(std::move(var_evaluator)));
2210 CheapestValueSelector* value_selector =
2211 RevAlloc(new CheapestValueSelector(std::move(value_evaluator), nullptr));
2212 return BaseAssignVariables::MakePhase(
2214 [var_selector](Solver* solver, const std::vector<IntVar*>& vars,
2215 int first_unbound, int last_unbound) {
2216 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2219 [value_selector](const IntVar* var, int64_t id) {
2220 return value_selector->Select(var, id);
2229 CheapestValueSelector* value_selector = RevAlloc(new CheapestValueSelector(
2230 std::move(value_evaluator), std::move(tie_breaker)));
2231 return BaseAssignVariables::MakePhase(
2233 BaseAssignVariables::MakeVariableSelector(this, vars, var_str),
2235 [value_selector](const IntVar* var, int64_t id) {
2236 return value_selector->Select(var, id);
2245 CheapestVarSelector* const var_selector =
2246 RevAlloc(new CheapestVarSelector(std::move(var_evaluator)));
2247 CheapestValueSelector* value_selector = RevAlloc(new CheapestValueSelector(
2248 std::move(value_evaluator), std::move(tie_breaker)));
2249 return BaseAssignVariables::MakePhase(
2251 [var_selector](Solver* solver, const std::vector<IntVar*>& vars,
2252 int first_unbound, int last_unbound) {
2253 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2256 [value_selector](const IntVar* var, int64_t id) {
2257 return value_selector->Select(var, id);
2265 return MakePhase(vars, std::move(eval), nullptr, str);
2272 BaseVariableAssignmentSelector* selector = nullptr;
2277 RevAlloc(new StaticEvaluatorSelector(this, vars, std::move(eval)));
2281 selector = RevAlloc(new DynamicEvaluatorSelector(
2282 this, vars, std::move(eval), std::move(tie_breaker)));
2287 new BaseAssignVariables(selector, BaseAssignVariables::ASSIGN));
2293class AssignVariablesFromAssignment : public DecisionBuilder {
2295 AssignVariablesFromAssignment(const Assignment* const assignment,
2297 const std::vector<IntVar*>& vars)
2298 : assignment_(assignment), db_(db), vars_(vars), iter_(0) {}
2300 ~AssignVariablesFromAssignment() override {}
2302 Decision* Next(Solver* const s) override {
2303 if (iter_ < vars_.size()) {
2304 IntVar* const var = vars_[iter_++];
2306 new AssignOneVariableValue(var, assignment_->Value(var)));
2308 return db_->Next(s);
2312 void Accept(ModelVisitor* const visitor) const override {
2313 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
2314 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2316 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
2320 const Assignment* const assignment_;
2321 DecisionBuilder* const db_;
2322 const std::vector<IntVar*> vars_;
2329 const std::vector<IntVar*>& vars) {
2330 return RevAlloc(new AssignVariablesFromAssignment(assignment, db, vars));
2360 const auto other_fields =
2362 if (fields != other_fields) return fields < other_fields;
2364 DCHECK_EQ(other.solution, nullptr);
2367 for (int i = 0; i < solution->NumObjectives(); ++i) {
2368 const int64_t value = solution->ObjectiveValueFromIndex(i);
2416 if (prototype_ != nullptr && objective != nullptr) {
2417 prototype_->AddObjective(objective);
2472 CHECK_GE(n, 0) << "wrong index in solution getter";
2473 CHECK_LT(n, solution_data_.size()) << "wrong index in solution getter";
2556 explicit FirstSolutionCollector(Solver* s);
2557 ~FirstSolutionCollector() override;
2558 void EnterSearch() override;
2559 bool AtSolution() override;
2561 std::string DebugString() const override;
2567FirstSolutionCollector::FirstSolutionCollector(Solver* const s,
2568 const Assignment* const a)
2571FirstSolutionCollector::FirstSolutionCollector(Solver* const s)
2574FirstSolutionCollector::~FirstSolutionCollector() {}
2576void FirstSolutionCollector::EnterSearch() {
2577 SolutionCollector::EnterSearch();
2581bool FirstSolutionCollector::AtSolution() {
2589void FirstSolutionCollector::Install() {
2590 SolutionCollector::Install();
2591 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2594std::string FirstSolutionCollector::DebugString() const {
2595 if (prototype_ == nullptr) {
2596 return "FirstSolutionCollector()";
2598 return "FirstSolutionCollector(" + prototype_->DebugString() + ")";
2604 const Assignment* const assignment) {
2605 return RevAlloc(new FirstSolutionCollector(this, assignment));
2609 return RevAlloc(new FirstSolutionCollector(this));
2619 explicit LastSolutionCollector(Solver* s);
2620 ~LastSolutionCollector() override;
2621 bool AtSolution() override;
2623 std::string DebugString() const override;
2626LastSolutionCollector::LastSolutionCollector(Solver* const s,
2627 const Assignment* const a)
2628 : SolutionCollector(s, a) {}
2630LastSolutionCollector::LastSolutionCollector(Solver* const s)
2633LastSolutionCollector::~LastSolutionCollector() {}
2635bool LastSolutionCollector::AtSolution() {
2641void LastSolutionCollector::Install() {
2642 SolutionCollector::Install();
2643 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2646std::string LastSolutionCollector::DebugString() const {
2647 if (prototype_ == nullptr) {
2648 return "LastSolutionCollector()";
2650 return "LastSolutionCollector(" + prototype_->DebugString() + ")";
2656 const Assignment* const assignment) {
2657 return RevAlloc(new LastSolutionCollector(this, assignment));
2661 return RevAlloc(new LastSolutionCollector(this));
2669 BestValueSolutionCollector(Solver* solver, const Assignment* assignment,
2670 std::vector<bool> maximize);
2671 BestValueSolutionCollector(Solver* solver, std::vector<bool> maximize);
2672 ~BestValueSolutionCollector() override {}
2673 void EnterSearch() override;
2674 bool AtSolution() override;
2676 std::string DebugString() const override;
2679 void ResetBestObjective() {
2680 for (int i = 0; i < maximize_.size(); ++i) {
2681 best_[i] = maximize_[i] ? std::numeric_limits<int64_t>::min()
2682 : std::numeric_limits<int64_t>::max();
2686 const std::vector<bool> maximize_;
2687 std::vector<int64_t> best_;
2690BestValueSolutionCollector::BestValueSolutionCollector(
2691 Solver* solver, const Assignment* assignment, std::vector<bool> maximize)
2692 : SolutionCollector(solver, assignment),
2693 maximize_(std::move(maximize)),
2694 best_(maximize_.size()) {
2698BestValueSolutionCollector::BestValueSolutionCollector(
2699 Solver* solver, std::vector<bool> maximize)
2701 maximize_(std::move(maximize)),
2702 best_(maximize_.size()) {
2706void BestValueSolutionCollector::EnterSearch() {
2707 SolutionCollector::EnterSearch();
2711bool BestValueSolutionCollector::AtSolution() {
2712 if (prototype_ != nullptr && prototype_->HasObjective()) {
2713 const int size = std::min(prototype_->NumObjectives(),
2714 static_cast<int>(maximize_.size()));
2717 bool is_improvement = false;
2718 for (int i = 0; i < size; ++i) {
2719 const IntVar* objective = prototype_->ObjectiveFromIndex(i);
2720 const int64_t objective_value =
2721 maximize_[i] ? CapOpp(objective->Max()) : objective->Min();
2722 if (objective_value < best_[i]) {
2725 } else if (objective_value > best_[i]) {
2729 if (solution_count() == 0 || is_improvement) {
2732 for (int i = 0; i < size; ++i) {
2734 ? CapOpp(prototype_->ObjectiveFromIndex(i)->Max())
2735 : prototype_->ObjectiveFromIndex(i)->Min();
2742void BestValueSolutionCollector::Install() {
2743 SolutionCollector::Install();
2744 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2747std::string BestValueSolutionCollector::DebugString() const {
2748 if (prototype_ == nullptr) {
2749 return "BestValueSolutionCollector()";
2751 return "BestValueSolutionCollector(" + prototype_->DebugString() + ")";
2757 const Assignment* const assignment, bool maximize) {
2758 return RevAlloc(new BestValueSolutionCollector(this, assignment, {maximize}));
2762 const Assignment* assignment, std::vector<bool> maximize) {
2764 new BestValueSolutionCollector(this, assignment, std::move(maximize)));
2768 return RevAlloc(new BestValueSolutionCollector(this, {maximize}));
2772 std::vector<bool> maximize) {
2773 return RevAlloc(new BestValueSolutionCollector(this, std::move(maximize)));
2781 NBestValueSolutionCollector(Solver* solver, const Assignment* assignment,
2782 int solution_count, std::vector<bool> maximize);
2783 NBestValueSolutionCollector(Solver* solver, int solution_count,
2784 std::vector<bool> maximize);
2785 ~NBestValueSolutionCollector() override { Clear(); }
2786 void EnterSearch() override;
2787 void ExitSearch() override;
2788 bool AtSolution() override;
2790 std::string DebugString() const override;
2795 const std::vector<bool> maximize_;
2796 std::priority_queue<std::pair<std::vector<int64_t>, SolutionData>>
2798 const int solution_count_;
2801NBestValueSolutionCollector::NBestValueSolutionCollector(
2802 Solver* solver, const Assignment* assignment, int solution_count,
2803 std::vector<bool> maximize)
2804 : SolutionCollector(solver, assignment),
2805 maximize_(std::move(maximize)),
2806 solution_count_(solution_count) {}
2808NBestValueSolutionCollector::NBestValueSolutionCollector(
2809 Solver* solver, int solution_count, std::vector<bool> maximize)
2811 maximize_(std::move(maximize)),
2812 solution_count_(solution_count) {}
2814void NBestValueSolutionCollector::EnterSearch() {
2815 SolutionCollector::EnterSearch();
2818 if (solution_count_ > 1) {
2819 solver()->SetUseFastLocalSearch(false);
2824void NBestValueSolutionCollector::ExitSearch() {
2825 while (!solutions_pq_.empty()) {
2826 Push(solutions_pq_.top().second);
2831bool NBestValueSolutionCollector::AtSolution() {
2832 if (prototype_ != nullptr && prototype_->HasObjective()) {
2833 const int size = std::min(prototype_->NumObjectives(),
2834 static_cast<int>(maximize_.size()));
2835 std::vector<int64_t> objective_values(size);
2836 for (int i = 0; i < size; ++i) {
2837 objective_values[i] =
2838 maximize_[i] ? CapOpp(prototype_->ObjectiveFromIndex(i)->Max())
2839 : prototype_->ObjectiveFromIndex(i)->Min();
2841 if (solutions_pq_.size() < solution_count_) {
2843 {std::move(objective_values), BuildSolutionDataForCurrentState()});
2844 } else if (!solutions_pq_.empty()) {
2845 const auto& [top_obj_value, top_sol_data] = solutions_pq_.top();
2846 if (std::lexicographical_compare(
2847 objective_values.begin(), objective_values.end(),
2848 top_obj_value.begin(), top_obj_value.end())) {
2849 FreeSolution(top_sol_data.solution);
2852 {std::move(objective_values), BuildSolutionDataForCurrentState()});
2859void NBestValueSolutionCollector::Install() {
2860 SolutionCollector::Install();
2861 ListenToEvent(Solver::MonitorEvent::kExitSearch);
2862 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2865std::string NBestValueSolutionCollector::DebugString() const {
2866 if (prototype_ == nullptr) {
2867 return "NBestValueSolutionCollector()";
2869 return "NBestValueSolutionCollector(" + prototype_->DebugString() + ")";
2873void NBestValueSolutionCollector::Clear() {
2874 while (!solutions_pq_.empty()) {
2875 delete solutions_pq_.top().second.solution;
2883 const Assignment* assignment, int solution_count, bool maximize) {
2884 if (solution_count == 1) {
2887 return RevAlloc(new NBestValueSolutionCollector(this, assignment,
2893 if (solution_count == 1) {
2897 new NBestValueSolutionCollector(this, solution_count, {maximize}));
2901 const Assignment* assignment, int solution_count,
2902 std::vector<bool> maximize) {
2903 if (solution_count == 1) {
2907 return RevAlloc(new NBestValueSolutionCollector(
2908 this, assignment, solution_count, std::move(maximize)));
2912 int solution_count, std::vector<bool> maximize) {
2913 if (solution_count == 1) {
2916 return RevAlloc(new NBestValueSolutionCollector(this, solution_count,
2926 explicit AllSolutionCollector(Solver* s);
2927 ~AllSolutionCollector() override;
2928 bool AtSolution() override;
2930 std::string DebugString() const override;
2933AllSolutionCollector::AllSolutionCollector(Solver* const s,
2934 const Assignment* const a)
2935 : SolutionCollector(s, a) {}
2937AllSolutionCollector::AllSolutionCollector(Solver* const s)
2940AllSolutionCollector::~AllSolutionCollector() {}
2942bool AllSolutionCollector::AtSolution() {
2947void AllSolutionCollector::Install() {
2948 SolutionCollector::Install();
2949 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2952std::string AllSolutionCollector::DebugString() const {
2953 if (prototype_ == nullptr) {
2954 return "AllSolutionCollector()";
2956 return "AllSolutionCollector(" + prototype_->DebugString() + ")";
2962 const Assignment* const assignment) {
2963 return RevAlloc(new AllSolutionCollector(this, assignment));
2967 return RevAlloc(new AllSolutionCollector(this));
2975 std::vector<BaseObjectiveMonitor*> monitors,
2976 int num_max_local_optima_before_metaheuristic_switch)
2978 monitors_(std::move(monitors)),
2979 enabled_monitors_(monitors_.size(), true),
2980 local_optimum_limit_(num_max_local_optima_before_metaheuristic_switch) {
2985 enabled_monitors_.assign(monitors_.size(), true);
2986 for (auto& monitor : monitors_) {
2987 monitor->set_active(monitor == monitors_[active_monitor_]);
3017 const bool ok = monitors_[active_monitor_]->AtLocalOptimum();
3019 enabled_monitors_[active_monitor_] = false;
3021 if (++num_local_optimum_ >= local_optimum_limit_ || !ok) {
3022 monitors_[active_monitor_]->set_active(false);
3023 int next_active_monitor = (active_monitor_ + 1) % monitors_.size();
3024 while (!enabled_monitors_[next_active_monitor]) {
3025 if (next_active_monitor == active_monitor_) return false;
3026 next_active_monitor = (active_monitor_ + 1) % monitors_.size();
3028 active_monitor_ = next_active_monitor;
3029 monitors_[active_monitor_]->set_active(true);
3031 VLOG(2) << "Switching to monitor " << active_monitor_ << " "
3051 int Size() const override { return monitors_[active_monitor_]->Size(); }
3063 const std::vector<BaseObjectiveMonitor*> monitors_;
3064 std::vector<bool> enabled_monitors_;
3066 int num_local_optimum_ = 0;
3071 std::vector<BaseObjectiveMonitor*> monitors,
3072 int num_max_local_optima_before_metaheuristic_switch) {
3074 std::move(monitors), num_max_local_optima_before_metaheuristic_switch));
3078 const std::vector<bool>& maximize,
3079 std::vector<IntVar*> vars,
3080 std::vector<int64_t> steps)
3083 objective_vars_(std::move(vars)),
3084 minimization_vars_(objective_vars_),
3085 upper_bounds_(Size() + 1, nullptr),
3086 steps_(std::move(steps)),
3087 best_values_(Size(), std::numeric_limits<int64_t>::max()),
3088 current_values_(Size(), std::numeric_limits<int64_t>::max()) {
3089 DCHECK_GT(Size(), 0);
3090 DCHECK_EQ(objective_vars_.size(), steps_.size());
3091 DCHECK_EQ(objective_vars_.size(), maximize.size());
3092 DCHECK(std::all_of(steps_.begin(), steps_.end(),
3093 [](int64_t step) { return step > 0; }));
3094 for (int i = 0; i < Size(); ++i) {
3096 minimization_vars_[i] = solver->MakeOpposite(objective_vars_[i])->Var();
3100 minimization_vars_.push_back(solver->MakeIntConst(1));
3101 upper_bounds_.back() = solver->MakeIntConst(0);
3113 best_values_.assign(Size(), std::numeric_limits<int64_t>::max());
3119 for (int i = 0; i < Size(); ++i) {
3120 if (VLOG_IS_ON(2) && !ObjectiveVar(i)->Bound()) {
3126 if (std::lexicographical_compare(current_values_.begin(),
3127 current_values_.end(), best_values_.begin(),
3136 if (delta == nullptr) return true;
3137 const bool delta_has_objective = delta->HasObjective();
3138 if (!delta_has_objective) {
3141 const Assignment* const local_search_state =
3143 for (int i = 0; i < Size(); ++i) {
3147 if (delta_has_objective) {
3150 if (solver()->UseFastLocalSearch() &&
3151 i < local_search_state->NumObjectives()) {
3159 if (delta_has_objective) {
3162 if (solver()->UseFastLocalSearch() &&
3186 int num_values_at_max = 0;
3187 for (int i = 0; i < Size(); ++i) {
3189 DCHECK_EQ(num_values_at_max, 0);
3194 DCHECK(num_values_at_max == 0 || num_values_at_max == Size());
3195 return num_values_at_max < Size();
3221class ApplyBoundDecisionBuilder : public DecisionBuilder {
3223 explicit ApplyBoundDecisionBuilder(OptimizeVar* optimize_var)
3224 : optimize_var_(optimize_var) {}
3225 ~ApplyBoundDecisionBuilder() override = default;
3226 Decision* Next(Solver*) override {
3227 optimize_var_->ApplyBound();
3232 OptimizeVar* optimize_var_;
3237 if (!solver()->SolveAndCommit(
3238 solver()->RevAlloc(new ApplyBoundDecisionBuilder(this)))) {
3257 for (int i = 0; i < Size(); ++i) {
3261 if (!minimization_var->Bound()) return true;
3262 const int64_t value = minimization_var->Value();
3279 for (int i = 0; i < Size(); ++i) {
3281 &out, "%s%s(%s, step = %d, best = %d)", i == 0 ? "" : "; ",
3282 Maximize(i) ? "MaximizeVar" : "MinimizeVar",
3302 std::vector<IntVar*> variables,
3303 std::vector<int64_t> steps) {
3309class WeightedOptimizeVar : public OptimizeVar {
3311 WeightedOptimizeVar(Solver* solver, bool maximize,
3312 const std::vector<IntVar*>& sub_objectives,
3313 const std::vector<int64_t>& weights, int64_t step)
3315 solver->MakeScalProd(sub_objectives, weights)->Var(), step),
3316 sub_objectives_(sub_objectives),
3318 CHECK_EQ(sub_objectives.size(), weights.size());
3321 ~WeightedOptimizeVar() override {}
3322 std::string Name() const override;
3325 const std::vector<IntVar*> sub_objectives_;
3326 const std::vector<int64_t> weights_;
3329std::string WeightedOptimizeVar::Name() const { return "weighted objective"; }
3333 bool maximize, const std::vector<IntVar*>& sub_objectives,
3334 const std::vector<int64_t>& weights, int64_t step) {
3336 new WeightedOptimizeVar(this, maximize, sub_objectives, weights, step));
3340 const std::vector<IntVar*>& sub_objectives,
3341 const std::vector<int64_t>& weights, int64_t step) {
3343 new WeightedOptimizeVar(this, false, sub_objectives, weights, step));
3347 const std::vector<IntVar*>& sub_objectives,
3348 const std::vector<int64_t>& weights, int64_t step) {
3350 new WeightedOptimizeVar(this, true, sub_objectives, weights, step));
3354 bool maximize, const std::vector<IntVar*>& sub_objectives,
3377 Metaheuristic(Solver* solver, const std::vector<bool>& maximize,
3378 std::vector<IntVar*> objectives, std::vector<int64_t> steps);
3379 ~Metaheuristic() override {}
3381 void EnterSearch() override;
3382 void RefuteDecision(Decision* d) override;
3385Metaheuristic::Metaheuristic(Solver* solver, const std::vector<bool>& maximize,
3386 std::vector<IntVar*> objectives,
3387 std::vector<int64_t> steps)
3388 : ObjectiveMonitor(solver, maximize, std::move(objectives),
3391void Metaheuristic::EnterSearch() {
3392 ObjectiveMonitor::EnterSearch();
3395 solver()->SetUseFastLocalSearch(false);
3398void Metaheuristic::RefuteDecision(Decision*) {
3399 for (int i = 0; i < Size(); ++i) {
3400 const int64_t objective_value = MinimizationVar(i)->Min();
3401 if (objective_value > BestInternalValue(i)) break;
3402 if (objective_value <= CapSub(BestInternalValue(i), Step(i))) return;
3409class TabuSearch : public Metaheuristic {
3411 TabuSearch(Solver* solver, const std::vector<bool>& maximize,
3412 std::vector<IntVar*> objectives, std::vector<int64_t> steps,
3413 const std::vector<IntVar*>& vars, int64_t keep_tenure,
3414 int64_t forbid_tenure, double tabu_factor);
3415 ~TabuSearch() override {}
3416 void EnterSearch() override;
3417 void ApplyDecision(Decision* d) override;
3418 bool AtSolution() override;
3419 bool AcceptSolution() override;
3420 bool AtLocalOptimum() override;
3421 bool AcceptDelta(Assignment* delta, Assignment* deltadelta) override;
3423 void BeginNextDecision(DecisionBuilder* const) override {
3424 if (stop_search_) solver()->Fail();
3426 void RefuteDecision(Decision* const d) override {
3427 Metaheuristic::RefuteDecision(d);
3428 if (stop_search_) solver()->Fail();
3430 std::string DebugString() const override { return "Tabu Search"; }
3438 typedef std::list<VarValue> TabuList;
3440 virtual std::vector<IntVar*> CreateTabuVars();
3441 const TabuList& forbid_tabu_list() { return forbid_tabu_list_; }
3442 IntVar* vars(int index) const { return vars_[index]; }
3445 void AgeList(int64_t tenure, TabuList* list);
3447 int64_t TabuLimit() const {
3448 return (synced_keep_tabu_list_.size() + synced_forbid_tabu_list_.size()) *
3452 const std::vector<IntVar*> vars_;
3453 Assignment::IntContainer assignment_container_;
3454 bool has_stored_assignment_ = false;
3455 std::vector<int64_t> last_values_;
3456 TabuList keep_tabu_list_;
3457 TabuList synced_keep_tabu_list_;
3459 TabuList forbid_tabu_list_;
3460 TabuList synced_forbid_tabu_list_;
3464 int64_t solution_count_ = 0;
3465 bool stop_search_ = false;
3466 std::vector<int64_t> delta_values_;
3467 SparseBitset<> delta_vars_;
3468 std::vector<int> var_index_to_index_;
3471TabuSearch::TabuSearch(Solver* solver, const std::vector<bool>& maximize,
3472 std::vector<IntVar*> objectives,
3473 std::vector<int64_t> steps,
3474 const std::vector<IntVar*>& vars, int64_t keep_tenure,
3475 int64_t forbid_tenure, double tabu_factor)
3476 : Metaheuristic(solver, maximize, std::move(objectives), std::move(steps)),
3478 last_values_(Size(), std::numeric_limits<int64_t>::max()),
3479 keep_tenure_(keep_tenure),
3480 forbid_tenure_(forbid_tenure),
3481 tabu_factor_(tabu_factor),
3483 delta_values_(vars.size(), 0),
3484 delta_vars_(vars.size()) {
3485 for (int index = 0; index < vars_.size(); ++index) {
3486 assignment_container_.FastAdd(vars_[index]);
3487 DCHECK_EQ(vars_[index], assignment_container_.Element(index).Var());
3488 const int var_index = vars_[index]->index();
3489 if (var_index >= var_index_to_index_.size()) {
3490 var_index_to_index_.resize(var_index + 1, -1);
3492 var_index_to_index_[var_index] = index;
3496void TabuSearch::EnterSearch() {
3497 Metaheuristic::EnterSearch();
3498 solver()->SetUseFastLocalSearch(true);
3500 has_stored_assignment_ = false;
3505void TabuSearch::ApplyDecision(Decision* const d) {
3506 Solver* const s = solver();
3507 if (d == s->balancing_decision()) {
3511 synced_keep_tabu_list_ = keep_tabu_list_;
3512 synced_forbid_tabu_list_ = forbid_tabu_list_;
3513 Constraint* tabu_ct = nullptr;
3517 const std::vector<IntVar*> tabu_vars = CreateTabuVars();
3518 if (!tabu_vars.empty()) {
3519 IntVar* tabu_var = s->MakeIsGreaterOrEqualCstVar(
3520 s->MakeSum(tabu_vars)->Var(), TabuLimit());
3523 IntVar* aspiration = MakeMinimizationVarsLessOrEqualWithStepsStatus(
3524 [this](int i) { return BestInternalValue(i); });
3525 tabu_ct = s->MakeSumGreaterOrEqual({aspiration, tabu_var}, int64_t{1});
3528 if (tabu_ct != nullptr) s->AddConstraint(tabu_ct);
3531 if (CurrentInternalValuesAreConstraining()) {
3532 MakeMinimizationVarsLessOrEqualWithSteps(
3533 [this](int i) { return CurrentInternalValue(i); });
3537bool TabuSearch::AcceptSolution() {
3539 if (found_initial_solution_) {
3540 for (int i = 0; i < Size(); ++i) {
3541 if (last_values_[i] != MinimizationVar(i)->Min()) {
3550std::vector<IntVar*> TabuSearch::CreateTabuVars() {
3551 Solver* const s = solver();
3559 std::vector<IntVar*> tabu_vars;
3560 for (const auto [var_index, value, unused_stamp] : keep_tabu_list_) {
3561 tabu_vars.push_back(s->MakeIsEqualCstVar(vars(var_index), value));
3563 for (const auto [var_index, value, unused_stamp] : forbid_tabu_list_) {
3564 tabu_vars.push_back(s->MakeIsDifferentCstVar(vars(var_index), value));
3569bool TabuSearch::AtSolution() {
3571 if (!ObjectiveMonitor::AtSolution()) {
3574 for (int i = 0; i < Size(); ++i) {
3575 last_values_[i] = CurrentInternalValue(i);
3580 if (0 != stamp_ && has_stored_assignment_) {
3581 for (int index = 0; index < vars_.size(); ++index) {
3582 IntVar* var = vars(index);
3583 const int64_t old_value = assignment_container_.Element(index).Value();
3584 const int64_t new_value = var->Value();
3585 if (old_value != new_value) {
3587 keep_tabu_list_.push_front({index, new_value, stamp_});
3589 if (forbid_tenure_ > 0) {
3590 forbid_tabu_list_.push_front({index, old_value, stamp_});
3595 assignment_container_.Store();
3596 has_stored_assignment_ = true;
3601bool TabuSearch::AtLocalOptimum() {
3602 solver()->SetUseFastLocalSearch(false);
3605 if (stamp_ > 0 && solution_count_ == 0 && keep_tabu_list_.empty() &&
3606 forbid_tabu_list_.empty()) {
3611 for (int i = 0; i < Size(); ++i) {
3612 SetCurrentInternalValue(i, std::numeric_limits<int64_t>::max());
3614 return found_initial_solution_;
3617bool TabuSearch::AcceptDelta(Assignment* delta, Assignment* deltadelta) {
3618 if (delta == nullptr) return true;
3619 if (!Metaheuristic::AcceptDelta(delta, deltadelta)) return false;
3620 if (synced_keep_tabu_list_.empty() && synced_forbid_tabu_list_.empty()) {
3623 const Assignment::IntContainer& delta_container = delta->IntVarContainer();
3625 for (const IntVarElement& element : delta_container.elements()) {
3626 if (!element.Bound()) return true;
3629 for (const IntVarElement& element : delta_container.elements()) {
3630 const int var_index = element.Var()->index();
3631 if (var_index >= var_index_to_index_.size()) continue;
3632 const int index = var_index_to_index_[var_index];
3633 if (index == -1) continue;
3634 delta_values_[index] = element.Value();
3635 delta_vars_.Set(index);
3638 auto get_value = [this](int var_index) {
3639 return delta_vars_[var_index]
3640 ? delta_values_[var_index]
3641 : assignment_container_.Element(var_index).Value();
3643 const int64_t tabu_limit = TabuLimit();
3644 for (const auto [var_index, value, unused_stamp] : synced_keep_tabu_list_) {
3645 if (get_value(var_index) == value) {
3646 if (++num_respected >= tabu_limit) return true;
3649 for (const auto [var_index, value, unused_stamp] : synced_forbid_tabu_list_) {
3650 if (get_value(var_index) != value) {
3651 if (++num_respected >= tabu_limit) return true;
3654 if (num_respected >= tabu_limit) return true;
3659 delta->SetObjectiveMinFromIndex(0, CapAdd(BestInternalValue(0), Step(0)));
3661 delta->SetObjectiveMaxFromIndex(0, CapSub(BestInternalValue(0), Step(0)));
3664 for (int i = 0; i < Size(); ++i) {
3666 delta->SetObjectiveMinFromIndex(i, BestInternalValue(i));
3668 delta->SetObjectiveMaxFromIndex(i, BestInternalValue(i));
3676void TabuSearch::AcceptNeighbor() {
3682void TabuSearch::AgeList(int64_t tenure, TabuList* list) {
3683 while (!list->empty() && list->back().stamp < stamp_ - tenure) {
3688void TabuSearch::AgeLists() {
3689 AgeList(keep_tenure_, &keep_tabu_list_);
3690 AgeList(forbid_tenure_, &forbid_tabu_list_);
3694class GenericTabuSearch : public TabuSearch {
3696 GenericTabuSearch(Solver* solver, bool maximize, IntVar* objective,
3697 int64_t step, const std::vector<IntVar*>& vars,
3699 : TabuSearch(solver, {maximize}, {objective}, {step}, vars, 0,
3701 std::string DebugString() const override { return "Generic Tabu Search"; }
3704 std::vector<IntVar*> CreateTabuVars() override;
3707std::vector<IntVar*> GenericTabuSearch::CreateTabuVars() {
3708 Solver* const s = solver();
3712 std::vector<IntVar*> forbid_values;
3713 for (const auto [var_index, value, unused_stamp] : forbid_tabu_list()) {
3714 forbid_values.push_back(s->MakeIsDifferentCstVar(vars(var_index), value));
3716 std::vector<IntVar*> tabu_vars;
3717 if (!forbid_values.empty()) {
3718 tabu_vars.push_back(s->MakeIsGreaterCstVar(s->MakeSum(forbid_values), 0));
3727 const std::vector<IntVar*>& vars,
3731 return RevAlloc(new TabuSearch(this, {maximize}, {objective}, {step}, vars,
3736 const std::vector<bool>& maximize, std::vector<IntVar*> objectives,
3737 std::vector<int64_t> steps, const std::vector<IntVar*>& vars,
3738 int64_t keep_tenure, int64_t forbid_tenure, double tabu_factor) {
3739 return RevAlloc(new TabuSearch(this, maximize, std::move(objectives),
3740 std::move(steps), vars, keep_tenure,
3745 bool maximize, IntVar* const v, int64_t step,
3746 const std::vector<IntVar*>& tabu_vars, int64_t forbid_tenure) {
3748 new GenericTabuSearch(this, maximize, v, step, tabu_vars, forbid_tenure));
3754class SimulatedAnnealing : public Metaheuristic {
3756 SimulatedAnnealing(Solver* solver, const std::vector<bool>& maximize,
3757 std::vector<IntVar*> objectives,
3758 std::vector<int64_t> steps,
3759 std::vector<int64_t> initial_temperatures);
3760 ~SimulatedAnnealing() override {}
3761 void ApplyDecision(Decision* d) override;
3762 bool AtLocalOptimum() override;
3763 void AcceptNeighbor() override;
3764 std::string DebugString() const override { return "Simulated Annealing"; }
3767 double Temperature(int index) const {
3769 ? (1.0 * temperature0_[index]) / iteration_
3773 const std::vector<int64_t> temperature0_;
3778SimulatedAnnealing::SimulatedAnnealing(
3779 Solver* solver, const std::vector<bool>& maximize,
3780 std::vector<IntVar*> objectives, std::vector<int64_t> steps,
3781 std::vector<int64_t> initial_temperatures)
3782 : Metaheuristic(solver, maximize, std::move(objectives), std::move(steps)),
3783 temperature0_(std::move(initial_temperatures)),
3800void SimulatedAnnealing::ApplyDecision(Decision* const d) {
3801 Solver* const s = solver();
3802 if (d == s->balancing_decision()) {
3805 if (CurrentInternalValuesAreConstraining()) {
3806 MakeMinimizationVarsLessOrEqualWithSteps([this](int i) {
3807 const double rand_double = absl::Uniform<double>(rand_, 0.0, 1.0);
3808#if defined(_MSC_VER) || defined(__ANDROID__)
3809 const double rand_log2_double = log(rand_double) / log(2.0L);
3811 const double rand_log2_double = log2(rand_double);
3813 const int64_t energy_bound = Temperature(i) * rand_log2_double;
3816 return CapSub(CurrentInternalValue(i), energy_bound);
3821bool SimulatedAnnealing::AtLocalOptimum() {
3822 for (int i = 0; i < Size(); ++i) {
3823 SetCurrentInternalValue(i, std::numeric_limits<int64_t>::max());
3826 if (!found_initial_solution_) return false;
3827 for (int i = 0; i < Size(); ++i) {
3828 if (Temperature(i) <= 0) return false;
3833void SimulatedAnnealing::AcceptNeighbor() {
3842 int64_t initial_temperature) {
3843 return RevAlloc(new SimulatedAnnealing(this, {maximize}, {v}, {step},
3848 const std::vector<bool>& maximize, std::vector<IntVar*> vars,
3849 std::vector<int64_t> steps, std::vector<int64_t> initial_temperatures) {
3850 return RevAlloc(new SimulatedAnnealing(this, maximize, std::move(vars),
3862class GuidedLocalSearchPenaltiesTable {
3868 explicit GuidedLocalSearchPenaltiesTable(int num_vars);
3869 bool HasPenalties() const { return has_values_; }
3870 void IncrementPenalty(const VarValue& var_value);
3871 int64_t GetPenalty(const VarValue& var_value) const;
3875 std::vector<std::vector<int64_t>> penalties_;
3879GuidedLocalSearchPenaltiesTable::GuidedLocalSearchPenaltiesTable(int num_vars)
3880 : penalties_(num_vars), has_values_(false) {}
3882void GuidedLocalSearchPenaltiesTable::IncrementPenalty(
3883 const VarValue& var_value) {
3884 std::vector<int64_t>& var_penalties = penalties_[var_value.var];
3885 const int64_t value = var_value.value;
3886 if (value >= var_penalties.size()) {
3887 var_penalties.resize(value + 1, 0);
3893void GuidedLocalSearchPenaltiesTable::Reset() {
3895 for (int i = 0; i < penalties_.size(); ++i) {
3896 penalties_[i].clear();
3900int64_t GuidedLocalSearchPenaltiesTable::GetPenalty(
3901 const VarValue& var_value) const {
3902 const std::vector<int64_t>& var_penalties = penalties_[var_value.var];
3903 const int64_t value = var_value.value;
3904 return (value >= var_penalties.size()) ? 0 : var_penalties[value];
3908class GuidedLocalSearchPenaltiesMap {
3914 friend bool operator==(const VarValue& lhs, const VarValue& rhs) {
3915 return lhs.var == rhs.var && lhs.value == rhs.value;
3918 friend H AbslHashValue(H h, const VarValue& var_value) {
3919 return H::combine(std::move(h), var_value.var, var_value.value);
3922 explicit GuidedLocalSearchPenaltiesMap(int num_vars);
3923 bool HasPenalties() const { return (!penalties_.empty()); }
3924 void IncrementPenalty(const VarValue& var_value);
3925 int64_t GetPenalty(const VarValue& var_value) const;
3930 absl::flat_hash_map<VarValue, int64_t> penalties_;
3933GuidedLocalSearchPenaltiesMap::GuidedLocalSearchPenaltiesMap(int num_vars)
3934 : penalized_(num_vars, false) {}
3936void GuidedLocalSearchPenaltiesMap::IncrementPenalty(
3937 const VarValue& var_value) {
3939 penalized_.Set(var_value.var, true);
3942void GuidedLocalSearchPenaltiesMap::Reset() {
3944 penalized_.Clear();
3947int64_t GuidedLocalSearchPenaltiesMap::GetPenalty(
3948 const VarValue& var_value) const {
3949 return (penalized_.Get(var_value.var))
3955class GuidedLocalSearch : public Metaheuristic {
3958 Solver* solver, IntVar* objective, bool maximize, int64_t step,
3959 const std::vector<IntVar*>& vars, double penalty_factor,
3960 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
3962 bool reset_penalties_on_new_best_solution);
3963 ~GuidedLocalSearch() override {}
3964 bool AcceptDelta(Assignment* delta, Assignment* deltadelta) override;
3965 void ApplyDecision(Decision* d) override;
3966 bool AtSolution() override;
3967 void EnterSearch() override;
3968 bool AtLocalOptimum() override;
3969 virtual int64_t AssignmentElementPenalty(int index) const = 0;
3970 virtual int64_t AssignmentPenalty(int64_t var, int64_t value) const = 0;
3971 virtual int64_t Evaluate(const Assignment* delta, int64_t current_penalty,
3973 virtual IntExpr* MakeElementPenalty(int index) = 0;
3974 std::string DebugString() const override { return "Guided Local Search"; }
3980 template <typename T, typename IndexType = int64_t>
3983 explicit DirtyArray(IndexType size)
3984 : base_data_(size), modified_data_(size), touched_(size) {}
3987 void Set(IndexType i, const T& value) {
3988 modified_data_[i] = value;
3992 void SetAll(const T& value) {
3993 for (IndexType i = 0; i < modified_data_.size(); ++i) {
3998 T Get(IndexType i) const { return modified_data_[i]; }
4002 for (const IndexType index : touched_.PositionsSetAtLeastOnce()) {
4003 base_data_[index] = modified_data_[index];
4005 touched_.ResetAllToFalse();
4009 for (const IndexType index : touched_.PositionsSetAtLeastOnce()) {
4010 modified_data_[index] = base_data_[index];
4012 touched_.ResetAllToFalse();
4016 int NumSetValues() const {
4017 return touched_.NumberOfSetCallsWithDifferentArguments();
4021 std::vector<T> base_data_;
4022 std::vector<T> modified_data_;
4023 SparseBitset<IndexType> touched_;
4026 int64_t GetValue(int64_t index) const {
4029 IntVar* GetVar(int64_t index) const {
4030 return assignment_.Element(index).Var();
4032 void AddVars(const std::vector<IntVar*>& vars);
4033 int NumPrimaryVars() const { return num_vars_; }
4034 int GetLocalIndexFromVar(IntVar* var) const {
4035 const int var_index = var->index();
4036 return (var_index < var_index_to_local_index_.size())
4037 ? var_index_to_local_index_[var_index]
4042 IntVar* penalized_objective_;
4043 Assignment::IntContainer assignment_;
4044 int64_t assignment_penalized_value_;
4045 int64_t old_penalized_value_;
4047 std::vector<int> var_index_to_local_index_;
4048 const double penalty_factor_;
4050 DirtyArray<int64_t> penalized_values_;
4052 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4054 const bool reset_penalties_on_new_best_solution_;
4058GuidedLocalSearch<P>::GuidedLocalSearch(
4059 Solver* solver, IntVar* objective, bool maximize, int64_t step,
4060 const std::vector<IntVar*>& vars, double penalty_factor,
4061 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4063 bool reset_penalties_on_new_best_solution)
4064 : Metaheuristic(solver, {maximize}, {objective}, {step}),
4065 penalized_objective_(nullptr),
4066 assignment_penalized_value_(0),
4069 penalty_factor_(penalty_factor),
4071 penalized_values_(vars.size()),
4073 get_equivalent_pairs_(std::move(get_equivalent_pairs)),
4074 reset_penalties_on_new_best_solution_(
4075 reset_penalties_on_new_best_solution) {
4080void GuidedLocalSearch<P>::AddVars(const std::vector<IntVar*>& vars) {
4081 const int offset = assignment_.Size();
4082 if (vars.empty()) return;
4083 assignment_.Resize(offset + vars.size());
4084 for (int i = 0; i < vars.size(); ++i) {
4085 assignment_.AddAtPosition(vars[i], offset + i);
4087 const int max_var_index =
4088 (*std::max_element(vars.begin(), vars.end(), [](IntVar* a, IntVar* b) {
4089 return a->index() < b->index();
4091 if (max_var_index >= var_index_to_local_index_.size()) {
4092 var_index_to_local_index_.resize(max_var_index + 1, -1);
4094 for (int i = 0; i < vars.size(); ++i) {
4095 var_index_to_local_index_[vars[i]->index()] = offset + i;
4107void GuidedLocalSearch<P>::ApplyDecision(Decision* const d) {
4108 if (d == solver()->balancing_decision()) {
4111 assignment_penalized_value_ = 0;
4112 if (penalties_.HasPenalties()) {
4116 std::vector<IntVar*> elements;
4117 for (int i = 0; i < num_vars_; ++i) {
4118 elements.push_back(MakeElementPenalty(i)->Var());
4119 const int64_t penalty = AssignmentElementPenalty(i);
4120 penalized_values_.Set(i, penalty);
4121 assignment_penalized_value_ =
4122 CapAdd(assignment_penalized_value_, penalty);
4124 solver()->SaveAndSetValue(
4125 reinterpret_cast<void**>(&penalized_objective_),
4126 reinterpret_cast<void*>(solver()->MakeSum(elements)->Var()));
4128 penalized_values_.Commit();
4129 old_penalized_value_ = assignment_penalized_value_;
4131 IntExpr* max_pen_exp = solver()->MakeDifference(
4132 CapSub(CurrentInternalValue(0), Step(0)), penalized_objective_);
4135 ->MakeMax(max_pen_exp, CapSub(BestInternalValue(0), Step(0)))
4136 ->Var();
4138 solver()->MakeLessOrEqual(MinimizationVar(0), max_exp));
4140 penalized_objective_ = nullptr;
4141 const int64_t bound =
4142 (CurrentInternalValue(0) < std::numeric_limits<int64_t>::max())
4143 ? CapSub(CurrentInternalValue(0), Step(0))
4144 : CurrentInternalValue(0);
4145 MinimizationVar(0)->SetMax(bound);
4150void GuidedLocalSearch<P>::ResetPenalties() {
4151 assignment_penalized_value_ = 0;
4152 old_penalized_value_ = 0;
4153 penalized_values_.SetAll(0);
4154 penalized_values_.Commit();
4159bool GuidedLocalSearch<P>::AtSolution() {
4160 const int64_t old_best = BestInternalValue(0);
4164 if (penalized_objective_ != nullptr && penalized_objective_->Bound()) {
4169 if (reset_penalties_on_new_best_solution_ &&
4170 old_best != BestInternalValue(0)) {
4172 DCHECK_EQ(CurrentInternalValue(0), BestInternalValue(0));
4176 0, CapAdd(CurrentInternalValue(0), penalized_objective_->Value()));
4184void GuidedLocalSearch<P>::EnterSearch() {
4185 Metaheuristic::EnterSearch();
4186 solver()->SetUseFastLocalSearch(true);
4187 penalized_objective_ = nullptr;
4194bool GuidedLocalSearch<P>::AcceptDelta(Assignment* delta,
4196 if (delta == nullptr && deltadelta == nullptr) return true;
4197 if (!penalties_.HasPenalties()) {
4198 return Metaheuristic::AcceptDelta(delta, deltadelta);
4201 if (!deltadelta->Empty()) {
4203 DCHECK_EQ(penalized_values_.NumSetValues(), 0);
4204 penalty = Evaluate(delta, assignment_penalized_value_, true);
4206 penalty = Evaluate(deltadelta, old_penalized_value_, true);
4211 penalized_values_.Revert();
4214 DCHECK_EQ(penalized_values_.NumSetValues(), 0);
4215 penalty = Evaluate(delta, assignment_penalized_value_, false);
4217 old_penalized_value_ = penalty;
4218 if (!delta->HasObjective()) {
4219 delta->AddObjective(ObjectiveVar(0));
4221 if (delta->Objective() == ObjectiveVar(0)) {
4222 const int64_t bound =
4223 std::max(CapSub(CapSub(CurrentInternalValue(0), Step(0)), penalty),
4224 CapSub(BestInternalValue(0), Step(0)));
4226 delta->SetObjectiveMin(std::max(CapOpp(bound), delta->ObjectiveMin()));
4228 delta->SetObjectiveMax(std::min(bound, delta->ObjectiveMax()));
4237bool GuidedLocalSearch<P>::AtLocalOptimum() {
4238 solver()->SetUseFastLocalSearch(false);
4239 std::vector<double> utilities(num_vars_);
4240 double max_utility = -std::numeric_limits<double>::infinity();
4241 for (int var = 0; var < num_vars_; ++var) {
4242 const IntVarElement& element = assignment_.Element(var);
4247 const int64_t value = element.Value();
4250 const int64_t cost = (value != var) ? AssignmentPenalty(var, value) : 0;
4251 const double utility = cost / (penalties_.GetPenalty({var, value}) + 1.0);
4252 utilities[var] = utility;
4253 if (utility > max_utility) max_utility = utility;
4255 for (int var = 0; var < num_vars_; ++var) {
4256 if (utilities[var] == max_utility) {
4257 const IntVarElement& element = assignment_.Element(var);
4259 const int64_t value = element.Value();
4260 if (get_equivalent_pairs_ == nullptr) {
4261 penalties_.IncrementPenalty({var, value});
4263 for (const auto [other_var, other_value] :
4264 get_equivalent_pairs_(var, value)) {
4265 penalties_.IncrementPenalty({other_var, other_value});
4270 SetCurrentInternalValue(0, std::numeric_limits<int64_t>::max());
4275class BinaryGuidedLocalSearch : public GuidedLocalSearch<P> {
4278 Solver* solver, IntVar* objective,
4279 std::function<int64_t(int64_t, int64_t)> objective_function,
4280 bool maximize, int64_t step, const std::vector<IntVar*>& vars,
4282 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4284 bool reset_penalties_on_new_best_solution);
4285 ~BinaryGuidedLocalSearch() override {}
4286 IntExpr* MakeElementPenalty(int index) override;
4287 int64_t AssignmentElementPenalty(int index) const override;
4288 int64_t AssignmentPenalty(int64_t var, int64_t value) const override;
4289 int64_t Evaluate(const Assignment* delta, int64_t current_penalty,
4290 bool incremental) override;
4293 int64_t PenalizedValue(int64_t i, int64_t j) const;
4294 std::function<int64_t(int64_t, int64_t)> objective_function_;
4298BinaryGuidedLocalSearch<P>::BinaryGuidedLocalSearch(
4299 Solver* const solver, IntVar* const objective,
4300 std::function<int64_t(int64_t, int64_t)> objective_function, bool maximize,
4301 int64_t step, const std::vector<IntVar*>& vars, double penalty_factor,
4302 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4304 bool reset_penalties_on_new_best_solution)
4305 : GuidedLocalSearch<P>(solver, objective, maximize, step, vars,
4306 penalty_factor, std::move(get_equivalent_pairs),
4307 reset_penalties_on_new_best_solution),
4308 objective_function_(std::move(objective_function)) {
4309 solver->SetGuidedLocalSearchPenaltyCallback(
4310 [this](int64_t i, int64_t j, int64_t) { return PenalizedValue(i, j); });
4314IntExpr* BinaryGuidedLocalSearch<P>::MakeElementPenalty(int index) {
4315 return this->solver()->MakeElement(
4316 [this, index](int64_t i) { return PenalizedValue(index, i); },
4321int64_t BinaryGuidedLocalSearch<P>::AssignmentElementPenalty(int index) const {
4322 return PenalizedValue(index, this->GetValue(index));
4326int64_t BinaryGuidedLocalSearch<P>::AssignmentPenalty(int64_t var,
4328 return objective_function_(var, value);
4332int64_t BinaryGuidedLocalSearch<P>::Evaluate(const Assignment* delta,
4335 int64_t penalty = current_penalty;
4337 for (const IntVarElement& new_element : container.elements()) {
4338 const int index = this->GetLocalIndexFromVar(new_element.Var());
4339 if (index == -1) continue;
4340 penalty = CapSub(penalty, this->penalized_values_.Get(index));
4341 if (new_element.Activated()) {
4342 const int64_t new_penalty = PenalizedValue(index, new_element.Value());
4343 penalty = CapAdd(penalty, new_penalty);
4345 this->penalized_values_.Set(index, new_penalty);
4354int64_t BinaryGuidedLocalSearch<P>::PenalizedValue(int64_t i, int64_t j) const {
4355 const int64_t penalty = this->penalties_.GetPenalty({i, j});
4357 if (penalty == 0) return 0;
4358 const double penalized_value_fp =
4359 this->penalty_factor_ * penalty * objective_function_(i, j);
4360 const int64_t penalized_value =
4361 (penalized_value_fp <= std::numeric_limits<int64_t>::max())
4362 ? static_cast<int64_t>(penalized_value_fp)
4363 : std::numeric_limits<int64_t>::max();
4368class TernaryGuidedLocalSearch : public GuidedLocalSearch<P> {
4370 TernaryGuidedLocalSearch(
4371 Solver* solver, IntVar* objective,
4372 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
4373 bool maximize, int64_t step, const std::vector<IntVar*>& vars,
4374 const std::vector<IntVar*>& secondary_vars, double penalty_factor,
4375 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4377 bool reset_penalties_on_new_best_solution);
4378 ~TernaryGuidedLocalSearch() override {}
4379 IntExpr* MakeElementPenalty(int index) override;
4380 int64_t AssignmentElementPenalty(int index) const override;
4381 int64_t AssignmentPenalty(int64_t var, int64_t value) const override;
4382 int64_t Evaluate(const Assignment* delta, int64_t current_penalty,
4383 bool incremental) override;
4386 int64_t PenalizedValue(int64_t i, int64_t j, int64_t k) const;
4388 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function_;
4389 std::vector<int> secondary_values_;
4393TernaryGuidedLocalSearch<P>::TernaryGuidedLocalSearch(
4394 Solver* const solver, IntVar* const objective,
4395 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
4396 bool maximize, int64_t step, const std::vector<IntVar*>& vars,
4397 const std::vector<IntVar*>& secondary_vars, double penalty_factor,
4398 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4400 bool reset_penalties_on_new_best_solution)
4401 : GuidedLocalSearch<P>(solver, objective, maximize, step, vars,
4402 penalty_factor, std::move(get_equivalent_pairs),
4403 reset_penalties_on_new_best_solution),
4404 objective_function_(std::move(objective_function)),
4405 secondary_values_(this->NumPrimaryVars(), -1) {
4406 this->AddVars(secondary_vars);
4407 solver->SetGuidedLocalSearchPenaltyCallback(
4408 [this](int64_t i, int64_t j, int64_t k) {
4409 return PenalizedValue(i, j, k);
4414IntExpr* TernaryGuidedLocalSearch<P>::MakeElementPenalty(int index) {
4415 Solver* const solver = this->solver();
4417 solver->AddConstraint(solver->MakeLightElement(
4418 [this, index](int64_t j, int64_t k) {
4419 return PenalizedValue(index, j, k);
4421 var, this->GetVar(index), this->GetVar(this->NumPrimaryVars() + index)));
4426int64_t TernaryGuidedLocalSearch<P>::AssignmentElementPenalty(int index) const {
4427 return PenalizedValue(index, this->GetValue(index),
4428 this->GetValue(this->NumPrimaryVars() + index));
4432int64_t TernaryGuidedLocalSearch<P>::AssignmentPenalty(int64_t var,
4434 return objective_function_(var, value,
4435 this->GetValue(this->NumPrimaryVars() + var));
4439int64_t TernaryGuidedLocalSearch<P>::Evaluate(const Assignment* delta,
4442 int64_t penalty = current_penalty;
4447 for (const IntVarElement& new_element : container.elements()) {
4448 const int index = this->GetLocalIndexFromVar(new_element.Var());
4449 if (index != -1 && index < this->NumPrimaryVars()) {
4450 secondary_values_[index] = -1;
4453 for (const IntVarElement& new_element : container.elements()) {
4454 const int index = this->GetLocalIndexFromVar(new_element.Var());
4455 if (!new_element.Activated()) continue;
4456 if (index != -1 && index >= this->NumPrimaryVars()) {
4457 secondary_values_[index - this->NumPrimaryVars()] = new_element.Value();
4460 for (const IntVarElement& new_element : container.elements()) {
4461 const int index = this->GetLocalIndexFromVar(new_element.Var());
4463 if (index == -1 || index >= this->NumPrimaryVars()) {
4466 penalty = CapSub(penalty, this->penalized_values_.Get(index));
4468 if (new_element.Activated() && secondary_values_[index] != -1) {
4469 const int64_t new_penalty =
4470 PenalizedValue(index, new_element.Value(), secondary_values_[index]);
4471 penalty = CapAdd(penalty, new_penalty);
4473 this->penalized_values_.Set(index, new_penalty);
4482int64_t TernaryGuidedLocalSearch<P>::PenalizedValue(int64_t i, int64_t j,
4484 const int64_t penalty = this->penalties_.GetPenalty({i, j});
4486 if (penalty == 0) return 0;
4487 const double penalized_value_fp =
4488 this->penalty_factor_ * penalty * objective_function_(i, j, k);
4489 const int64_t penalized_value =
4490 (penalized_value_fp < std::numeric_limits<int64_t>::max())
4491 ? static_cast<int64_t>(penalized_value_fp)
4492 : std::numeric_limits<int64_t>::max();
4498 bool maximize, IntVar* const objective,
4500 const std::vector<IntVar*>& vars, double penalty_factor,
4501 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4503 bool reset_penalties_on_new_best_solution) {
4504 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
4505 return RevAlloc(new BinaryGuidedLocalSearch<GuidedLocalSearchPenaltiesMap>(
4506 this, objective, std::move(objective_function), maximize, step, vars,
4507 penalty_factor, std::move(get_equivalent_pairs),
4508 reset_penalties_on_new_best_solution));
4511 new BinaryGuidedLocalSearch<GuidedLocalSearchPenaltiesTable>(
4512 this, objective, std::move(objective_function), maximize, step,
4513 vars, penalty_factor, std::move(get_equivalent_pairs),
4519 bool maximize, IntVar* const objective,
4521 const std::vector<IntVar*>& vars,
4522 const std::vector<IntVar*>& secondary_vars, double penalty_factor,
4523 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4525 bool reset_penalties_on_new_best_solution) {
4526 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
4527 return RevAlloc(new TernaryGuidedLocalSearch<GuidedLocalSearchPenaltiesMap>(
4528 this, objective, std::move(objective_function), maximize, step, vars,
4529 secondary_vars, penalty_factor, std::move(get_equivalent_pairs),
4530 reset_penalties_on_new_best_solution));
4533 new TernaryGuidedLocalSearch<GuidedLocalSearchPenaltiesTable>(
4534 this, objective, std::move(objective_function), maximize, step,
4535 vars, secondary_vars, penalty_factor,
4536 std::move(get_equivalent_pairs),
4576void SearchLimit::TopPeriodicCheck() {
4577 if (solver()->TopLevelSearch() != solver()->ActiveSearch()) {
4586 int64_t solutions, bool smart_time_check,
4590 solver_time_at_limit_start_(s->Now()),
4591 last_time_elapsed_(absl::ZeroDuration()),
4615 reinterpret_cast<const RegularLimit* const>(limit);
4616 duration_limit_ = regular->duration_limit_;
4617 branches_ = regular->branches_;
4618 failures_ = regular->failures_;
4619 solutions_ = regular->solutions_;
4620 smart_time_check_ = regular->smart_time_check_;
4635 return s->branches() - branches_offset_ >= branches_ ||
4636 s->failures() - failures_offset_ >= failures_ || CheckTime(offset) ||
4637 s->solutions() - solutions_offset_ >= solutions_;
4642 int64_t progress = GetPercent(s->branches(), branches_offset_, branches_);
4643 progress = std::max(progress,
4644 GetPercent(s->failures(), failures_offset_, failures_));
4646 progress, GetPercent(s->solutions(), solutions_offset_, solutions_));
4648 progress = std::max(progress, (100 * TimeElapsed()) / duration_limit());
4655 branches_offset_ = s->branches();
4656 failures_offset_ = s->failures();
4657 solver_time_at_limit_start_ = s->Now();
4658 last_time_elapsed_ = absl::ZeroDuration();
4659 solutions_offset_ = s->solutions();
4668 branches_ -= s->branches() - branches_offset_;
4669 failures_ -= s->failures() - failures_offset_;
4670 duration_limit_ -= s->Now() - solver_time_at_limit_start_;
4671 solutions_ -= s->solutions() - solutions_offset_;
4692 "RegularLimit(crossed = %i, duration_limit = %s, "
4693 "branches = %d, failures = %d, solutions = %d cumulative = %s",
4713bool RegularLimit::CheckTime(absl::Duration offset) {
4717absl::Duration RegularLimit::TimeElapsed() {
4718 const int64_t kMaxSkip = 100;
4719 const int64_t kCheckWarmupIterations = 100;
4722 next_check_ <= check_count_) {
4723 Solver* const s = solver();
4724 absl::Duration elapsed = s->Now() - solver_time_at_limit_start_;
4725 if (smart_time_check_ && check_count_ > kCheckWarmupIterations &&
4726 elapsed > absl::ZeroDuration()) {
4728 check_count_ * absl::FDivDuration(duration_limit_, elapsed));
4730 std::min(check_count_ + kMaxSkip, estimated_check_count_at_limit);
4732 last_time_elapsed_ = elapsed;
4734 return last_time_elapsed_;
4738 return MakeLimit(time, std::numeric_limits<int64_t>::max(),
4739 std::numeric_limits<int64_t>::max(),
4752 return MakeLimit(absl::InfiniteDuration(),
4753 std::numeric_limits<int64_t>::max(), failures,
4759 return MakeLimit(absl::InfiniteDuration(),
4760 std::numeric_limits<int64_t>::max(),
4761 std::numeric_limits<int64_t>::max(), solutions,
4780 return MakeLimit(proto.time() == std::numeric_limits<int64_t>::max()
4781 ? absl::InfiniteDuration()
4782 : absl::Milliseconds(proto.time()),
4789 proto.set_time(std::numeric_limits<int64_t>::max());
4790 proto.set_branches(std::numeric_limits<int64_t>::max());
4791 proto.set_failures(std::numeric_limits<int64_t>::max());
4792 proto.set_solutions(std::numeric_limits<int64_t>::max());
4802 double objective_scaling_factor, double objective_offset,
4803 double improvement_rate_coefficient,
4804 int improvement_rate_solutions_distance)
4806 std::vector<bool>{maximize},
4807 std::vector<double>{objective_scaling_factor},
4808 std::vector<double>{objective_offset},
4813 Solver* solver, std::vector<IntVar*> objective_vars,
4814 std::vector<bool> maximize, std::vector<double> objective_scaling_factors,
4815 std::vector<double> objective_offsets, double improvement_rate_coefficient,
4816 int improvement_rate_solutions_distance)
4818 objective_vars_(std::move(objective_vars)),
4819 maximize_(std::move(maximize)),
4820 objective_scaling_factors_(std::move(objective_scaling_factors)),
4821 objective_offsets_(std::move(objective_offsets)),
4822 improvement_rate_coefficient_(improvement_rate_coefficient),
4823 improvement_rate_solutions_distance_(improvement_rate_solutions_distance),
4824 best_objectives_(objective_vars_.size()),
4825 improvements_(objective_vars_.size()),
4826 thresholds_(objective_vars_.size(),
4827 std::numeric_limits<double>::infinity()) {
4839 for (int i = 0; i < objective_vars_.size(); ++i) {
4840 best_objectives_[i] = std::numeric_limits<double>::infinity();
4841 improvements_[i].clear();
4842 thresholds_[i] = std::numeric_limits<double>::infinity();
4851 objective_vars_ = improv->objective_vars_;
4852 maximize_ = improv->maximize_;
4853 objective_scaling_factors_ = improv->objective_scaling_factors_;
4854 objective_offsets_ = improv->objective_offsets_;
4855 improvement_rate_coefficient_ = improv->improvement_rate_coefficient_;
4856 improvement_rate_solutions_distance_ =
4857 improv->improvement_rate_solutions_distance_;
4858 improvements_ = improv->improvements_;
4859 thresholds_ = improv->thresholds_;
4860 best_objectives_ = improv->best_objectives_;
4861 objective_updated_ = improv->objective_updated_;
4867 solver(), objective_vars_, maximize_, objective_scaling_factors_,
4868 objective_offsets_, improvement_rate_coefficient_,
4873 if (!objective_updated_) {
4876 objective_updated_ = false;
4878 std::vector<double> improvement_rates(improvements_.size());
4879 for (int i = 0; i < improvements_.size(); ++i) {
4880 if (improvements_[i].size() <= improvement_rate_solutions_distance_) {
4884 const auto [cur_obj, cur_neighbors] = improvements_[i].back();
4885 const auto [prev_obj, prev_neighbors] = improvements_[i].front();
4886 DCHECK_GT(cur_neighbors, prev_neighbors);
4888 (prev_obj - cur_obj) / (cur_neighbors - prev_neighbors);
4889 if (gradient_stage_) continue;
4890 const double scaled_improvement_rate =
4891 improvement_rate_coefficient_ * improvement_rates[i];
4892 if (scaled_improvement_rate < thresholds_[i]) {
4894 } else if (scaled_improvement_rate > thresholds_[i]) {
4898 if (gradient_stage_ && std::lexicographical_compare(
4899 improvement_rates.begin(), improvement_rates.end(),
4900 thresholds_.begin(), thresholds_.end())) {
4907 std::vector<double> scaled_new_objectives(objective_vars_.size());
4908 for (int i = 0; i < objective_vars_.size(); ++i) {
4909 const int64_t new_objective =
4910 objective_vars_[i] != nullptr && objective_vars_[i]->Bound()
4911 ? objective_vars_[i]->Min()
4912 : (maximize_[i] ? solver()
4920 scaled_new_objectives[i] = (maximize_[i] ? -objective_scaling_factors_[i]
4921 : objective_scaling_factors_[i]) *
4922 (new_objective + objective_offsets_[i]);
4924 const bool is_improvement = std::lexicographical_compare(
4925 scaled_new_objectives.begin(), scaled_new_objectives.end(),
4926 best_objectives_.begin(), best_objectives_.end());
4927 if (gradient_stage_ && !is_improvement) {
4931 for (int i = 0; i < objective_vars_.size(); ++i) {
4932 if (thresholds_[i] == std::numeric_limits<double>::infinity()) {
4939 objective_updated_ = true;
4940 for (int i = 0; i < objective_vars_.size(); ++i) {
4941 improvements_[i].push_back(
4942 std::make_pair(scaled_new_objectives[i], solver()->neighbors()));
4946 if (improvements_[i].size() - 1 > improvement_rate_solutions_distance_) {
4947 improvements_[i].pop_front();
4949 DCHECK_LE(improvements_[i].size() - 1,
4950 improvement_rate_solutions_distance_);
4958 IntVar* objective_var, bool maximize, double objective_scaling_factor,
4959 double objective_offset, double improvement_rate_coefficient,
4960 int improvement_rate_solutions_distance) {
4962 this, objective_var, maximize, objective_scaling_factor, objective_offset,
4963 improvement_rate_coefficient, improvement_rate_solutions_distance));
4967 std::vector<IntVar*> objective_vars, std::vector<bool> maximize,
4968 std::vector<double> objective_scaling_factors,
4969 std::vector<double> objective_offsets, double improvement_rate_coefficient,
4970 int improvement_rate_solutions_distance) {
4972 this, std::move(objective_vars), std::move(maximize),
4973 std::move(objective_scaling_factors), std::move(objective_offsets),
4974 improvement_rate_coefficient, improvement_rate_solutions_distance));
4982 : SearchLimit(limit_1->solver()), limit_1_(limit_1), limit_2_(limit_2) {
4983 CHECK(limit_1 != nullptr);
4984 CHECK(limit_2 != nullptr);
4985 CHECK_EQ(limit_1->solver(), limit_2->solver())
4986 << "Illegal arguments: cannot combines limits that belong to different "
4987 << "solvers, because the reversible allocations could delete one and "
4991 bool CheckWithOffset(absl::Duration offset) override {
4994 const bool check_1 = limit_1_->CheckWithOffset(offset);
4995 const bool check_2 = limit_2_->CheckWithOffset(offset);
4996 return check_1 || check_2;
5004 void Copy(const SearchLimit* const) override {
5005 LOG(FATAL) << "Not implemented.";
5008 SearchLimit* MakeClone() const override {
5010 return solver()->MakeLimit(limit_1_->MakeClone(), limit_2_->MakeClone());
5013 void EnterSearch() override {
5017 void BeginNextDecision(DecisionBuilder* const b) override {
5018 limit_1_->BeginNextDecision(b);
5019 limit_2_->BeginNextDecision(b);
5021 void PeriodicCheck() override {
5022 limit_1_->PeriodicCheck();
5023 limit_2_->PeriodicCheck();
5025 void RefuteDecision(Decision* const d) override {
5026 limit_1_->RefuteDecision(d);
5027 limit_2_->RefuteDecision(d);
5029 std::string DebugString() const override {
5030 return absl::StrCat("OR limit (", limit_1_->DebugString(), " OR ",
5031 limit_2_->DebugString(), ")");
5035 SearchLimit* const limit_1_;
5036 SearchLimit* const limit_2_;
5042 return RevAlloc(new ORLimit(limit_1, limit_2));
5048 CustomLimit(Solver* s, std::function<bool()> limiter);
5049 bool CheckWithOffset(absl::Duration offset) override;
5051 void Copy(const SearchLimit* limit) override;
5052 SearchLimit* MakeClone() const override;
5055 std::function<bool()> limiter_;
5058CustomLimit::CustomLimit(Solver* const s, std::function<bool()> limiter)
5059 : SearchLimit(s), limiter_(std::move(limiter)) {}
5061bool CustomLimit::CheckWithOffset(absl::Duration) {
5063 if (limiter_) return limiter_();
5067void CustomLimit::Init() {}
5069void CustomLimit::Copy(const SearchLimit* const limit) {
5070 const CustomLimit* const custom =
5071 reinterpret_cast<const CustomLimit* const>(limit);
5072 limiter_ = custom->limiter_;
5075SearchLimit* CustomLimit::MakeClone() const {
5076 return solver()->RevAlloc(new CustomLimit(solver(), limiter_));
5081 return RevAlloc(new CustomLimit(this, std::move(limiter)));
5089 explicit SolveOnce(DecisionBuilder* const db) : db_(db) {
5093 SolveOnce(DecisionBuilder* const db,
5094 const std::vector<SearchMonitor*>& monitors)
5095 : db_(db), monitors_(monitors) {
5101 Decision* Next(Solver* s) override {
5102 bool res = s->SolveAndCommit(db_, monitors_);
5109 std::string DebugString() const override {
5110 return absl::StrFormat("SolveOnce(%s)", db_->DebugString());
5113 void Accept(ModelVisitor* const visitor) const override {
5114 db_->Accept(visitor);
5118 DecisionBuilder* const db_;
5119 std::vector<SearchMonitor*> monitors_;
5124 return RevAlloc(new SolveOnce(db));
5129 std::vector<SearchMonitor*> monitors;
5130 monitors.push_back(monitor1);
5131 return RevAlloc(new SolveOnce(db, monitors));
5137 std::vector<SearchMonitor*> monitors;
5138 monitors.push_back(monitor1);
5139 monitors.push_back(monitor2);
5140 return RevAlloc(new SolveOnce(db, monitors));
5147 std::vector<SearchMonitor*> monitors;
5148 monitors.push_back(monitor1);
5149 monitors.push_back(monitor2);
5150 monitors.push_back(monitor3);
5151 return RevAlloc(new SolveOnce(db, monitors));
5159 std::vector<SearchMonitor*> monitors;
5160 monitors.push_back(monitor1);
5161 monitors.push_back(monitor2);
5162 monitors.push_back(monitor3);
5163 monitors.push_back(monitor4);
5164 return RevAlloc(new SolveOnce(db, monitors));
5168 DecisionBuilder* const db, const std::vector<SearchMonitor*>& monitors) {
5169 return RevAlloc(new SolveOnce(db, monitors));
5178 bool maximize, int64_t step)
5186 CHECK(solution->HasObjective());
5190 NestedOptimize(DecisionBuilder* const db, Assignment* const solution,
5191 bool maximize, int64_t step,
5192 const std::vector<SearchMonitor*>& monitors)
5200 CHECK(solution != nullptr);
5201 CHECK(solution->HasObjective());
5206 Solver* const solver = solution_->solver();
5207 collector_ = solver->MakeLastSolutionCollector(solution_);
5208 monitors_.push_back(collector_);
5209 OptimizeVar* const optimize =
5210 solver->MakeOptimize(maximize_, solution_->Objective(), step_);
5211 monitors_.push_back(optimize);
5214 Decision* Next(Solver* solver) override {
5215 solver->Solve(db_, monitors_);
5223 std::string DebugString() const override {
5224 return absl::StrFormat("NestedOptimize(db = %s, maximize = %d, step = %d)",
5228 void Accept(ModelVisitor* const visitor) const override {
5229 db_->Accept(visitor);
5233 DecisionBuilder* const db_;
5234 Assignment* const solution_;
5237 std::vector<SearchMonitor*> monitors_;
5238 SolutionCollector* collector_;
5244 bool maximize, int64_t step) {
5245 return RevAlloc(new NestedOptimize(db, solution, maximize, step));
5250 bool maximize, int64_t step,
5252 std::vector<SearchMonitor*> monitors;
5253 monitors.push_back(monitor1);
5254 return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));
5259 bool maximize, int64_t step,
5262 std::vector<SearchMonitor*> monitors;
5263 monitors.push_back(monitor1);
5264 monitors.push_back(monitor2);
5265 return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));
5270 bool maximize, int64_t step,
5274 std::vector<SearchMonitor*> monitors;
5275 monitors.push_back(monitor1);
5276 monitors.push_back(monitor2);
5277 monitors.push_back(monitor3);
5278 return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));
5285 std::vector<SearchMonitor*> monitors;
5286 monitors.push_back(monitor1);
5287 monitors.push_back(monitor2);
5288 monitors.push_back(monitor3);
5289 monitors.push_back(monitor4);
5290 return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));
5295 int64_t step, const std::vector<SearchMonitor*>& monitors) {
5296 return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));
5305 DCHECK_LT(i, std::numeric_limits<int32_t>::max());
5311 while (power < (i + 1)) {
5317 return NextLuby(i - (power / 2) + 1);
5320class LubyRestart : public SearchMonitor {
5322 LubyRestart(Solver* const s, int scale_factor)
5324 scale_factor_(scale_factor),
5327 next_step_(scale_factor) {
5328 CHECK_GE(scale_factor, 1);
5331 ~LubyRestart() override {}
5333 void BeginFail() override {
5334 if (++current_fails_ >= next_step_) {
5336 next_step_ = NextLuby(++iteration_) * scale_factor_;
5337 solver()->RestartCurrentSearch();
5341 void Install() override { ListenToEvent(Solver::MonitorEvent::kBeginFail); }
5343 std::string DebugString() const override {
5344 return absl::StrFormat("LubyRestart(%i)", scale_factor_);
5356 return RevAlloc(new LubyRestart(this, scale_factor));
5364 ConstantRestart(Solver* const s, int frequency)
5365 : SearchMonitor(s), frequency_(frequency), current_fails_(0) {
5369 ~ConstantRestart() override {}
5371 void BeginFail() override {
5372 if (++current_fails_ >= frequency_) {
5374 solver()->RestartCurrentSearch();
5378 void Install() override { ListenToEvent(Solver::MonitorEvent::kBeginFail); }
5380 std::string DebugString() const override {
5381 return absl::StrFormat("ConstantRestart(%i)", frequency_);
5391 return RevAlloc(new ConstantRestart(this, frequency));
5414 const std::vector<SymmetryBreaker*>& visitors)
5417 clauses_(visitors.size()),
5418 decisions_(visitors.size()),
5419 directions_(visitors.size()) {
5420 for (int i = 0; i < visitors_.size(); ++i) {
5429 for (int i = 0; i < visitors_.size(); ++i) {
5430 const void* const last = clauses_[i].Last();
5431 d->Accept(visitors_[i]);
5432 if (last != clauses_[i].Last()) {
5434 decisions_[i].Push(solver(), d);
5435 directions_[i].Push(solver(), false);
5442 for (int i = 0; i < visitors_.size(); ++i) {
5443 if (decisions_[i].Last() != nullptr && decisions_[i].LastValue() == d) {
5456 std::vector<IntVar*> guard;
5460 while (tmp.ok()) {
5461 IntVar* const term = *tmp;
5463 if (term->Max() == 0) {
5467 if (term->Min() == 0) {
5468 DCHECK_EQ(1, term->Max());
5476 guard.push_back(clauses_[index].LastValue());
5477 directions_[index].SetLastValue(true);
5482 ct = solver()->MakeEquality(solver()->MakeMin(guard), Zero());
5485 solver()->AddConstraint(ct);
5489 clauses_[visitor->index_in_symmetry_manager()].Push(solver(), term);
5492 std::string DebugString() const override { return "SymmetryManager"; }
5495 const std::vector<SymmetryBreaker*> visitors_;
5496 std::vector<SimpleRevFIFO<IntVar*>> clauses_;
5497 std::vector<SimpleRevFIFO<Decision*>> decisions_;
5512 IntVar* const var, int64_t value) {
5520 IntVar* const var, int64_t value) {
const E & Element(const V *const var) const
int64_t Value(const IntVar *var) const
int64_t ObjectiveValueFromIndex(int index) const
bool HasObjective() const
void AddObjectives(const std::vector< IntVar * > &vars)
int64_t EndValue(const IntervalVar *var) const
const std::vector< int > & Unperformed(const SequenceVar *var) const
int64_t PerformedValue(const IntervalVar *var) const
int64_t StartValue(const IntervalVar *var) const
int64_t ObjectiveMinFromIndex(int index) const
void SetObjectiveMinFromIndex(int index, int64_t m)
const std::vector< int > & ForwardSequence(const SequenceVar *var) const
AssignmentContainer< IntVar, IntVarElement > IntContainer
IntVar * Objective() const
int64_t ObjectiveMaxFromIndex(int index) const
void SetObjectiveMaxFromIndex(int index, int64_t m)
int64_t DurationValue(const IntervalVar *var) const
IntVar * ObjectiveFromIndex(int index) const
const std::vector< int > & BackwardSequence(const SequenceVar *var) const
BaseObjectiveMonitor(Solver *solver)
bool Get(uint32_t index) const
void Set(uint32_t index, bool value)
virtual Decision * Next(Solver *s)=0
virtual void Accept(ModelVisitor *visitor) const
std::string DebugString() const override
virtual void Accept(DecisionVisitor *visitor) const
Accepts the given visitor.
bool CheckWithOffset(absl::Duration offset) override
Definition search.cc:4872
~ImprovementSearchLimit() override
Definition search.cc:4831
ImprovementSearchLimit(Solver *solver, IntVar *objective_var, bool maximize, double objective_scaling_factor, double objective_offset, double improvement_rate_coefficient, int improvement_rate_solutions_distance)
Definition search.cc:4800
void Init() override
This method is called when the search limit is initialized.
Definition search.cc:4838
void Install() override
Definition search.cc:4833
void Copy(const SearchLimit *limit) override
Definition search.cc:4848
bool AtSolution() override
Definition search.cc:4906
virtual void SetValue(int64_t v)
This method sets the value of the expression.
virtual bool Bound() const
Returns true if the min and the max of the expression are equal.
virtual void SetMax(int64_t m)=0
virtual int64_t Min() const =0
virtual void SetMin(int64_t m)=0
virtual int64_t Max() const =0
IntVar * Var() override
Creates a variable from the expression.
virtual int64_t Value() const =0
virtual void RemoveValue(int64_t v)=0
This method removes the value 'v' from the domain of the variable.
static int64_t FastInt64Round(double x)
static const char kStepArgument[]
static const char kSolutionLimitArgument[]
static const char kSearchLimitExtension[]
static const char kFailuresLimitArgument[]
static const char kObjectiveExtension[]
virtual void VisitIntegerArgument(const std::string &arg_name, int64_t value)
Visit integer arguments.
static const char kExpressionArgument[]
virtual void VisitIntegerVariableArrayArgument(const std::string &arg_name, const std::vector< IntVar * > &arguments)
virtual void VisitIntegerArrayArgument(const std::string &arg_name, const std::vector< int64_t > &values)
static const char kCumulativeArgument[]
static const char kBranchesLimitArgument[]
virtual void EndVisitExtension(const std::string &type)
virtual void BeginVisitExtension(const std::string &type)
static const char kSmartTimeCheckArgument[]
static const char kTimeLimitArgument[]
bool CurrentInternalValuesAreConstraining() const
Definition search.cc:3185
const std::vector< IntVar * > & minimization_vars() const
const std::vector< IntVar * > & objective_vars() const
int64_t Step(int index) const override
int Size() const override
void MakeMinimizationVarsLessOrEqualWithSteps(const T &upper_bounds)
bool found_initial_solution_
int64_t CurrentInternalValue(int index) const
bool Maximize(int index) const override
bool AcceptDelta(Assignment *delta, Assignment *deltadelta) override
Definition search.cc:3135
void Accept(ModelVisitor *visitor) const override
Accepts the given model visitor.
Definition search.cc:3175
int64_t BestValue(int index) const override
bool AtSolution() override
Definition search.cc:3118
ObjectiveMonitor(Solver *solver, const std::vector< bool > &maximize, std::vector< IntVar * > vars, std::vector< int64_t > steps)
Definition search.cc:3077
IntVar * ObjectiveVar(int index) const override
IntVar * MinimizationVar(int index) const override
void ApplyBound()
Definition search.cc:3213
bool AtSolution() override
Definition search.cc:3270
IntVar * var() const
Returns the variable that is optimized.
OptimizeVar(Solver *solver, bool maximize, IntVar *var, int64_t step)
Definition search.cc:3198
std::string DebugString() const override
Definition search.cc:3277
bool AcceptSolution() override
Definition search.cc:3250
virtual std::string Name() const
Definition search.cc:3275
std::string DebugString() const override
void set_branches(::int64_t value)
void set_failures(::int64_t value)
::int64_t branches() const
bool smart_time_check() const
void set_solutions(::int64_t value)
void set_smart_time_check(bool value)
void set_time(::int64_t value)
void set_cumulative(bool value)
::int64_t failures() const
::int64_t solutions() const
absl::Duration duration_limit() const
bool IsUncheckedSolutionLimitReached() override
Definition search.cc:4684
void Install() override
Definition search.cc:4605
bool CheckWithOffset(absl::Duration offset) override
Definition search.cc:4632
~RegularLimit() override
Definition search.cc:4603
int64_t wall_time() const
void Init() override
This method is called when the search limit is initialized.
Definition search.cc:4653
int64_t solutions() const
int ProgressPercent() override
Definition search.cc:4640
std::string DebugString() const override
Definition search.cc:4690
void Accept(ModelVisitor *visitor) const override
Accepts the given model visitor.
Definition search.cc:4698
RegularLimit(Solver *s, absl::Duration time, int64_t branches, int64_t failures, int64_t solutions, bool smart_time_check, bool cumulative)
Definition search.cc:4584
void Copy(const SearchLimit *limit) override
Definition search.cc:4613
void UpdateLimits(absl::Duration time, int64_t branches, int64_t failures, int64_t solutions)
Definition search.cc:4675
RegularLimit * MakeIdenticalClone() const
Definition search.cc:4626
Definition search.cc:2972
bool AcceptDelta(Assignment *delta, Assignment *deltadelta) override
Definition search.cc:3004
bool Maximize(int index) const override
Definition search.cc:3045
void BeginNextDecision(DecisionBuilder *db) override
Before calling DecisionBuilder::Next.
Definition search.cc:3007
void AcceptNeighbor() override
After accepting a neighbor during local search.
Definition search.cc:2994
int64_t BestValue(int index) const override
Definition search.cc:3048
bool AcceptSolution() override
Definition search.cc:3013
IntVar * MinimizationVar(int index) const override
Definition search.cc:3039
std::string DebugString() const override
Definition search.cc:3052
IntVar * ObjectiveVar(int index) const override
Definition search.cc:3036
int64_t Step(int index) const override
Definition search.cc:3042
int Size() const override
Definition search.cc:3051
bool AtLocalOptimum() override
Definition search.cc:3016
bool AtSolution() override
Definition search.cc:2997
void Accept(ModelVisitor *visitor) const override
Accepts the given model visitor.
Definition search.cc:3055
RoundRobinCompoundObjectiveMonitor(std::vector< BaseObjectiveMonitor * > monitors, int num_max_local_optima_before_metaheuristic_switch)
Definition search.cc:2974
Base class of all search limits.
~SearchLimit() override
Definition search.cc:4545
void BeginNextDecision(DecisionBuilder *b) override
Before calling DecisionBuilder::Next.
Definition search.cc:4559
void PeriodicCheck() override
Periodic call to check limits in long running methods.
Definition search.cc:4569
bool crossed() const
Returns true if the limit has been crossed.
virtual void Init()=0
This method is called when the search limit is initialized.
void Install() override
Definition search.cc:4547
SearchLimit(Solver *const s)
void OutputDecision()
Definition search.cc:258
virtual void OutputLine(const std::string &line)
Definition search.cc:306
bool AtSolution() override
Definition search.cc:116
void AcceptUncheckedNeighbor() override
After accepting an unchecked neighbor during local search.
Definition search.cc:220
SearchLog(Solver *solver, std::vector< IntVar * > vars, std::string vars_name, std::vector< double > scaling_factors, std::vector< double > offsets, std::function< std::string()> display_callback, bool display_on_new_solutions_only, int period)
Definition search.cc:62
void RefuteDecision(Decision *decision) override
Before refuting the decision.
Definition search.cc:253
std::string DebugString() const override
Definition search.cc:86
~SearchLog() override
Definition search.cc:84
void ApplyDecision(Decision *decision) override
Before applying the decision.
Definition search.cc:245
void Maintain()
Definition search.cc:288
A search monitor is a simple set of callbacks to monitor all search events.
static constexpr int kNoProgress
SearchMonitor(Solver *const s)
void ListenToEvent(Solver::MonitorEvent event)
This iterator is not stable with respect to deletion.
int64_t branches(int n) const
Returns the number of branches when the nth solution was found.
Definition search.cc:2494
SolutionData BuildSolutionDataForCurrentState()
Definition search.cc:2444
void AddObjectives(const std::vector< IntVar * > &objectives)
Definition search.cc:2421
const std::vector< int > & ForwardSequence(int n, SequenceVar *var) const
Definition search.cc:2534
int64_t objective_value(int n) const
Returns the objective value of the nth solution.
Definition search.cc:2504
~SolutionCollector() override
Definition search.cc:2346
std::vector< std::unique_ptr< Assignment > > solution_pool_
int64_t PerformedValue(int n, IntervalVar *var) const
This is a shortcut to get the PerformedValue of 'var' in the nth solution.
Definition search.cc:2530
void FreeSolution(Assignment *solution)
Definition search.cc:2465
void Push(const SolutionData &data)
const std::vector< int > & Unperformed(int n, SequenceVar *var) const
Definition search.cc:2544
void AddObjective(IntVar *objective)
Definition search.cc:2415
bool has_solution() const
Returns whether any solutions were stored during the search.
Definition search.cc:2487
void check_index(int n) const
Definition search.cc:2471
int solution_count() const
Returns how many solutions were stored during the search.
Definition search.cc:2485
void Install() override
Definition search.cc:2375
int64_t wall_time(int n) const
Returns the wall time in ms for the nth solution.
Definition search.cc:2489
int64_t DurationValue(int n, IntervalVar *var) const
This is a shortcut to get the DurationValue of 'var' in the nth solution.
Definition search.cc:2522
int64_t ObjectiveValueFromIndex(int n, int index) const
Returns the value of the index-th objective of the nth solution.
Definition search.cc:2509
int64_t failures(int n) const
Definition search.cc:2499
const std::vector< int > & BackwardSequence(int n, SequenceVar *var) const
Definition search.cc:2539
int64_t StartValue(int n, IntervalVar *var) const
This is a shortcut to get the StartValue of 'var' in the nth solution.
Definition search.cc:2518
SolutionCollector(Solver *solver, const Assignment *assignment)
Definition search.cc:2337
int64_t Value(int n, IntVar *var) const
This is a shortcut to get the Value of 'var' in the nth solution.
Definition search.cc:2514
std::vector< Assignment * > recycle_solutions_
std::vector< SolutionData > solution_data_
std::unique_ptr< Assignment > prototype_
Assignment * last_solution_or_null() const
Returns the last solution if there are any, nullptr otherwise.
Definition search.cc:2481
int64_t EndValue(int n, IntervalVar *var) const
This is a shortcut to get the EndValue of 'var' in the nth solution.
Definition search.cc:2526
std::function< int64_t(Solver *solver, const std::vector< IntVar * > &vars, int64_t first_unbound, int64_t last_unbound)> VariableIndexSelector
Decision * MakeAssignVariablesValuesOrDoNothing(const std::vector< IntVar * > &vars, const std::vector< int64_t > &values)
Definition search.cc:1880
DecisionBuilder * MakeSolveOnce(DecisionBuilder *db)
Definition search.cc:5123
int64_t accepted_neighbors() const
The number of accepted neighbors.
SearchMonitor * MakeEnterSearchCallback(std::function< void()> callback)
--— Callback-based search monitors --—
Definition search.cc:516
Decision * MakeAssignVariableValueOrFail(IntVar *var, int64_t value)
Definition search.cc:1680
IntVar * MakeIsEqualCstVar(IntExpr *var, int64_t value)
status var of (var == value)
Decision * MakeVariableLessOrEqualValue(IntVar *var, int64_t value)
Definition search.cc:1768
SearchMonitor * MakeLubyRestart(int scale_factor)
Definition search.cc:5355
int64_t branches() const
The number of branches explored since the creation of the solver.
OptimizeVar * MakeWeightedOptimize(bool maximize, const std::vector< IntVar * > &sub_objectives, const std::vector< int64_t > &weights, int64_t step)
Creates a weighted objective with a given sense (true = maximization).
Definition search.cc:3332
SearchMonitor * MakeConstantRestart(int frequency)
Definition search.cc:5390
int64_t solutions() const
The number of solutions found since the start of the search.
DecisionBuilder * MakeNestedOptimize(DecisionBuilder *db, Assignment *solution, bool maximize, int64_t step)
Definition search.cc:5242
ABSL_MUST_USE_RESULT RegularLimit * MakeSolutionsLimit(int64_t solutions)
Definition search.cc:4758
SolutionCollector * MakeBestValueSolutionCollector(const Assignment *assignment, bool maximize)
Definition search.cc:2756
IntVar * MakeIsLessOrEqualCstVar(IntExpr *var, int64_t value)
status var of (var <= value)
ABSL_MUST_USE_RESULT SearchLimit * MakeCustomLimit(std::function< bool()> limiter)
Definition search.cc:5080
void Fail()
Abandon the current branch in the search tree. A backtrack will follow.
ABSL_MUST_USE_RESULT RegularLimit * MakeFailuresLimit(int64_t failures)
Definition search.cc:4751
OptimizeVar * MakeWeightedMinimize(const std::vector< IntVar * > &sub_objectives, const std::vector< int64_t > &weights, int64_t step)
Definition search.cc:3339
Decision * MakeVariableGreaterOrEqualValue(IntVar *var, int64_t value)
Definition search.cc:1773
ABSL_MUST_USE_RESULT RegularLimit * MakeTimeLimit(absl::Duration time)
Creates a search limit that constrains the running time.
Definition search.cc:4737
std::function< int64_t(int64_t)> IndexEvaluator1
Callback typedefs.
std::function< int64_t(int64_t, int64_t, int64_t)> IndexEvaluator3
DecisionBuilder * Compose(DecisionBuilder *db1, DecisionBuilder *db2)
Definition search.cc:635
ObjectiveMonitor * MakeTabuSearch(bool maximize, IntVar *objective, int64_t step, const std::vector< IntVar * > &vars, int64_t keep_tenure, int64_t forbid_tenure, double tabu_factor)
MetaHeuristics which try to get the search out of local optima.
Definition search.cc:3725
DecisionBuilder * MakePhase(const std::vector< IntVar * > &vars, IntVarStrategy var_str, IntValueStrategy val_str)
Phases on IntVar arrays.
Definition search.cc:2142
Decision * MakeAssignVariablesValuesOrFail(const std::vector< IntVar * > &vars, const std::vector< int64_t > &values)
Definition search.cc:1887
Decision * MakeSplitVariableDomain(IntVar *var, int64_t val, bool start_with_lower_half)
Definition search.cc:1763
ABSL_MUST_USE_RESULT ImprovementSearchLimit * MakeLexicographicImprovementLimit(std::vector< IntVar * > objective_vars, std::vector< bool > maximize, std::vector< double > objective_scaling_factors, std::vector< double > objective_offsets, double improvement_rate_coefficient, int improvement_rate_solutions_distance)
Definition search.cc:4966
OptimizeVar * MakeOptimize(bool maximize, IntVar *v, int64_t step)
Creates a objective with a given sense (true = maximization).
Definition search.cc:3296
std::function< void(Solver *)> Action
SearchMonitor * MakeAtSolutionCallback(std::function< void()> callback)
Definition search.cc:491
@ CHOOSE_MIN_SIZE_LOWEST_MIN
@ CHOOSE_RANDOM
Randomly select one of the remaining unbound variables.
@ CHOOSE_MIN_SIZE_LOWEST_MAX
@ INT_VAR_DEFAULT
The default behavior is CHOOSE_FIRST_UNBOUND.
@ INT_VAR_SIMPLE
The simple selection is CHOOSE_FIRST_UNBOUND.
@ CHOOSE_MIN_SIZE_HIGHEST_MAX
@ CHOOSE_MAX_REGRET_ON_MIN
@ CHOOSE_MIN_SIZE_HIGHEST_MIN
DecisionBuilder * Try(DecisionBuilder *db1, DecisionBuilder *db2)
Definition search.cc:783
std::function< int64_t(int64_t, int64_t)> IndexEvaluator2
SolutionCollector * MakeAllSolutionCollector()
Definition search.cc:2966
int64_t unchecked_solutions() const
The number of unchecked solutions found by local search.
IntVar * MakeIsGreaterOrEqualCstVar(IntExpr *var, int64_t value)
status var of (var >= value)
Decision * MakeDecision(Action apply, Action refute)
Definition search.cc:693
ObjectiveMonitor * MakeLexicographicSimulatedAnnealing(const std::vector< bool > &maximize, std::vector< IntVar * > vars, std::vector< int64_t > steps, std::vector< int64_t > initial_temperatures)
Definition search.cc:3847
SolutionCollector * MakeFirstSolutionCollector()
Definition search.cc:2608
SolutionCollector * MakeLastSolutionCollector()
Definition search.cc:2660
@ kIsUncheckedSolutionLimitReached
friend class SearchMonitor
SolutionCollector * MakeBestLexicographicValueSolutionCollector(const Assignment *assignment, std::vector< bool > maximize)
Definition search.cc:2761
SearchMonitor * MakeExitSearchCallback(std::function< void()> callback)
Definition search.cc:541
SearchMonitor * MakeSearchTrace(const std::string &prefix)
Definition search.cc:462
Decision * MakeAssignVariablesValues(const std::vector< IntVar * > &vars, const std::vector< int64_t > &values)
Definition search.cc:1872
SolutionCollector * MakeNBestValueSolutionCollector(const Assignment *assignment, int solution_count, bool maximize)
Definition search.cc:2882
ObjectiveMonitor * MakeLexicographicTabuSearch(const std::vector< bool > &maximize, std::vector< IntVar * > objectives, std::vector< int64_t > steps, const std::vector< IntVar * > &vars, int64_t keep_tenure, int64_t forbid_tenure, double tabu_factor)
Definition search.cc:3735
DecisionBuilder * MakeDecisionBuilderFromAssignment(Assignment *assignment, DecisionBuilder *db, const std::vector< IntVar * > &vars)
Definition search.cc:2327
int64_t wall_time() const
ABSL_MUST_USE_RESULT RegularLimit * MakeBranchesLimit(int64_t branches)
Definition search.cc:4744
SearchMonitor * MakeSearchLog(int branch_period)
Definition search.cc:334
ObjectiveMonitor * MakeSimulatedAnnealing(bool maximize, IntVar *v, int64_t step, int64_t initial_temperature)
Creates a Simulated Annealing monitor.
Definition search.cc:3840
OptimizeVar * MakeMinimize(IntVar *v, int64_t step)
Creates a minimization objective.
Definition search.cc:3288
ObjectiveMonitor * MakeGuidedLocalSearch(bool maximize, IntVar *objective, IndexEvaluator2 objective_function, int64_t step, const std::vector< IntVar * > &vars, double penalty_factor, std::function< std::vector< std::pair< int64_t, int64_t > >(int64_t, int64_t)> get_equivalent_pairs=nullptr, bool reset_penalties_on_new_best_solution=false)
Definition search.cc:4497
ABSL_MUST_USE_RESULT RegularLimit * MakeLimit(absl::Duration time, int64_t branches, int64_t failures, int64_t solutions, bool smart_time_check=false, bool cumulative=false)
Definition search.cc:4772
OptimizeVar * MakeWeightedMaximize(const std::vector< IntVar * > &sub_objectives, const std::vector< int64_t > &weights, int64_t step)
Creates a maximization weigthed objective.
Definition search.cc:3346
Decision * MakeAssignVariableValueOrDoNothing(IntVar *var, int64_t value)
Definition search.cc:1709
SolutionCollector * MakeNBestLexicographicValueSolutionCollector(const Assignment *assignment, int solution_count, std::vector< bool > maximize)
Definition search.cc:2900
ConstraintSolverParameters parameters() const
Stored Parameters.
std::function< bool(int64_t, int64_t, int64_t)> VariableValueComparator
ObjectiveMonitor * MakeGenericTabuSearch(bool maximize, IntVar *v, int64_t step, const std::vector< IntVar * > &tabu_vars, int64_t forbid_tenure)
Definition search.cc:3744
Assignment * GetOrCreateLocalSearchState()
Returns (or creates) an assignment representing the state of local search.
@ ASSIGN_MAX_VALUE
Selects the max value of the selected variable.
@ INT_VALUE_DEFAULT
The default behavior is ASSIGN_MIN_VALUE.
@ INT_VALUE_SIMPLE
The simple selection is ASSIGN_MIN_VALUE.
@ 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.
OptimizeVar * MakeLexicographicOptimize(std::vector< bool > maximize, std::vector< IntVar * > variables, std::vector< int64_t > steps)
Definition search.cc:3301
SearchMonitor * MakeSymmetryManager(const std::vector< SymmetryBreaker * > &visitors)
Symmetry Breaking.
Definition search.cc:5529
int64_t failures() const
The number of failures encountered since the creation of the solver.
RegularLimitParameters MakeDefaultRegularLimitParameters() const
Creates a regular limit proto containing default values.
Definition search.cc:4787
Solver(const std::string &name)
Solver API.
BaseObjectiveMonitor * MakeRoundRobinCompoundObjectiveMonitor(std::vector< BaseObjectiveMonitor * > monitors, int num_max_local_optima_before_metaheuristic_switch)
Definition search.cc:3070
static int64_t MemoryUsage()
Current memory usage in bytes.
void SetUseFastLocalSearch(bool use_fast_local_search)
OptimizeVar * MakeMaximize(IntVar *v, int64_t step)
Creates a maximization objective.
Definition search.cc:3292
@ CHOOSE_DYNAMIC_GLOBAL_BEST
@ CHOOSE_STATIC_GLOBAL_BEST
ABSL_MUST_USE_RESULT ImprovementSearchLimit * MakeImprovementLimit(IntVar *objective_var, bool maximize, double objective_scaling_factor, double objective_offset, double improvement_rate_coefficient, int improvement_rate_solutions_distance)
Definition search.cc:4957
std::function< int64_t(const IntVar *v, int64_t id)> VariableValueSelector
void Set(IntegerType index)
void AddIntegerVariableGreaterOrEqualValueClause(IntVar *var, int64_t value)
Definition search.cc:5511
void AddIntegerVariableLessOrEqualValueClause(IntVar *var, int64_t value)
Definition search.cc:5519
void AddIntegerVariableEqualValueClause(IntVar *var, int64_t value)
Definition search.cc:5503
Definition search.cc:5411
void EndNextDecision(DecisionBuilder *const, Decision *const d) override
After calling DecisionBuilder::Next, along with the returned decision.
Definition search.cc:5427
void CheckSymmetries(int index)
Definition search.cc:5451
void AddTermToClause(SymmetryBreaker *const visitor, IntVar *const term)
Definition search.cc:5488
~SymmetryManager() override
Definition search.cc:5425
SymmetryManager(Solver *const s, const std::vector< SymmetryBreaker * > &visitors)
Definition search.cc:5413
std::string DebugString() const override
Definition search.cc:5492
bool operator==(const ProtoEnumIterator< E > &a, const ProtoEnumIterator< E > &b)
const MapUtilMappedT< Collection > & FindWithDefault(const Collection &collection, const KeyType &key, const MapUtilMappedT< Collection > &value)
For infeasible and unbounded see Not checked if options check_solutions_if_inf_or_unbounded and the If options first_solution_only is false
H AbslHashValue(H h, std::shared_ptr< Variable > i)
dual_gradient T(y - `dual_solution`) class DiagonalTrustRegionProblemFromQp
std::function< int64_t(const Model &)> Value(IntegerVariable v)
int64_t CapAdd(int64_t x, int64_t y)
std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
void AcceptNeighbor(Search *search)
int64_t CapSub(int64_t x, int64_t y)
std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)
std::string MemoryUsage()
BaseAssignVariables::Mode ChooseMode(Solver::IntValueStrategy val_str)
Definition search.cc:2132
int64_t CapOpp(int64_t v)
bool AcceptDelta(Search *search, Assignment *delta, Assignment *deltadelta)
ABSL_FLAG(bool, cp_use_sparse_gls_penalties, false, "Use sparse implementation to store Guided Local Search penalties")
int64_t ObjectiveValue() const
Definition search.cc:2348
bool operator<(const SolutionData &other) const
Definition search.cc:2357
int64_t ObjectiveValueFromIndex(int index) const
Definition search.cc:2352
Creates a search monitor from logging parameters.
static const int64_t kint64max