27#include "absl/container/flat_hash_map.h"
28#include "absl/flags/flag.h"
29#include "absl/log/check.h"
30#include "absl/random/distributions.h"
31#include "absl/strings/str_cat.h"
32#include "absl/strings/str_format.h"
33#include "absl/strings/str_join.h"
34#include "absl/strings/string_view.h"
35#include "absl/time/time.h"
36#include "absl/types/span.h"
44#include "ortools/constraint_solver/search_limit.pb.h"
50 "Use sparse implementation to store Guided Local Search penalties");
52 "Whether search related logging should be "
54ABSL_FLAG(int64_t, cp_large_domain_no_splitting_limit, 0xFFFFF,
55 "Size limit to allow holes in variables from the strategy.");
61 std::string vars_name, std::vector<double> scaling_factors,
62 std::vector<double> offsets,
63 std::function<std::string()> display_callback,
64 bool display_on_new_solutions_only,
int period)
68 vars_(
std::move(vars)),
69 vars_name_(
std::move(vars_name)),
70 scaling_factors_(
std::move(scaling_factors)),
71 offsets_(
std::move(offsets)),
72 display_callback_(
std::move(display_callback)),
73 display_on_new_solutions_only_(display_on_new_solutions_only),
75 objective_min_(vars_.size(),
std::numeric_limits<int64_t>::max()),
76 objective_max_(vars_.size(),
std::numeric_limits<int64_t>::min()),
77 min_right_depth_(
std::numeric_limits<int32_t>::max()),
79 sliding_min_depth_(0),
80 sliding_max_depth_(0) {}
87 const std::string buffer =
88 (!display_on_new_solutions_only_ && display_callback_ !=
nullptr)
89 ? absl::StrFormat(
"Start search (%s, %s)", MemoryUsage(),
91 : absl::StrFormat(
"Start search (%s)", MemoryUsage());
94 min_right_depth_ = std::numeric_limits<int32_t>::max();
97 last_objective_value_.clear();
98 last_objective_timestamp_ = timer_->GetDuration();
103 int64_t ms = absl::ToInt64Milliseconds(timer_->GetDuration());
107 const std::string buffer = absl::StrFormat(
108 "End search (time = %d ms, branches = %d, failures = %d, %s, speed = %d "
110 ms, branches,
solver()->failures(), MemoryUsage(), branches * 1000 / ms);
117 std::string obj_str =
"";
118 std::vector<int64_t> current;
119 bool objective_updated =
false;
120 const auto scaled_str = [
this](absl::Span<const int64_t> values) {
121 std::vector<std::string> value_strings(values.size());
122 for (
int i = 0; i < values.size(); ++i) {
123 if (scaling_factors_[i] != 1.0 || offsets_[i] != 0.0) {
125 absl::StrFormat(
"%d (%.8lf)", values[i],
126 scaling_factors_[i] * (values[i] + offsets_[i]));
128 value_strings[i] = absl::StrCat(values[i]);
131 return absl::StrJoin(value_strings,
", ");
133 bool all_vars_bound = !vars_.empty();
134 for (
IntVar* var : vars_) {
135 all_vars_bound &= var->Bound();
137 if (all_vars_bound) {
138 for (
IntVar* var : vars_) {
139 current.push_back(var->Value());
140 objective_updated =
true;
142 absl::StrAppend(&obj_str,
143 vars_name_.empty() ?
"" : absl::StrCat(vars_name_,
" = "),
144 scaled_str(current),
", ");
146 current.push_back(
solver()->GetOrCreateLocalSearchState()->ObjectiveMin());
147 absl::StrAppend(&obj_str,
"objective = ", scaled_str(current),
", ");
148 objective_updated =
true;
150 const absl::Duration now = timer_->GetDuration();
151 if (objective_updated) {
152 if (!last_objective_value_.empty()) {
153 const int64_t elapsed_ms =
154 absl::ToInt64Milliseconds(now - last_objective_timestamp_);
155 for (
int i = 0; i < current.size(); ++i) {
156 const double improvement_rate =
157 100.0 * 1000.0 * (current[i] - last_objective_value_[i]) /
158 std::max<int64_t>(1, last_objective_value_[i] * elapsed_ms);
159 absl::StrAppend(&obj_str,
"improvement rate = ", improvement_rate,
161 last_objective_value_[i] = current[i];
164 last_objective_value_ = current;
166 last_objective_timestamp_ = now;
167 if (!objective_min_.empty() &&
168 std::lexicographical_compare(objective_min_.begin(),
169 objective_min_.end(), current.begin(),
171 absl::StrAppend(&obj_str,
172 vars_name_.empty() ?
"" : absl::StrCat(vars_name_,
" "),
173 "minimum = ", scaled_str(objective_min_),
", ");
176 objective_min_ = current;
178 if (!objective_max_.empty() &&
179 std::lexicographical_compare(current.begin(), current.end(),
180 objective_max_.begin(),
181 objective_max_.end())) {
182 absl::StrAppend(&obj_str,
183 vars_name_.empty() ?
"" : absl::StrCat(vars_name_,
" "),
184 "maximum = ", scaled_str(objective_max_),
", ");
186 objective_max_ = current;
190 absl::StrAppendFormat(&log,
191 "Solution #%d (%stime = %d ms, branches = %d,"
192 " failures = %d, depth = %d",
193 nsol_++, obj_str, absl::ToInt64Milliseconds(now),
195 if (!
solver()->SearchContext().empty()) {
196 absl::StrAppendFormat(&log,
", %s",
solver()->SearchContext());
198 if (
solver()->accepted_neighbors() != neighbors_offset_) {
199 absl::StrAppendFormat(&log,
200 ", neighbors = %d, filtered neighbors = %d,"
201 " accepted neighbors = %d",
203 solver()->accepted_neighbors());
205 absl::StrAppendFormat(&log,
", %s", MemoryUsage());
208 absl::StrAppendFormat(&log,
", limit = %d%%", progress);
210 if (display_callback_) {
211 absl::StrAppendFormat(&log,
", %s", display_callback_());
223 std::string buffer = absl::StrFormat(
224 "Finished search tree (time = %d ms, branches = %d,"
226 absl::ToInt64Milliseconds(timer_->GetDuration()),
solver()->branches(),
228 if (
solver()->neighbors() != 0) {
229 absl::StrAppendFormat(&buffer,
230 ", neighbors = %d, filtered neighbors = %d,"
231 " accepted neigbors = %d",
233 solver()->accepted_neighbors());
235 absl::StrAppendFormat(&buffer,
", %s", MemoryUsage());
236 if (!display_on_new_solutions_only_ && display_callback_) {
237 absl::StrAppendFormat(&buffer,
", %s", display_callback_());
246 if (b % period_ == 0 && b > 0) {
252 min_right_depth_ = std::min(min_right_depth_,
solver()->SearchDepth());
257 std::string buffer = absl::StrFormat(
258 "%d branches, %d ms, %d failures",
solver()->branches(),
259 absl::ToInt64Milliseconds(timer_->GetDuration()),
solver()->failures());
260 if (min_right_depth_ != std::numeric_limits<int32_t>::max() &&
263 absl::StrAppendFormat(&buffer,
", tree pos=%d/%d/%d minref=%d max=%d",
264 sliding_min_depth_, depth, sliding_max_depth_,
265 min_right_depth_, max_depth_);
266 sliding_min_depth_ = depth;
267 sliding_max_depth_ = depth;
269 if (!objective_min_.empty() &&
270 objective_min_[0] != std::numeric_limits<int64_t>::max() &&
271 objective_max_[0] != std::numeric_limits<int64_t>::min()) {
272 const std::string name =
273 vars_name_.empty() ?
"" : absl::StrCat(
" ", vars_name_);
274 absl::StrAppendFormat(&buffer,
277 name, objective_min_[0], name, objective_max_[0]);
281 absl::StrAppendFormat(&buffer,
", limit = %d%%", progress);
288 sliding_min_depth_ = std::min(current_depth, sliding_min_depth_);
289 sliding_max_depth_ = std::max(current_depth, sliding_max_depth_);
290 max_depth_ = std::max(current_depth, max_depth_);
296 const int64_t delta = std::max<int64_t>(
297 absl::ToInt64Milliseconds(timer_->GetDuration() - tick_), 0);
298 const std::string buffer = absl::StrFormat(
299 "Root node processed (time = %d ms, constraints = %d, %s)", delta,
300 solver()->constraints(), MemoryUsage());
305 if (absl::GetFlag(FLAGS_cp_log_to_vlog)) {
312std::string SearchLog::MemoryUsage() {
313 static const int64_t kDisplayThreshold = 2;
314 static const int64_t kKiloByte = 1024;
315 static const int64_t kMegaByte = kKiloByte * kKiloByte;
316 static const int64_t kGigaByte = kMegaByte * kKiloByte;
318 if (memory_usage > kDisplayThreshold * kGigaByte) {
319 return absl::StrFormat(
"memory used = %.2lf GB",
320 memory_usage * 1.0 / kGigaByte);
321 }
else if (memory_usage > kDisplayThreshold * kMegaByte) {
322 return absl::StrFormat(
"memory used = %.2lf MB",
323 memory_usage * 1.0 / kMegaByte);
324 }
else if (memory_usage > kDisplayThreshold * kKiloByte) {
325 return absl::StrFormat(
"memory used = %2lf KB",
326 memory_usage * 1.0 / kKiloByte);
328 return absl::StrFormat(
"memory used = %d", memory_usage);
333 return MakeSearchLog(branch_period, std::vector<IntVar*>{},
nullptr);
337 return MakeSearchLog(branch_period, std::vector<IntVar*>{var},
nullptr);
341 int branch_period, std::function<std::string()> display_callback) {
343 std::move(display_callback));
347 int branch_period,
IntVar* var,
348 std::function<std::string()> display_callback) {
349 return MakeSearchLog(branch_period, std::vector<IntVar*>{var},
350 std::move(display_callback));
354 int branch_period, std::vector<IntVar*> vars,
355 std::function<std::string()> display_callback) {
357 std::move(display_callback),
true,
367 std::function<std::string()> display_callback) {
369 std::vector<double> scaling_factors(vars.size(), 1.0);
370 std::vector<double> offsets(vars.size(), 0.0);
372 this, std::move(vars), opt_var->
Name(), std::move(scaling_factors),
373 std::move(offsets), std::move(display_callback),
374 true, branch_period));
379 <<
"Either variables are empty or objective is nullptr.";
380 std::vector<IntVar*> vars =
parameters.objective !=
nullptr
383 std::vector<double> scaling_factors = std::move(
parameters.scaling_factors);
384 scaling_factors.resize(vars.size(), 1.0);
385 std::vector<double> offsets = std::move(
parameters.offsets);
386 offsets.resize(vars.size(), 0.0);
388 this, std::move(vars),
"", std::move(scaling_factors), std::move(offsets),
397 SearchTrace(
Solver*
const s,
const std::string& prefix)
399 ~SearchTrace()
override {}
401 void EnterSearch()
override {
402 LOG(INFO) << prefix_ <<
" EnterSearch(" << solver()->
SolveDepth() <<
")";
404 void RestartSearch()
override {
405 LOG(INFO) << prefix_ <<
" RestartSearch(" << solver()->
SolveDepth() <<
")";
407 void ExitSearch()
override {
408 LOG(INFO) << prefix_ <<
" ExitSearch(" << solver()->
SolveDepth() <<
")";
410 void BeginNextDecision(DecisionBuilder*
const b)
override {
411 LOG(INFO) << prefix_ <<
" BeginNextDecision(" <<
b <<
") ";
413 void EndNextDecision(DecisionBuilder*
const b, Decision*
const d)
override {
415 LOG(INFO) << prefix_ <<
" EndNextDecision(" <<
b <<
", " << d <<
") ";
417 LOG(INFO) << prefix_ <<
" EndNextDecision(" <<
b <<
") ";
420 void ApplyDecision(Decision*
const d)
override {
421 LOG(INFO) << prefix_ <<
" ApplyDecision(" << d <<
") ";
423 void RefuteDecision(Decision*
const d)
override {
424 LOG(INFO) << prefix_ <<
" RefuteDecision(" << d <<
") ";
426 void AfterDecision(Decision*
const d,
bool apply)
override {
427 LOG(INFO) << prefix_ <<
" AfterDecision(" << d <<
", " << apply <<
") ";
429 void BeginFail()
override {
430 LOG(INFO) << prefix_ <<
" BeginFail(" << solver()->
SearchDepth() <<
")";
432 void EndFail()
override {
433 LOG(INFO) << prefix_ <<
" EndFail(" << solver()->
SearchDepth() <<
")";
435 void BeginInitialPropagation()
override {
436 LOG(INFO) << prefix_ <<
" BeginInitialPropagation()";
438 void EndInitialPropagation()
override {
439 LOG(INFO) << prefix_ <<
" EndInitialPropagation()";
441 bool AtSolution()
override {
442 LOG(INFO) << prefix_ <<
" AtSolution()";
445 bool AcceptSolution()
override {
446 LOG(INFO) << prefix_ <<
" AcceptSolution()";
449 void NoMoreSolutions()
override {
450 LOG(INFO) << prefix_ <<
" NoMoreSolutions()";
453 std::string DebugString()
const override {
return "SearchTrace"; }
456 const std::string prefix_;
461 return RevAlloc(
new SearchTrace(
this, prefix));
468 AtSolutionCallback(
Solver*
const solver, std::function<
void()> callback)
470 ~AtSolutionCallback()
override {}
471 bool AtSolution()
override;
472 void Install()
override;
475 const std::function<void()> callback_;
478bool AtSolutionCallback::AtSolution() {
483void AtSolutionCallback::Install() {
484 ListenToEvent(Solver::MonitorEvent::kAtSolution);
490 return RevAlloc(
new AtSolutionCallback(
this, std::move(callback)));
496 EnterSearchCallback(
Solver*
const solver, std::function<
void()> callback)
498 ~EnterSearchCallback()
override {}
499 void EnterSearch()
override;
500 void Install()
override;
503 const std::function<void()> callback_;
506void EnterSearchCallback::EnterSearch() { callback_(); }
508void EnterSearchCallback::Install() {
509 ListenToEvent(Solver::MonitorEvent::kEnterSearch);
515 return RevAlloc(
new EnterSearchCallback(
this, std::move(callback)));
521 ExitSearchCallback(
Solver*
const solver, std::function<
void()> callback)
523 ~ExitSearchCallback()
override {}
524 void ExitSearch()
override;
525 void Install()
override;
528 const std::function<void()> callback_;
531void ExitSearchCallback::ExitSearch() { callback_(); }
533void ExitSearchCallback::Install() {
534 ListenToEvent(Solver::MonitorEvent::kExitSearch);
540 return RevAlloc(
new ExitSearchCallback(
this, std::move(callback)));
548 CompositeDecisionBuilder();
549 explicit CompositeDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs);
550 ~CompositeDecisionBuilder()
override;
552 void AppendMonitors(
Solver* solver,
553 std::vector<SearchMonitor*>* monitors)
override;
557 std::vector<DecisionBuilder*> builders_;
560CompositeDecisionBuilder::CompositeDecisionBuilder() {}
562CompositeDecisionBuilder::CompositeDecisionBuilder(
563 const std::vector<DecisionBuilder*>& dbs) {
564 for (
int i = 0;
i < dbs.size(); ++
i) {
569CompositeDecisionBuilder::~CompositeDecisionBuilder() {}
571void CompositeDecisionBuilder::Add(DecisionBuilder*
const db) {
573 builders_.push_back(db);
577void CompositeDecisionBuilder::AppendMonitors(
578 Solver*
const solver, std::vector<SearchMonitor*>*
const monitors) {
579 for (DecisionBuilder*
const db : builders_) {
580 db->AppendMonitors(solver, monitors);
584void CompositeDecisionBuilder::Accept(ModelVisitor*
const visitor)
const {
585 for (DecisionBuilder*
const db : builders_) {
594class ComposeDecisionBuilder :
public CompositeDecisionBuilder {
596 ComposeDecisionBuilder();
597 explicit ComposeDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs);
598 ~ComposeDecisionBuilder()
override;
599 Decision*
Next(Solver* s)
override;
600 std::string DebugString()
const override;
606ComposeDecisionBuilder::ComposeDecisionBuilder() : start_index_(0) {}
608ComposeDecisionBuilder::ComposeDecisionBuilder(
609 const std::vector<DecisionBuilder*>& dbs)
610 : CompositeDecisionBuilder(dbs), start_index_(0) {}
612ComposeDecisionBuilder::~ComposeDecisionBuilder() {}
614Decision* ComposeDecisionBuilder::Next(Solver*
const s) {
615 const int size = builders_.size();
616 for (
int i = start_index_;
i < size; ++
i) {
617 Decision* d = builders_[
i]->Next(s);
619 s->SaveAndSetValue(&start_index_, i);
623 s->SaveAndSetValue(&start_index_, size);
627std::string ComposeDecisionBuilder::DebugString()
const {
628 return absl::StrFormat(
"ComposeDecisionBuilder(%s)",
635 ComposeDecisionBuilder* c =
RevAlloc(
new ComposeDecisionBuilder());
644 ComposeDecisionBuilder* c =
RevAlloc(
new ComposeDecisionBuilder());
655 ComposeDecisionBuilder* c =
RevAlloc(
new ComposeDecisionBuilder());
664 if (dbs.size() == 1) {
667 return RevAlloc(
new ComposeDecisionBuilder(dbs));
673class ClosureDecision :
public Decision {
676 : apply_(
std::move(apply)), refute_(
std::move(refute)) {}
677 ~ClosureDecision()
override {}
679 void Apply(Solver*
const s)
override { apply_(s); }
681 void Refute(Solver*
const s)
override { refute_(s); }
683 std::string DebugString()
const override {
return "ClosureDecision"; }
686 Solver::Action apply_;
687 Solver::Action refute_;
692 return RevAlloc(
new ClosureDecision(std::move(apply), std::move(refute)));
699class TryDecisionBuilder;
701class TryDecision :
public Decision {
703 explicit TryDecision(TryDecisionBuilder* try_builder);
704 ~TryDecision()
override;
705 void Apply(
Solver* solver)
override;
706 void Refute(
Solver* solver)
override;
707 std::string DebugString()
const override {
return "TryDecision"; }
710 TryDecisionBuilder*
const try_builder_;
713class TryDecisionBuilder :
public CompositeDecisionBuilder {
715 TryDecisionBuilder();
716 explicit TryDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs);
717 ~TryDecisionBuilder()
override;
718 Decision*
Next(Solver* solver)
override;
719 std::string DebugString()
const override;
720 void AdvanceToNextBuilder(Solver* solver);
723 TryDecision try_decision_;
724 int current_builder_;
725 bool start_new_builder_;
728TryDecision::TryDecision(TryDecisionBuilder*
const try_builder)
729 : try_builder_(try_builder) {}
731TryDecision::~TryDecision() {}
733void TryDecision::Apply(Solver*
const) {}
735void TryDecision::Refute(Solver*
const solver) {
736 try_builder_->AdvanceToNextBuilder(solver);
739TryDecisionBuilder::TryDecisionBuilder()
740 : CompositeDecisionBuilder(),
742 current_builder_(-1),
743 start_new_builder_(
true) {}
745TryDecisionBuilder::TryDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs)
746 : CompositeDecisionBuilder(dbs),
748 current_builder_(-1),
749 start_new_builder_(
true) {}
751TryDecisionBuilder::~TryDecisionBuilder() {}
753Decision* TryDecisionBuilder::Next(Solver*
const solver) {
754 if (current_builder_ < 0) {
755 solver->SaveAndSetValue(¤t_builder_, 0);
756 start_new_builder_ =
true;
758 if (start_new_builder_) {
759 start_new_builder_ =
false;
760 return &try_decision_;
762 return builders_[current_builder_]->Next(solver);
766std::string TryDecisionBuilder::DebugString()
const {
767 return absl::StrFormat(
"TryDecisionBuilder(%s)",
771void TryDecisionBuilder::AdvanceToNextBuilder(Solver*
const solver) {
773 start_new_builder_ =
true;
774 if (current_builder_ >= builders_.size()) {
783 TryDecisionBuilder* try_db =
RevAlloc(
new TryDecisionBuilder());
792 TryDecisionBuilder* try_db =
RevAlloc(
new TryDecisionBuilder());
803 TryDecisionBuilder* try_db =
RevAlloc(
new TryDecisionBuilder());
812 return RevAlloc(
new TryDecisionBuilder(dbs));
820class BaseVariableAssignmentSelector :
public BaseObject {
822 BaseVariableAssignmentSelector(
Solver* solver,
823 const std::vector<IntVar*>& vars)
827 last_unbound_(vars.size() - 1) {}
829 ~BaseVariableAssignmentSelector()
override {}
831 virtual int64_t SelectValue(
const IntVar* v, int64_t
id) = 0;
834 virtual int64_t ChooseVariable() = 0;
836 int64_t ChooseVariableWrapper() {
838 for (i = first_unbound_.Value(); i <= last_unbound_.Value(); ++i) {
839 if (!vars_[i]->Bound()) {
843 first_unbound_.SetValue(solver_, i);
844 if (i > last_unbound_.Value()) {
847 for (i = last_unbound_.Value(); i >= first_unbound_.Value(); --i) {
848 if (!vars_[i]->Bound()) {
852 last_unbound_.SetValue(solver_, i);
853 return ChooseVariable();
856 void Accept(ModelVisitor*
const visitor)
const {
857 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
858 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
860 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
863 const std::vector<IntVar*>& vars()
const {
return vars_; }
866 Solver*
const solver_;
867 std::vector<IntVar*> vars_;
868 Rev<int64_t> first_unbound_;
869 Rev<int64_t> last_unbound_;
874int64_t ChooseFirstUnbound(Solver*,
const std::vector<IntVar*>& vars,
875 int64_t first_unbound, int64_t last_unbound) {
876 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
877 if (!vars[i]->Bound()) {
886int64_t ChooseMinSizeLowestMin(Solver*,
const std::vector<IntVar*>& vars,
887 int64_t first_unbound, int64_t last_unbound) {
888 uint64_t best_size = std::numeric_limits<uint64_t>::max();
889 int64_t best_min = std::numeric_limits<int64_t>::max();
890 int64_t best_index = -1;
891 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
892 IntVar*
const var = vars[
i];
894 if (var->Size() < best_size ||
895 (var->Size() == best_size && var->Min() < best_min)) {
896 best_size = var->Size();
897 best_min = var->Min();
907int64_t ChooseMinSizeHighestMin(Solver*,
const std::vector<IntVar*>& vars,
908 int64_t first_unbound, int64_t last_unbound) {
909 uint64_t best_size = std::numeric_limits<uint64_t>::max();
910 int64_t best_min = std::numeric_limits<int64_t>::min();
911 int64_t best_index = -1;
912 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
913 IntVar*
const var = vars[
i];
915 if (var->Size() < best_size ||
916 (var->Size() == best_size && var->Min() > best_min)) {
917 best_size = var->Size();
918 best_min = var->Min();
928int64_t ChooseMinSizeLowestMax(Solver*,
const std::vector<IntVar*>& vars,
929 int64_t first_unbound, int64_t last_unbound) {
930 uint64_t best_size = std::numeric_limits<uint64_t>::max();
931 int64_t best_max = std::numeric_limits<int64_t>::max();
932 int64_t best_index = -1;
933 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
934 IntVar*
const var = vars[
i];
936 if (var->Size() < best_size ||
937 (var->Size() == best_size && var->Max() < best_max)) {
938 best_size = var->Size();
939 best_max = var->Max();
949int64_t ChooseMinSizeHighestMax(Solver*,
const std::vector<IntVar*>& vars,
950 int64_t first_unbound, int64_t last_unbound) {
951 uint64_t best_size = std::numeric_limits<uint64_t>::max();
952 int64_t best_max = std::numeric_limits<int64_t>::min();
953 int64_t best_index = -1;
954 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
955 IntVar*
const var = vars[
i];
957 if (var->Size() < best_size ||
958 (var->Size() == best_size && var->Max() > best_max)) {
959 best_size = var->Size();
960 best_max = var->Max();
970int64_t ChooseLowestMin(Solver*,
const std::vector<IntVar*>& vars,
971 int64_t first_unbound, int64_t last_unbound) {
972 int64_t best_min = std::numeric_limits<int64_t>::max();
973 int64_t best_index = -1;
974 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
975 IntVar*
const var = vars[
i];
977 if (var->Min() < best_min) {
978 best_min = var->Min();
988int64_t ChooseHighestMax(Solver*,
const std::vector<IntVar*>& vars,
989 int64_t first_unbound, int64_t last_unbound) {
990 int64_t best_max = std::numeric_limits<int64_t>::min();
991 int64_t best_index = -1;
992 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
993 IntVar*
const var = vars[
i];
995 if (var->Max() > best_max) {
996 best_max = var->Max();
1006int64_t ChooseMinSize(Solver*,
const std::vector<IntVar*>& vars,
1007 int64_t first_unbound, int64_t last_unbound) {
1008 uint64_t best_size = std::numeric_limits<uint64_t>::max();
1009 int64_t best_index = -1;
1010 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
1011 IntVar*
const var = vars[
i];
1012 if (!var->Bound()) {
1013 if (var->Size() < best_size) {
1014 best_size = var->Size();
1024int64_t ChooseMaxSize(Solver*,
const std::vector<IntVar*>& vars,
1025 int64_t first_unbound, int64_t last_unbound) {
1026 uint64_t best_size = 0;
1027 int64_t best_index = -1;
1028 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
1029 IntVar*
const var = vars[
i];
1030 if (!var->Bound()) {
1031 if (var->Size() > best_size) {
1032 best_size = var->Size();
1042class HighestRegretSelectorOnMin :
public BaseObject {
1044 explicit HighestRegretSelectorOnMin(
const std::vector<IntVar*>& vars)
1045 : iterators_(vars.size()) {
1046 for (int64_t i = 0;
i < vars.size(); ++
i) {
1047 iterators_[
i] = vars[
i]->MakeDomainIterator(
true);
1050 ~HighestRegretSelectorOnMin()
override {};
1051 int64_t Choose(Solver* s,
const std::vector<IntVar*>& vars,
1052 int64_t first_unbound, int64_t last_unbound);
1053 std::string DebugString()
const override {
return "MaxRegretSelector"; }
1055 int64_t ComputeRegret(IntVar* var, int64_t index)
const {
1056 DCHECK(!var->Bound());
1057 const int64_t vmin = var->Min();
1058 IntVarIterator*
const iterator = iterators_[index];
1061 return iterator->Value() - vmin;
1065 std::vector<IntVarIterator*> iterators_;
1068int64_t HighestRegretSelectorOnMin::Choose(Solver*
const,
1069 const std::vector<IntVar*>& vars,
1070 int64_t first_unbound,
1071 int64_t last_unbound) {
1072 int64_t best_regret = 0;
1074 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
1075 IntVar*
const var = vars[
i];
1076 if (!var->Bound()) {
1077 const int64_t regret = ComputeRegret(var, i);
1078 if (regret > best_regret) {
1079 best_regret = regret;
1089int64_t ChooseRandom(Solver* solver,
const std::vector<IntVar*>& vars,
1090 int64_t first_unbound, int64_t last_unbound) {
1091 const int64_t span = last_unbound - first_unbound + 1;
1092 const int64_t shift = solver->Rand32(span);
1093 for (int64_t i = 0;
i < span; ++
i) {
1094 const int64_t index = (
i + shift) % span + first_unbound;
1095 if (!vars[index]->Bound()) {
1104class CheapestVarSelector :
public BaseObject {
1106 explicit CheapestVarSelector(std::function<int64_t(int64_t)> var_evaluator)
1107 : var_evaluator_(std::move(var_evaluator)) {}
1108 ~CheapestVarSelector()
override {};
1109 int64_t Choose(Solver* s,
const std::vector<IntVar*>& vars,
1110 int64_t first_unbound, int64_t last_unbound);
1111 std::string DebugString()
const override {
return "CheapestVarSelector"; }
1114 std::function<int64_t(int64_t)> var_evaluator_;
1117int64_t CheapestVarSelector::Choose(Solver*
const,
1118 const std::vector<IntVar*>& vars,
1119 int64_t first_unbound,
1120 int64_t last_unbound) {
1121 int64_t best_eval = std::numeric_limits<int64_t>::max();
1123 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
1124 if (!vars[i]->Bound()) {
1125 const int64_t eval = var_evaluator_(i);
1126 if (eval < best_eval) {
1138class PathSelector :
public BaseObject {
1140 PathSelector() : first_(std::numeric_limits<int64_t>::max()) {}
1141 ~PathSelector()
override {};
1142 int64_t Choose(Solver* s,
const std::vector<IntVar*>& vars);
1143 std::string DebugString()
const override {
return "ChooseNextOnPath"; }
1146 bool UpdateIndex(
const std::vector<IntVar*>& vars, int64_t* index)
const;
1147 bool FindPathStart(
const std::vector<IntVar*>& vars, int64_t* index)
const;
1149 Rev<int64_t> first_;
1152int64_t PathSelector::Choose(Solver*
const s,
1153 const std::vector<IntVar*>& vars) {
1154 int64_t index = first_.Value();
1155 if (!UpdateIndex(vars, &index)) {
1159 while (vars[index]->Bound()) {
1160 index = vars[index]->Value();
1161 if (!UpdateIndex(vars, &index)) {
1165 if (count >= vars.size() &&
1166 !FindPathStart(vars, &index)) {
1170 first_.SetValue(s, index);
1174bool PathSelector::UpdateIndex(
const std::vector<IntVar*>& vars,
1175 int64_t* index)
const {
1176 if (*index >= vars.size()) {
1177 if (!FindPathStart(vars, index)) {
1190bool PathSelector::FindPathStart(
const std::vector<IntVar*>& vars,
1191 int64_t* index)
const {
1193 for (int64_t i = vars.size() - 1; i >= 0; --i) {
1194 if (vars[i]->Bound()) {
1195 const int64_t next = vars[
i]->Value();
1196 if (next < vars.size() && !vars[next]->Bound()) {
1203 for (int64_t i = vars.size() - 1; i >= 0; --i) {
1204 if (!vars[i]->Bound()) {
1205 bool has_possible_prev =
false;
1206 for (int64_t j = 0; j < vars.size(); ++j) {
1207 if (vars[j]->Contains(i)) {
1208 has_possible_prev =
true;
1212 if (!has_possible_prev) {
1219 for (int64_t i = 0;
i < vars.size(); ++
i) {
1220 if (!vars[i]->Bound()) {
1230int64_t SelectMinValue(
const IntVar* v, int64_t) {
return v->Min(); }
1234int64_t SelectMaxValue(
const IntVar* v, int64_t) {
return v->Max(); }
1238int64_t SelectRandomValue(
const IntVar* v, int64_t) {
1239 const uint64_t span = v->Max() - v->Min() + 1;
1240 if (span > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {
1244 const uint64_t size = v->Size();
1245 Solver*
const s = v->solver();
1246 if (size > span / 4) {
1249 const int64_t value = v->Min() + s->Rand64(span);
1250 if (v->Contains(value)) {
1255 int64_t index = s->Rand64(size);
1256 if (index <= size / 2) {
1257 for (int64_t i = v->Min(); i <= v->Max(); ++
i) {
1258 if (v->Contains(i)) {
1266 for (int64_t i = v->Max(); i > v->Min(); --i) {
1267 if (v->Contains(i)) {
1281int64_t SelectCenterValue(
const IntVar* v, int64_t) {
1282 const int64_t vmin = v->Min();
1283 const int64_t vmax = v->Max();
1284 if (vmax - vmin > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {
1288 const int64_t mid = (vmin + vmax) / 2;
1289 if (v->Contains(mid)) {
1292 const int64_t diameter = vmax - mid;
1293 for (int64_t i = 1;
i <= diameter; ++
i) {
1294 if (v->Contains(mid - i)) {
1297 if (v->Contains(mid + i)) {
1306int64_t SelectSplitValue(
const IntVar* v, int64_t) {
1307 const int64_t vmin = v->Min();
1308 const int64_t vmax = v->Max();
1309 const uint64_t delta = vmax - vmin;
1310 const int64_t mid = vmin + delta / 2;
1316class CheapestValueSelector :
public BaseObject {
1318 CheapestValueSelector(std::function<int64_t(int64_t, int64_t)> eval,
1319 std::function<int64_t(int64_t)> tie_breaker)
1320 : eval_(std::move(eval)), tie_breaker_(std::move(tie_breaker)) {}
1321 ~CheapestValueSelector()
override {}
1322 int64_t Select(
const IntVar* v, int64_t
id);
1323 std::string DebugString()
const override {
return "CheapestValue"; }
1326 std::function<int64_t(int64_t, int64_t)> eval_;
1327 std::function<int64_t(int64_t)> tie_breaker_;
1328 std::vector<int64_t> cache_;
1331int64_t CheapestValueSelector::Select(
const IntVar* v, int64_t
id) {
1333 int64_t best = std::numeric_limits<int64_t>::max();
1334 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(
false));
1335 for (
const int64_t i : InitAndGetValues(it.get())) {
1336 int64_t eval = eval_(
id, i);
1340 cache_.push_back(i);
1341 }
else if (eval == best) {
1342 cache_.push_back(i);
1345 DCHECK_GT(cache_.size(), 0);
1346 if (tie_breaker_ ==
nullptr || cache_.size() == 1) {
1347 return cache_.back();
1349 return cache_[tie_breaker_(cache_.size())];
1361class BestValueByComparisonSelector :
public BaseObject {
1363 explicit BestValueByComparisonSelector(
1364 Solver::VariableValueComparator comparator)
1365 : comparator_(std::move(comparator)) {}
1366 ~BestValueByComparisonSelector()
override {}
1367 int64_t Select(
const IntVar* v, int64_t
id);
1368 std::string DebugString()
const override {
1369 return "BestValueByComparisonSelector";
1373 Solver::VariableValueComparator comparator_;
1376int64_t BestValueByComparisonSelector::Select(
const IntVar* v, int64_t
id) {
1377 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(
false));
1380 int64_t best_value = it->Value();
1381 for (it->Next(); it->Ok(); it->Next()) {
1382 const int64_t candidate_value = it->Value();
1383 if (comparator_(
id, candidate_value, best_value)) {
1384 best_value = candidate_value;
1392class VariableAssignmentSelector :
public BaseVariableAssignmentSelector {
1394 VariableAssignmentSelector(Solver* solver,
const std::vector<IntVar*>& vars,
1395 Solver::VariableIndexSelector var_selector,
1396 Solver::VariableValueSelector value_selector,
1397 const std::string& name)
1398 : BaseVariableAssignmentSelector(solver, vars),
1399 var_selector_(std::move(var_selector)),
1400 value_selector_(std::move(value_selector)),
1402 ~VariableAssignmentSelector()
override {}
1403 int64_t SelectValue(
const IntVar* var, int64_t
id)
override {
1404 return value_selector_(var,
id);
1406 int64_t ChooseVariable()
override {
1407 return var_selector_(solver_, vars_, first_unbound_.Value(),
1408 last_unbound_.Value());
1410 std::string DebugString()
const override;
1413 Solver::VariableIndexSelector var_selector_;
1414 Solver::VariableValueSelector value_selector_;
1415 const std::string name_;
1418std::string VariableAssignmentSelector::DebugString()
const {
1424class BaseEvaluatorSelector :
public BaseVariableAssignmentSelector {
1426 BaseEvaluatorSelector(Solver* solver,
const std::vector<IntVar*>& vars,
1427 std::function<int64_t(int64_t, int64_t)> evaluator);
1428 ~BaseEvaluatorSelector()
override {}
1432 Element() : var(0), value(0) {}
1433 Element(int64_t i, int64_t j) : var(
i), value(j) {}
1438 std::string DebugStringInternal(absl::string_view name)
const {
1442 std::function<int64_t(int64_t, int64_t)> evaluator_;
1445BaseEvaluatorSelector::BaseEvaluatorSelector(
1446 Solver* solver,
const std::vector<IntVar*>& vars,
1447 std::function<int64_t(int64_t, int64_t)> evaluator)
1448 : BaseVariableAssignmentSelector(solver, vars),
1449 evaluator_(std::move(evaluator)) {}
1453class DynamicEvaluatorSelector :
public BaseEvaluatorSelector {
1455 DynamicEvaluatorSelector(Solver* solver,
const std::vector<IntVar*>& vars,
1456 std::function<int64_t(int64_t, int64_t)> evaluator,
1457 std::function<int64_t(int64_t)> tie_breaker);
1458 ~DynamicEvaluatorSelector()
override {}
1459 int64_t SelectValue(
const IntVar* var, int64_t
id)
override;
1460 int64_t ChooseVariable()
override;
1461 std::string DebugString()
const override;
1465 std::function<int64_t(int64_t)> tie_breaker_;
1466 std::vector<Element> cache_;
1469DynamicEvaluatorSelector::DynamicEvaluatorSelector(
1470 Solver* solver,
const std::vector<IntVar*>& vars,
1471 std::function<int64_t(int64_t, int64_t)> evaluator,
1472 std::function<int64_t(int64_t)> tie_breaker)
1473 : BaseEvaluatorSelector(solver, vars, std::move(evaluator)),
1475 tie_breaker_(std::move(tie_breaker)) {}
1477int64_t DynamicEvaluatorSelector::SelectValue(
const IntVar*, int64_t) {
1478 return cache_[first_].value;
1481int64_t DynamicEvaluatorSelector::ChooseVariable() {
1482 int64_t best_evaluation = std::numeric_limits<int64_t>::max();
1484 for (int64_t i = 0;
i < vars_.size(); ++
i) {
1485 const IntVar*
const var = vars_[
i];
1486 if (!var->Bound()) {
1487 std::unique_ptr<IntVarIterator> it(var->MakeDomainIterator(
false));
1488 for (
const int64_t j : InitAndGetValues(it.get())) {
1489 const int64_t value = evaluator_(i, j);
1490 if (value < best_evaluation) {
1491 best_evaluation = value;
1493 cache_.push_back(Element(i, j));
1494 }
else if (value == best_evaluation && tie_breaker_) {
1495 cache_.push_back(Element(i, j));
1501 if (cache_.empty()) {
1505 if (tie_breaker_ ==
nullptr || cache_.size() == 1) {
1507 return cache_.front().var;
1509 first_ = tie_breaker_(cache_.size());
1510 return cache_[first_].var;
1514std::string DynamicEvaluatorSelector::DebugString()
const {
1515 return DebugStringInternal(
"AssignVariablesOnDynamicEvaluator");
1520class StaticEvaluatorSelector :
public BaseEvaluatorSelector {
1522 StaticEvaluatorSelector(
1523 Solver* solver,
const std::vector<IntVar*>& vars,
1524 const std::function<int64_t(int64_t, int64_t)>& evaluator);
1525 ~StaticEvaluatorSelector()
override {}
1526 int64_t SelectValue(
const IntVar* var, int64_t
id)
override;
1527 int64_t ChooseVariable()
override;
1528 std::string DebugString()
const override;
1533 explicit Compare(std::function<int64_t(int64_t, int64_t)> evaluator)
1534 : evaluator_(std::move(evaluator)) {}
1535 bool operator()(
const Element& lhs,
const Element& rhs)
const {
1536 const int64_t value_lhs =
Value(lhs);
1537 const int64_t value_rhs =
Value(rhs);
1538 return value_lhs < value_rhs ||
1539 (value_lhs == value_rhs &&
1540 (lhs.var < rhs.var ||
1541 (lhs.var == rhs.var && lhs.value < rhs.value)));
1543 int64_t
Value(
const Element& element)
const {
1544 return evaluator_(element.var, element.value);
1548 std::function<int64_t(int64_t, int64_t)> evaluator_;
1552 std::vector<Element> elements_;
1556StaticEvaluatorSelector::StaticEvaluatorSelector(
1557 Solver* solver,
const std::vector<IntVar*>& vars,
1558 const std::function<int64_t(int64_t, int64_t)>& evaluator)
1559 : BaseEvaluatorSelector(solver, vars, evaluator),
1563int64_t StaticEvaluatorSelector::SelectValue(
const IntVar*, int64_t) {
1564 return elements_[first_].value;
1567int64_t StaticEvaluatorSelector::ChooseVariable() {
1570 int64_t element_size = 0;
1571 for (int64_t i = 0;
i < vars_.size(); ++
i) {
1572 if (!vars_[i]->Bound()) {
1573 element_size += vars_[
i]->Size();
1576 elements_.resize(element_size);
1578 for (
int i = 0;
i < vars_.size(); ++
i) {
1579 const IntVar*
const var = vars_[
i];
1580 if (!var->Bound()) {
1581 std::unique_ptr<IntVarIterator> it(var->MakeDomainIterator(
false));
1582 for (
const int64_t value : InitAndGetValues(it.get())) {
1583 elements_[count++] = Element(i, value);
1588 std::sort(elements_.begin(), elements_.end(), comp_);
1589 solver_->SaveAndSetValue<int64_t>(&first_, 0);
1591 for (int64_t i = first_;
i < elements_.size(); ++
i) {
1592 const Element& element = elements_[
i];
1593 IntVar*
const var = vars_[element.var];
1594 if (!var->Bound() && var->Contains(element.value)) {
1595 solver_->SaveAndSetValue(&first_, i);
1599 solver_->SaveAndSetValue(&first_,
static_cast<int64_t
>(elements_.size()));
1603std::string StaticEvaluatorSelector::DebugString()
const {
1604 return DebugStringInternal(
"AssignVariablesOnStaticEvaluator");
1609class AssignOneVariableValue :
public Decision {
1611 AssignOneVariableValue(IntVar* v, int64_t val);
1612 ~AssignOneVariableValue()
override {}
1613 void Apply(Solver* s)
override;
1614 void Refute(Solver* s)
override;
1615 std::string DebugString()
const override;
1616 void Accept(DecisionVisitor*
const visitor)
const override {
1617 visitor->VisitSetVariableValue(var_, value_);
1625AssignOneVariableValue::AssignOneVariableValue(IntVar*
const v, int64_t val)
1626 : var_(v), value_(val) {}
1628std::string AssignOneVariableValue::DebugString()
const {
1629 return absl::StrFormat(
"[%s == %d] or [%s != %d]", var_->
DebugString(),
1633void AssignOneVariableValue::Apply(Solver*
const) { var_->
SetValue(value_); }
1635void AssignOneVariableValue::Refute(Solver*
const) {
1641 return RevAlloc(
new AssignOneVariableValue(var, val));
1647class AssignOneVariableValueOrFail :
public Decision {
1649 AssignOneVariableValueOrFail(
IntVar* v, int64_t value);
1650 ~AssignOneVariableValueOrFail()
override {}
1651 void Apply(Solver* s)
override;
1652 void Refute(Solver* s)
override;
1653 std::string DebugString()
const override;
1654 void Accept(DecisionVisitor*
const visitor)
const override {
1655 visitor->VisitSetVariableValue(var_, value_);
1660 const int64_t value_;
1663AssignOneVariableValueOrFail::AssignOneVariableValueOrFail(IntVar*
const v,
1665 : var_(v), value_(value) {}
1667std::string AssignOneVariableValueOrFail::DebugString()
const {
1668 return absl::StrFormat(
"[%s == %d] or fail", var_->
DebugString(), value_);
1671void AssignOneVariableValueOrFail::Apply(Solver*
const) {
1675void AssignOneVariableValueOrFail::Refute(Solver*
const s) { s->Fail(); }
1680 return RevAlloc(
new AssignOneVariableValueOrFail(var, value));
1686class AssignOneVariableValueDoNothing :
public Decision {
1688 AssignOneVariableValueDoNothing(
IntVar*
const v, int64_t value)
1689 : var_(v), value_(value) {}
1690 ~AssignOneVariableValueDoNothing()
override {}
1691 void Apply(Solver*
const)
override { var_->
SetValue(value_); }
1692 void Refute(Solver*
const)
override {}
1693 std::string DebugString()
const override {
1694 return absl::StrFormat(
"[%s == %d] or []", var_->
DebugString(), value_);
1696 void Accept(DecisionVisitor*
const visitor)
const override {
1697 visitor->VisitSetVariableValue(var_, value_);
1702 const int64_t value_;
1709 return RevAlloc(
new AssignOneVariableValueDoNothing(var, value));
1715class SplitOneVariable :
public Decision {
1717 SplitOneVariable(
IntVar* v, int64_t val,
bool start_with_lower_half);
1718 ~SplitOneVariable()
override {}
1719 void Apply(Solver* s)
override;
1720 void Refute(Solver* s)
override;
1721 std::string DebugString()
const override;
1722 void Accept(DecisionVisitor*
const visitor)
const override {
1723 visitor->VisitSplitVariableDomain(var_, value_, start_with_lower_half_);
1728 const int64_t value_;
1729 const bool start_with_lower_half_;
1732SplitOneVariable::SplitOneVariable(IntVar*
const v, int64_t val,
1733 bool start_with_lower_half)
1734 : var_(v), value_(val), start_with_lower_half_(start_with_lower_half) {}
1736std::string SplitOneVariable::DebugString()
const {
1737 if (start_with_lower_half_) {
1738 return absl::StrFormat(
"[%s <= %d]", var_->
DebugString(), value_);
1740 return absl::StrFormat(
"[%s >= %d]", var_->
DebugString(), value_);
1744void SplitOneVariable::Apply(Solver*
const) {
1745 if (start_with_lower_half_) {
1748 var_->
SetMin(value_ + 1);
1752void SplitOneVariable::Refute(Solver*
const) {
1753 if (start_with_lower_half_) {
1754 var_->
SetMin(value_ + 1);
1762 bool start_with_lower_half) {
1763 return RevAlloc(
new SplitOneVariable(var, val, start_with_lower_half));
1779class AssignVariablesValues :
public Decision {
1785 enum class RefutationBehavior { kForbidAssignment, kDoNothing, kFail };
1786 AssignVariablesValues(
1787 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values,
1788 RefutationBehavior refutation = RefutationBehavior::kForbidAssignment);
1789 ~AssignVariablesValues()
override {}
1790 void Apply(Solver* s)
override;
1791 void Refute(Solver* s)
override;
1792 std::string DebugString()
const override;
1793 void Accept(DecisionVisitor*
const visitor)
const override {
1794 for (
int i = 0;
i < vars_.size(); ++
i) {
1795 visitor->VisitSetVariableValue(vars_[i], values_[i]);
1799 virtual void Accept(ModelVisitor*
const visitor)
const {
1800 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
1801 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1803 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
1807 const std::vector<IntVar*> vars_;
1808 const std::vector<int64_t> values_;
1809 const RefutationBehavior refutation_;
1812AssignVariablesValues::AssignVariablesValues(
const std::vector<IntVar*>& vars,
1813 const std::vector<int64_t>& values,
1814 RefutationBehavior refutation)
1815 : vars_(vars), values_(values), refutation_(refutation) {}
1817std::string AssignVariablesValues::DebugString()
const {
1819 if (vars_.empty()) out +=
"do nothing";
1820 for (
int i = 0;
i < vars_.size(); ++
i) {
1821 absl::StrAppendFormat(&out,
"[%s == %d]", vars_[i]->DebugString(),
1824 switch (refutation_) {
1825 case RefutationBehavior::kForbidAssignment:
1826 out +=
" or forbid assignment";
1828 case RefutationBehavior::kDoNothing:
1829 out +=
" or do nothing";
1831 case RefutationBehavior::kFail:
1838void AssignVariablesValues::Apply(Solver*
const) {
1839 if (vars_.empty())
return;
1840 vars_[0]->FreezeQueue();
1841 for (
int i = 0;
i < vars_.size(); ++
i) {
1842 vars_[
i]->SetValue(values_[i]);
1844 vars_[0]->UnfreezeQueue();
1847void AssignVariablesValues::Refute(Solver*
const s) {
1848 switch (refutation_) {
1849 case RefutationBehavior::kForbidAssignment: {
1850 std::vector<IntVar*> terms;
1851 for (
int i = 0;
i < vars_.size(); ++
i) {
1852 IntVar* term = s->MakeBoolVar();
1853 s->AddConstraint(s->MakeIsDifferentCstCt(vars_[i], values_[i], term));
1854 terms.push_back(term);
1856 s->AddConstraint(s->MakeSumGreaterOrEqual(terms, 1));
1859 case RefutationBehavior::kDoNothing: {
1862 case RefutationBehavior::kFail: {
1871 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1872 CHECK_EQ(vars.size(), values.size());
1873 return RevAlloc(
new AssignVariablesValues(
1875 AssignVariablesValues::RefutationBehavior::kForbidAssignment));
1879 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1880 CHECK_EQ(vars.size(), values.size());
1881 return RevAlloc(
new AssignVariablesValues(
1882 vars, values, AssignVariablesValues::RefutationBehavior::kDoNothing));
1886 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1887 CHECK_EQ(vars.size(), values.size());
1888 return RevAlloc(
new AssignVariablesValues(
1889 vars, values, AssignVariablesValues::RefutationBehavior::kFail));
1903 BaseAssignVariables(BaseVariableAssignmentSelector*
const selector, Mode mode)
1904 : selector_(selector), mode_(mode) {}
1906 ~BaseAssignVariables()
override;
1907 Decision*
Next(Solver* s)
override;
1908 std::string DebugString()
const override;
1909 static BaseAssignVariables* MakePhase(
1910 Solver* s,
const std::vector<IntVar*>& vars,
1911 Solver::VariableIndexSelector var_selector,
1912 Solver::VariableValueSelector value_selector,
1913 const std::string& value_selector_name, BaseAssignVariables::Mode mode);
1915 static Solver::VariableIndexSelector MakeVariableSelector(
1916 Solver*
const s,
const std::vector<IntVar*>& vars,
1917 Solver::IntVarStrategy str) {
1919 case Solver::INT_VAR_DEFAULT:
1920 case Solver::INT_VAR_SIMPLE:
1921 case Solver::CHOOSE_FIRST_UNBOUND:
1922 return ChooseFirstUnbound;
1923 case Solver::CHOOSE_RANDOM:
1924 return ChooseRandom;
1925 case Solver::CHOOSE_MIN_SIZE_LOWEST_MIN:
1926 return ChooseMinSizeLowestMin;
1927 case Solver::CHOOSE_MIN_SIZE_HIGHEST_MIN:
1928 return ChooseMinSizeHighestMin;
1929 case Solver::CHOOSE_MIN_SIZE_LOWEST_MAX:
1930 return ChooseMinSizeLowestMax;
1931 case Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX:
1932 return ChooseMinSizeHighestMax;
1933 case Solver::CHOOSE_LOWEST_MIN:
1934 return ChooseLowestMin;
1935 case Solver::CHOOSE_HIGHEST_MAX:
1936 return ChooseHighestMax;
1937 case Solver::CHOOSE_MIN_SIZE:
1938 return ChooseMinSize;
1939 case Solver::CHOOSE_MAX_SIZE:
1940 return ChooseMaxSize;
1941 case Solver::CHOOSE_MAX_REGRET_ON_MIN: {
1942 HighestRegretSelectorOnMin*
const selector =
1943 s->RevAlloc(
new HighestRegretSelectorOnMin(vars));
1944 return [selector](Solver* solver,
const std::vector<IntVar*>& vars,
1945 int first_unbound,
int last_unbound) {
1946 return selector->Choose(solver, vars, first_unbound, last_unbound);
1949 case Solver::CHOOSE_PATH: {
1950 PathSelector*
const selector = s->RevAlloc(
new PathSelector());
1951 return [selector](Solver* solver,
const std::vector<IntVar*>& vars, int,
1952 int) {
return selector->Choose(solver, vars); };
1955 LOG(FATAL) <<
"Unknown int var strategy " << str;
1960 static Solver::VariableValueSelector MakeValueSelector(
1961 Solver*
const, Solver::IntValueStrategy val_str) {
1963 case Solver::INT_VALUE_DEFAULT:
1964 case Solver::INT_VALUE_SIMPLE:
1965 case Solver::ASSIGN_MIN_VALUE:
1966 return SelectMinValue;
1967 case Solver::ASSIGN_MAX_VALUE:
1968 return SelectMaxValue;
1969 case Solver::ASSIGN_RANDOM_VALUE:
1970 return SelectRandomValue;
1971 case Solver::ASSIGN_CENTER_VALUE:
1972 return SelectCenterValue;
1973 case Solver::SPLIT_LOWER_HALF:
1974 return SelectSplitValue;
1975 case Solver::SPLIT_UPPER_HALF:
1976 return SelectSplitValue;
1978 LOG(FATAL) <<
"Unknown int value strategy " << val_str;
1983 void Accept(ModelVisitor*
const visitor)
const override {
1984 selector_->Accept(visitor);
1988 BaseVariableAssignmentSelector*
const selector_;
1992BaseAssignVariables::~BaseAssignVariables() {}
1994Decision* BaseAssignVariables::Next(Solver*
const s) {
1995 const std::vector<IntVar*>& vars = selector_->vars();
1996 int id = selector_->ChooseVariableWrapper();
1997 if (
id >= 0 &&
id < vars.size()) {
1998 IntVar*
const var = vars[id];
1999 const int64_t value = selector_->SelectValue(var,
id);
2002 return s->RevAlloc(
new AssignOneVariableValue(var, value));
2004 return s->RevAlloc(
new SplitOneVariable(var, value,
true));
2006 return s->RevAlloc(
new SplitOneVariable(var, value,
false));
2012std::string BaseAssignVariables::DebugString()
const {
2013 return selector_->DebugString();
2016BaseAssignVariables* BaseAssignVariables::MakePhase(
2017 Solver*
const s,
const std::vector<IntVar*>& vars,
2020 const std::string& value_selector_name, BaseAssignVariables::Mode mode) {
2021 BaseVariableAssignmentSelector*
const selector =
2022 s->RevAlloc(
new VariableAssignmentSelector(
2023 s, vars, std::move(var_selector), std::move(value_selector),
2024 value_selector_name));
2025 return s->RevAlloc(
new BaseAssignVariables(selector, mode));
2033 return "ChooseFirstUnbound";
2035 return "ChooseRandom";
2037 return "ChooseMinSizeLowestMin";
2039 return "ChooseMinSizeHighestMin";
2041 return "ChooseMinSizeLowestMax";
2043 return "ChooseMinSizeHighestMax";
2045 return "ChooseLowestMin";
2047 return "ChooseHighestMax";
2049 return "ChooseMinSize";
2051 return "ChooseMaxSize;";
2053 return "HighestRegretSelectorOnMin";
2055 return "PathSelector";
2057 LOG(FATAL) <<
"Unknown int var strategy " << var_str;
2067 return "SelectMinValue";
2069 return "SelectMaxValue";
2071 return "SelectRandomValue";
2073 return "SelectCenterValue";
2075 return "SelectSplitValue";
2077 return "SelectSplitValue";
2079 LOG(FATAL) <<
"Unknown int value strategy " << val_str;
2086 return ChooseVariableName(var_str) +
"_" + SelectValueName(val_str);
2093 std::vector<IntVar*> vars(1);
2095 return MakePhase(vars, var_str, val_str);
2101 std::vector<IntVar*> vars(2);
2104 return MakePhase(vars, var_str, val_str);
2111 std::vector<IntVar*> vars(3);
2115 return MakePhase(vars, var_str, val_str);
2122 std::vector<IntVar*> vars(4);
2127 return MakePhase(vars, var_str, val_str);
2131 BaseAssignVariables::Mode mode = BaseAssignVariables::ASSIGN;
2133 mode = BaseAssignVariables::SPLIT_LOWER;
2135 mode = BaseAssignVariables::SPLIT_UPPER;
2143 return BaseAssignVariables::MakePhase(
2145 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str),
2146 BaseAssignVariables::MakeValueSelector(
this, val_str),
2147 BuildHeuristicsName(var_str, val_str),
2154 CHECK(var_evaluator !=
nullptr);
2155 CheapestVarSelector*
const var_selector =
2156 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2157 return BaseAssignVariables::MakePhase(
2160 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2161 int first_unbound,
int last_unbound) {
2162 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2164 BaseAssignVariables::MakeValueSelector(
this, val_str),
2165 "ChooseCheapestVariable_" +
2166 SelectValueName(val_str),
2173 CheapestValueSelector*
const value_selector =
2174 RevAlloc(
new CheapestValueSelector(std::move(value_evaluator),
nullptr));
2175 return BaseAssignVariables::MakePhase(
2178 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str),
2180 [value_selector](
const IntVar* var, int64_t
id) {
2181 return value_selector->Select(var,
id);
2183 ChooseVariableName(var_str) +
2184 "_SelectCheapestValue",
2185 BaseAssignVariables::ASSIGN);
2191 BestValueByComparisonSelector*
const value_selector =
RevAlloc(
2192 new BestValueByComparisonSelector(std::move(var_val1_val2_comparator)));
2193 return BaseAssignVariables::MakePhase(
2195 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str),
2197 [value_selector](
const IntVar* var, int64_t
id) {
2198 return value_selector->Select(var,
id);
2200 "CheapestValue", BaseAssignVariables::ASSIGN);
2206 CheapestVarSelector*
const var_selector =
2207 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2208 CheapestValueSelector* value_selector =
2209 RevAlloc(
new CheapestValueSelector(std::move(value_evaluator),
nullptr));
2210 return BaseAssignVariables::MakePhase(
2212 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2213 int first_unbound,
int last_unbound) {
2214 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2217 [value_selector](
const IntVar* var, int64_t id) {
2218 return value_selector->Select(var,
id);
2220 "CheapestValue", BaseAssignVariables::ASSIGN);
2227 CheapestValueSelector* value_selector =
RevAlloc(
new CheapestValueSelector(
2228 std::move(value_evaluator), std::move(tie_breaker)));
2229 return BaseAssignVariables::MakePhase(
2231 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str),
2233 [value_selector](
const IntVar* var, int64_t
id) {
2234 return value_selector->Select(var,
id);
2236 "CheapestValue", BaseAssignVariables::ASSIGN);
2243 CheapestVarSelector*
const var_selector =
2244 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2245 CheapestValueSelector* value_selector =
RevAlloc(
new CheapestValueSelector(
2246 std::move(value_evaluator), std::move(tie_breaker)));
2247 return BaseAssignVariables::MakePhase(
2249 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2250 int first_unbound,
int last_unbound) {
2251 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2254 [value_selector](
const IntVar* var, int64_t id) {
2255 return value_selector->Select(var,
id);
2257 "CheapestValue", BaseAssignVariables::ASSIGN);
2263 return MakePhase(vars, std::move(eval),
nullptr, str);
2270 BaseVariableAssignmentSelector* selector =
nullptr;
2275 RevAlloc(
new StaticEvaluatorSelector(
this, vars, std::move(eval)));
2279 selector =
RevAlloc(
new DynamicEvaluatorSelector(
2280 this, vars, std::move(eval), std::move(tie_breaker)));
2285 new BaseAssignVariables(selector, BaseAssignVariables::ASSIGN));
2293 AssignVariablesFromAssignment(
const Assignment*
const assignment,
2295 const std::vector<IntVar*>& vars)
2296 : assignment_(assignment), db_(db), vars_(vars), iter_(0) {}
2298 ~AssignVariablesFromAssignment()
override {}
2300 Decision*
Next(Solver*
const s)
override {
2301 if (iter_ < vars_.size()) {
2302 IntVar*
const var = vars_[iter_++];
2304 new AssignOneVariableValue(var, assignment_->
Value(var)));
2306 return db_->
Next(s);
2310 void Accept(ModelVisitor*
const visitor)
const override {
2311 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
2312 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2314 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
2318 const Assignment*
const assignment_;
2319 DecisionBuilder*
const db_;
2320 const std::vector<IntVar*> vars_;
2327 const std::vector<IntVar*>& vars) {
2328 return RevAlloc(
new AssignVariablesFromAssignment(assignment, db, vars));
2358 const auto other_fields =
2360 if (fields != other_fields)
return fields < other_fields;
2362 DCHECK_EQ(other.
solution,
nullptr);
2365 for (
int i = 0; i <
solution->NumObjectives(); ++i) {
2366 const int64_t value =
solution->ObjectiveValueFromIndex(i);
2368 if (value != other_value)
return value < other_value;
2414 if (
prototype_ !=
nullptr && objective !=
nullptr) {
2470 CHECK_GE(n, 0) <<
"wrong index in solution getter";
2471 CHECK_LT(n,
solution_data_.size()) <<
"wrong index in solution getter";
2554 explicit FirstSolutionCollector(
Solver* s);
2555 ~FirstSolutionCollector()
override;
2556 void EnterSearch()
override;
2557 bool AtSolution()
override;
2558 void Install()
override;
2559 std::string DebugString()
const override;
2565FirstSolutionCollector::FirstSolutionCollector(Solver*
const s,
2566 const Assignment*
const a)
2569FirstSolutionCollector::FirstSolutionCollector(
Solver*
const s)
2572FirstSolutionCollector::~FirstSolutionCollector() {}
2574void FirstSolutionCollector::EnterSearch() {
2575 SolutionCollector::EnterSearch();
2579bool FirstSolutionCollector::AtSolution() {
2587void FirstSolutionCollector::Install() {
2588 SolutionCollector::Install();
2589 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2592std::string FirstSolutionCollector::DebugString()
const {
2593 if (prototype_ ==
nullptr) {
2594 return "FirstSolutionCollector()";
2596 return "FirstSolutionCollector(" + prototype_->DebugString() +
")";
2603 return RevAlloc(
new FirstSolutionCollector(
this, assignment));
2607 return RevAlloc(
new FirstSolutionCollector(
this));
2617 explicit LastSolutionCollector(
Solver* s);
2618 ~LastSolutionCollector()
override;
2619 bool AtSolution()
override;
2620 void Install()
override;
2621 std::string DebugString()
const override;
2624LastSolutionCollector::LastSolutionCollector(Solver*
const s,
2625 const Assignment*
const a)
2626 : SolutionCollector(s, a) {}
2628LastSolutionCollector::LastSolutionCollector(
Solver*
const s)
2631LastSolutionCollector::~LastSolutionCollector() {}
2633bool LastSolutionCollector::AtSolution() {
2639void LastSolutionCollector::Install() {
2640 SolutionCollector::Install();
2641 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2644std::string LastSolutionCollector::DebugString()
const {
2645 if (prototype_ ==
nullptr) {
2646 return "LastSolutionCollector()";
2648 return "LastSolutionCollector(" + prototype_->DebugString() +
")";
2655 return RevAlloc(
new LastSolutionCollector(
this, assignment));
2659 return RevAlloc(
new LastSolutionCollector(
this));
2668 std::vector<bool> maximize);
2669 BestValueSolutionCollector(
Solver* solver, std::vector<bool> maximize);
2670 ~BestValueSolutionCollector()
override {}
2671 void EnterSearch()
override;
2672 bool AtSolution()
override;
2673 void Install()
override;
2674 std::string DebugString()
const override;
2677 void ResetBestObjective() {
2678 for (
int i = 0; i < maximize_.size(); ++i) {
2679 best_[i] = maximize_[i] ? std::numeric_limits<int64_t>::min()
2680 :
std::numeric_limits<int64_t>::max();
2684 const std::vector<bool> maximize_;
2685 std::vector<int64_t> best_;
2688BestValueSolutionCollector::BestValueSolutionCollector(
2689 Solver* solver,
const Assignment* assignment, std::vector<bool> maximize)
2690 : SolutionCollector(solver, assignment),
2691 maximize_(std::move(maximize)),
2692 best_(maximize_.size()) {
2693 ResetBestObjective();
2696BestValueSolutionCollector::BestValueSolutionCollector(
2697 Solver* solver, std::vector<bool> maximize)
2699 maximize_(std::move(maximize)),
2700 best_(maximize_.size()) {
2701 ResetBestObjective();
2704void BestValueSolutionCollector::EnterSearch() {
2705 SolutionCollector::EnterSearch();
2706 ResetBestObjective();
2709bool BestValueSolutionCollector::AtSolution() {
2710 if (prototype_ !=
nullptr && prototype_->HasObjective()) {
2711 const int size = std::min(prototype_->NumObjectives(),
2712 static_cast<int>(maximize_.size()));
2715 bool is_improvement =
false;
2716 for (
int i = 0;
i < size; ++
i) {
2717 const IntVar* objective = prototype_->ObjectiveFromIndex(i);
2718 const int64_t objective_value =
2719 maximize_[
i] ?
CapOpp(objective->Max()) : objective->Min();
2720 if (objective_value < best_[i]) {
2721 is_improvement =
true;
2723 }
else if (objective_value > best_[i]) {
2727 if (solution_count() == 0 || is_improvement) {
2730 for (
int i = 0;
i < size; ++
i) {
2731 best_[
i] = maximize_[
i]
2732 ?
CapOpp(prototype_->ObjectiveFromIndex(i)->Max())
2733 : prototype_->ObjectiveFromIndex(
i)->Min();
2740void BestValueSolutionCollector::Install() {
2741 SolutionCollector::Install();
2742 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2745std::string BestValueSolutionCollector::DebugString()
const {
2746 if (prototype_ ==
nullptr) {
2747 return "BestValueSolutionCollector()";
2749 return "BestValueSolutionCollector(" + prototype_->DebugString() +
")";
2755 const Assignment*
const assignment,
bool maximize) {
2756 return RevAlloc(
new BestValueSolutionCollector(
this, assignment, {maximize}));
2760 const Assignment* assignment, std::vector<bool> maximize) {
2762 new BestValueSolutionCollector(
this, assignment, std::move(maximize)));
2766 return RevAlloc(
new BestValueSolutionCollector(
this, {maximize}));
2770 std::vector<bool> maximize) {
2771 return RevAlloc(
new BestValueSolutionCollector(
this, std::move(maximize)));
2780 int solution_count, std::vector<bool> maximize);
2781 NBestValueSolutionCollector(
Solver* solver,
int solution_count,
2782 std::vector<bool> maximize);
2783 ~NBestValueSolutionCollector()
override { Clear(); }
2784 void EnterSearch()
override;
2785 void ExitSearch()
override;
2786 bool AtSolution()
override;
2787 void Install()
override;
2788 std::string DebugString()
const override;
2793 const std::vector<bool> maximize_;
2794 std::priority_queue<std::pair<std::vector<int64_t>, SolutionData>>
2796 const int solution_count_;
2799NBestValueSolutionCollector::NBestValueSolutionCollector(
2800 Solver* solver,
const Assignment* assignment,
int solution_count,
2801 std::vector<bool> maximize)
2802 : SolutionCollector(solver, assignment),
2803 maximize_(std::move(maximize)),
2804 solution_count_(solution_count) {}
2806NBestValueSolutionCollector::NBestValueSolutionCollector(
2807 Solver* solver,
int solution_count, std::vector<bool> maximize)
2809 maximize_(std::move(maximize)),
2810 solution_count_(solution_count) {}
2812void NBestValueSolutionCollector::EnterSearch() {
2813 SolutionCollector::EnterSearch();
2816 if (solution_count_ > 1) {
2817 solver()->SetUseFastLocalSearch(
false);
2822void NBestValueSolutionCollector::ExitSearch() {
2823 while (!solutions_pq_.empty()) {
2824 Push(solutions_pq_.top().second);
2825 solutions_pq_.pop();
2829bool NBestValueSolutionCollector::AtSolution() {
2830 if (prototype_ !=
nullptr && prototype_->HasObjective()) {
2831 const int size = std::min(prototype_->NumObjectives(),
2832 static_cast<int>(maximize_.size()));
2833 std::vector<int64_t> objective_values(size);
2834 for (
int i = 0;
i < size; ++
i) {
2835 objective_values[
i] =
2836 maximize_[
i] ?
CapOpp(prototype_->ObjectiveFromIndex(i)->Max())
2837 : prototype_->ObjectiveFromIndex(
i)->Min();
2839 if (solutions_pq_.size() < solution_count_) {
2841 {std::move(objective_values), BuildSolutionDataForCurrentState()});
2842 }
else if (!solutions_pq_.empty()) {
2843 const auto& [top_obj_value, top_sol_data] = solutions_pq_.top();
2844 if (std::lexicographical_compare(
2845 objective_values.begin(), objective_values.end(),
2846 top_obj_value.begin(), top_obj_value.end())) {
2847 FreeSolution(top_sol_data.solution);
2848 solutions_pq_.pop();
2850 {std::move(objective_values), BuildSolutionDataForCurrentState()});
2857void NBestValueSolutionCollector::Install() {
2858 SolutionCollector::Install();
2859 ListenToEvent(Solver::MonitorEvent::kExitSearch);
2860 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2863std::string NBestValueSolutionCollector::DebugString()
const {
2864 if (prototype_ ==
nullptr) {
2865 return "NBestValueSolutionCollector()";
2867 return "NBestValueSolutionCollector(" + prototype_->DebugString() +
")";
2871void NBestValueSolutionCollector::Clear() {
2872 while (!solutions_pq_.empty()) {
2873 delete solutions_pq_.top().second.solution;
2874 solutions_pq_.pop();
2881 const Assignment* assignment,
int solution_count,
bool maximize) {
2882 if (solution_count == 1) {
2885 return RevAlloc(
new NBestValueSolutionCollector(
this, assignment,
2886 solution_count, {maximize}));
2891 if (solution_count == 1) {
2895 new NBestValueSolutionCollector(
this, solution_count, {maximize}));
2899 const Assignment* assignment,
int solution_count,
2900 std::vector<bool> maximize) {
2901 if (solution_count == 1) {
2903 std::move(maximize));
2905 return RevAlloc(
new NBestValueSolutionCollector(
2906 this, assignment, solution_count, std::move(maximize)));
2910 int solution_count, std::vector<bool> maximize) {
2911 if (solution_count == 1) {
2914 return RevAlloc(
new NBestValueSolutionCollector(
this, solution_count,
2915 std::move(maximize)));
2924 explicit AllSolutionCollector(
Solver* s);
2925 ~AllSolutionCollector()
override;
2926 bool AtSolution()
override;
2927 void Install()
override;
2928 std::string DebugString()
const override;
2931AllSolutionCollector::AllSolutionCollector(Solver*
const s,
2932 const Assignment*
const a)
2933 : SolutionCollector(s, a) {}
2935AllSolutionCollector::AllSolutionCollector(
Solver*
const s)
2938AllSolutionCollector::~AllSolutionCollector() {}
2940bool AllSolutionCollector::AtSolution() {
2945void AllSolutionCollector::Install() {
2946 SolutionCollector::Install();
2947 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2950std::string AllSolutionCollector::DebugString()
const {
2951 if (prototype_ ==
nullptr) {
2952 return "AllSolutionCollector()";
2954 return "AllSolutionCollector(" + prototype_->DebugString() +
")";
2961 return RevAlloc(
new AllSolutionCollector(
this, assignment));
2965 return RevAlloc(
new AllSolutionCollector(
this));
2973 std::vector<BaseObjectiveMonitor*> monitors,
2974 int num_max_local_optima_before_metaheuristic_switch)
2976 monitors_(
std::move(monitors)),
2977 enabled_monitors_(monitors_.size(), true),
2978 local_optimum_limit_(num_max_local_optima_before_metaheuristic_switch) {
2981 active_monitor_ = 0;
2982 num_local_optimum_ = 0;
2983 enabled_monitors_.assign(monitors_.size(),
true);
2984 for (
auto& monitor : monitors_) {
2985 monitor->set_active(monitor == monitors_[active_monitor_]);
2986 monitor->EnterSearch();
2990 monitors_[active_monitor_]->ApplyDecision(d);
2993 monitors_[active_monitor_]->AcceptNeighbor();
2997 for (
auto& monitor : monitors_) {
2998 ok &= monitor->AtSolution();
3003 return monitors_[active_monitor_]->AcceptDelta(delta, deltadelta);
3006 monitors_[active_monitor_]->BeginNextDecision(db);
3009 monitors_[active_monitor_]->RefuteDecision(d);
3012 return monitors_[active_monitor_]->AcceptSolution();
3015 const bool ok = monitors_[active_monitor_]->LocalOptimum();
3017 enabled_monitors_[active_monitor_] =
false;
3019 if (++num_local_optimum_ >= local_optimum_limit_ || !ok) {
3020 monitors_[active_monitor_]->set_active(
false);
3021 int next_active_monitor = (active_monitor_ + 1) % monitors_.size();
3022 while (!enabled_monitors_[next_active_monitor]) {
3023 if (next_active_monitor == active_monitor_)
return false;
3024 next_active_monitor = (active_monitor_ + 1) % monitors_.size();
3026 active_monitor_ = next_active_monitor;
3027 monitors_[active_monitor_]->set_active(
true);
3028 num_local_optimum_ = 0;
3029 VLOG(2) <<
"Switching to monitor " << active_monitor_ <<
" "
3030 << monitors_[active_monitor_]->DebugString();
3035 return monitors_[active_monitor_]->ObjectiveVar(index);
3038 return monitors_[active_monitor_]->MinimizationVar(index);
3040 int64_t
Step(
int index)
const override {
3041 return monitors_[active_monitor_]->Step(index);
3044 return monitors_[active_monitor_]->Maximize(index);
3047 return monitors_[active_monitor_]->BestValue(index);
3049 int Size()
const override {
return monitors_[active_monitor_]->Size(); }
3051 return monitors_[active_monitor_]->DebugString();
3055 for (
auto& monitor : monitors_) {
3056 monitor->Accept(visitor);
3061 const std::vector<BaseObjectiveMonitor*> monitors_;
3062 std::vector<bool> enabled_monitors_;
3063 int active_monitor_ = 0;
3064 int num_local_optimum_ = 0;
3065 const int local_optimum_limit_;
3069 std::vector<BaseObjectiveMonitor*> monitors,
3070 int num_max_local_optima_before_metaheuristic_switch) {
3072 std::move(monitors), num_max_local_optima_before_metaheuristic_switch));
3076 const std::vector<bool>& maximize,
3077 std::vector<IntVar*> vars,
3078 std::vector<int64_t> steps)
3081 objective_vars_(
std::move(vars)),
3082 minimization_vars_(objective_vars_),
3083 upper_bounds_(
Size() + 1, nullptr),
3084 steps_(
std::move(steps)),
3085 best_values_(
Size(),
std::numeric_limits<int64_t>::max()),
3086 current_values_(
Size(),
std::numeric_limits<int64_t>::max()) {
3087 DCHECK_GT(
Size(), 0);
3088 DCHECK_EQ(objective_vars_.size(), steps_.size());
3089 DCHECK_EQ(objective_vars_.size(), maximize.size());
3090 DCHECK(std::all_of(steps_.begin(), steps_.end(),
3091 [](int64_t step) { return step > 0; }));
3092 for (
int i = 0; i <
Size(); ++i) {
3094 minimization_vars_[i] =
solver->MakeOpposite(objective_vars_[i])->Var();
3098 minimization_vars_.push_back(
solver->MakeIntConst(1));
3099 upper_bounds_.back() =
solver->MakeIntConst(0);
3100 steps_.push_back(1);
3111 best_values_.assign(
Size(), std::numeric_limits<int64_t>::max());
3112 current_values_ = best_values_;
3117 for (
int i = 0; i <
Size(); ++i) {
3124 if (std::lexicographical_compare(current_values_.begin(),
3125 current_values_.end(), best_values_.begin(),
3126 best_values_.end())) {
3127 best_values_ = current_values_;
3134 if (delta ==
nullptr)
return true;
3135 const bool delta_has_objective = delta->
HasObjective();
3136 if (!delta_has_objective) {
3141 for (
int i = 0; i <
Size(); ++i) {
3145 if (delta_has_objective) {
3148 if (
solver()->UseFastLocalSearch() &&
3149 i < local_search_state->NumObjectives()) {
3157 if (delta_has_objective) {
3160 if (
solver()->UseFastLocalSearch() &&
3161 i < local_search_state->NumObjectives()) {
3179 minimization_vars_);
3184 int num_values_at_max = 0;
3185 for (
int i = 0; i <
Size(); ++i) {
3187 DCHECK_EQ(num_values_at_max, 0);
3189 ++num_values_at_max;
3192 DCHECK(num_values_at_max == 0 || num_values_at_max ==
Size());
3193 return num_values_at_max <
Size();
3199 std::vector<IntVar*>{var}, {step}) {}
3202 std::vector<IntVar*> vars, std::vector<int64_t> steps)
3206 if (
solver()->SearchDepth() == 0) {
3227 for (
int i = 0; i <
Size(); ++i) {
3231 if (!minimization_var->
Bound())
return true;
3232 const int64_t value = minimization_var->
Value();
3249 for (
int i = 0; i <
Size(); ++i) {
3250 absl::StrAppendFormat(
3251 &out,
"%s%s(%s, step = %d, best = %d)", i == 0 ?
"" :
"; ",
3252 Maximize(i) ?
"MaximizeVar" :
"MinimizeVar",
3272 std::vector<IntVar*> variables,
3273 std::vector<int64_t> steps) {
3275 std::move(variables), std::move(steps)));
3281 WeightedOptimizeVar(
Solver* solver,
bool maximize,
3282 const std::vector<IntVar*>& sub_objectives,
3283 const std::vector<int64_t>& weights, int64_t step)
3285 solver->MakeScalProd(sub_objectives, weights)->Var(), step),
3286 sub_objectives_(sub_objectives),
3288 CHECK_EQ(sub_objectives.size(), weights.size());
3291 ~WeightedOptimizeVar()
override {}
3292 std::string Name()
const override;
3295 const std::vector<IntVar*> sub_objectives_;
3296 const std::vector<int64_t> weights_;
3299std::string WeightedOptimizeVar::Name()
const {
return "weighted objective"; }
3303 bool maximize,
const std::vector<IntVar*>& sub_objectives,
3304 const std::vector<int64_t>& weights, int64_t step) {
3306 new WeightedOptimizeVar(
this, maximize, sub_objectives, weights, step));
3310 const std::vector<IntVar*>& sub_objectives,
3311 const std::vector<int64_t>& weights, int64_t step) {
3313 new WeightedOptimizeVar(
this,
false, sub_objectives, weights, step));
3317 const std::vector<IntVar*>& sub_objectives,
3318 const std::vector<int64_t>& weights, int64_t step) {
3320 new WeightedOptimizeVar(
this,
true, sub_objectives, weights, step));
3324 bool maximize,
const std::vector<IntVar*>& sub_objectives,
3325 const std::vector<int>& weights, int64_t step) {
3331 const std::vector<IntVar*>& sub_objectives,
const std::vector<int>& weights,
3337 const std::vector<IntVar*>& sub_objectives,
const std::vector<int>& weights,
3347 Metaheuristic(
Solver* solver,
const std::vector<bool>& maximize,
3348 std::vector<IntVar*> objectives, std::vector<int64_t> steps);
3349 ~Metaheuristic()
override {}
3351 void EnterSearch()
override;
3352 void RefuteDecision(Decision* d)
override;
3355Metaheuristic::Metaheuristic(Solver* solver,
const std::vector<bool>& maximize,
3356 std::vector<IntVar*> objectives,
3357 std::vector<int64_t> steps)
3358 : ObjectiveMonitor(solver, maximize, std::move(objectives),
3359 std::move(steps)) {}
3361void Metaheuristic::EnterSearch() {
3362 ObjectiveMonitor::EnterSearch();
3365 solver()->SetUseFastLocalSearch(
false);
3368void Metaheuristic::RefuteDecision(Decision*) {
3369 for (
int i = 0;
i < Size(); ++
i) {
3370 const int64_t objective_value = MinimizationVar(i)->Min();
3371 if (objective_value > BestInternalValue(i))
break;
3372 if (objective_value <=
CapSub(BestInternalValue(i), Step(i)))
return;
3379class TabuSearch :
public Metaheuristic {
3381 TabuSearch(Solver* solver,
const std::vector<bool>& maximize,
3382 std::vector<IntVar*> objectives, std::vector<int64_t> steps,
3383 const std::vector<IntVar*>& vars, int64_t keep_tenure,
3384 int64_t forbid_tenure,
double tabu_factor);
3385 ~TabuSearch()
override {}
3386 void EnterSearch()
override;
3387 void ApplyDecision(Decision* d)
override;
3388 bool AtSolution()
override;
3389 bool LocalOptimum()
override;
3390 bool AcceptDelta(Assignment* delta, Assignment* deltadelta)
override;
3392 std::string DebugString()
const override {
return "Tabu Search"; }
3400 typedef std::list<VarValue> TabuList;
3402 virtual std::vector<IntVar*> CreateTabuVars();
3403 const TabuList& forbid_tabu_list() {
return forbid_tabu_list_; }
3404 IntVar* vars(
int index)
const {
return vars_[index]; }
3407 void AgeList(int64_t tenure, TabuList* list);
3409 int64_t TabuLimit()
const {
3410 return (synced_keep_tabu_list_.size() + synced_forbid_tabu_list_.size()) *
3414 const std::vector<IntVar*> vars_;
3415 Assignment::IntContainer assignment_container_;
3416 bool has_stored_assignment_ =
false;
3417 std::vector<int64_t> last_values_;
3418 TabuList keep_tabu_list_;
3419 TabuList synced_keep_tabu_list_;
3420 int64_t keep_tenure_;
3421 TabuList forbid_tabu_list_;
3422 TabuList synced_forbid_tabu_list_;
3423 int64_t forbid_tenure_;
3424 double tabu_factor_;
3428TabuSearch::TabuSearch(Solver* solver,
const std::vector<bool>& maximize,
3429 std::vector<IntVar*> objectives,
3430 std::vector<int64_t> steps,
3431 const std::vector<IntVar*>& vars, int64_t keep_tenure,
3432 int64_t forbid_tenure,
double tabu_factor)
3433 : Metaheuristic(solver, maximize, std::move(objectives), std::move(steps)),
3435 last_values_(Size(), std::numeric_limits<int64_t>::max()),
3436 keep_tenure_(keep_tenure),
3437 forbid_tenure_(forbid_tenure),
3438 tabu_factor_(tabu_factor),
3440 for (
int index = 0; index < vars_.size(); ++index) {
3441 assignment_container_.FastAdd(vars_[index]);
3442 DCHECK_EQ(vars_[index], assignment_container_.Element(index).Var());
3446void TabuSearch::EnterSearch() {
3447 Metaheuristic::EnterSearch();
3448 solver()->SetUseFastLocalSearch(
true);
3450 has_stored_assignment_ =
false;
3453void TabuSearch::ApplyDecision(Decision*
const d) {
3454 Solver*
const s = solver();
3455 if (d == s->balancing_decision()) {
3459 synced_keep_tabu_list_ = keep_tabu_list_;
3460 synced_forbid_tabu_list_ = forbid_tabu_list_;
3461 Constraint* tabu_ct =
nullptr;
3465 const std::vector<IntVar*> tabu_vars = CreateTabuVars();
3466 if (!tabu_vars.empty()) {
3467 IntVar* tabu_var = s->MakeIsGreaterOrEqualCstVar(
3468 s->MakeSum(tabu_vars)->Var(), TabuLimit());
3471 IntVar* aspiration = MakeMinimizationVarsLessOrEqualWithStepsStatus(
3472 [
this](
int i) {
return BestInternalValue(i); });
3473 tabu_ct = s->MakeSumGreaterOrEqual({aspiration, tabu_var}, int64_t{1});
3476 if (tabu_ct !=
nullptr) s->AddConstraint(tabu_ct);
3479 if (CurrentInternalValuesAreConstraining()) {
3480 MakeMinimizationVarsLessOrEqualWithSteps(
3481 [
this](
int i) {
return CurrentInternalValue(i); });
3484 if (found_initial_solution_) {
3485 Constraint* plateau_ct =
nullptr;
3487 plateau_ct = s->MakeNonEquality(MinimizationVar(0), last_values_[0]);
3489 std::vector<IntVar*> plateau_vars(Size());
3490 for (
int i = 0;
i < Size(); ++
i) {
3492 s->MakeIsEqualCstVar(MinimizationVar(i), last_values_[i]);
3494 plateau_ct = s->MakeSumLessOrEqual(plateau_vars, Size() - 1);
3496 s->AddConstraint(plateau_ct);
3500std::vector<IntVar*> TabuSearch::CreateTabuVars() {
3501 Solver*
const s = solver();
3509 std::vector<IntVar*> tabu_vars;
3510 for (
const auto [var_index, value, unused_stamp] : keep_tabu_list_) {
3511 tabu_vars.push_back(s->MakeIsEqualCstVar(vars(var_index), value));
3513 for (
const auto [var_index, value, unused_stamp] : forbid_tabu_list_) {
3514 tabu_vars.push_back(s->MakeIsDifferentCstVar(vars(var_index), value));
3519bool TabuSearch::AtSolution() {
3520 if (!ObjectiveMonitor::AtSolution()) {
3523 for (
int i = 0;
i < Size(); ++
i) {
3524 last_values_[
i] = CurrentInternalValue(i);
3529 if (0 != stamp_ && has_stored_assignment_) {
3530 for (
int index = 0; index < vars_.size(); ++index) {
3531 IntVar* var = vars(index);
3532 const int64_t old_value = assignment_container_.
Element(index).
Value();
3533 const int64_t new_value = var->Value();
3534 if (old_value != new_value) {
3535 if (keep_tenure_ > 0) {
3536 keep_tabu_list_.push_front({index, new_value, stamp_});
3538 if (forbid_tenure_ > 0) {
3539 forbid_tabu_list_.push_front({index, old_value, stamp_});
3544 assignment_container_.
Store();
3545 has_stored_assignment_ =
true;
3550bool TabuSearch::LocalOptimum() {
3551 solver()->SetUseFastLocalSearch(
false);
3553 for (
int i = 0;
i < Size(); ++
i) {
3554 SetCurrentInternalValue(i, std::numeric_limits<int64_t>::max());
3556 return found_initial_solution_;
3559bool TabuSearch::AcceptDelta(Assignment* delta, Assignment* deltadelta) {
3560 if (delta ==
nullptr)
return true;
3561 if (!Metaheuristic::AcceptDelta(delta, deltadelta))
return false;
3562 if (synced_keep_tabu_list_.empty() && synced_forbid_tabu_list_.empty()) {
3565 const Assignment::IntContainer& delta_container = delta->IntVarContainer();
3567 for (
const IntVarElement& element : delta_container.elements()) {
3568 if (!element.Bound())
return true;
3570 int num_respected = 0;
3572 auto get_value = [
this, &delta_container](
int var_index) {
3573 const IntVarElement* element =
3574 delta_container.ElementPtrOrNull(vars(var_index));
3575 return (element !=
nullptr)
3579 for (
const auto [var_index, value, unused_stamp] : synced_keep_tabu_list_) {
3580 if (get_value(var_index) == value) {
3584 for (
const auto [var_index, value, unused_stamp] : synced_forbid_tabu_list_) {
3585 if (get_value(var_index) != value) {
3589 const int64_t tabu_limit = TabuLimit();
3590 if (num_respected >= tabu_limit)
return true;
3595 delta->SetObjectiveMinFromIndex(0,
CapAdd(BestInternalValue(0), Step(0)));
3597 delta->SetObjectiveMaxFromIndex(0,
CapSub(BestInternalValue(0), Step(0)));
3600 for (
int i = 0;
i < Size(); ++
i) {
3602 delta->SetObjectiveMinFromIndex(i, BestInternalValue(i));
3604 delta->SetObjectiveMaxFromIndex(i, BestInternalValue(i));
3612void TabuSearch::AcceptNeighbor() {
3618void TabuSearch::AgeList(int64_t tenure, TabuList* list) {
3619 while (!list->empty() && list->back().stamp < stamp_ - tenure) {
3624void TabuSearch::AgeLists() {
3625 AgeList(keep_tenure_, &keep_tabu_list_);
3626 AgeList(forbid_tenure_, &forbid_tabu_list_);
3630class GenericTabuSearch :
public TabuSearch {
3632 GenericTabuSearch(Solver* solver,
bool maximize, IntVar* objective,
3633 int64_t step,
const std::vector<IntVar*>& vars,
3634 int64_t forbid_tenure)
3635 : TabuSearch(solver, {maximize}, {objective}, {step}, vars, 0,
3636 forbid_tenure, 1) {}
3637 std::string DebugString()
const override {
return "Generic Tabu Search"; }
3640 std::vector<IntVar*> CreateTabuVars()
override;
3643std::vector<IntVar*> GenericTabuSearch::CreateTabuVars() {
3644 Solver*
const s = solver();
3648 std::vector<IntVar*> forbid_values;
3649 for (
const auto [var_index, value, unused_stamp] : forbid_tabu_list()) {
3650 forbid_values.push_back(s->MakeIsDifferentCstVar(vars(var_index), value));
3652 std::vector<IntVar*> tabu_vars;
3653 if (!forbid_values.empty()) {
3654 tabu_vars.push_back(s->MakeIsGreaterCstVar(s->MakeSum(forbid_values), 0));
3663 const std::vector<IntVar*>& vars,
3664 int64_t keep_tenure,
3665 int64_t forbid_tenure,
3666 double tabu_factor) {
3667 return RevAlloc(
new TabuSearch(
this, {maximize}, {objective}, {step}, vars,
3668 keep_tenure, forbid_tenure, tabu_factor));
3672 const std::vector<bool>& maximize, std::vector<IntVar*> objectives,
3673 std::vector<int64_t> steps,
const std::vector<IntVar*>& vars,
3674 int64_t keep_tenure, int64_t forbid_tenure,
double tabu_factor) {
3675 return RevAlloc(
new TabuSearch(
this, maximize, std::move(objectives),
3676 std::move(steps), vars, keep_tenure,
3677 forbid_tenure, tabu_factor));
3681 bool maximize,
IntVar*
const v, int64_t step,
3682 const std::vector<IntVar*>& tabu_vars, int64_t forbid_tenure) {
3684 new GenericTabuSearch(
this, maximize, v, step, tabu_vars, forbid_tenure));
3690class SimulatedAnnealing :
public Metaheuristic {
3692 SimulatedAnnealing(
Solver* solver,
const std::vector<bool>& maximize,
3693 std::vector<IntVar*> objectives,
3694 std::vector<int64_t> steps,
3695 std::vector<int64_t> initial_temperatures);
3696 ~SimulatedAnnealing()
override {}
3697 void ApplyDecision(Decision* d)
override;
3698 bool LocalOptimum()
override;
3699 void AcceptNeighbor()
override;
3700 std::string DebugString()
const override {
return "Simulated Annealing"; }
3703 double Temperature(
int index)
const {
3704 return iteration_ > 0
3705 ? (1.0 * temperature0_[index]) / iteration_
3709 const std::vector<int64_t> temperature0_;
3714SimulatedAnnealing::SimulatedAnnealing(
3715 Solver* solver,
const std::vector<bool>& maximize,
3716 std::vector<IntVar*> objectives, std::vector<int64_t> steps,
3717 std::vector<int64_t> initial_temperatures)
3718 : Metaheuristic(solver, maximize, std::move(objectives), std::move(steps)),
3719 temperature0_(std::move(initial_temperatures)),
3736void SimulatedAnnealing::ApplyDecision(
Decision*
const d) {
3737 Solver*
const s = solver();
3738 if (d == s->balancing_decision()) {
3741 if (CurrentInternalValuesAreConstraining()) {
3742 MakeMinimizationVarsLessOrEqualWithSteps([
this](
int i) {
3743 const double rand_double = absl::Uniform<double>(rand_, 0.0, 1.0);
3744#if defined(_MSC_VER) || defined(__ANDROID__)
3745 const double rand_log2_double = log(rand_double) / log(2.0L);
3747 const double rand_log2_double = log2(rand_double);
3749 const int64_t energy_bound = Temperature(i) * rand_log2_double;
3752 return CapSub(CurrentInternalValue(i), energy_bound);
3757bool SimulatedAnnealing::LocalOptimum() {
3758 for (
int i = 0;
i < Size(); ++
i) {
3759 SetCurrentInternalValue(i, std::numeric_limits<int64_t>::max());
3762 if (!found_initial_solution_)
return false;
3763 for (
int i = 0;
i < Size(); ++
i) {
3764 if (Temperature(i) <= 0)
return false;
3769void SimulatedAnnealing::AcceptNeighbor() {
3770 if (iteration_ > 0) {
3778 int64_t initial_temperature) {
3779 return RevAlloc(
new SimulatedAnnealing(
this, {maximize}, {v}, {step},
3780 {initial_temperature}));
3784 const std::vector<bool>& maximize, std::vector<IntVar*> vars,
3785 std::vector<int64_t> steps, std::vector<int64_t> initial_temperatures) {
3786 return RevAlloc(
new SimulatedAnnealing(
this, maximize, std::move(vars),
3788 std::move(initial_temperatures)));
3798class GuidedLocalSearchPenaltiesTable {
3804 explicit GuidedLocalSearchPenaltiesTable(
int num_vars);
3805 bool HasPenalties()
const {
return has_values_; }
3806 void IncrementPenalty(
const VarValue& var_value);
3807 int64_t GetPenalty(
const VarValue& var_value)
const;
3811 std::vector<std::vector<int64_t>> penalties_;
3815GuidedLocalSearchPenaltiesTable::GuidedLocalSearchPenaltiesTable(
int num_vars)
3816 : penalties_(num_vars), has_values_(
false) {}
3818void GuidedLocalSearchPenaltiesTable::IncrementPenalty(
3819 const VarValue& var_value) {
3820 std::vector<int64_t>& var_penalties = penalties_[var_value.var];
3821 const int64_t value = var_value.value;
3822 if (value >= var_penalties.size()) {
3823 var_penalties.resize(value + 1, 0);
3825 ++var_penalties[value];
3829void GuidedLocalSearchPenaltiesTable::Reset() {
3830 has_values_ =
false;
3831 for (
int i = 0;
i < penalties_.size(); ++
i) {
3832 penalties_[
i].clear();
3836int64_t GuidedLocalSearchPenaltiesTable::GetPenalty(
3837 const VarValue& var_value)
const {
3838 const std::vector<int64_t>& var_penalties = penalties_[var_value.var];
3839 const int64_t value = var_value.value;
3840 return (value >= var_penalties.size()) ? 0 : var_penalties[value];
3844class GuidedLocalSearchPenaltiesMap {
3850 friend bool operator==(
const VarValue& lhs,
const VarValue& rhs) {
3851 return lhs.var == rhs.var && lhs.value == rhs.value;
3853 template <
typename H>
3855 return H::combine(std::move(h), var_value.var, var_value.value);
3858 explicit GuidedLocalSearchPenaltiesMap(
int num_vars);
3859 bool HasPenalties()
const {
return (!penalties_.empty()); }
3860 void IncrementPenalty(
const VarValue& var_value);
3861 int64_t GetPenalty(
const VarValue& var_value)
const;
3866 absl::flat_hash_map<VarValue, int64_t> penalties_;
3869GuidedLocalSearchPenaltiesMap::GuidedLocalSearchPenaltiesMap(
int num_vars)
3870 : penalized_(num_vars,
false) {}
3872void GuidedLocalSearchPenaltiesMap::IncrementPenalty(
3873 const VarValue& var_value) {
3874 ++penalties_[var_value];
3875 penalized_.
Set(var_value.var,
true);
3878void GuidedLocalSearchPenaltiesMap::Reset() {
3883int64_t GuidedLocalSearchPenaltiesMap::GetPenalty(
3884 const VarValue& var_value)
const {
3885 return (penalized_.
Get(var_value.var))
3890template <
typename P>
3891class GuidedLocalSearch :
public Metaheuristic {
3894 Solver* solver, IntVar* objective,
bool maximize, int64_t step,
3895 const std::vector<IntVar*>& vars,
double penalty_factor,
3896 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
3897 get_equivalent_pairs,
3898 bool reset_penalties_on_new_best_solution);
3899 ~GuidedLocalSearch()
override {}
3900 bool AcceptDelta(Assignment* delta, Assignment* deltadelta)
override;
3901 void ApplyDecision(Decision* d)
override;
3902 bool AtSolution()
override;
3903 void EnterSearch()
override;
3904 bool LocalOptimum()
override;
3905 virtual int64_t AssignmentElementPenalty(
int index)
const = 0;
3906 virtual int64_t AssignmentPenalty(int64_t var, int64_t value)
const = 0;
3907 virtual int64_t Evaluate(
const Assignment* delta, int64_t current_penalty,
3908 bool incremental) = 0;
3909 virtual IntExpr* MakeElementPenalty(
int index) = 0;
3910 std::string DebugString()
const override {
return "Guided Local Search"; }
3916 template <
typename T,
typename IndexType =
int64_t>
3919 explicit DirtyArray(IndexType size)
3920 : base_data_(size), modified_data_(size), touched_(size) {}
3923 void Set(IndexType i,
const T& value) {
3924 modified_data_[
i] = value;
3928 void SetAll(
const T& value) {
3929 for (IndexType i = 0;
i < modified_data_.size(); ++
i) {
3934 T Get(IndexType i)
const {
return modified_data_[
i]; }
3938 for (
const IndexType index : touched_.PositionsSetAtLeastOnce()) {
3939 base_data_[index] = modified_data_[index];
3941 touched_.SparseClearAll();
3945 for (
const IndexType index : touched_.PositionsSetAtLeastOnce()) {
3946 modified_data_[index] = base_data_[index];
3948 touched_.SparseClearAll();
3952 int NumSetValues()
const {
3953 return touched_.NumberOfSetCallsWithDifferentArguments();
3957 std::vector<T> base_data_;
3958 std::vector<T> modified_data_;
3959 SparseBitset<IndexType> touched_;
3962 int64_t GetValue(int64_t index)
const {
3965 IntVar* GetVar(int64_t index)
const {
3968 void AddVars(
const std::vector<IntVar*>& vars);
3969 int NumPrimaryVars()
const {
return num_vars_; }
3970 int GetLocalIndexFromVar(IntVar* var)
const {
3971 const int var_index = var->index();
3972 return (var_index < var_index_to_local_index_.size())
3973 ? var_index_to_local_index_[var_index]
3976 void ResetPenalties();
3978 IntVar* penalized_objective_;
3979 Assignment::IntContainer assignment_;
3980 int64_t assignment_penalized_value_;
3981 int64_t old_penalized_value_;
3982 const int num_vars_;
3983 std::vector<int> var_index_to_local_index_;
3984 const double penalty_factor_;
3986 DirtyArray<int64_t> penalized_values_;
3988 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
3989 get_equivalent_pairs_;
3990 const bool reset_penalties_on_new_best_solution_;
3993template <
typename P>
3995 Solver* solver, IntVar* objective,
bool maximize, int64_t step,
3996 const std::vector<IntVar*>& vars,
double penalty_factor,
3997 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
3998 get_equivalent_pairs,
3999 bool reset_penalties_on_new_best_solution)
4000 : Metaheuristic(solver, {maximize}, {objective}, {step}),
4001 penalized_objective_(
nullptr),
4002 assignment_penalized_value_(0),
4003 old_penalized_value_(0),
4004 num_vars_(vars.size()),
4005 penalty_factor_(penalty_factor),
4006 penalties_(vars.size()),
4007 penalized_values_(vars.size()),
4008 incremental_(
false),
4009 get_equivalent_pairs_(std::move(get_equivalent_pairs)),
4010 reset_penalties_on_new_best_solution_(
4011 reset_penalties_on_new_best_solution) {
4015template <
typename P>
4017 const int offset = assignment_.Size();
4018 if (vars.empty())
return;
4019 assignment_.Resize(offset + vars.size());
4020 for (
int i = 0;
i < vars.size(); ++
i) {
4021 assignment_.AddAtPosition(vars[i], offset + i);
4023 const int max_var_index =
4024 (*std::max_element(vars.begin(), vars.end(), [](
IntVar* a,
IntVar* b) {
4025 return a->index() < b->index();
4027 if (max_var_index >= var_index_to_local_index_.size()) {
4028 var_index_to_local_index_.resize(max_var_index + 1, -1);
4030 for (
int i = 0;
i < vars.size(); ++
i) {
4031 var_index_to_local_index_[vars[
i]->index()] = offset +
i;
4042template <
typename P>
4044 if (d == solver()->balancing_decision()) {
4047 assignment_penalized_value_ = 0;
4048 if (penalties_.HasPenalties()) {
4052 std::vector<IntVar*> elements;
4053 for (
int i = 0;
i < num_vars_; ++
i) {
4054 elements.push_back(MakeElementPenalty(i)->Var());
4055 const int64_t penalty = AssignmentElementPenalty(i);
4056 penalized_values_.Set(i, penalty);
4057 assignment_penalized_value_ =
4058 CapAdd(assignment_penalized_value_, penalty);
4060 solver()->SaveAndSetValue(
4061 reinterpret_cast<void**
>(&penalized_objective_),
4062 reinterpret_cast<void*
>(solver()->MakeSum(elements)->Var()));
4064 penalized_values_.Commit();
4065 old_penalized_value_ = assignment_penalized_value_;
4066 incremental_ =
false;
4067 IntExpr* max_pen_exp = solver()->MakeDifference(
4068 CapSub(CurrentInternalValue(0), Step(0)), penalized_objective_);
4071 ->MakeMax(max_pen_exp,
CapSub(BestInternalValue(0), Step(0)))
4073 solver()->AddConstraint(
4074 solver()->MakeLessOrEqual(MinimizationVar(0), max_exp));
4076 penalized_objective_ =
nullptr;
4077 const int64_t
bound =
4078 (CurrentInternalValue(0) < std::numeric_limits<int64_t>::max())
4079 ?
CapSub(CurrentInternalValue(0), Step(0))
4080 : CurrentInternalValue(0);
4081 MinimizationVar(0)->SetMax(bound);
4085template <
typename P>
4087 assignment_penalized_value_ = 0;
4088 old_penalized_value_ = 0;
4089 penalized_values_.SetAll(0);
4090 penalized_values_.Commit();
4094template <
typename P>
4096 const int64_t old_best = BestInternalValue(0);
4100 if (penalized_objective_ !=
nullptr && penalized_objective_->Bound()) {
4105 if (reset_penalties_on_new_best_solution_ &&
4106 old_best != BestInternalValue(0)) {
4108 DCHECK_EQ(CurrentInternalValue(0), BestInternalValue(0));
4111 SetCurrentInternalValue(
4112 0,
CapAdd(CurrentInternalValue(0), penalized_objective_->Value()));
4115 assignment_.Store();
4119template <
typename P>
4121 Metaheuristic::EnterSearch();
4122 solver()->SetUseFastLocalSearch(
true);
4123 penalized_objective_ =
nullptr;
4129template <
typename P>
4132 if (delta ==
nullptr && deltadelta ==
nullptr)
return true;
4133 if (!penalties_.HasPenalties()) {
4134 return Metaheuristic::AcceptDelta(delta, deltadelta);
4136 int64_t penalty = 0;
4137 if (!deltadelta->Empty()) {
4138 if (!incremental_) {
4139 DCHECK_EQ(penalized_values_.NumSetValues(), 0);
4140 penalty = Evaluate(delta, assignment_penalized_value_,
true);
4142 penalty = Evaluate(deltadelta, old_penalized_value_,
true);
4144 incremental_ =
true;
4147 penalized_values_.Revert();
4149 incremental_ =
false;
4150 DCHECK_EQ(penalized_values_.NumSetValues(), 0);
4151 penalty = Evaluate(delta, assignment_penalized_value_,
false);
4153 old_penalized_value_ = penalty;
4154 if (!delta->HasObjective()) {
4155 delta->AddObjective(ObjectiveVar(0));
4157 if (delta->Objective() == ObjectiveVar(0)) {
4158 const int64_t
bound =
4159 std::max(
CapSub(
CapSub(CurrentInternalValue(0), Step(0)), penalty),
4160 CapSub(BestInternalValue(0), Step(0)));
4162 delta->SetObjectiveMin(std::max(
CapOpp(bound), delta->ObjectiveMin()));
4164 delta->SetObjectiveMax(std::min(bound, delta->ObjectiveMax()));
4172template <
typename P>
4174 solver()->SetUseFastLocalSearch(
false);
4175 std::vector<double> utilities(num_vars_);
4176 double max_utility = -std::numeric_limits<double>::infinity();
4177 for (
int var = 0; var < num_vars_; ++var) {
4179 if (!element.Bound()) {
4183 const int64_t value = element.Value();
4186 const int64_t cost = (value != var) ? AssignmentPenalty(var, value) : 0;
4187 const double utility = cost / (penalties_.GetPenalty({var, value}) + 1.0);
4188 utilities[var] = utility;
4189 if (utility > max_utility) max_utility = utility;
4191 for (
int var = 0; var < num_vars_; ++var) {
4192 if (utilities[var] == max_utility) {
4194 DCHECK(element.Bound());
4195 const int64_t value = element.Value();
4196 if (get_equivalent_pairs_ ==
nullptr) {
4197 penalties_.IncrementPenalty({var, value});
4199 for (
const auto [other_var, other_value] :
4200 get_equivalent_pairs_(var, value)) {
4201 penalties_.IncrementPenalty({other_var, other_value});
4206 SetCurrentInternalValue(0, std::numeric_limits<int64_t>::max());
4210template <
typename P>
4213 BinaryGuidedLocalSearch(
4214 Solver* solver, IntVar* objective,
4215 std::function<int64_t(int64_t, int64_t)> objective_function,
4216 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
4217 double penalty_factor,
4218 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4219 get_equivalent_pairs,
4220 bool reset_penalties_on_new_best_solution);
4221 ~BinaryGuidedLocalSearch()
override {}
4222 IntExpr* MakeElementPenalty(
int index)
override;
4223 int64_t AssignmentElementPenalty(
int index)
const override;
4224 int64_t AssignmentPenalty(int64_t var, int64_t value)
const override;
4225 int64_t Evaluate(
const Assignment* delta, int64_t current_penalty,
4226 bool incremental)
override;
4229 int64_t PenalizedValue(int64_t i, int64_t j)
const;
4230 std::function<int64_t(int64_t, int64_t)> objective_function_;
4233template <
typename P>
4234BinaryGuidedLocalSearch<P>::BinaryGuidedLocalSearch(
4236 std::function<int64_t(int64_t, int64_t)> objective_function,
bool maximize,
4237 int64_t step,
const std::vector<IntVar*>& vars,
double penalty_factor,
4238 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4239 get_equivalent_pairs,
4240 bool reset_penalties_on_new_best_solution)
4242 penalty_factor, std::move(get_equivalent_pairs),
4243 reset_penalties_on_new_best_solution),
4244 objective_function_(std::move(objective_function)) {
4245 solver->SetGuidedLocalSearchPenaltyCallback(
4246 [
this](int64_t i, int64_t j, int64_t) {
return PenalizedValue(i, j); });
4249template <
typename P>
4250IntExpr* BinaryGuidedLocalSearch<P>::MakeElementPenalty(
int index) {
4251 return this->solver()->MakeElement(
4252 [
this, index](int64_t i) {
return PenalizedValue(index, i); },
4253 this->GetVar(index));
4256template <
typename P>
4257int64_t BinaryGuidedLocalSearch<P>::AssignmentElementPenalty(
int index)
const {
4258 return PenalizedValue(index, this->GetValue(index));
4261template <
typename P>
4262int64_t BinaryGuidedLocalSearch<P>::AssignmentPenalty(int64_t var,
4263 int64_t value)
const {
4264 return objective_function_(var, value);
4267template <
typename P>
4268int64_t BinaryGuidedLocalSearch<P>::Evaluate(
const Assignment* delta,
4269 int64_t current_penalty,
4271 int64_t penalty = current_penalty;
4273 for (
const IntVarElement& new_element : container.elements()) {
4274 const int index = this->GetLocalIndexFromVar(new_element.Var());
4275 if (index == -1)
continue;
4276 penalty =
CapSub(penalty, this->penalized_values_.Get(index));
4277 if (new_element.Activated()) {
4278 const int64_t new_penalty = PenalizedValue(index, new_element.Value());
4279 penalty =
CapAdd(penalty, new_penalty);
4281 this->penalized_values_.Set(index, new_penalty);
4289template <
typename P>
4290int64_t BinaryGuidedLocalSearch<P>::PenalizedValue(int64_t i, int64_t j)
const {
4291 const int64_t penalty = this->penalties_.GetPenalty({
i, j});
4293 if (penalty == 0)
return 0;
4294 const double penalized_value_fp =
4295 this->penalty_factor_ * penalty * objective_function_(i, j);
4296 const int64_t penalized_value =
4297 (penalized_value_fp <= std::numeric_limits<int64_t>::max())
4298 ?
static_cast<int64_t
>(penalized_value_fp)
4299 : std::numeric_limits<int64_t>::max();
4300 return penalized_value;
4303template <
typename P>
4306 TernaryGuidedLocalSearch(
4307 Solver* solver, IntVar* objective,
4308 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
4309 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
4310 const std::vector<IntVar*>& secondary_vars,
double penalty_factor,
4311 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4312 get_equivalent_pairs,
4313 bool reset_penalties_on_new_best_solution);
4314 ~TernaryGuidedLocalSearch()
override {}
4315 IntExpr* MakeElementPenalty(
int index)
override;
4316 int64_t AssignmentElementPenalty(
int index)
const override;
4317 int64_t AssignmentPenalty(int64_t var, int64_t value)
const override;
4318 int64_t Evaluate(
const Assignment* delta, int64_t current_penalty,
4319 bool incremental)
override;
4322 int64_t PenalizedValue(int64_t i, int64_t j, int64_t k)
const;
4324 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function_;
4325 std::vector<int> secondary_values_;
4328template <
typename P>
4329TernaryGuidedLocalSearch<P>::TernaryGuidedLocalSearch(
4331 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
4332 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
4333 const std::vector<IntVar*>& secondary_vars,
double penalty_factor,
4334 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4335 get_equivalent_pairs,
4336 bool reset_penalties_on_new_best_solution)
4338 penalty_factor, std::move(get_equivalent_pairs),
4339 reset_penalties_on_new_best_solution),
4340 objective_function_(std::move(objective_function)),
4341 secondary_values_(this->NumPrimaryVars(), -1) {
4342 this->AddVars(secondary_vars);
4343 solver->SetGuidedLocalSearchPenaltyCallback(
4344 [
this](int64_t i, int64_t j, int64_t k) {
4345 return PenalizedValue(i, j, k);
4349template <
typename P>
4350IntExpr* TernaryGuidedLocalSearch<P>::MakeElementPenalty(
int index) {
4351 Solver*
const solver = this->solver();
4353 solver->AddConstraint(solver->MakeLightElement(
4354 [
this, index](int64_t j, int64_t k) {
4355 return PenalizedValue(index, j, k);
4357 var, this->GetVar(index), this->GetVar(this->NumPrimaryVars() + index)));
4361template <
typename P>
4362int64_t TernaryGuidedLocalSearch<P>::AssignmentElementPenalty(
int index)
const {
4363 return PenalizedValue(index, this->GetValue(index),
4364 this->GetValue(this->NumPrimaryVars() + index));
4367template <
typename P>
4368int64_t TernaryGuidedLocalSearch<P>::AssignmentPenalty(int64_t var,
4369 int64_t value)
const {
4370 return objective_function_(var, value,
4371 this->GetValue(this->NumPrimaryVars() + var));
4374template <
typename P>
4375int64_t TernaryGuidedLocalSearch<P>::Evaluate(
const Assignment* delta,
4376 int64_t current_penalty,
4378 int64_t penalty = current_penalty;
4383 for (
const IntVarElement& new_element : container.elements()) {
4384 const int index = this->GetLocalIndexFromVar(new_element.Var());
4385 if (index != -1 && index < this->NumPrimaryVars()) {
4386 secondary_values_[index] = -1;
4389 for (
const IntVarElement& new_element : container.elements()) {
4390 const int index = this->GetLocalIndexFromVar(new_element.Var());
4391 if (!new_element.Activated())
continue;
4392 if (index != -1 && index >= this->NumPrimaryVars()) {
4393 secondary_values_[index - this->NumPrimaryVars()] = new_element.Value();
4396 for (
const IntVarElement& new_element : container.elements()) {
4397 const int index = this->GetLocalIndexFromVar(new_element.Var());
4399 if (index == -1 || index >= this->NumPrimaryVars()) {
4402 penalty =
CapSub(penalty, this->penalized_values_.Get(index));
4404 if (new_element.Activated() && secondary_values_[index] != -1) {
4405 const int64_t new_penalty =
4406 PenalizedValue(index, new_element.Value(), secondary_values_[index]);
4407 penalty =
CapAdd(penalty, new_penalty);
4409 this->penalized_values_.Set(index, new_penalty);
4417template <
typename P>
4418int64_t TernaryGuidedLocalSearch<P>::PenalizedValue(int64_t i, int64_t j,
4420 const int64_t penalty = this->penalties_.GetPenalty({
i, j});
4422 if (penalty == 0)
return 0;
4423 const double penalized_value_fp =
4424 this->penalty_factor_ * penalty * objective_function_(i, j, k);
4425 const int64_t penalized_value =
4426 (penalized_value_fp < std::numeric_limits<int64_t>::max())
4427 ?
static_cast<int64_t
>(penalized_value_fp)
4428 : std::numeric_limits<int64_t>::max();
4429 return penalized_value;
4434 bool maximize,
IntVar*
const objective,
4436 const std::vector<IntVar*>& vars,
double penalty_factor,
4437 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4438 get_equivalent_pairs,
4439 bool reset_penalties_on_new_best_solution) {
4440 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
4441 return RevAlloc(
new BinaryGuidedLocalSearch<GuidedLocalSearchPenaltiesMap>(
4442 this, objective, std::move(objective_function), maximize, step, vars,
4443 penalty_factor, std::move(get_equivalent_pairs),
4444 reset_penalties_on_new_best_solution));
4447 new BinaryGuidedLocalSearch<GuidedLocalSearchPenaltiesTable>(
4448 this, objective, std::move(objective_function), maximize, step,
4449 vars, penalty_factor, std::move(get_equivalent_pairs),
4450 reset_penalties_on_new_best_solution));
4455 bool maximize,
IntVar*
const objective,
4457 const std::vector<IntVar*>& vars,
4458 const std::vector<IntVar*>& secondary_vars,
double penalty_factor,
4459 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4460 get_equivalent_pairs,
4461 bool reset_penalties_on_new_best_solution) {
4462 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
4463 return RevAlloc(
new TernaryGuidedLocalSearch<GuidedLocalSearchPenaltiesMap>(
4464 this, objective, std::move(objective_function), maximize, step, vars,
4465 secondary_vars, penalty_factor, std::move(get_equivalent_pairs),
4466 reset_penalties_on_new_best_solution));
4469 new TernaryGuidedLocalSearch<GuidedLocalSearchPenaltiesTable>(
4470 this, objective, std::move(objective_function), maximize, step,
4471 vars, secondary_vars, penalty_factor,
4472 std::move(get_equivalent_pairs),
4473 reset_penalties_on_new_best_solution));
4506 if (crossed_ ||
Check()) {
4512void SearchLimit::TopPeriodicCheck() {
4513 if (
solver()->TopLevelSearch() !=
solver()->ActiveSearch()) {
4522 int64_t
solutions,
bool smart_time_check,
4525 duration_limit_(time),
4526 solver_time_at_limit_start_(s->Now()),
4527 last_time_elapsed_(
absl::ZeroDuration()),
4530 smart_time_check_(smart_time_check),
4532 branches_offset_(0),
4534 failures_offset_(0),
4536 solutions_offset_(0),
4537 cumulative_(cumulative) {}
4552 duration_limit_ = regular->duration_limit_;
4553 branches_ = regular->branches_;
4554 failures_ = regular->failures_;
4555 solutions_ = regular->solutions_;
4556 smart_time_check_ = regular->smart_time_check_;
4557 cumulative_ = regular->cumulative_;
4571 return s->
branches() - branches_offset_ >= branches_ ||
4572 s->
failures() - failures_offset_ >= failures_ || CheckTime(offset) ||
4573 s->
solutions() - solutions_offset_ >= solutions_;
4578 int64_t progress = GetPercent(s->
branches(), branches_offset_, branches_);
4579 progress = std::max(progress,
4580 GetPercent(s->
failures(), failures_offset_, failures_));
4581 progress = std::max(
4582 progress, GetPercent(s->
solutions(), solutions_offset_, solutions_));
4584 progress = std::max(progress, (100 * TimeElapsed()) /
duration_limit());
4593 solver_time_at_limit_start_ = s->
Now();
4594 last_time_elapsed_ = absl::ZeroDuration();
4604 branches_ -= s->
branches() - branches_offset_;
4605 failures_ -= s->
failures() - failures_offset_;
4606 duration_limit_ -= s->
Now() - solver_time_at_limit_start_;
4607 solutions_ -= s->
solutions() - solutions_offset_;
4614 duration_limit_ = time;
4627 return absl::StrFormat(
4628 "RegularLimit(crossed = %i, duration_limit = %s, "
4629 "branches = %d, failures = %d, solutions = %d cumulative = %s",
4631 solutions_, (cumulative_ ?
"true" :
"false"));
4649bool RegularLimit::CheckTime(absl::Duration offset) {
4653absl::Duration RegularLimit::TimeElapsed() {
4654 const int64_t kMaxSkip = 100;
4655 const int64_t kCheckWarmupIterations = 100;
4658 next_check_ <= check_count_) {
4659 Solver*
const s =
solver();
4660 absl::Duration elapsed = s->Now() - solver_time_at_limit_start_;
4661 if (smart_time_check_ && check_count_ > kCheckWarmupIterations &&
4662 elapsed > absl::ZeroDuration()) {
4664 check_count_ * absl::FDivDuration(duration_limit_, elapsed));
4666 std::min(check_count_ + kMaxSkip, estimated_check_count_at_limit);
4668 last_time_elapsed_ = elapsed;
4670 return last_time_elapsed_;
4674 return MakeLimit(time, std::numeric_limits<int64_t>::max(),
4675 std::numeric_limits<int64_t>::max(),
4676 std::numeric_limits<int64_t>::max(),
4682 std::numeric_limits<int64_t>::max(),
4683 std::numeric_limits<int64_t>::max(),
4688 return MakeLimit(absl::InfiniteDuration(),
4689 std::numeric_limits<int64_t>::max(),
failures,
4690 std::numeric_limits<int64_t>::max(),
4695 return MakeLimit(absl::InfiniteDuration(),
4696 std::numeric_limits<int64_t>::max(),
4697 std::numeric_limits<int64_t>::max(),
solutions,
4703 bool smart_time_check,
bool cumulative) {
4705 smart_time_check, cumulative);
4710 bool smart_time_check,
bool cumulative) {
4712 smart_time_check, cumulative));
4716 return MakeLimit(proto.time() == std::numeric_limits<int64_t>::max()
4717 ? absl::InfiniteDuration()
4718 : absl::Milliseconds(proto.time()),
4719 proto.branches(), proto.failures(), proto.solutions(),
4720 proto.smart_time_check(), proto.cumulative());
4724 RegularLimitParameters proto;
4725 proto.set_time(std::numeric_limits<int64_t>::max());
4726 proto.set_branches(std::numeric_limits<int64_t>::max());
4727 proto.set_failures(std::numeric_limits<int64_t>::max());
4728 proto.set_solutions(std::numeric_limits<int64_t>::max());
4729 proto.set_smart_time_check(
false);
4730 proto.set_cumulative(
false);
4738 double objective_scaling_factor,
double objective_offset,
4739 double improvement_rate_coefficient,
4740 int improvement_rate_solutions_distance)
4742 std::vector<bool>{maximize},
4743 std::vector<double>{objective_scaling_factor},
4744 std::vector<double>{objective_offset},
4745 improvement_rate_coefficient,
4746 improvement_rate_solutions_distance) {}
4750 std::vector<bool> maximize, std::vector<double> objective_scaling_factors,
4751 std::vector<double> objective_offsets,
double improvement_rate_coefficient,
4752 int improvement_rate_solutions_distance)
4754 objective_vars_(
std::move(objective_vars)),
4755 maximize_(
std::move(maximize)),
4756 objective_scaling_factors_(
std::move(objective_scaling_factors)),
4757 objective_offsets_(
std::move(objective_offsets)),
4758 improvement_rate_coefficient_(improvement_rate_coefficient),
4759 improvement_rate_solutions_distance_(improvement_rate_solutions_distance),
4760 best_objectives_(objective_vars_.size()),
4761 improvements_(objective_vars_.size()),
4762 thresholds_(objective_vars_.size(),
4763 std::numeric_limits<double>::infinity()) {
4775 for (
int i = 0; i < objective_vars_.size(); ++i) {
4776 best_objectives_[i] = std::numeric_limits<double>::infinity();
4777 improvements_[i].clear();
4778 thresholds_[i] = std::numeric_limits<double>::infinity();
4780 objective_updated_ =
false;
4781 gradient_stage_ =
true;
4787 objective_vars_ = improv->objective_vars_;
4788 maximize_ = improv->maximize_;
4789 objective_scaling_factors_ = improv->objective_scaling_factors_;
4790 objective_offsets_ = improv->objective_offsets_;
4791 improvement_rate_coefficient_ = improv->improvement_rate_coefficient_;
4792 improvement_rate_solutions_distance_ =
4793 improv->improvement_rate_solutions_distance_;
4794 improvements_ = improv->improvements_;
4795 thresholds_ = improv->thresholds_;
4796 best_objectives_ = improv->best_objectives_;
4797 objective_updated_ = improv->objective_updated_;
4798 gradient_stage_ = improv->gradient_stage_;
4803 solver(), objective_vars_, maximize_, objective_scaling_factors_,
4804 objective_offsets_, improvement_rate_coefficient_,
4805 improvement_rate_solutions_distance_));
4809 if (!objective_updated_) {
4812 objective_updated_ =
false;
4814 std::vector<double> improvement_rates(improvements_.size());
4815 for (
int i = 0; i < improvements_.size(); ++i) {
4816 if (improvements_[i].size() <= improvement_rate_solutions_distance_) {
4820 const auto [cur_obj, cur_neighbors] = improvements_[i].back();
4821 const auto [prev_obj, prev_neighbors] = improvements_[i].front();
4822 DCHECK_GT(cur_neighbors, prev_neighbors);
4823 improvement_rates[i] =
4824 (prev_obj - cur_obj) / (cur_neighbors - prev_neighbors);
4825 if (gradient_stage_)
continue;
4826 const double scaled_improvement_rate =
4827 improvement_rate_coefficient_ * improvement_rates[i];
4828 if (scaled_improvement_rate < thresholds_[i]) {
4830 }
else if (scaled_improvement_rate > thresholds_[i]) {
4834 if (gradient_stage_ && std::lexicographical_compare(
4835 improvement_rates.begin(), improvement_rates.end(),
4836 thresholds_.begin(), thresholds_.end())) {
4837 thresholds_ = std::move(improvement_rates);
4843 std::vector<double> scaled_new_objectives(objective_vars_.size());
4844 for (
int i = 0; i < objective_vars_.size(); ++i) {
4845 const int64_t new_objective =
4846 objective_vars_[i] !=
nullptr && objective_vars_[i]->Bound()
4847 ? objective_vars_[i]->Min()
4848 : (maximize_[i] ?
solver()
4856 scaled_new_objectives[i] = (maximize_[i] ? -objective_scaling_factors_[i]
4857 : objective_scaling_factors_[i]) *
4858 (new_objective + objective_offsets_[i]);
4860 const bool is_improvement = std::lexicographical_compare(
4861 scaled_new_objectives.begin(), scaled_new_objectives.end(),
4862 best_objectives_.begin(), best_objectives_.end());
4863 if (gradient_stage_ && !is_improvement) {
4864 gradient_stage_ =
false;
4867 for (
int i = 0; i < objective_vars_.size(); ++i) {
4868 if (thresholds_[i] == std::numeric_limits<double>::infinity()) {
4869 thresholds_[i] = -1;
4874 if (is_improvement) {
4875 objective_updated_ =
true;
4876 for (
int i = 0; i < objective_vars_.size(); ++i) {
4877 improvements_[i].push_back(
4878 std::make_pair(scaled_new_objectives[i],
solver()->neighbors()));
4882 if (improvements_[i].size() - 1 > improvement_rate_solutions_distance_) {
4883 improvements_[i].pop_front();
4885 DCHECK_LE(improvements_[i].size() - 1,
4886 improvement_rate_solutions_distance_);
4888 best_objectives_ = std::move(scaled_new_objectives);
4894 IntVar* objective_var,
bool maximize,
double objective_scaling_factor,
4895 double objective_offset,
double improvement_rate_coefficient,
4896 int improvement_rate_solutions_distance) {
4898 this, objective_var, maximize, objective_scaling_factor, objective_offset,
4899 improvement_rate_coefficient, improvement_rate_solutions_distance));
4903 std::vector<IntVar*> objective_vars, std::vector<bool> maximize,
4904 std::vector<double> objective_scaling_factors,
4905 std::vector<double> objective_offsets,
double improvement_rate_coefficient,
4906 int improvement_rate_solutions_distance) {
4908 this, std::move(objective_vars), std::move(maximize),
4909 std::move(objective_scaling_factors), std::move(objective_offsets),
4910 improvement_rate_coefficient, improvement_rate_solutions_distance));
4918 :
SearchLimit(limit_1->solver()), limit_1_(limit_1), limit_2_(limit_2) {
4919 CHECK(limit_1 !=
nullptr);
4920 CHECK(limit_2 !=
nullptr);
4922 <<
"Illegal arguments: cannot combines limits that belong to different "
4923 <<
"solvers, because the reversible allocations could delete one and "
4924 <<
"not the other.";
4927 bool CheckWithOffset(absl::Duration offset)
override {
4930 const bool check_1 = limit_1_->CheckWithOffset(offset);
4931 const bool check_2 = limit_2_->CheckWithOffset(offset);
4932 return check_1 || check_2;
4935 void Init()
override {
4940 void Copy(
const SearchLimit*
const)
override {
4941 LOG(FATAL) <<
"Not implemented.";
4944 SearchLimit* MakeClone()
const override {
4946 return solver()->MakeLimit(limit_1_->MakeClone(), limit_2_->MakeClone());
4949 void EnterSearch()
override {
4950 limit_1_->EnterSearch();
4951 limit_2_->EnterSearch();
4953 void BeginNextDecision(DecisionBuilder*
const b)
override {
4954 limit_1_->BeginNextDecision(b);
4955 limit_2_->BeginNextDecision(b);
4957 void PeriodicCheck()
override {
4958 limit_1_->PeriodicCheck();
4959 limit_2_->PeriodicCheck();
4961 void RefuteDecision(Decision*
const d)
override {
4962 limit_1_->RefuteDecision(d);
4963 limit_2_->RefuteDecision(d);
4965 std::string DebugString()
const override {
4966 return absl::StrCat(
"OR limit (", limit_1_->DebugString(),
" OR ",
4967 limit_2_->DebugString(),
")");
4971 SearchLimit*
const limit_1_;
4972 SearchLimit*
const limit_2_;
4978 return RevAlloc(
new ORLimit(limit_1, limit_2));
4984 CustomLimit(
Solver* s, std::function<
bool()> limiter);
4985 bool CheckWithOffset(absl::Duration offset)
override;
4986 void Init()
override;
4991 std::function<bool()> limiter_;
4994CustomLimit::CustomLimit(Solver*
const s, std::function<
bool()> limiter)
4995 : SearchLimit(s), limiter_(
std::move(limiter)) {}
4997bool CustomLimit::CheckWithOffset(absl::Duration) {
4999 if (limiter_)
return limiter_();
5003void CustomLimit::Init() {}
5005void CustomLimit::Copy(
const SearchLimit*
const limit) {
5006 const CustomLimit*
const custom =
5007 reinterpret_cast<const CustomLimit* const
>(limit);
5008 limiter_ = custom->limiter_;
5011SearchLimit* CustomLimit::MakeClone()
const {
5012 return solver()->RevAlloc(
new CustomLimit(solver(), limiter_));
5017 return RevAlloc(
new CustomLimit(
this, std::move(limiter)));
5026 CHECK(db !=
nullptr);
5029 SolveOnce(DecisionBuilder*
const db,
5030 const std::vector<SearchMonitor*>& monitors)
5031 : db_(db), monitors_(monitors) {
5032 CHECK(db !=
nullptr);
5035 ~SolveOnce()
override {}
5037 Decision*
Next(Solver* s)
override {
5038 bool res = s->SolveAndCommit(db_, monitors_);
5045 std::string DebugString()
const override {
5046 return absl::StrFormat(
"SolveOnce(%s)", db_->
DebugString());
5049 void Accept(ModelVisitor*
const visitor)
const override {
5054 DecisionBuilder*
const db_;
5055 std::vector<SearchMonitor*> monitors_;
5060 return RevAlloc(
new SolveOnce(db));
5065 std::vector<SearchMonitor*> monitors;
5066 monitors.push_back(monitor1);
5067 return RevAlloc(
new SolveOnce(db, monitors));
5073 std::vector<SearchMonitor*> monitors;
5074 monitors.push_back(monitor1);
5075 monitors.push_back(monitor2);
5076 return RevAlloc(
new SolveOnce(db, monitors));
5083 std::vector<SearchMonitor*> monitors;
5084 monitors.push_back(monitor1);
5085 monitors.push_back(monitor2);
5086 monitors.push_back(monitor3);
5087 return RevAlloc(
new SolveOnce(db, monitors));
5095 std::vector<SearchMonitor*> monitors;
5096 monitors.push_back(monitor1);
5097 monitors.push_back(monitor2);
5098 monitors.push_back(monitor3);
5099 monitors.push_back(monitor4);
5100 return RevAlloc(
new SolveOnce(db, monitors));
5104 DecisionBuilder*
const db,
const std::vector<SearchMonitor*>& monitors) {
5105 return RevAlloc(
new SolveOnce(db, monitors));
5114 bool maximize, int64_t step)
5117 maximize_(maximize),
5119 collector_(nullptr) {
5120 CHECK(db !=
nullptr);
5126 NestedOptimize(DecisionBuilder*
const db, Assignment*
const solution,
5127 bool maximize, int64_t step,
5128 const std::vector<SearchMonitor*>& monitors)
5130 solution_(solution),
5131 maximize_(maximize),
5133 monitors_(monitors),
5134 collector_(nullptr) {
5135 CHECK(db !=
nullptr);
5136 CHECK(solution !=
nullptr);
5137 CHECK(solution->HasObjective());
5141 void AddMonitors() {
5142 Solver*
const solver = solution_->
solver();
5143 collector_ = solver->MakeLastSolutionCollector(solution_);
5144 monitors_.push_back(collector_);
5145 OptimizeVar*
const optimize =
5146 solver->MakeOptimize(maximize_, solution_->
Objective(), step_);
5147 monitors_.push_back(optimize);
5150 Decision*
Next(Solver* solver)
override {
5151 solver->Solve(db_, monitors_);
5159 std::string DebugString()
const override {
5160 return absl::StrFormat(
"NestedOptimize(db = %s, maximize = %d, step = %d)",
5164 void Accept(ModelVisitor*
const visitor)
const override {
5169 DecisionBuilder*
const db_;
5170 Assignment*
const solution_;
5171 const bool maximize_;
5172 const int64_t step_;
5173 std::vector<SearchMonitor*> monitors_;
5174 SolutionCollector* collector_;
5180 bool maximize, int64_t step) {
5186 bool maximize, int64_t step,
5188 std::vector<SearchMonitor*> monitors;
5189 monitors.push_back(monitor1);
5190 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5195 bool maximize, int64_t step,
5198 std::vector<SearchMonitor*> monitors;
5199 monitors.push_back(monitor1);
5200 monitors.push_back(monitor2);
5201 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5206 bool maximize, int64_t step,
5210 std::vector<SearchMonitor*> monitors;
5211 monitors.push_back(monitor1);
5212 monitors.push_back(monitor2);
5213 monitors.push_back(monitor3);
5214 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5221 std::vector<SearchMonitor*> monitors;
5222 monitors.push_back(monitor1);
5223 monitors.push_back(monitor2);
5224 monitors.push_back(monitor3);
5225 monitors.push_back(monitor4);
5226 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5231 int64_t step,
const std::vector<SearchMonitor*>& monitors) {
5232 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5239int64_t NextLuby(
int i) {
5241 DCHECK_LT(i, std::numeric_limits<int32_t>::max());
5247 while (power < (i + 1)) {
5250 if (power == i + 1) {
5253 return NextLuby(i - (power / 2) + 1);
5256class LubyRestart :
public SearchMonitor {
5258 LubyRestart(Solver*
const s,
int scale_factor)
5260 scale_factor_(scale_factor),
5263 next_step_(scale_factor) {
5264 CHECK_GE(scale_factor, 1);
5267 ~LubyRestart()
override {}
5269 void BeginFail()
override {
5270 if (++current_fails_ >= next_step_) {
5272 next_step_ = NextLuby(++iteration_) * scale_factor_;
5273 solver()->RestartCurrentSearch();
5277 void Install()
override { ListenToEvent(Solver::MonitorEvent::kBeginFail); }
5279 std::string DebugString()
const override {
5280 return absl::StrFormat(
"LubyRestart(%i)", scale_factor_);
5284 const int scale_factor_;
5286 int64_t current_fails_;
5292 return RevAlloc(
new LubyRestart(
this, scale_factor));
5300 ConstantRestart(
Solver*
const s,
int frequency)
5301 :
SearchMonitor(s), frequency_(frequency), current_fails_(0) {
5302 CHECK_GE(frequency, 1);
5305 ~ConstantRestart()
override {}
5307 void BeginFail()
override {
5308 if (++current_fails_ >= frequency_) {
5310 solver()->RestartCurrentSearch();
5314 void Install()
override { ListenToEvent(Solver::MonitorEvent::kBeginFail); }
5316 std::string DebugString()
const override {
5317 return absl::StrFormat(
"ConstantRestart(%i)", frequency_);
5321 const int frequency_;
5322 int64_t current_fails_;
5327 return RevAlloc(
new ConstantRestart(
this, frequency));
5350 const std::vector<SymmetryBreaker*>& visitors)
5352 visitors_(visitors),
5353 clauses_(visitors.size()),
5354 decisions_(visitors.size()),
5355 directions_(visitors.size()) {
5356 for (
int i = 0; i < visitors_.size(); ++i) {
5357 visitors_[i]->set_symmetry_manager_and_index(
this, i);
5365 for (
int i = 0; i < visitors_.size(); ++i) {
5366 const void*
const last = clauses_[i].Last();
5368 if (last != clauses_[i].Last()) {
5370 decisions_[i].Push(
solver(), d);
5371 directions_[i].Push(
solver(),
false);
5378 for (
int i = 0; i < visitors_.size(); ++i) {
5379 if (decisions_[i].Last() !=
nullptr && decisions_[i].LastValue() == d) {
5392 std::vector<IntVar*> guard;
5397 IntVar*
const term = *tmp;
5399 if (term->
Max() == 0) {
5403 if (term->
Min() == 0) {
5404 DCHECK_EQ(1, term->
Max());
5406 guard.push_back(term);
5412 guard.push_back(clauses_[index].LastValue());
5413 directions_[index].SetLastValue(
true);
5420 DCHECK(ct !=
nullptr);
5421 solver()->AddConstraint(ct);
5425 clauses_[visitor->index_in_symmetry_manager()].Push(
solver(), term);
5428 std::string
DebugString()
const override {
return "SymmetryManager"; }
5431 const std::vector<SymmetryBreaker*> visitors_;
5432 std::vector<SimpleRevFIFO<IntVar*>> clauses_;
5433 std::vector<SimpleRevFIFO<Decision*>> decisions_;
5434 std::vector<SimpleRevFIFO<bool>> directions_;
5441 CHECK(var !=
nullptr);
5444 symmetry_manager()->AddTermToClause(
this, term);
5448 IntVar*
const var, int64_t value) {
5449 CHECK(var !=
nullptr);
5452 symmetry_manager()->AddTermToClause(
this, term);
5456 IntVar*
const var, int64_t value) {
5457 CHECK(var !=
nullptr);
5460 symmetry_manager()->AddTermToClause(
this, term);
5466 const std::vector<SymmetryBreaker*>& visitors) {
5471 std::vector<SymmetryBreaker*> visitors;
5472 visitors.push_back(v1);
5478 std::vector<SymmetryBreaker*> visitors;
5479 visitors.push_back(v1);
5480 visitors.push_back(v2);
5487 std::vector<SymmetryBreaker*> visitors;
5488 visitors.push_back(v1);
5489 visitors.push_back(v2);
5490 visitors.push_back(v3);
5498 std::vector<SymmetryBreaker*> visitors;
5499 visitors.push_back(v1);
5500 visitors.push_back(v2);
5501 visitors.push_back(v3);
5502 visitors.push_back(v4);
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)
void Clear()
Clears all bits in the bitmap.
virtual Decision * Next(Solver *s)=0
virtual void Accept(ModelVisitor *visitor) const
std::string DebugString() const override
-------— Decision Builder -------—
virtual void Accept(DecisionVisitor *visitor) const
Accepts the given visitor.
The consistency level is maintained up to kRedundancy.
GuidedLocalSearch(SetCoverInvariant *inv)
bool CheckWithOffset(absl::Duration offset) override
~ImprovementSearchLimit() override
ImprovementSearchLimit(Solver *solver, IntVar *objective_var, bool maximize, double objective_scaling_factor, double objective_offset, double improvement_rate_coefficient, int improvement_rate_solutions_distance)
--— Improvement Search Limit --—
void Init() override
This method is called when the search limit is initialized.
void Install() override
A search monitors adds itself on the active search.
void Copy(const SearchLimit *limit) override
bool AtSolution() override
SearchLimit * MakeClone() const override
Allocates a clone of the limit.
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
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
void Accept(ModelVisitor *visitor) const override
Accepts the given model visitor.
int64_t BestValue(int index) const override
bool AtSolution() override
ObjectiveMonitor(Solver *solver, const std::vector< bool > &maximize, std::vector< IntVar * > vars, std::vector< int64_t > steps)
void EnterSearch() override
Beginning of the search.
IntVar * ObjectiveVar(int index) const override
IntVar * MinimizationVar(int index) const override
void BeginNextDecision(DecisionBuilder *db) override
Internal methods.
void RefuteDecision(Decision *d) override
Before refuting the decision.
bool AtSolution() override
IntVar * var() const
Returns the variable that is optimized.
OptimizeVar(Solver *solver, bool maximize, IntVar *var, int64_t step)
std::string DebugString() const override
bool AcceptSolution() override
virtual std::string Name() const
std::string DebugString() const override
absl::Duration duration_limit() const
SearchLimit * MakeClone() const override
Allocates a clone of the limit.
bool IsUncheckedSolutionLimitReached() override
void Install() override
A search monitors adds itself on the active search.
bool CheckWithOffset(absl::Duration offset) override
int64_t wall_time() const
void Init() override
This method is called when the search limit is initialized.
int64_t solutions() const
int ProgressPercent() override
std::string DebugString() const override
void Accept(ModelVisitor *visitor) const override
Accepts the given model visitor.
void ExitSearch() override
End of the search.
RegularLimit(Solver *s, absl::Duration time, int64_t branches, int64_t failures, int64_t solutions, bool smart_time_check, bool cumulative)
--— Regular Limit --—
void Copy(const SearchLimit *limit) override
void UpdateLimits(absl::Duration time, int64_t branches, int64_t failures, int64_t solutions)
RegularLimit * MakeIdenticalClone() const
-------— Objective Management -------—
bool AcceptDelta(Assignment *delta, Assignment *deltadelta) override
void EnterSearch() override
Beginning of the search.
bool LocalOptimum() override
bool Maximize(int index) const override
void BeginNextDecision(DecisionBuilder *db) override
Before calling DecisionBuilder::Next.
void ApplyDecision(Decision *d) override
Before applying the decision.
void AcceptNeighbor() override
After accepting a neighbor during local search.
int64_t BestValue(int index) const override
bool AcceptSolution() override
IntVar * MinimizationVar(int index) const override
std::string DebugString() const override
void RefuteDecision(Decision *d) override
Before refuting the decision.
IntVar * ObjectiveVar(int index) const override
int64_t Step(int index) const override
int Size() const override
bool AtSolution() override
void Accept(ModelVisitor *visitor) const override
Accepts the given model visitor.
RoundRobinCompoundObjectiveMonitor(std::vector< BaseObjectiveMonitor * > monitors, int num_max_local_optima_before_metaheuristic_switch)
Base class of all search limits.
~SearchLimit() override
-------— Search Limits -------—
void BeginNextDecision(DecisionBuilder *b) override
Before calling DecisionBuilder::Next.
void PeriodicCheck() override
Periodic call to check limits in long running methods.
bool crossed() const
Returns true if the limit has been crossed.
void EnterSearch() override
Internal methods.
virtual void Init()=0
This method is called when the search limit is initialized.
void Install() override
A search monitors adds itself on the active search.
SearchLimit(Solver *const s)
void RefuteDecision(Decision *d) override
Before refuting the decision.
void BeginFail() override
Just when the failure occurs.
void NoMoreSolutions() override
When the search tree is finished.
virtual void OutputLine(const std::string &line)
bool AtSolution() override
void AcceptUncheckedNeighbor() override
After accepting an unchecked neighbor during local search.
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)
-------— Search Log ------—
void EndInitialPropagation() override
After the initial propagation.
void BeginInitialPropagation() override
Before the initial propagation.
void RefuteDecision(Decision *decision) override
Before refuting the decision.
void ExitSearch() override
End of the search.
std::string DebugString() const override
void EnterSearch() override
Beginning of the search.
void ApplyDecision(Decision *decision) override
Before applying the decision.
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.
SolutionData BuildSolutionDataForCurrentState()
void AddObjectives(const std::vector< IntVar * > &objectives)
const std::vector< int > & ForwardSequence(int n, SequenceVar *var) const
int64_t objective_value(int n) const
Returns the objective value of the nth solution.
~SolutionCollector() override
void Add(IntVar *var)
Add API.
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.
void EnterSearch() override
Beginning of the search.
void FreeSolution(Assignment *solution)
void Push(const SolutionData &data)
void PopSolution()
Remove and delete the last popped solution.
const std::vector< int > & Unperformed(int n, SequenceVar *var) const
void AddObjective(IntVar *objective)
bool has_solution() const
Returns whether any solutions were stored during the search.
void check_index(int n) const
int solution_count() const
Returns how many solutions were stored during the search.
void Install() override
A search monitors adds itself on the active search.
int64_t wall_time(int n) const
Returns the wall time in ms for the nth solution.
void PushSolution()
Push the current state as a new solution.
int64_t DurationValue(int n, IntervalVar *var) const
This is a shortcut to get the DurationValue of 'var' in the nth solution.
int64_t ObjectiveValueFromIndex(int n, int index) const
Returns the value of the index-th objective of the nth solution.
int64_t failures(int n) const
const std::vector< int > & BackwardSequence(int n, SequenceVar *var) const
int64_t StartValue(int n, IntervalVar *var) const
This is a shortcut to get the StartValue of 'var' in the nth solution.
SolutionCollector(Solver *solver, const Assignment *assignment)
-------— Solution Collectors --------—
Assignment * solution(int n) const
Returns the nth solution.
int64_t Value(int n, IntVar *var) const
This is a shortcut to get the Value of 'var' in the nth solution.
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.
int64_t EndValue(int n, IntervalVar *var) const
This is a shortcut to get the EndValue of 'var' in the nth solution.
For the time being, Solver is neither MT_SAFE nor MT_HOT.
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)
DecisionBuilder * MakeSolveOnce(DecisionBuilder *db)
int64_t accepted_neighbors() const
The number of accepted neighbors.
SearchMonitor * MakeEnterSearchCallback(std::function< void()> callback)
--— Callback-based search monitors --—
Decision * MakeAssignVariableValueOrFail(IntVar *var, int64_t value)
IntVar * MakeIsEqualCstVar(IntExpr *var, int64_t value)
status var of (var == value)
Decision * MakeVariableLessOrEqualValue(IntVar *var, int64_t value)
SearchMonitor * MakeLubyRestart(int scale_factor)
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).
SearchMonitor * MakeConstantRestart(int frequency)
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)
ABSL_MUST_USE_RESULT RegularLimit * MakeSolutionsLimit(int64_t solutions)
SolutionCollector * MakeBestValueSolutionCollector(const Assignment *assignment, bool maximize)
IntVar * MakeIsLessOrEqualCstVar(IntExpr *var, int64_t value)
status var of (var <= value)
ABSL_MUST_USE_RESULT SearchLimit * MakeCustomLimit(std::function< bool()> limiter)
void Fail()
Abandon the current branch in the search tree. A backtrack will follow.
ABSL_MUST_USE_RESULT RegularLimit * MakeFailuresLimit(int64_t failures)
OptimizeVar * MakeWeightedMinimize(const std::vector< IntVar * > &sub_objectives, const std::vector< int64_t > &weights, int64_t step)
Decision * MakeVariableGreaterOrEqualValue(IntVar *var, int64_t value)
ABSL_MUST_USE_RESULT RegularLimit * MakeTimeLimit(absl::Duration time)
Creates a search limit that constrains the running time.
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)
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.
DecisionBuilder * MakePhase(const std::vector< IntVar * > &vars, IntVarStrategy var_str, IntValueStrategy val_str)
Decision * MakeAssignVariableValue(IntVar *var, int64_t val)
Decisions.
Decision * MakeAssignVariablesValuesOrFail(const std::vector< IntVar * > &vars, const std::vector< int64_t > &values)
Decision * MakeSplitVariableDomain(IntVar *var, int64_t val, bool start_with_lower_half)
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)
OptimizeVar * MakeOptimize(bool maximize, IntVar *v, int64_t step)
Creates a objective with a given sense (true = maximization).
std::function< void(Solver *)> Action
SearchMonitor * MakeAtSolutionCallback(std::function< void()> callback)
@ 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)
std::function< int64_t(int64_t, int64_t)> IndexEvaluator2
SolutionCollector * MakeAllSolutionCollector()
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)
ObjectiveMonitor * MakeLexicographicSimulatedAnnealing(const std::vector< bool > &maximize, std::vector< IntVar * > vars, std::vector< int64_t > steps, std::vector< int64_t > initial_temperatures)
SolutionCollector * MakeFirstSolutionCollector()
SolutionCollector * MakeLastSolutionCollector()
@ kIsUncheckedSolutionLimitReached
friend class SearchMonitor
SolutionCollector * MakeBestLexicographicValueSolutionCollector(const Assignment *assignment, std::vector< bool > maximize)
SearchMonitor * MakeExitSearchCallback(std::function< void()> callback)
SearchMonitor * MakeSearchTrace(const std::string &prefix)
Decision * MakeAssignVariablesValues(const std::vector< IntVar * > &vars, const std::vector< int64_t > &values)
SolutionCollector * MakeNBestValueSolutionCollector(const Assignment *assignment, int solution_count, bool maximize)
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)
DecisionBuilder * MakeDecisionBuilderFromAssignment(Assignment *assignment, DecisionBuilder *db, const std::vector< IntVar * > &vars)
int64_t wall_time() const
ABSL_MUST_USE_RESULT RegularLimit * MakeBranchesLimit(int64_t branches)
SearchMonitor * MakeSearchLog(int branch_period)
ObjectiveMonitor * MakeSimulatedAnnealing(bool maximize, IntVar *v, int64_t step, int64_t initial_temperature)
OptimizeVar * MakeMinimize(IntVar *v, int64_t step)
Creates a minimization objective.
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)
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)
OptimizeVar * MakeWeightedMaximize(const std::vector< IntVar * > &sub_objectives, const std::vector< int64_t > &weights, int64_t step)
Creates a maximization weigthed objective.
Decision * MakeAssignVariableValueOrDoNothing(IntVar *var, int64_t value)
SolutionCollector * MakeNBestLexicographicValueSolutionCollector(const Assignment *assignment, int solution_count, std::vector< bool > maximize)
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)
Assignment * GetOrCreateLocalSearchState()
@ 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)
SearchMonitor * MakeSymmetryManager(const std::vector< SymmetryBreaker * > &visitors)
Symmetry Breaking.
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.
Solver(const std::string &name)
Solver API.
BaseObjectiveMonitor * MakeRoundRobinCompoundObjectiveMonitor(std::vector< BaseObjectiveMonitor * > monitors, int num_max_local_optima_before_metaheuristic_switch)
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.
@ 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)
std::function< int64_t(const IntVar *v, int64_t id)> VariableValueSelector
void AddIntegerVariableGreaterOrEqualValueClause(IntVar *var, int64_t value)
void AddIntegerVariableLessOrEqualValueClause(IntVar *var, int64_t value)
void AddIntegerVariableEqualValueClause(IntVar *var, int64_t value)
--— Symmetry Breaker --—
-------— Symmetry Breaking -------—
void EndNextDecision(DecisionBuilder *const, Decision *const d) override
After calling DecisionBuilder::Next, along with the returned decision.
void CheckSymmetries(int index)
void RefuteDecision(Decision *d) override
Before refuting the decision.
void AddTermToClause(SymmetryBreaker *const visitor, IntVar *const term)
~SymmetryManager() override
SymmetryManager(Solver *const s, const std::vector< SymmetryBreaker * > &visitors)
std::string DebugString() const override
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
problem is infeasible or unbounded (default).
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)
This checks that the variable is fixed.
In SWIG mode, we don't want anything besides these top-level includes.
int64_t CapAdd(int64_t x, int64_t y)
std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)
Join v[i]->DebugString().
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)
Notifies the search that a neighbor has been accepted by local search.
int64_t CapSub(int64_t x, int64_t y)
std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)
--— Vector manipulations --—
BaseAssignVariables::Mode ChooseMode(Solver::IntValueStrategy val_str)
int64_t CapOpp(int64_t v)
Note(user): -kint64min != kint64max, but kint64max == ~kint64min.
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
bool operator<(const SolutionData &other) const
int64_t ObjectiveValueFromIndex(int index) const
Creates a search monitor from logging parameters.
static const int64_t kint64max