27#include "absl/container/flat_hash_map.h"
28#include "absl/flags/flag.h"
29#include "absl/log/check.h"
30#include "absl/log/log.h"
31#include "absl/log/vlog_is_on.h"
32#include "absl/random/distributions.h"
33#include "absl/strings/str_cat.h"
34#include "absl/strings/str_format.h"
35#include "absl/strings/str_join.h"
36#include "absl/strings/string_view.h"
37#include "absl/time/time.h"
38#include "absl/types/span.h"
52 "Use sparse implementation to store Guided Local Search penalties");
54 "Whether search related logging should be "
56ABSL_FLAG(int64_t, cp_large_domain_no_splitting_limit, 0xFFFFF,
57 "Size limit to allow holes in variables from the strategy.");
63 std::string vars_name, std::vector<double> scaling_factors,
64 std::vector<double> offsets,
65 std::function<std::string()> display_callback,
66 bool display_on_new_solutions_only,
int period)
70 vars_(
std::move(vars)),
71 vars_name_(
std::move(vars_name)),
72 scaling_factors_(
std::move(scaling_factors)),
73 offsets_(
std::move(offsets)),
74 display_callback_(
std::move(display_callback)),
75 display_on_new_solutions_only_(display_on_new_solutions_only),
77 objective_min_(vars_.size(),
std::numeric_limits<int64_t>::max()),
78 objective_max_(vars_.size(),
std::numeric_limits<int64_t>::min()),
79 min_right_depth_(
std::numeric_limits<int32_t>::max()),
81 sliding_min_depth_(0),
82 sliding_max_depth_(0) {}
89 const std::string buffer =
90 (!display_on_new_solutions_only_ && display_callback_ !=
nullptr)
91 ? absl::StrFormat(
"Start search (%s, %s)",
MemoryUsage(),
93 : absl::StrFormat(
"Start search (%s)",
MemoryUsage());
96 min_right_depth_ = std::numeric_limits<int32_t>::max();
99 last_objective_value_.clear();
100 last_objective_timestamp_ = timer_->GetDuration();
105 int64_t ms = absl::ToInt64Milliseconds(timer_->GetDuration());
109 const std::string buffer = absl::StrFormat(
110 "End search (time = %d ms, branches = %d, failures = %d, %s, speed = %d "
119 std::string obj_str =
"";
120 std::vector<int64_t> current;
121 bool objective_updated =
false;
122 const auto scaled_str = [
this](absl::Span<const int64_t> values) {
123 std::vector<std::string> value_strings(values.size());
124 for (
int i = 0; i < values.size(); ++i) {
125 if (scaling_factors_[i] != 1.0 || offsets_[i] != 0.0) {
127 absl::StrFormat(
"%d (%.8lf)", values[i],
128 scaling_factors_[i] * (values[i] + offsets_[i]));
130 value_strings[i] = absl::StrCat(values[i]);
133 return absl::StrJoin(value_strings,
", ");
135 bool all_vars_bound = !vars_.empty();
136 for (
IntVar* var : vars_) {
137 all_vars_bound &= var->Bound();
139 if (all_vars_bound) {
140 for (
IntVar* var : vars_) {
141 current.push_back(var->Value());
142 objective_updated =
true;
144 absl::StrAppend(&obj_str,
145 vars_name_.empty() ?
"" : absl::StrCat(vars_name_,
" = "),
146 scaled_str(current),
", ");
148 current.push_back(
solver()->GetOrCreateLocalSearchState()->ObjectiveMin());
149 absl::StrAppend(&obj_str,
"objective = ", scaled_str(current),
", ");
150 objective_updated =
true;
152 const absl::Duration now = timer_->GetDuration();
153 if (objective_updated) {
154 if (!last_objective_value_.empty()) {
155 const int64_t elapsed_ms =
156 absl::ToInt64Milliseconds(now - last_objective_timestamp_);
157 for (
int i = 0; i < current.size(); ++i) {
158 const double improvement_rate =
159 100.0 * 1000.0 * (current[i] - last_objective_value_[i]) /
160 std::max<int64_t>(1, last_objective_value_[i] * elapsed_ms);
161 absl::StrAppend(&obj_str,
"improvement rate = ", improvement_rate,
163 last_objective_value_[i] = current[i];
166 last_objective_value_ = current;
168 last_objective_timestamp_ = now;
169 if (!objective_min_.empty() &&
170 std::lexicographical_compare(objective_min_.begin(),
171 objective_min_.end(), current.begin(),
173 absl::StrAppend(&obj_str,
174 vars_name_.empty() ?
"" : absl::StrCat(vars_name_,
" "),
175 "minimum = ", scaled_str(objective_min_),
", ");
178 objective_min_ = current;
180 if (!objective_max_.empty() &&
181 std::lexicographical_compare(current.begin(), current.end(),
182 objective_max_.begin(),
183 objective_max_.end())) {
184 absl::StrAppend(&obj_str,
185 vars_name_.empty() ?
"" : absl::StrCat(vars_name_,
" "),
186 "maximum = ", scaled_str(objective_max_),
", ");
188 objective_max_ = current;
192 absl::StrAppendFormat(&log,
193 "Solution #%d (%stime = %d ms, branches = %d,"
194 " failures = %d, depth = %d",
195 nsol_++, obj_str, absl::ToInt64Milliseconds(now),
197 if (!
solver()->SearchContext().empty()) {
198 absl::StrAppendFormat(&log,
", %s",
solver()->SearchContext());
200 if (
solver()->accepted_neighbors() != neighbors_offset_) {
201 absl::StrAppendFormat(&log,
202 ", neighbors = %d, filtered neighbors = %d,"
203 " accepted neighbors = %d",
205 solver()->accepted_neighbors());
207 absl::StrAppendFormat(&log,
", %s",
MemoryUsage());
210 absl::StrAppendFormat(&log,
", limit = %d%%", progress);
212 if (display_callback_) {
213 absl::StrAppendFormat(&log,
", %s", display_callback_());
225 std::string buffer = absl::StrFormat(
226 "Finished search tree (time = %d ms, branches = %d,"
228 absl::ToInt64Milliseconds(timer_->GetDuration()),
solver()->branches(),
230 if (
solver()->neighbors() != 0) {
231 absl::StrAppendFormat(&buffer,
232 ", neighbors = %d, filtered neighbors = %d,"
233 " accepted neigbors = %d",
235 solver()->accepted_neighbors());
237 absl::StrAppendFormat(&buffer,
", %s",
MemoryUsage());
238 if (!display_on_new_solutions_only_ && display_callback_) {
239 absl::StrAppendFormat(&buffer,
", %s", display_callback_());
248 if (b % period_ == 0 && b > 0) {
254 min_right_depth_ = std::min(min_right_depth_,
solver()->SearchDepth());
259 std::string buffer = absl::StrFormat(
260 "%d branches, %d ms, %d failures",
solver()->branches(),
261 absl::ToInt64Milliseconds(timer_->GetDuration()),
solver()->failures());
262 if (min_right_depth_ != std::numeric_limits<int32_t>::max() &&
265 absl::StrAppendFormat(&buffer,
", tree pos=%d/%d/%d minref=%d max=%d",
266 sliding_min_depth_, depth, sliding_max_depth_,
267 min_right_depth_, max_depth_);
268 sliding_min_depth_ = depth;
269 sliding_max_depth_ = depth;
271 if (!objective_min_.empty() &&
272 objective_min_[0] != std::numeric_limits<int64_t>::max() &&
273 objective_max_[0] != std::numeric_limits<int64_t>::min()) {
274 const std::string name =
275 vars_name_.empty() ?
"" : absl::StrCat(
" ", vars_name_);
276 absl::StrAppendFormat(&buffer,
279 name, objective_min_[0], name, objective_max_[0]);
283 absl::StrAppendFormat(&buffer,
", limit = %d%%", progress);
290 sliding_min_depth_ = std::min(current_depth, sliding_min_depth_);
291 sliding_max_depth_ = std::max(current_depth, sliding_max_depth_);
292 max_depth_ = std::max(current_depth, max_depth_);
298 const int64_t delta = std::max<int64_t>(
299 absl::ToInt64Milliseconds(timer_->GetDuration() - tick_), 0);
300 const std::string buffer = absl::StrFormat(
301 "Root node processed (time = %d ms, constraints = %d, %s)", delta,
307 if (absl::GetFlag(FLAGS_cp_log_to_vlog)) {
314std::string SearchLog::MemoryUsage() {
315 static const int64_t kDisplayThreshold = 2;
316 static const int64_t kKiloByte = 1024;
317 static const int64_t kMegaByte = kKiloByte * kKiloByte;
318 static const int64_t kGigaByte = kMegaByte * kKiloByte;
320 if (memory_usage > kDisplayThreshold * kGigaByte) {
321 return absl::StrFormat(
"memory used = %.2lf GB",
322 memory_usage * 1.0 / kGigaByte);
323 }
else if (memory_usage > kDisplayThreshold * kMegaByte) {
324 return absl::StrFormat(
"memory used = %.2lf MB",
325 memory_usage * 1.0 / kMegaByte);
326 }
else if (memory_usage > kDisplayThreshold * kKiloByte) {
327 return absl::StrFormat(
"memory used = %2lf KB",
328 memory_usage * 1.0 / kKiloByte);
330 return absl::StrFormat(
"memory used = %d", memory_usage);
335 return MakeSearchLog(branch_period, std::vector<IntVar*>{},
nullptr);
339 return MakeSearchLog(branch_period, std::vector<IntVar*>{var},
nullptr);
343 int branch_period, std::function<std::string()> display_callback) {
345 std::move(display_callback));
349 int branch_period,
IntVar* var,
350 std::function<std::string()> display_callback) {
351 return MakeSearchLog(branch_period, std::vector<IntVar*>{var},
352 std::move(display_callback));
356 int branch_period, std::vector<IntVar*> vars,
357 std::function<std::string()> display_callback) {
359 std::move(display_callback),
true,
369 std::function<std::string()> display_callback) {
371 std::vector<double> scaling_factors(vars.size(), 1.0);
372 std::vector<double> offsets(vars.size(), 0.0);
374 this, std::move(vars), opt_var->
Name(), std::move(scaling_factors),
375 std::move(offsets), std::move(display_callback),
376 true, branch_period));
381 <<
"Either variables are empty or objective is nullptr.";
382 std::vector<IntVar*> vars =
parameters.objective !=
nullptr
385 std::vector<double> scaling_factors = std::move(
parameters.scaling_factors);
386 scaling_factors.resize(vars.size(), 1.0);
387 std::vector<double> offsets = std::move(
parameters.offsets);
388 offsets.resize(vars.size(), 0.0);
390 this, std::move(vars),
"", std::move(scaling_factors), std::move(offsets),
399 SearchTrace(
Solver*
const s,
const std::string& prefix)
401 ~SearchTrace()
override {}
403 void EnterSearch()
override {
404 LOG(INFO) << prefix_ <<
" EnterSearch(" << solver()->
SolveDepth() <<
")";
406 void RestartSearch()
override {
407 LOG(INFO) << prefix_ <<
" RestartSearch(" << solver()->
SolveDepth() <<
")";
409 void ExitSearch()
override {
410 LOG(INFO) << prefix_ <<
" ExitSearch(" << solver()->
SolveDepth() <<
")";
412 void BeginNextDecision(DecisionBuilder*
const b)
override {
413 LOG(INFO) << prefix_ <<
" BeginNextDecision(" <<
b <<
") ";
415 void EndNextDecision(DecisionBuilder*
const b, Decision*
const d)
override {
417 LOG(INFO) << prefix_ <<
" EndNextDecision(" <<
b <<
", " << d <<
") ";
419 LOG(INFO) << prefix_ <<
" EndNextDecision(" <<
b <<
") ";
422 void ApplyDecision(Decision*
const d)
override {
423 LOG(INFO) << prefix_ <<
" ApplyDecision(" << d <<
") ";
425 void RefuteDecision(Decision*
const d)
override {
426 LOG(INFO) << prefix_ <<
" RefuteDecision(" << d <<
") ";
428 void AfterDecision(Decision*
const d,
bool apply)
override {
429 LOG(INFO) << prefix_ <<
" AfterDecision(" << d <<
", " << apply <<
") ";
431 void BeginFail()
override {
432 LOG(INFO) << prefix_ <<
" BeginFail(" << solver()->
SearchDepth() <<
")";
434 void EndFail()
override {
435 LOG(INFO) << prefix_ <<
" EndFail(" << solver()->
SearchDepth() <<
")";
437 void BeginInitialPropagation()
override {
438 LOG(INFO) << prefix_ <<
" BeginInitialPropagation()";
440 void EndInitialPropagation()
override {
441 LOG(INFO) << prefix_ <<
" EndInitialPropagation()";
443 bool AtSolution()
override {
444 LOG(INFO) << prefix_ <<
" AtSolution()";
447 bool AcceptSolution()
override {
448 LOG(INFO) << prefix_ <<
" AcceptSolution()";
451 void NoMoreSolutions()
override {
452 LOG(INFO) << prefix_ <<
" NoMoreSolutions()";
455 std::string DebugString()
const override {
return "SearchTrace"; }
458 const std::string prefix_;
463 return RevAlloc(
new SearchTrace(
this, prefix));
470 AtSolutionCallback(
Solver*
const solver, std::function<
void()> callback)
472 ~AtSolutionCallback()
override {}
473 bool AtSolution()
override;
474 void Install()
override;
477 const std::function<void()> callback_;
480bool AtSolutionCallback::AtSolution() {
485void AtSolutionCallback::Install() {
486 ListenToEvent(Solver::MonitorEvent::kAtSolution);
492 return RevAlloc(
new AtSolutionCallback(
this, std::move(callback)));
498 EnterSearchCallback(
Solver*
const solver, std::function<
void()> callback)
500 ~EnterSearchCallback()
override {}
501 void EnterSearch()
override;
502 void Install()
override;
505 const std::function<void()> callback_;
508void EnterSearchCallback::EnterSearch() { callback_(); }
510void EnterSearchCallback::Install() {
511 ListenToEvent(Solver::MonitorEvent::kEnterSearch);
517 return RevAlloc(
new EnterSearchCallback(
this, std::move(callback)));
523 ExitSearchCallback(
Solver*
const solver, std::function<
void()> callback)
525 ~ExitSearchCallback()
override {}
526 void ExitSearch()
override;
527 void Install()
override;
530 const std::function<void()> callback_;
533void ExitSearchCallback::ExitSearch() { callback_(); }
535void ExitSearchCallback::Install() {
536 ListenToEvent(Solver::MonitorEvent::kExitSearch);
542 return RevAlloc(
new ExitSearchCallback(
this, std::move(callback)));
550 CompositeDecisionBuilder();
551 explicit CompositeDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs);
552 ~CompositeDecisionBuilder()
override;
554 void AppendMonitors(
Solver* solver,
555 std::vector<SearchMonitor*>* monitors)
override;
559 std::vector<DecisionBuilder*> builders_;
562CompositeDecisionBuilder::CompositeDecisionBuilder() {}
564CompositeDecisionBuilder::CompositeDecisionBuilder(
565 const std::vector<DecisionBuilder*>& dbs) {
566 for (
int i = 0;
i < dbs.size(); ++
i) {
571CompositeDecisionBuilder::~CompositeDecisionBuilder() {}
573void CompositeDecisionBuilder::Add(DecisionBuilder*
const db) {
575 builders_.push_back(db);
579void CompositeDecisionBuilder::AppendMonitors(
580 Solver*
const solver, std::vector<SearchMonitor*>*
const monitors) {
581 for (DecisionBuilder*
const db : builders_) {
582 db->AppendMonitors(solver, monitors);
586void CompositeDecisionBuilder::Accept(ModelVisitor*
const visitor)
const {
587 for (DecisionBuilder*
const db : builders_) {
596class ComposeDecisionBuilder :
public CompositeDecisionBuilder {
598 ComposeDecisionBuilder();
599 explicit ComposeDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs);
600 ~ComposeDecisionBuilder()
override;
601 Decision*
Next(Solver* s)
override;
602 std::string DebugString()
const override;
608ComposeDecisionBuilder::ComposeDecisionBuilder() : start_index_(0) {}
610ComposeDecisionBuilder::ComposeDecisionBuilder(
611 const std::vector<DecisionBuilder*>& dbs)
612 : CompositeDecisionBuilder(dbs), start_index_(0) {}
614ComposeDecisionBuilder::~ComposeDecisionBuilder() {}
616Decision* ComposeDecisionBuilder::Next(Solver*
const s) {
617 const int size = builders_.size();
618 for (
int i = start_index_;
i < size; ++
i) {
619 Decision* d = builders_[
i]->Next(s);
621 s->SaveAndSetValue(&start_index_, i);
625 s->SaveAndSetValue(&start_index_, size);
629std::string ComposeDecisionBuilder::DebugString()
const {
630 return absl::StrFormat(
"ComposeDecisionBuilder(%s)",
637 ComposeDecisionBuilder* c =
RevAlloc(
new ComposeDecisionBuilder());
646 ComposeDecisionBuilder* c =
RevAlloc(
new ComposeDecisionBuilder());
657 ComposeDecisionBuilder* c =
RevAlloc(
new ComposeDecisionBuilder());
666 if (dbs.size() == 1) {
669 return RevAlloc(
new ComposeDecisionBuilder(dbs));
675class ClosureDecision :
public Decision {
678 : apply_(
std::move(apply)), refute_(
std::move(refute)) {}
679 ~ClosureDecision()
override {}
681 void Apply(Solver*
const s)
override { apply_(s); }
683 void Refute(Solver*
const s)
override { refute_(s); }
685 std::string DebugString()
const override {
return "ClosureDecision"; }
688 Solver::Action apply_;
689 Solver::Action refute_;
694 return RevAlloc(
new ClosureDecision(std::move(apply), std::move(refute)));
701class TryDecisionBuilder;
703class TryDecision :
public Decision {
705 explicit TryDecision(TryDecisionBuilder* try_builder);
706 ~TryDecision()
override;
707 void Apply(
Solver* solver)
override;
708 void Refute(
Solver* solver)
override;
709 std::string DebugString()
const override {
return "TryDecision"; }
712 TryDecisionBuilder*
const try_builder_;
715class TryDecisionBuilder :
public CompositeDecisionBuilder {
717 TryDecisionBuilder();
718 explicit TryDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs);
719 ~TryDecisionBuilder()
override;
720 Decision*
Next(Solver* solver)
override;
721 std::string DebugString()
const override;
722 void AdvanceToNextBuilder(Solver* solver);
725 TryDecision try_decision_;
726 int current_builder_;
727 bool start_new_builder_;
730TryDecision::TryDecision(TryDecisionBuilder*
const try_builder)
731 : try_builder_(try_builder) {}
733TryDecision::~TryDecision() {}
735void TryDecision::Apply(Solver*
const) {}
737void TryDecision::Refute(Solver*
const solver) {
738 try_builder_->AdvanceToNextBuilder(solver);
741TryDecisionBuilder::TryDecisionBuilder()
742 : CompositeDecisionBuilder(),
744 current_builder_(-1),
745 start_new_builder_(
true) {}
747TryDecisionBuilder::TryDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs)
748 : CompositeDecisionBuilder(dbs),
750 current_builder_(-1),
751 start_new_builder_(
true) {}
753TryDecisionBuilder::~TryDecisionBuilder() {}
755Decision* TryDecisionBuilder::Next(Solver*
const solver) {
756 if (current_builder_ < 0) {
757 solver->SaveAndSetValue(¤t_builder_, 0);
758 start_new_builder_ =
true;
760 if (start_new_builder_) {
761 start_new_builder_ =
false;
762 return &try_decision_;
764 return builders_[current_builder_]->Next(solver);
768std::string TryDecisionBuilder::DebugString()
const {
769 return absl::StrFormat(
"TryDecisionBuilder(%s)",
773void TryDecisionBuilder::AdvanceToNextBuilder(Solver*
const solver) {
775 start_new_builder_ =
true;
776 if (current_builder_ >= builders_.size()) {
785 TryDecisionBuilder* try_db =
RevAlloc(
new TryDecisionBuilder());
794 TryDecisionBuilder* try_db =
RevAlloc(
new TryDecisionBuilder());
805 TryDecisionBuilder* try_db =
RevAlloc(
new TryDecisionBuilder());
814 return RevAlloc(
new TryDecisionBuilder(dbs));
822class BaseVariableAssignmentSelector :
public BaseObject {
824 BaseVariableAssignmentSelector(
Solver* solver,
825 const std::vector<IntVar*>& vars)
829 last_unbound_(vars.size() - 1) {}
831 ~BaseVariableAssignmentSelector()
override {}
833 virtual int64_t SelectValue(
const IntVar* v, int64_t
id) = 0;
836 virtual int64_t ChooseVariable() = 0;
838 int64_t ChooseVariableWrapper() {
840 for (i = first_unbound_.Value(); i <= last_unbound_.Value(); ++i) {
841 if (!vars_[i]->Bound()) {
845 first_unbound_.SetValue(solver_, i);
846 if (i > last_unbound_.Value()) {
849 for (i = last_unbound_.Value(); i >= first_unbound_.Value(); --i) {
850 if (!vars_[i]->Bound()) {
854 last_unbound_.SetValue(solver_, i);
855 return ChooseVariable();
858 void Accept(ModelVisitor*
const visitor)
const {
859 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
860 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
862 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
865 const std::vector<IntVar*>& vars()
const {
return vars_; }
868 Solver*
const solver_;
869 std::vector<IntVar*> vars_;
870 Rev<int64_t> first_unbound_;
871 Rev<int64_t> last_unbound_;
876int64_t ChooseFirstUnbound(Solver*,
const std::vector<IntVar*>& vars,
877 int64_t first_unbound, int64_t last_unbound) {
878 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
879 if (!vars[i]->Bound()) {
888int64_t ChooseMinSizeLowestMin(Solver*,
const std::vector<IntVar*>& vars,
889 int64_t first_unbound, int64_t last_unbound) {
890 uint64_t best_size = std::numeric_limits<uint64_t>::max();
891 int64_t best_min = std::numeric_limits<int64_t>::max();
892 int64_t best_index = -1;
893 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
894 IntVar*
const var = vars[
i];
896 if (var->Size() < best_size ||
897 (var->Size() == best_size && var->Min() < best_min)) {
898 best_size = var->Size();
899 best_min = var->Min();
909int64_t ChooseMinSizeHighestMin(Solver*,
const std::vector<IntVar*>& vars,
910 int64_t first_unbound, int64_t last_unbound) {
911 uint64_t best_size = std::numeric_limits<uint64_t>::max();
912 int64_t best_min = std::numeric_limits<int64_t>::min();
913 int64_t best_index = -1;
914 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
915 IntVar*
const var = vars[
i];
917 if (var->Size() < best_size ||
918 (var->Size() == best_size && var->Min() > best_min)) {
919 best_size = var->Size();
920 best_min = var->Min();
930int64_t ChooseMinSizeLowestMax(Solver*,
const std::vector<IntVar*>& vars,
931 int64_t first_unbound, int64_t last_unbound) {
932 uint64_t best_size = std::numeric_limits<uint64_t>::max();
933 int64_t best_max = std::numeric_limits<int64_t>::max();
934 int64_t best_index = -1;
935 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
936 IntVar*
const var = vars[
i];
938 if (var->Size() < best_size ||
939 (var->Size() == best_size && var->Max() < best_max)) {
940 best_size = var->Size();
941 best_max = var->Max();
951int64_t ChooseMinSizeHighestMax(Solver*,
const std::vector<IntVar*>& vars,
952 int64_t first_unbound, int64_t last_unbound) {
953 uint64_t best_size = std::numeric_limits<uint64_t>::max();
954 int64_t best_max = std::numeric_limits<int64_t>::min();
955 int64_t best_index = -1;
956 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
957 IntVar*
const var = vars[
i];
959 if (var->Size() < best_size ||
960 (var->Size() == best_size && var->Max() > best_max)) {
961 best_size = var->Size();
962 best_max = var->Max();
972int64_t ChooseLowestMin(Solver*,
const std::vector<IntVar*>& vars,
973 int64_t first_unbound, int64_t last_unbound) {
974 int64_t best_min = std::numeric_limits<int64_t>::max();
975 int64_t best_index = -1;
976 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
977 IntVar*
const var = vars[
i];
979 if (var->Min() < best_min) {
980 best_min = var->Min();
990int64_t ChooseHighestMax(Solver*,
const std::vector<IntVar*>& vars,
991 int64_t first_unbound, int64_t last_unbound) {
992 int64_t best_max = std::numeric_limits<int64_t>::min();
993 int64_t best_index = -1;
994 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
995 IntVar*
const var = vars[
i];
997 if (var->Max() > best_max) {
998 best_max = var->Max();
1008int64_t ChooseMinSize(Solver*,
const std::vector<IntVar*>& vars,
1009 int64_t first_unbound, int64_t last_unbound) {
1010 uint64_t best_size = std::numeric_limits<uint64_t>::max();
1011 int64_t best_index = -1;
1012 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
1013 IntVar*
const var = vars[
i];
1014 if (!var->Bound()) {
1015 if (var->Size() < best_size) {
1016 best_size = var->Size();
1026int64_t ChooseMaxSize(Solver*,
const std::vector<IntVar*>& vars,
1027 int64_t first_unbound, int64_t last_unbound) {
1028 uint64_t best_size = 0;
1029 int64_t best_index = -1;
1030 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
1031 IntVar*
const var = vars[
i];
1032 if (!var->Bound()) {
1033 if (var->Size() > best_size) {
1034 best_size = var->Size();
1044class HighestRegretSelectorOnMin :
public BaseObject {
1046 explicit HighestRegretSelectorOnMin(
const std::vector<IntVar*>& vars)
1047 : iterators_(vars.size()) {
1048 for (int64_t i = 0;
i < vars.size(); ++
i) {
1049 iterators_[
i] = vars[
i]->MakeDomainIterator(
true);
1052 ~HighestRegretSelectorOnMin()
override {};
1053 int64_t Choose(Solver* s,
const std::vector<IntVar*>& vars,
1054 int64_t first_unbound, int64_t last_unbound);
1055 std::string DebugString()
const override {
return "MaxRegretSelector"; }
1057 int64_t ComputeRegret(IntVar* var, int64_t index)
const {
1058 DCHECK(!var->Bound());
1059 const int64_t vmin = var->Min();
1060 IntVarIterator*
const iterator = iterators_[index];
1063 return iterator->Value() - vmin;
1067 std::vector<IntVarIterator*> iterators_;
1070int64_t HighestRegretSelectorOnMin::Choose(Solver*
const,
1071 const std::vector<IntVar*>& vars,
1072 int64_t first_unbound,
1073 int64_t last_unbound) {
1074 int64_t best_regret = 0;
1076 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
1077 IntVar*
const var = vars[
i];
1078 if (!var->Bound()) {
1079 const int64_t regret = ComputeRegret(var, i);
1080 if (regret > best_regret) {
1081 best_regret = regret;
1091int64_t ChooseRandom(Solver* solver,
const std::vector<IntVar*>& vars,
1092 int64_t first_unbound, int64_t last_unbound) {
1093 const int64_t span = last_unbound - first_unbound + 1;
1094 const int64_t shift = solver->Rand32(span);
1095 for (int64_t i = 0;
i < span; ++
i) {
1096 const int64_t index = (
i + shift) % span + first_unbound;
1097 if (!vars[index]->Bound()) {
1106class CheapestVarSelector :
public BaseObject {
1108 explicit CheapestVarSelector(std::function<int64_t(int64_t)> var_evaluator)
1109 : var_evaluator_(std::move(var_evaluator)) {}
1110 ~CheapestVarSelector()
override {};
1111 int64_t Choose(Solver* s,
const std::vector<IntVar*>& vars,
1112 int64_t first_unbound, int64_t last_unbound);
1113 std::string DebugString()
const override {
return "CheapestVarSelector"; }
1116 std::function<int64_t(int64_t)> var_evaluator_;
1119int64_t CheapestVarSelector::Choose(Solver*
const,
1120 const std::vector<IntVar*>& vars,
1121 int64_t first_unbound,
1122 int64_t last_unbound) {
1123 int64_t best_eval = std::numeric_limits<int64_t>::max();
1125 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
1126 if (!vars[i]->Bound()) {
1127 const int64_t eval = var_evaluator_(i);
1128 if (eval < best_eval) {
1140class PathSelector :
public BaseObject {
1142 PathSelector() : first_(std::numeric_limits<int64_t>::max()) {}
1143 ~PathSelector()
override {};
1144 int64_t Choose(Solver* s,
const std::vector<IntVar*>& vars);
1145 std::string DebugString()
const override {
return "ChooseNextOnPath"; }
1148 bool UpdateIndex(
const std::vector<IntVar*>& vars, int64_t* index)
const;
1149 bool FindPathStart(
const std::vector<IntVar*>& vars, int64_t* index)
const;
1151 Rev<int64_t> first_;
1154int64_t PathSelector::Choose(Solver*
const s,
1155 const std::vector<IntVar*>& vars) {
1156 int64_t index = first_.Value();
1157 if (!UpdateIndex(vars, &index)) {
1161 while (vars[index]->Bound()) {
1162 index = vars[index]->Value();
1163 if (!UpdateIndex(vars, &index)) {
1167 if (count >= vars.size() &&
1168 !FindPathStart(vars, &index)) {
1172 first_.SetValue(s, index);
1176bool PathSelector::UpdateIndex(
const std::vector<IntVar*>& vars,
1177 int64_t* index)
const {
1178 if (*index >= vars.size()) {
1179 if (!FindPathStart(vars, index)) {
1192bool PathSelector::FindPathStart(
const std::vector<IntVar*>& vars,
1193 int64_t* index)
const {
1195 for (int64_t i = vars.size() - 1; i >= 0; --i) {
1196 if (vars[i]->Bound()) {
1197 const int64_t next = vars[
i]->Value();
1198 if (next < vars.size() && !vars[next]->Bound()) {
1205 for (int64_t i = vars.size() - 1; i >= 0; --i) {
1206 if (!vars[i]->Bound()) {
1207 bool has_possible_prev =
false;
1208 for (int64_t j = 0; j < vars.size(); ++j) {
1209 if (vars[j]->Contains(i)) {
1210 has_possible_prev =
true;
1214 if (!has_possible_prev) {
1221 for (int64_t i = 0;
i < vars.size(); ++
i) {
1222 if (!vars[i]->Bound()) {
1232int64_t SelectMinValue(
const IntVar* v, int64_t) {
return v->Min(); }
1236int64_t SelectMaxValue(
const IntVar* v, int64_t) {
return v->Max(); }
1240int64_t SelectRandomValue(
const IntVar* v, int64_t) {
1241 const uint64_t span = v->Max() - v->Min() + 1;
1242 if (span > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {
1246 const uint64_t size = v->Size();
1247 Solver*
const s = v->solver();
1248 if (size > span / 4) {
1251 const int64_t value = v->Min() + s->Rand64(span);
1252 if (v->Contains(value)) {
1257 int64_t index = s->Rand64(size);
1258 if (index <= size / 2) {
1259 for (int64_t i = v->Min(); i <= v->Max(); ++
i) {
1260 if (v->Contains(i)) {
1268 for (int64_t i = v->Max(); i > v->Min(); --i) {
1269 if (v->Contains(i)) {
1283int64_t SelectCenterValue(
const IntVar* v, int64_t) {
1284 const int64_t vmin = v->Min();
1285 const int64_t vmax = v->Max();
1286 if (vmax - vmin > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {
1290 const int64_t mid = (vmin + vmax) / 2;
1291 if (v->Contains(mid)) {
1294 const int64_t diameter = vmax - mid;
1295 for (int64_t i = 1;
i <= diameter; ++
i) {
1296 if (v->Contains(mid - i)) {
1299 if (v->Contains(mid + i)) {
1308int64_t SelectSplitValue(
const IntVar* v, int64_t) {
1309 const int64_t vmin = v->Min();
1310 const int64_t vmax = v->Max();
1311 const uint64_t delta = vmax - vmin;
1312 const int64_t mid = vmin + delta / 2;
1318class CheapestValueSelector :
public BaseObject {
1320 CheapestValueSelector(std::function<int64_t(int64_t, int64_t)> eval,
1321 std::function<int64_t(int64_t)> tie_breaker)
1322 : eval_(std::move(eval)), tie_breaker_(std::move(tie_breaker)) {}
1323 ~CheapestValueSelector()
override {}
1324 int64_t Select(
const IntVar* v, int64_t
id);
1325 std::string DebugString()
const override {
return "CheapestValue"; }
1328 std::function<int64_t(int64_t, int64_t)> eval_;
1329 std::function<int64_t(int64_t)> tie_breaker_;
1330 std::vector<int64_t> cache_;
1333int64_t CheapestValueSelector::Select(
const IntVar* v, int64_t
id) {
1335 int64_t best = std::numeric_limits<int64_t>::max();
1336 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(
false));
1337 for (
const int64_t i : InitAndGetValues(it.get())) {
1338 int64_t eval = eval_(
id, i);
1342 cache_.push_back(i);
1343 }
else if (eval == best) {
1344 cache_.push_back(i);
1347 DCHECK_GT(cache_.size(), 0);
1348 if (tie_breaker_ ==
nullptr || cache_.size() == 1) {
1349 return cache_.back();
1351 return cache_[tie_breaker_(cache_.size())];
1363class BestValueByComparisonSelector :
public BaseObject {
1365 explicit BestValueByComparisonSelector(
1366 Solver::VariableValueComparator comparator)
1367 : comparator_(std::move(comparator)) {}
1368 ~BestValueByComparisonSelector()
override {}
1369 int64_t Select(
const IntVar* v, int64_t
id);
1370 std::string DebugString()
const override {
1371 return "BestValueByComparisonSelector";
1375 Solver::VariableValueComparator comparator_;
1378int64_t BestValueByComparisonSelector::Select(
const IntVar* v, int64_t
id) {
1379 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(
false));
1382 int64_t best_value = it->Value();
1383 for (it->Next(); it->Ok(); it->Next()) {
1384 const int64_t candidate_value = it->Value();
1385 if (comparator_(
id, candidate_value, best_value)) {
1386 best_value = candidate_value;
1394class VariableAssignmentSelector :
public BaseVariableAssignmentSelector {
1396 VariableAssignmentSelector(Solver* solver,
const std::vector<IntVar*>& vars,
1397 Solver::VariableIndexSelector var_selector,
1398 Solver::VariableValueSelector value_selector,
1399 const std::string& name)
1400 : BaseVariableAssignmentSelector(solver, vars),
1401 var_selector_(std::move(var_selector)),
1402 value_selector_(std::move(value_selector)),
1404 ~VariableAssignmentSelector()
override {}
1405 int64_t SelectValue(
const IntVar* var, int64_t
id)
override {
1406 return value_selector_(var,
id);
1408 int64_t ChooseVariable()
override {
1409 return var_selector_(solver_, vars_, first_unbound_.Value(),
1410 last_unbound_.Value());
1412 std::string DebugString()
const override;
1415 Solver::VariableIndexSelector var_selector_;
1416 Solver::VariableValueSelector value_selector_;
1417 const std::string name_;
1420std::string VariableAssignmentSelector::DebugString()
const {
1426class BaseEvaluatorSelector :
public BaseVariableAssignmentSelector {
1428 BaseEvaluatorSelector(Solver* solver,
const std::vector<IntVar*>& vars,
1429 std::function<int64_t(int64_t, int64_t)> evaluator);
1430 ~BaseEvaluatorSelector()
override {}
1434 Element() : var(0), value(0) {}
1435 Element(int64_t i, int64_t j) : var(
i), value(j) {}
1440 std::string DebugStringInternal(absl::string_view name)
const {
1444 std::function<int64_t(int64_t, int64_t)> evaluator_;
1447BaseEvaluatorSelector::BaseEvaluatorSelector(
1448 Solver* solver,
const std::vector<IntVar*>& vars,
1449 std::function<int64_t(int64_t, int64_t)> evaluator)
1450 : BaseVariableAssignmentSelector(solver, vars),
1451 evaluator_(std::move(evaluator)) {}
1455class DynamicEvaluatorSelector :
public BaseEvaluatorSelector {
1457 DynamicEvaluatorSelector(Solver* solver,
const std::vector<IntVar*>& vars,
1458 std::function<int64_t(int64_t, int64_t)> evaluator,
1459 std::function<int64_t(int64_t)> tie_breaker);
1460 ~DynamicEvaluatorSelector()
override {}
1461 int64_t SelectValue(
const IntVar* var, int64_t
id)
override;
1462 int64_t ChooseVariable()
override;
1463 std::string DebugString()
const override;
1467 std::function<int64_t(int64_t)> tie_breaker_;
1468 std::vector<Element> cache_;
1471DynamicEvaluatorSelector::DynamicEvaluatorSelector(
1472 Solver* solver,
const std::vector<IntVar*>& vars,
1473 std::function<int64_t(int64_t, int64_t)> evaluator,
1474 std::function<int64_t(int64_t)> tie_breaker)
1475 : BaseEvaluatorSelector(solver, vars, std::move(evaluator)),
1477 tie_breaker_(std::move(tie_breaker)) {}
1479int64_t DynamicEvaluatorSelector::SelectValue(
const IntVar*, int64_t) {
1480 return cache_[first_].value;
1483int64_t DynamicEvaluatorSelector::ChooseVariable() {
1484 int64_t best_evaluation = std::numeric_limits<int64_t>::max();
1486 for (int64_t i = 0;
i < vars_.size(); ++
i) {
1487 const IntVar*
const var = vars_[
i];
1488 if (!var->Bound()) {
1489 std::unique_ptr<IntVarIterator> it(var->MakeDomainIterator(
false));
1490 for (
const int64_t j : InitAndGetValues(it.get())) {
1491 const int64_t value = evaluator_(i, j);
1492 if (value < best_evaluation) {
1493 best_evaluation = value;
1495 cache_.push_back(Element(i, j));
1496 }
else if (value == best_evaluation && tie_breaker_) {
1497 cache_.push_back(Element(i, j));
1503 if (cache_.empty()) {
1507 if (tie_breaker_ ==
nullptr || cache_.size() == 1) {
1509 return cache_.front().var;
1511 first_ = tie_breaker_(cache_.size());
1512 return cache_[first_].var;
1516std::string DynamicEvaluatorSelector::DebugString()
const {
1517 return DebugStringInternal(
"AssignVariablesOnDynamicEvaluator");
1522class StaticEvaluatorSelector :
public BaseEvaluatorSelector {
1524 StaticEvaluatorSelector(
1525 Solver* solver,
const std::vector<IntVar*>& vars,
1526 const std::function<int64_t(int64_t, int64_t)>& evaluator);
1527 ~StaticEvaluatorSelector()
override {}
1528 int64_t SelectValue(
const IntVar* var, int64_t
id)
override;
1529 int64_t ChooseVariable()
override;
1530 std::string DebugString()
const override;
1535 explicit Compare(std::function<int64_t(int64_t, int64_t)> evaluator)
1536 : evaluator_(std::move(evaluator)) {}
1537 bool operator()(
const Element& lhs,
const Element& rhs)
const {
1538 const int64_t value_lhs =
Value(lhs);
1539 const int64_t value_rhs =
Value(rhs);
1540 return value_lhs < value_rhs ||
1541 (value_lhs == value_rhs &&
1542 (lhs.var < rhs.var ||
1543 (lhs.var == rhs.var && lhs.value < rhs.value)));
1545 int64_t
Value(
const Element& element)
const {
1546 return evaluator_(element.var, element.value);
1550 std::function<int64_t(int64_t, int64_t)> evaluator_;
1554 std::vector<Element> elements_;
1558StaticEvaluatorSelector::StaticEvaluatorSelector(
1559 Solver* solver,
const std::vector<IntVar*>& vars,
1560 const std::function<int64_t(int64_t, int64_t)>& evaluator)
1561 : BaseEvaluatorSelector(solver, vars, evaluator),
1565int64_t StaticEvaluatorSelector::SelectValue(
const IntVar*, int64_t) {
1566 return elements_[first_].value;
1569int64_t StaticEvaluatorSelector::ChooseVariable() {
1572 int64_t element_size = 0;
1573 for (int64_t i = 0;
i < vars_.size(); ++
i) {
1574 if (!vars_[i]->Bound()) {
1575 element_size += vars_[
i]->Size();
1578 elements_.resize(element_size);
1580 for (
int i = 0;
i < vars_.size(); ++
i) {
1581 const IntVar*
const var = vars_[
i];
1582 if (!var->Bound()) {
1583 std::unique_ptr<IntVarIterator> it(var->MakeDomainIterator(
false));
1584 for (
const int64_t value : InitAndGetValues(it.get())) {
1585 elements_[count++] = Element(i, value);
1590 std::sort(elements_.begin(), elements_.end(), comp_);
1591 solver_->SaveAndSetValue<int64_t>(&first_, 0);
1593 for (int64_t i = first_;
i < elements_.size(); ++
i) {
1594 const Element& element = elements_[
i];
1595 IntVar*
const var = vars_[element.var];
1596 if (!var->Bound() && var->Contains(element.value)) {
1597 solver_->SaveAndSetValue(&first_, i);
1601 solver_->SaveAndSetValue(&first_,
static_cast<int64_t
>(elements_.size()));
1605std::string StaticEvaluatorSelector::DebugString()
const {
1606 return DebugStringInternal(
"AssignVariablesOnStaticEvaluator");
1611class AssignOneVariableValue :
public Decision {
1613 AssignOneVariableValue(IntVar* v, int64_t val);
1614 ~AssignOneVariableValue()
override {}
1615 void Apply(Solver* s)
override;
1616 void Refute(Solver* s)
override;
1617 std::string DebugString()
const override;
1618 void Accept(DecisionVisitor*
const visitor)
const override {
1619 visitor->VisitSetVariableValue(var_, value_);
1627AssignOneVariableValue::AssignOneVariableValue(IntVar*
const v, int64_t val)
1628 : var_(v), value_(val) {}
1630std::string AssignOneVariableValue::DebugString()
const {
1631 return absl::StrFormat(
"[%s == %d] or [%s != %d]", var_->
DebugString(),
1635void AssignOneVariableValue::Apply(Solver*
const) { var_->
SetValue(value_); }
1637void AssignOneVariableValue::Refute(Solver*
const) {
1643 return RevAlloc(
new AssignOneVariableValue(var, val));
1649class AssignOneVariableValueOrFail :
public Decision {
1651 AssignOneVariableValueOrFail(
IntVar* v, int64_t value);
1652 ~AssignOneVariableValueOrFail()
override {}
1653 void Apply(Solver* s)
override;
1654 void Refute(Solver* s)
override;
1655 std::string DebugString()
const override;
1656 void Accept(DecisionVisitor*
const visitor)
const override {
1657 visitor->VisitSetVariableValue(var_, value_);
1662 const int64_t value_;
1665AssignOneVariableValueOrFail::AssignOneVariableValueOrFail(IntVar*
const v,
1667 : var_(v), value_(value) {}
1669std::string AssignOneVariableValueOrFail::DebugString()
const {
1670 return absl::StrFormat(
"[%s == %d] or fail", var_->
DebugString(), value_);
1673void AssignOneVariableValueOrFail::Apply(Solver*
const) {
1677void AssignOneVariableValueOrFail::Refute(Solver*
const s) { s->Fail(); }
1682 return RevAlloc(
new AssignOneVariableValueOrFail(var, value));
1688class AssignOneVariableValueDoNothing :
public Decision {
1690 AssignOneVariableValueDoNothing(
IntVar*
const v, int64_t value)
1691 : var_(v), value_(value) {}
1692 ~AssignOneVariableValueDoNothing()
override {}
1693 void Apply(Solver*
const)
override { var_->
SetValue(value_); }
1694 void Refute(Solver*
const)
override {}
1695 std::string DebugString()
const override {
1696 return absl::StrFormat(
"[%s == %d] or []", var_->
DebugString(), value_);
1698 void Accept(DecisionVisitor*
const visitor)
const override {
1699 visitor->VisitSetVariableValue(var_, value_);
1704 const int64_t value_;
1711 return RevAlloc(
new AssignOneVariableValueDoNothing(var, value));
1717class SplitOneVariable :
public Decision {
1719 SplitOneVariable(
IntVar* v, int64_t val,
bool start_with_lower_half);
1720 ~SplitOneVariable()
override {}
1721 void Apply(Solver* s)
override;
1722 void Refute(Solver* s)
override;
1723 std::string DebugString()
const override;
1724 void Accept(DecisionVisitor*
const visitor)
const override {
1725 visitor->VisitSplitVariableDomain(var_, value_, start_with_lower_half_);
1730 const int64_t value_;
1731 const bool start_with_lower_half_;
1734SplitOneVariable::SplitOneVariable(IntVar*
const v, int64_t val,
1735 bool start_with_lower_half)
1736 : var_(v), value_(val), start_with_lower_half_(start_with_lower_half) {}
1738std::string SplitOneVariable::DebugString()
const {
1739 if (start_with_lower_half_) {
1740 return absl::StrFormat(
"[%s <= %d]", var_->
DebugString(), value_);
1742 return absl::StrFormat(
"[%s >= %d]", var_->
DebugString(), value_);
1746void SplitOneVariable::Apply(Solver*
const) {
1747 if (start_with_lower_half_) {
1750 var_->
SetMin(value_ + 1);
1754void SplitOneVariable::Refute(Solver*
const) {
1755 if (start_with_lower_half_) {
1756 var_->
SetMin(value_ + 1);
1764 bool start_with_lower_half) {
1765 return RevAlloc(
new SplitOneVariable(var, val, start_with_lower_half));
1781class AssignVariablesValues :
public Decision {
1787 enum class RefutationBehavior { kForbidAssignment, kDoNothing, kFail };
1788 AssignVariablesValues(
1789 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values,
1790 RefutationBehavior refutation = RefutationBehavior::kForbidAssignment);
1791 ~AssignVariablesValues()
override {}
1792 void Apply(Solver* s)
override;
1793 void Refute(Solver* s)
override;
1794 std::string DebugString()
const override;
1795 void Accept(DecisionVisitor*
const visitor)
const override {
1796 for (
int i = 0;
i < vars_.size(); ++
i) {
1797 visitor->VisitSetVariableValue(vars_[i], values_[i]);
1801 virtual void Accept(ModelVisitor*
const visitor)
const {
1802 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
1803 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1805 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
1809 const std::vector<IntVar*> vars_;
1810 const std::vector<int64_t> values_;
1811 const RefutationBehavior refutation_;
1814AssignVariablesValues::AssignVariablesValues(
const std::vector<IntVar*>& vars,
1815 const std::vector<int64_t>& values,
1816 RefutationBehavior refutation)
1817 : vars_(vars), values_(values), refutation_(refutation) {}
1819std::string AssignVariablesValues::DebugString()
const {
1821 if (vars_.empty()) out +=
"do nothing";
1822 for (
int i = 0;
i < vars_.size(); ++
i) {
1823 absl::StrAppendFormat(&out,
"[%s == %d]", vars_[i]->DebugString(),
1826 switch (refutation_) {
1827 case RefutationBehavior::kForbidAssignment:
1828 out +=
" or forbid assignment";
1830 case RefutationBehavior::kDoNothing:
1831 out +=
" or do nothing";
1833 case RefutationBehavior::kFail:
1840void AssignVariablesValues::Apply(Solver*
const) {
1841 if (vars_.empty())
return;
1842 vars_[0]->FreezeQueue();
1843 for (
int i = 0;
i < vars_.size(); ++
i) {
1844 vars_[
i]->SetValue(values_[i]);
1846 vars_[0]->UnfreezeQueue();
1849void AssignVariablesValues::Refute(Solver*
const s) {
1850 switch (refutation_) {
1851 case RefutationBehavior::kForbidAssignment: {
1852 std::vector<IntVar*> terms;
1853 for (
int i = 0;
i < vars_.size(); ++
i) {
1854 IntVar* term = s->MakeBoolVar();
1855 s->AddConstraint(s->MakeIsDifferentCstCt(vars_[i], values_[i], term));
1856 terms.push_back(term);
1858 s->AddConstraint(s->MakeSumGreaterOrEqual(terms, 1));
1861 case RefutationBehavior::kDoNothing: {
1864 case RefutationBehavior::kFail: {
1873 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1874 CHECK_EQ(vars.size(), values.size());
1875 return RevAlloc(
new AssignVariablesValues(
1877 AssignVariablesValues::RefutationBehavior::kForbidAssignment));
1881 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1882 CHECK_EQ(vars.size(), values.size());
1883 return RevAlloc(
new AssignVariablesValues(
1884 vars, values, AssignVariablesValues::RefutationBehavior::kDoNothing));
1888 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1889 CHECK_EQ(vars.size(), values.size());
1890 return RevAlloc(
new AssignVariablesValues(
1891 vars, values, AssignVariablesValues::RefutationBehavior::kFail));
1905 BaseAssignVariables(BaseVariableAssignmentSelector*
const selector, Mode mode)
1906 : selector_(selector), mode_(mode) {}
1908 ~BaseAssignVariables()
override;
1909 Decision*
Next(Solver* s)
override;
1910 std::string DebugString()
const override;
1911 static BaseAssignVariables* MakePhase(
1912 Solver* s,
const std::vector<IntVar*>& vars,
1913 Solver::VariableIndexSelector var_selector,
1914 Solver::VariableValueSelector value_selector,
1915 const std::string& value_selector_name, BaseAssignVariables::Mode mode);
1917 static Solver::VariableIndexSelector MakeVariableSelector(
1918 Solver*
const s,
const std::vector<IntVar*>& vars,
1919 Solver::IntVarStrategy str) {
1921 case Solver::INT_VAR_DEFAULT:
1922 case Solver::INT_VAR_SIMPLE:
1923 case Solver::CHOOSE_FIRST_UNBOUND:
1924 return ChooseFirstUnbound;
1925 case Solver::CHOOSE_RANDOM:
1926 return ChooseRandom;
1927 case Solver::CHOOSE_MIN_SIZE_LOWEST_MIN:
1928 return ChooseMinSizeLowestMin;
1929 case Solver::CHOOSE_MIN_SIZE_HIGHEST_MIN:
1930 return ChooseMinSizeHighestMin;
1931 case Solver::CHOOSE_MIN_SIZE_LOWEST_MAX:
1932 return ChooseMinSizeLowestMax;
1933 case Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX:
1934 return ChooseMinSizeHighestMax;
1935 case Solver::CHOOSE_LOWEST_MIN:
1936 return ChooseLowestMin;
1937 case Solver::CHOOSE_HIGHEST_MAX:
1938 return ChooseHighestMax;
1939 case Solver::CHOOSE_MIN_SIZE:
1940 return ChooseMinSize;
1941 case Solver::CHOOSE_MAX_SIZE:
1942 return ChooseMaxSize;
1943 case Solver::CHOOSE_MAX_REGRET_ON_MIN: {
1944 HighestRegretSelectorOnMin*
const selector =
1945 s->RevAlloc(
new HighestRegretSelectorOnMin(vars));
1946 return [selector](Solver* solver,
const std::vector<IntVar*>& vars,
1947 int first_unbound,
int last_unbound) {
1948 return selector->Choose(solver, vars, first_unbound, last_unbound);
1951 case Solver::CHOOSE_PATH: {
1952 PathSelector*
const selector = s->RevAlloc(
new PathSelector());
1953 return [selector](Solver* solver,
const std::vector<IntVar*>& vars, int,
1954 int) {
return selector->Choose(solver, vars); };
1957 LOG(FATAL) <<
"Unknown int var strategy " << str;
1962 static Solver::VariableValueSelector MakeValueSelector(
1963 Solver*
const, Solver::IntValueStrategy val_str) {
1965 case Solver::INT_VALUE_DEFAULT:
1966 case Solver::INT_VALUE_SIMPLE:
1967 case Solver::ASSIGN_MIN_VALUE:
1968 return SelectMinValue;
1969 case Solver::ASSIGN_MAX_VALUE:
1970 return SelectMaxValue;
1971 case Solver::ASSIGN_RANDOM_VALUE:
1972 return SelectRandomValue;
1973 case Solver::ASSIGN_CENTER_VALUE:
1974 return SelectCenterValue;
1975 case Solver::SPLIT_LOWER_HALF:
1976 return SelectSplitValue;
1977 case Solver::SPLIT_UPPER_HALF:
1978 return SelectSplitValue;
1980 LOG(FATAL) <<
"Unknown int value strategy " << val_str;
1985 void Accept(ModelVisitor*
const visitor)
const override {
1986 selector_->Accept(visitor);
1990 BaseVariableAssignmentSelector*
const selector_;
1994BaseAssignVariables::~BaseAssignVariables() {}
1996Decision* BaseAssignVariables::Next(Solver*
const s) {
1997 const std::vector<IntVar*>& vars = selector_->vars();
1998 int id = selector_->ChooseVariableWrapper();
1999 if (
id >= 0 &&
id < vars.size()) {
2000 IntVar*
const var = vars[id];
2001 const int64_t value = selector_->SelectValue(var,
id);
2004 return s->RevAlloc(
new AssignOneVariableValue(var, value));
2006 return s->RevAlloc(
new SplitOneVariable(var, value,
true));
2008 return s->RevAlloc(
new SplitOneVariable(var, value,
false));
2014std::string BaseAssignVariables::DebugString()
const {
2015 return selector_->DebugString();
2018BaseAssignVariables* BaseAssignVariables::MakePhase(
2019 Solver*
const s,
const std::vector<IntVar*>& vars,
2022 const std::string& value_selector_name, BaseAssignVariables::Mode mode) {
2023 BaseVariableAssignmentSelector*
const selector =
2024 s->RevAlloc(
new VariableAssignmentSelector(
2025 s, vars, std::move(var_selector), std::move(value_selector),
2026 value_selector_name));
2027 return s->RevAlloc(
new BaseAssignVariables(selector, mode));
2035 return "ChooseFirstUnbound";
2037 return "ChooseRandom";
2039 return "ChooseMinSizeLowestMin";
2041 return "ChooseMinSizeHighestMin";
2043 return "ChooseMinSizeLowestMax";
2045 return "ChooseMinSizeHighestMax";
2047 return "ChooseLowestMin";
2049 return "ChooseHighestMax";
2051 return "ChooseMinSize";
2053 return "ChooseMaxSize;";
2055 return "HighestRegretSelectorOnMin";
2057 return "PathSelector";
2059 LOG(FATAL) <<
"Unknown int var strategy " << var_str;
2069 return "SelectMinValue";
2071 return "SelectMaxValue";
2073 return "SelectRandomValue";
2075 return "SelectCenterValue";
2077 return "SelectSplitValue";
2079 return "SelectSplitValue";
2081 LOG(FATAL) <<
"Unknown int value strategy " << val_str;
2088 return ChooseVariableName(var_str) +
"_" + SelectValueName(val_str);
2095 std::vector<IntVar*> vars(1);
2097 return MakePhase(vars, var_str, val_str);
2103 std::vector<IntVar*> vars(2);
2106 return MakePhase(vars, var_str, val_str);
2113 std::vector<IntVar*> vars(3);
2117 return MakePhase(vars, var_str, val_str);
2124 std::vector<IntVar*> vars(4);
2129 return MakePhase(vars, var_str, val_str);
2133 BaseAssignVariables::Mode mode = BaseAssignVariables::ASSIGN;
2135 mode = BaseAssignVariables::SPLIT_LOWER;
2137 mode = BaseAssignVariables::SPLIT_UPPER;
2145 return BaseAssignVariables::MakePhase(
2147 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str),
2148 BaseAssignVariables::MakeValueSelector(
this, val_str),
2149 BuildHeuristicsName(var_str, val_str),
2156 CHECK(var_evaluator !=
nullptr);
2157 CheapestVarSelector*
const var_selector =
2158 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2159 return BaseAssignVariables::MakePhase(
2162 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2163 int first_unbound,
int last_unbound) {
2164 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2166 BaseAssignVariables::MakeValueSelector(
this, val_str),
2167 "ChooseCheapestVariable_" +
2168 SelectValueName(val_str),
2175 CheapestValueSelector*
const value_selector =
2176 RevAlloc(
new CheapestValueSelector(std::move(value_evaluator),
nullptr));
2177 return BaseAssignVariables::MakePhase(
2180 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str),
2182 [value_selector](
const IntVar* var, int64_t
id) {
2183 return value_selector->Select(var,
id);
2185 ChooseVariableName(var_str) +
2186 "_SelectCheapestValue",
2187 BaseAssignVariables::ASSIGN);
2193 BestValueByComparisonSelector*
const value_selector =
RevAlloc(
2194 new BestValueByComparisonSelector(std::move(var_val1_val2_comparator)));
2195 return BaseAssignVariables::MakePhase(
2197 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str),
2199 [value_selector](
const IntVar* var, int64_t
id) {
2200 return value_selector->Select(var,
id);
2202 "CheapestValue", BaseAssignVariables::ASSIGN);
2208 CheapestVarSelector*
const var_selector =
2209 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2210 CheapestValueSelector* value_selector =
2211 RevAlloc(
new CheapestValueSelector(std::move(value_evaluator),
nullptr));
2212 return BaseAssignVariables::MakePhase(
2214 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2215 int first_unbound,
int last_unbound) {
2216 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2219 [value_selector](
const IntVar* var, int64_t id) {
2220 return value_selector->Select(var,
id);
2222 "CheapestValue", BaseAssignVariables::ASSIGN);
2229 CheapestValueSelector* value_selector =
RevAlloc(
new CheapestValueSelector(
2230 std::move(value_evaluator), std::move(tie_breaker)));
2231 return BaseAssignVariables::MakePhase(
2233 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str),
2235 [value_selector](
const IntVar* var, int64_t
id) {
2236 return value_selector->Select(var,
id);
2238 "CheapestValue", BaseAssignVariables::ASSIGN);
2245 CheapestVarSelector*
const var_selector =
2246 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2247 CheapestValueSelector* value_selector =
RevAlloc(
new CheapestValueSelector(
2248 std::move(value_evaluator), std::move(tie_breaker)));
2249 return BaseAssignVariables::MakePhase(
2251 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2252 int first_unbound,
int last_unbound) {
2253 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2256 [value_selector](
const IntVar* var, int64_t id) {
2257 return value_selector->Select(var,
id);
2259 "CheapestValue", BaseAssignVariables::ASSIGN);
2265 return MakePhase(vars, std::move(eval),
nullptr, str);
2272 BaseVariableAssignmentSelector* selector =
nullptr;
2277 RevAlloc(
new StaticEvaluatorSelector(
this, vars, std::move(eval)));
2281 selector =
RevAlloc(
new DynamicEvaluatorSelector(
2282 this, vars, std::move(eval), std::move(tie_breaker)));
2287 new BaseAssignVariables(selector, BaseAssignVariables::ASSIGN));
2295 AssignVariablesFromAssignment(
const Assignment*
const assignment,
2297 const std::vector<IntVar*>& vars)
2298 : assignment_(assignment), db_(db), vars_(vars), iter_(0) {}
2300 ~AssignVariablesFromAssignment()
override {}
2302 Decision*
Next(Solver*
const s)
override {
2303 if (iter_ < vars_.size()) {
2304 IntVar*
const var = vars_[iter_++];
2306 new AssignOneVariableValue(var, assignment_->
Value(var)));
2308 return db_->
Next(s);
2312 void Accept(ModelVisitor*
const visitor)
const override {
2313 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
2314 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2316 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
2320 const Assignment*
const assignment_;
2321 DecisionBuilder*
const db_;
2322 const std::vector<IntVar*> vars_;
2329 const std::vector<IntVar*>& vars) {
2330 return RevAlloc(
new AssignVariablesFromAssignment(assignment, db, vars));
2360 const auto other_fields =
2362 if (fields != other_fields)
return fields < other_fields;
2364 DCHECK_EQ(other.
solution,
nullptr);
2367 for (
int i = 0; i <
solution->NumObjectives(); ++i) {
2368 const int64_t value =
solution->ObjectiveValueFromIndex(i);
2370 if (value != other_value)
return value < other_value;
2416 if (
prototype_ !=
nullptr && objective !=
nullptr) {
2472 CHECK_GE(n, 0) <<
"wrong index in solution getter";
2473 CHECK_LT(n,
solution_data_.size()) <<
"wrong index in solution getter";
2556 explicit FirstSolutionCollector(
Solver* s);
2557 ~FirstSolutionCollector()
override;
2558 void EnterSearch()
override;
2559 bool AtSolution()
override;
2560 void Install()
override;
2561 std::string DebugString()
const override;
2567FirstSolutionCollector::FirstSolutionCollector(Solver*
const s,
2568 const Assignment*
const a)
2571FirstSolutionCollector::FirstSolutionCollector(
Solver*
const s)
2574FirstSolutionCollector::~FirstSolutionCollector() {}
2576void FirstSolutionCollector::EnterSearch() {
2577 SolutionCollector::EnterSearch();
2581bool FirstSolutionCollector::AtSolution() {
2589void FirstSolutionCollector::Install() {
2590 SolutionCollector::Install();
2591 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2594std::string FirstSolutionCollector::DebugString()
const {
2595 if (prototype_ ==
nullptr) {
2596 return "FirstSolutionCollector()";
2598 return "FirstSolutionCollector(" + prototype_->DebugString() +
")";
2605 return RevAlloc(
new FirstSolutionCollector(
this, assignment));
2609 return RevAlloc(
new FirstSolutionCollector(
this));
2619 explicit LastSolutionCollector(
Solver* s);
2620 ~LastSolutionCollector()
override;
2621 bool AtSolution()
override;
2622 void Install()
override;
2623 std::string DebugString()
const override;
2626LastSolutionCollector::LastSolutionCollector(Solver*
const s,
2627 const Assignment*
const a)
2628 : SolutionCollector(s, a) {}
2630LastSolutionCollector::LastSolutionCollector(
Solver*
const s)
2633LastSolutionCollector::~LastSolutionCollector() {}
2635bool LastSolutionCollector::AtSolution() {
2641void LastSolutionCollector::Install() {
2642 SolutionCollector::Install();
2643 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2646std::string LastSolutionCollector::DebugString()
const {
2647 if (prototype_ ==
nullptr) {
2648 return "LastSolutionCollector()";
2650 return "LastSolutionCollector(" + prototype_->DebugString() +
")";
2657 return RevAlloc(
new LastSolutionCollector(
this, assignment));
2661 return RevAlloc(
new LastSolutionCollector(
this));
2670 std::vector<bool> maximize);
2671 BestValueSolutionCollector(
Solver* solver, std::vector<bool> maximize);
2672 ~BestValueSolutionCollector()
override {}
2673 void EnterSearch()
override;
2674 bool AtSolution()
override;
2675 void Install()
override;
2676 std::string DebugString()
const override;
2679 void ResetBestObjective() {
2680 for (
int i = 0; i < maximize_.size(); ++i) {
2681 best_[i] = maximize_[i] ? std::numeric_limits<int64_t>::min()
2682 :
std::numeric_limits<int64_t>::max();
2686 const std::vector<bool> maximize_;
2687 std::vector<int64_t> best_;
2690BestValueSolutionCollector::BestValueSolutionCollector(
2691 Solver* solver,
const Assignment* assignment, std::vector<bool> maximize)
2692 : SolutionCollector(solver, assignment),
2693 maximize_(std::move(maximize)),
2694 best_(maximize_.size()) {
2695 ResetBestObjective();
2698BestValueSolutionCollector::BestValueSolutionCollector(
2699 Solver* solver, std::vector<bool> maximize)
2701 maximize_(std::move(maximize)),
2702 best_(maximize_.size()) {
2703 ResetBestObjective();
2706void BestValueSolutionCollector::EnterSearch() {
2707 SolutionCollector::EnterSearch();
2708 ResetBestObjective();
2711bool BestValueSolutionCollector::AtSolution() {
2712 if (prototype_ !=
nullptr && prototype_->HasObjective()) {
2713 const int size = std::min(prototype_->NumObjectives(),
2714 static_cast<int>(maximize_.size()));
2717 bool is_improvement =
false;
2718 for (
int i = 0;
i < size; ++
i) {
2719 const IntVar* objective = prototype_->ObjectiveFromIndex(i);
2720 const int64_t objective_value =
2721 maximize_[
i] ?
CapOpp(objective->Max()) : objective->Min();
2722 if (objective_value < best_[i]) {
2723 is_improvement =
true;
2725 }
else if (objective_value > best_[i]) {
2729 if (solution_count() == 0 || is_improvement) {
2732 for (
int i = 0;
i < size; ++
i) {
2733 best_[
i] = maximize_[
i]
2734 ?
CapOpp(prototype_->ObjectiveFromIndex(i)->Max())
2735 : prototype_->ObjectiveFromIndex(
i)->Min();
2742void BestValueSolutionCollector::Install() {
2743 SolutionCollector::Install();
2744 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2747std::string BestValueSolutionCollector::DebugString()
const {
2748 if (prototype_ ==
nullptr) {
2749 return "BestValueSolutionCollector()";
2751 return "BestValueSolutionCollector(" + prototype_->DebugString() +
")";
2757 const Assignment*
const assignment,
bool maximize) {
2758 return RevAlloc(
new BestValueSolutionCollector(
this, assignment, {maximize}));
2762 const Assignment* assignment, std::vector<bool> maximize) {
2764 new BestValueSolutionCollector(
this, assignment, std::move(maximize)));
2768 return RevAlloc(
new BestValueSolutionCollector(
this, {maximize}));
2772 std::vector<bool> maximize) {
2773 return RevAlloc(
new BestValueSolutionCollector(
this, std::move(maximize)));
2782 int solution_count, std::vector<bool> maximize);
2783 NBestValueSolutionCollector(
Solver* solver,
int solution_count,
2784 std::vector<bool> maximize);
2785 ~NBestValueSolutionCollector()
override { Clear(); }
2786 void EnterSearch()
override;
2787 void ExitSearch()
override;
2788 bool AtSolution()
override;
2789 void Install()
override;
2790 std::string DebugString()
const override;
2795 const std::vector<bool> maximize_;
2796 std::priority_queue<std::pair<std::vector<int64_t>, SolutionData>>
2798 const int solution_count_;
2801NBestValueSolutionCollector::NBestValueSolutionCollector(
2802 Solver* solver,
const Assignment* assignment,
int solution_count,
2803 std::vector<bool> maximize)
2804 : SolutionCollector(solver, assignment),
2805 maximize_(std::move(maximize)),
2806 solution_count_(solution_count) {}
2808NBestValueSolutionCollector::NBestValueSolutionCollector(
2809 Solver* solver,
int solution_count, std::vector<bool> maximize)
2811 maximize_(std::move(maximize)),
2812 solution_count_(solution_count) {}
2814void NBestValueSolutionCollector::EnterSearch() {
2815 SolutionCollector::EnterSearch();
2818 if (solution_count_ > 1) {
2819 solver()->SetUseFastLocalSearch(
false);
2824void NBestValueSolutionCollector::ExitSearch() {
2825 while (!solutions_pq_.empty()) {
2826 Push(solutions_pq_.top().second);
2827 solutions_pq_.pop();
2831bool NBestValueSolutionCollector::AtSolution() {
2832 if (prototype_ !=
nullptr && prototype_->HasObjective()) {
2833 const int size = std::min(prototype_->NumObjectives(),
2834 static_cast<int>(maximize_.size()));
2835 std::vector<int64_t> objective_values(size);
2836 for (
int i = 0;
i < size; ++
i) {
2837 objective_values[
i] =
2838 maximize_[
i] ?
CapOpp(prototype_->ObjectiveFromIndex(i)->Max())
2839 : prototype_->ObjectiveFromIndex(
i)->Min();
2841 if (solutions_pq_.size() < solution_count_) {
2843 {std::move(objective_values), BuildSolutionDataForCurrentState()});
2844 }
else if (!solutions_pq_.empty()) {
2845 const auto& [top_obj_value, top_sol_data] = solutions_pq_.top();
2846 if (std::lexicographical_compare(
2847 objective_values.begin(), objective_values.end(),
2848 top_obj_value.begin(), top_obj_value.end())) {
2849 FreeSolution(top_sol_data.solution);
2850 solutions_pq_.pop();
2852 {std::move(objective_values), BuildSolutionDataForCurrentState()});
2859void NBestValueSolutionCollector::Install() {
2860 SolutionCollector::Install();
2861 ListenToEvent(Solver::MonitorEvent::kExitSearch);
2862 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2865std::string NBestValueSolutionCollector::DebugString()
const {
2866 if (prototype_ ==
nullptr) {
2867 return "NBestValueSolutionCollector()";
2869 return "NBestValueSolutionCollector(" + prototype_->DebugString() +
")";
2873void NBestValueSolutionCollector::Clear() {
2874 while (!solutions_pq_.empty()) {
2875 delete solutions_pq_.top().second.solution;
2876 solutions_pq_.pop();
2883 const Assignment* assignment,
int solution_count,
bool maximize) {
2884 if (solution_count == 1) {
2887 return RevAlloc(
new NBestValueSolutionCollector(
this, assignment,
2888 solution_count, {maximize}));
2893 if (solution_count == 1) {
2897 new NBestValueSolutionCollector(
this, solution_count, {maximize}));
2901 const Assignment* assignment,
int solution_count,
2902 std::vector<bool> maximize) {
2903 if (solution_count == 1) {
2905 std::move(maximize));
2907 return RevAlloc(
new NBestValueSolutionCollector(
2908 this, assignment, solution_count, std::move(maximize)));
2912 int solution_count, std::vector<bool> maximize) {
2913 if (solution_count == 1) {
2916 return RevAlloc(
new NBestValueSolutionCollector(
this, solution_count,
2917 std::move(maximize)));
2926 explicit AllSolutionCollector(
Solver* s);
2927 ~AllSolutionCollector()
override;
2928 bool AtSolution()
override;
2929 void Install()
override;
2930 std::string DebugString()
const override;
2933AllSolutionCollector::AllSolutionCollector(Solver*
const s,
2934 const Assignment*
const a)
2935 : SolutionCollector(s, a) {}
2937AllSolutionCollector::AllSolutionCollector(
Solver*
const s)
2940AllSolutionCollector::~AllSolutionCollector() {}
2942bool AllSolutionCollector::AtSolution() {
2947void AllSolutionCollector::Install() {
2948 SolutionCollector::Install();
2949 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2952std::string AllSolutionCollector::DebugString()
const {
2953 if (prototype_ ==
nullptr) {
2954 return "AllSolutionCollector()";
2956 return "AllSolutionCollector(" + prototype_->DebugString() +
")";
2963 return RevAlloc(
new AllSolutionCollector(
this, assignment));
2967 return RevAlloc(
new AllSolutionCollector(
this));
2975 std::vector<BaseObjectiveMonitor*> monitors,
2976 int num_max_local_optima_before_metaheuristic_switch)
2978 monitors_(
std::move(monitors)),
2979 enabled_monitors_(monitors_.size(), true),
2980 local_optimum_limit_(num_max_local_optima_before_metaheuristic_switch) {
2983 active_monitor_ = 0;
2984 num_local_optimum_ = 0;
2985 enabled_monitors_.assign(monitors_.size(),
true);
2986 for (
auto& monitor : monitors_) {
2987 monitor->set_active(monitor == monitors_[active_monitor_]);
2988 monitor->EnterSearch();
2992 monitors_[active_monitor_]->ApplyDecision(d);
2995 monitors_[active_monitor_]->AcceptNeighbor();
2999 for (
auto& monitor : monitors_) {
3000 ok &= monitor->AtSolution();
3005 return monitors_[active_monitor_]->AcceptDelta(delta, deltadelta);
3008 monitors_[active_monitor_]->BeginNextDecision(db);
3011 monitors_[active_monitor_]->RefuteDecision(d);
3014 return monitors_[active_monitor_]->AcceptSolution();
3017 const bool ok = monitors_[active_monitor_]->LocalOptimum();
3019 enabled_monitors_[active_monitor_] =
false;
3021 if (++num_local_optimum_ >= local_optimum_limit_ || !ok) {
3022 monitors_[active_monitor_]->set_active(
false);
3023 int next_active_monitor = (active_monitor_ + 1) % monitors_.size();
3024 while (!enabled_monitors_[next_active_monitor]) {
3025 if (next_active_monitor == active_monitor_)
return false;
3026 next_active_monitor = (active_monitor_ + 1) % monitors_.size();
3028 active_monitor_ = next_active_monitor;
3029 monitors_[active_monitor_]->set_active(
true);
3030 num_local_optimum_ = 0;
3031 VLOG(2) <<
"Switching to monitor " << active_monitor_ <<
" "
3032 << monitors_[active_monitor_]->DebugString();
3037 return monitors_[active_monitor_]->ObjectiveVar(index);
3040 return monitors_[active_monitor_]->MinimizationVar(index);
3042 int64_t
Step(
int index)
const override {
3043 return monitors_[active_monitor_]->Step(index);
3046 return monitors_[active_monitor_]->Maximize(index);
3049 return monitors_[active_monitor_]->BestValue(index);
3051 int Size()
const override {
return monitors_[active_monitor_]->Size(); }
3053 return monitors_[active_monitor_]->DebugString();
3057 for (
auto& monitor : monitors_) {
3058 monitor->Accept(visitor);
3063 const std::vector<BaseObjectiveMonitor*> monitors_;
3064 std::vector<bool> enabled_monitors_;
3065 int active_monitor_ = 0;
3066 int num_local_optimum_ = 0;
3067 const int local_optimum_limit_;
3071 std::vector<BaseObjectiveMonitor*> monitors,
3072 int num_max_local_optima_before_metaheuristic_switch) {
3074 std::move(monitors), num_max_local_optima_before_metaheuristic_switch));
3078 const std::vector<bool>& maximize,
3079 std::vector<IntVar*> vars,
3080 std::vector<int64_t> steps)
3083 objective_vars_(
std::move(vars)),
3084 minimization_vars_(objective_vars_),
3085 upper_bounds_(
Size() + 1, nullptr),
3086 steps_(
std::move(steps)),
3087 best_values_(
Size(),
std::numeric_limits<int64_t>::max()),
3088 current_values_(
Size(),
std::numeric_limits<int64_t>::max()) {
3089 DCHECK_GT(
Size(), 0);
3090 DCHECK_EQ(objective_vars_.size(), steps_.size());
3091 DCHECK_EQ(objective_vars_.size(), maximize.size());
3092 DCHECK(std::all_of(steps_.begin(), steps_.end(),
3093 [](int64_t step) { return step > 0; }));
3094 for (
int i = 0; i <
Size(); ++i) {
3096 minimization_vars_[i] =
solver->MakeOpposite(objective_vars_[i])->Var();
3100 minimization_vars_.push_back(
solver->MakeIntConst(1));
3101 upper_bounds_.back() =
solver->MakeIntConst(0);
3102 steps_.push_back(1);
3113 best_values_.assign(
Size(), std::numeric_limits<int64_t>::max());
3114 current_values_ = best_values_;
3119 for (
int i = 0; i <
Size(); ++i) {
3126 if (std::lexicographical_compare(current_values_.begin(),
3127 current_values_.end(), best_values_.begin(),
3128 best_values_.end())) {
3129 best_values_ = current_values_;
3136 if (delta ==
nullptr)
return true;
3137 const bool delta_has_objective = delta->
HasObjective();
3138 if (!delta_has_objective) {
3143 for (
int i = 0; i <
Size(); ++i) {
3147 if (delta_has_objective) {
3150 if (
solver()->UseFastLocalSearch() &&
3151 i < local_search_state->NumObjectives()) {
3159 if (delta_has_objective) {
3162 if (
solver()->UseFastLocalSearch() &&
3163 i < local_search_state->NumObjectives()) {
3181 minimization_vars_);
3186 int num_values_at_max = 0;
3187 for (
int i = 0; i <
Size(); ++i) {
3189 DCHECK_EQ(num_values_at_max, 0);
3191 ++num_values_at_max;
3194 DCHECK(num_values_at_max == 0 || num_values_at_max ==
Size());
3195 return num_values_at_max <
Size();
3201 std::vector<IntVar*>{var}, {step}) {}
3204 std::vector<IntVar*> vars, std::vector<int64_t> steps)
3208 if (
solver()->SearchDepth() == 0) {
3229 for (
int i = 0; i <
Size(); ++i) {
3233 if (!minimization_var->
Bound())
return true;
3234 const int64_t value = minimization_var->
Value();
3251 for (
int i = 0; i <
Size(); ++i) {
3252 absl::StrAppendFormat(
3253 &out,
"%s%s(%s, step = %d, best = %d)", i == 0 ?
"" :
"; ",
3254 Maximize(i) ?
"MaximizeVar" :
"MinimizeVar",
3274 std::vector<IntVar*> variables,
3275 std::vector<int64_t> steps) {
3277 std::move(variables), std::move(steps)));
3283 WeightedOptimizeVar(
Solver* solver,
bool maximize,
3284 const std::vector<IntVar*>& sub_objectives,
3285 const std::vector<int64_t>& weights, int64_t step)
3287 solver->MakeScalProd(sub_objectives, weights)->Var(), step),
3288 sub_objectives_(sub_objectives),
3290 CHECK_EQ(sub_objectives.size(), weights.size());
3293 ~WeightedOptimizeVar()
override {}
3294 std::string Name()
const override;
3297 const std::vector<IntVar*> sub_objectives_;
3298 const std::vector<int64_t> weights_;
3301std::string WeightedOptimizeVar::Name()
const {
return "weighted objective"; }
3305 bool maximize,
const std::vector<IntVar*>& sub_objectives,
3306 const std::vector<int64_t>& weights, int64_t step) {
3308 new WeightedOptimizeVar(
this, maximize, sub_objectives, weights, step));
3312 const std::vector<IntVar*>& sub_objectives,
3313 const std::vector<int64_t>& weights, int64_t step) {
3315 new WeightedOptimizeVar(
this,
false, sub_objectives, weights, step));
3319 const std::vector<IntVar*>& sub_objectives,
3320 const std::vector<int64_t>& weights, int64_t step) {
3322 new WeightedOptimizeVar(
this,
true, sub_objectives, weights, step));
3326 bool maximize,
const std::vector<IntVar*>& sub_objectives,
3327 const std::vector<int>& weights, int64_t step) {
3333 const std::vector<IntVar*>& sub_objectives,
const std::vector<int>& weights,
3339 const std::vector<IntVar*>& sub_objectives,
const std::vector<int>& weights,
3349 Metaheuristic(
Solver* solver,
const std::vector<bool>& maximize,
3350 std::vector<IntVar*> objectives, std::vector<int64_t> steps);
3351 ~Metaheuristic()
override {}
3353 void EnterSearch()
override;
3354 void RefuteDecision(Decision* d)
override;
3357Metaheuristic::Metaheuristic(Solver* solver,
const std::vector<bool>& maximize,
3358 std::vector<IntVar*> objectives,
3359 std::vector<int64_t> steps)
3360 : ObjectiveMonitor(solver, maximize, std::move(objectives),
3361 std::move(steps)) {}
3363void Metaheuristic::EnterSearch() {
3364 ObjectiveMonitor::EnterSearch();
3367 solver()->SetUseFastLocalSearch(
false);
3370void Metaheuristic::RefuteDecision(Decision*) {
3371 for (
int i = 0;
i < Size(); ++
i) {
3372 const int64_t objective_value = MinimizationVar(i)->Min();
3373 if (objective_value > BestInternalValue(i))
break;
3374 if (objective_value <=
CapSub(BestInternalValue(i), Step(i)))
return;
3381class TabuSearch :
public Metaheuristic {
3383 TabuSearch(Solver* solver,
const std::vector<bool>& maximize,
3384 std::vector<IntVar*> objectives, std::vector<int64_t> steps,
3385 const std::vector<IntVar*>& vars, int64_t keep_tenure,
3386 int64_t forbid_tenure,
double tabu_factor);
3387 ~TabuSearch()
override {}
3388 void EnterSearch()
override;
3389 void ApplyDecision(Decision* d)
override;
3390 bool AtSolution()
override;
3391 bool LocalOptimum()
override;
3392 bool AcceptDelta(Assignment* delta, Assignment* deltadelta)
override;
3394 std::string DebugString()
const override {
return "Tabu Search"; }
3402 typedef std::list<VarValue> TabuList;
3404 virtual std::vector<IntVar*> CreateTabuVars();
3405 const TabuList& forbid_tabu_list() {
return forbid_tabu_list_; }
3406 IntVar* vars(
int index)
const {
return vars_[index]; }
3409 void AgeList(int64_t tenure, TabuList* list);
3411 int64_t TabuLimit()
const {
3412 return (synced_keep_tabu_list_.size() + synced_forbid_tabu_list_.size()) *
3416 const std::vector<IntVar*> vars_;
3417 Assignment::IntContainer assignment_container_;
3418 bool has_stored_assignment_ =
false;
3419 std::vector<int64_t> last_values_;
3420 TabuList keep_tabu_list_;
3421 TabuList synced_keep_tabu_list_;
3422 int64_t keep_tenure_;
3423 TabuList forbid_tabu_list_;
3424 TabuList synced_forbid_tabu_list_;
3425 int64_t forbid_tenure_;
3426 double tabu_factor_;
3430TabuSearch::TabuSearch(Solver* solver,
const std::vector<bool>& maximize,
3431 std::vector<IntVar*> objectives,
3432 std::vector<int64_t> steps,
3433 const std::vector<IntVar*>& vars, int64_t keep_tenure,
3434 int64_t forbid_tenure,
double tabu_factor)
3435 : Metaheuristic(solver, maximize, std::move(objectives), std::move(steps)),
3437 last_values_(Size(), std::numeric_limits<int64_t>::max()),
3438 keep_tenure_(keep_tenure),
3439 forbid_tenure_(forbid_tenure),
3440 tabu_factor_(tabu_factor),
3442 for (
int index = 0; index < vars_.size(); ++index) {
3443 assignment_container_.FastAdd(vars_[index]);
3444 DCHECK_EQ(vars_[index], assignment_container_.Element(index).Var());
3448void TabuSearch::EnterSearch() {
3449 Metaheuristic::EnterSearch();
3450 solver()->SetUseFastLocalSearch(
true);
3452 has_stored_assignment_ =
false;
3455void TabuSearch::ApplyDecision(Decision*
const d) {
3456 Solver*
const s = solver();
3457 if (d == s->balancing_decision()) {
3461 synced_keep_tabu_list_ = keep_tabu_list_;
3462 synced_forbid_tabu_list_ = forbid_tabu_list_;
3463 Constraint* tabu_ct =
nullptr;
3467 const std::vector<IntVar*> tabu_vars = CreateTabuVars();
3468 if (!tabu_vars.empty()) {
3469 IntVar* tabu_var = s->MakeIsGreaterOrEqualCstVar(
3470 s->MakeSum(tabu_vars)->Var(), TabuLimit());
3473 IntVar* aspiration = MakeMinimizationVarsLessOrEqualWithStepsStatus(
3474 [
this](
int i) {
return BestInternalValue(i); });
3475 tabu_ct = s->MakeSumGreaterOrEqual({aspiration, tabu_var}, int64_t{1});
3478 if (tabu_ct !=
nullptr) s->AddConstraint(tabu_ct);
3481 if (CurrentInternalValuesAreConstraining()) {
3482 MakeMinimizationVarsLessOrEqualWithSteps(
3483 [
this](
int i) {
return CurrentInternalValue(i); });
3486 if (found_initial_solution_) {
3487 Constraint* plateau_ct =
nullptr;
3489 plateau_ct = s->MakeNonEquality(MinimizationVar(0), last_values_[0]);
3491 std::vector<IntVar*> plateau_vars(Size());
3492 for (
int i = 0;
i < Size(); ++
i) {
3494 s->MakeIsEqualCstVar(MinimizationVar(i), last_values_[i]);
3496 plateau_ct = s->MakeSumLessOrEqual(plateau_vars, Size() - 1);
3498 s->AddConstraint(plateau_ct);
3502std::vector<IntVar*> TabuSearch::CreateTabuVars() {
3503 Solver*
const s = solver();
3511 std::vector<IntVar*> tabu_vars;
3512 for (
const auto [var_index, value, unused_stamp] : keep_tabu_list_) {
3513 tabu_vars.push_back(s->MakeIsEqualCstVar(vars(var_index), value));
3515 for (
const auto [var_index, value, unused_stamp] : forbid_tabu_list_) {
3516 tabu_vars.push_back(s->MakeIsDifferentCstVar(vars(var_index), value));
3521bool TabuSearch::AtSolution() {
3522 if (!ObjectiveMonitor::AtSolution()) {
3525 for (
int i = 0;
i < Size(); ++
i) {
3526 last_values_[
i] = CurrentInternalValue(i);
3531 if (0 != stamp_ && has_stored_assignment_) {
3532 for (
int index = 0; index < vars_.size(); ++index) {
3533 IntVar* var = vars(index);
3534 const int64_t old_value = assignment_container_.
Element(index).
Value();
3535 const int64_t new_value = var->Value();
3536 if (old_value != new_value) {
3537 if (keep_tenure_ > 0) {
3538 keep_tabu_list_.push_front({index, new_value, stamp_});
3540 if (forbid_tenure_ > 0) {
3541 forbid_tabu_list_.push_front({index, old_value, stamp_});
3546 assignment_container_.
Store();
3547 has_stored_assignment_ =
true;
3552bool TabuSearch::LocalOptimum() {
3553 solver()->SetUseFastLocalSearch(
false);
3555 for (
int i = 0;
i < Size(); ++
i) {
3556 SetCurrentInternalValue(i, std::numeric_limits<int64_t>::max());
3558 return found_initial_solution_;
3561bool TabuSearch::AcceptDelta(Assignment* delta, Assignment* deltadelta) {
3562 if (delta ==
nullptr)
return true;
3563 if (!Metaheuristic::AcceptDelta(delta, deltadelta))
return false;
3564 if (synced_keep_tabu_list_.empty() && synced_forbid_tabu_list_.empty()) {
3567 const Assignment::IntContainer& delta_container = delta->IntVarContainer();
3569 for (
const IntVarElement& element : delta_container.elements()) {
3570 if (!element.Bound())
return true;
3572 int num_respected = 0;
3574 auto get_value = [
this, &delta_container](
int var_index) {
3575 const IntVarElement* element =
3576 delta_container.ElementPtrOrNull(vars(var_index));
3577 return (element !=
nullptr)
3581 for (
const auto [var_index, value, unused_stamp] : synced_keep_tabu_list_) {
3582 if (get_value(var_index) == value) {
3586 for (
const auto [var_index, value, unused_stamp] : synced_forbid_tabu_list_) {
3587 if (get_value(var_index) != value) {
3591 const int64_t tabu_limit = TabuLimit();
3592 if (num_respected >= tabu_limit)
return true;
3597 delta->SetObjectiveMinFromIndex(0,
CapAdd(BestInternalValue(0), Step(0)));
3599 delta->SetObjectiveMaxFromIndex(0,
CapSub(BestInternalValue(0), Step(0)));
3602 for (
int i = 0;
i < Size(); ++
i) {
3604 delta->SetObjectiveMinFromIndex(i, BestInternalValue(i));
3606 delta->SetObjectiveMaxFromIndex(i, BestInternalValue(i));
3614void TabuSearch::AcceptNeighbor() {
3620void TabuSearch::AgeList(int64_t tenure, TabuList* list) {
3621 while (!list->empty() && list->back().stamp < stamp_ - tenure) {
3626void TabuSearch::AgeLists() {
3627 AgeList(keep_tenure_, &keep_tabu_list_);
3628 AgeList(forbid_tenure_, &forbid_tabu_list_);
3632class GenericTabuSearch :
public TabuSearch {
3634 GenericTabuSearch(Solver* solver,
bool maximize, IntVar* objective,
3635 int64_t step,
const std::vector<IntVar*>& vars,
3636 int64_t forbid_tenure)
3637 : TabuSearch(solver, {maximize}, {objective}, {step}, vars, 0,
3638 forbid_tenure, 1) {}
3639 std::string DebugString()
const override {
return "Generic Tabu Search"; }
3642 std::vector<IntVar*> CreateTabuVars()
override;
3645std::vector<IntVar*> GenericTabuSearch::CreateTabuVars() {
3646 Solver*
const s = solver();
3650 std::vector<IntVar*> forbid_values;
3651 for (
const auto [var_index, value, unused_stamp] : forbid_tabu_list()) {
3652 forbid_values.push_back(s->MakeIsDifferentCstVar(vars(var_index), value));
3654 std::vector<IntVar*> tabu_vars;
3655 if (!forbid_values.empty()) {
3656 tabu_vars.push_back(s->MakeIsGreaterCstVar(s->MakeSum(forbid_values), 0));
3665 const std::vector<IntVar*>& vars,
3666 int64_t keep_tenure,
3667 int64_t forbid_tenure,
3668 double tabu_factor) {
3669 return RevAlloc(
new TabuSearch(
this, {maximize}, {objective}, {step}, vars,
3670 keep_tenure, forbid_tenure, tabu_factor));
3674 const std::vector<bool>& maximize, std::vector<IntVar*> objectives,
3675 std::vector<int64_t> steps,
const std::vector<IntVar*>& vars,
3676 int64_t keep_tenure, int64_t forbid_tenure,
double tabu_factor) {
3677 return RevAlloc(
new TabuSearch(
this, maximize, std::move(objectives),
3678 std::move(steps), vars, keep_tenure,
3679 forbid_tenure, tabu_factor));
3683 bool maximize,
IntVar*
const v, int64_t step,
3684 const std::vector<IntVar*>& tabu_vars, int64_t forbid_tenure) {
3686 new GenericTabuSearch(
this, maximize, v, step, tabu_vars, forbid_tenure));
3692class SimulatedAnnealing :
public Metaheuristic {
3694 SimulatedAnnealing(
Solver* solver,
const std::vector<bool>& maximize,
3695 std::vector<IntVar*> objectives,
3696 std::vector<int64_t> steps,
3697 std::vector<int64_t> initial_temperatures);
3698 ~SimulatedAnnealing()
override {}
3699 void ApplyDecision(Decision* d)
override;
3700 bool LocalOptimum()
override;
3701 void AcceptNeighbor()
override;
3702 std::string DebugString()
const override {
return "Simulated Annealing"; }
3705 double Temperature(
int index)
const {
3706 return iteration_ > 0
3707 ? (1.0 * temperature0_[index]) / iteration_
3711 const std::vector<int64_t> temperature0_;
3716SimulatedAnnealing::SimulatedAnnealing(
3717 Solver* solver,
const std::vector<bool>& maximize,
3718 std::vector<IntVar*> objectives, std::vector<int64_t> steps,
3719 std::vector<int64_t> initial_temperatures)
3720 : Metaheuristic(solver, maximize, std::move(objectives), std::move(steps)),
3721 temperature0_(std::move(initial_temperatures)),
3738void SimulatedAnnealing::ApplyDecision(
Decision*
const d) {
3739 Solver*
const s = solver();
3740 if (d == s->balancing_decision()) {
3743 if (CurrentInternalValuesAreConstraining()) {
3744 MakeMinimizationVarsLessOrEqualWithSteps([
this](
int i) {
3745 const double rand_double = absl::Uniform<double>(rand_, 0.0, 1.0);
3746#if defined(_MSC_VER) || defined(__ANDROID__)
3747 const double rand_log2_double = log(rand_double) / log(2.0L);
3749 const double rand_log2_double = log2(rand_double);
3751 const int64_t energy_bound = Temperature(i) * rand_log2_double;
3754 return CapSub(CurrentInternalValue(i), energy_bound);
3759bool SimulatedAnnealing::LocalOptimum() {
3760 for (
int i = 0;
i < Size(); ++
i) {
3761 SetCurrentInternalValue(i, std::numeric_limits<int64_t>::max());
3764 if (!found_initial_solution_)
return false;
3765 for (
int i = 0;
i < Size(); ++
i) {
3766 if (Temperature(i) <= 0)
return false;
3771void SimulatedAnnealing::AcceptNeighbor() {
3772 if (iteration_ > 0) {
3780 int64_t initial_temperature) {
3781 return RevAlloc(
new SimulatedAnnealing(
this, {maximize}, {v}, {step},
3782 {initial_temperature}));
3786 const std::vector<bool>& maximize, std::vector<IntVar*> vars,
3787 std::vector<int64_t> steps, std::vector<int64_t> initial_temperatures) {
3788 return RevAlloc(
new SimulatedAnnealing(
this, maximize, std::move(vars),
3790 std::move(initial_temperatures)));
3800class GuidedLocalSearchPenaltiesTable {
3806 explicit GuidedLocalSearchPenaltiesTable(
int num_vars);
3807 bool HasPenalties()
const {
return has_values_; }
3808 void IncrementPenalty(
const VarValue& var_value);
3809 int64_t GetPenalty(
const VarValue& var_value)
const;
3813 std::vector<std::vector<int64_t>> penalties_;
3817GuidedLocalSearchPenaltiesTable::GuidedLocalSearchPenaltiesTable(
int num_vars)
3818 : penalties_(num_vars), has_values_(
false) {}
3820void GuidedLocalSearchPenaltiesTable::IncrementPenalty(
3821 const VarValue& var_value) {
3822 std::vector<int64_t>& var_penalties = penalties_[var_value.var];
3823 const int64_t value = var_value.value;
3824 if (value >= var_penalties.size()) {
3825 var_penalties.resize(value + 1, 0);
3827 ++var_penalties[value];
3831void GuidedLocalSearchPenaltiesTable::Reset() {
3832 has_values_ =
false;
3833 for (
int i = 0;
i < penalties_.size(); ++
i) {
3834 penalties_[
i].clear();
3838int64_t GuidedLocalSearchPenaltiesTable::GetPenalty(
3839 const VarValue& var_value)
const {
3840 const std::vector<int64_t>& var_penalties = penalties_[var_value.var];
3841 const int64_t value = var_value.value;
3842 return (value >= var_penalties.size()) ? 0 : var_penalties[value];
3846class GuidedLocalSearchPenaltiesMap {
3852 friend bool operator==(
const VarValue& lhs,
const VarValue& rhs) {
3853 return lhs.var == rhs.var && lhs.value == rhs.value;
3855 template <
typename H>
3857 return H::combine(std::move(h), var_value.var, var_value.value);
3860 explicit GuidedLocalSearchPenaltiesMap(
int num_vars);
3861 bool HasPenalties()
const {
return (!penalties_.empty()); }
3862 void IncrementPenalty(
const VarValue& var_value);
3863 int64_t GetPenalty(
const VarValue& var_value)
const;
3868 absl::flat_hash_map<VarValue, int64_t> penalties_;
3871GuidedLocalSearchPenaltiesMap::GuidedLocalSearchPenaltiesMap(
int num_vars)
3872 : penalized_(num_vars,
false) {}
3874void GuidedLocalSearchPenaltiesMap::IncrementPenalty(
3875 const VarValue& var_value) {
3876 ++penalties_[var_value];
3877 penalized_.
Set(var_value.var,
true);
3880void GuidedLocalSearchPenaltiesMap::Reset() {
3885int64_t GuidedLocalSearchPenaltiesMap::GetPenalty(
3886 const VarValue& var_value)
const {
3887 return (penalized_.
Get(var_value.var))
3892template <
typename P>
3893class GuidedLocalSearch :
public Metaheuristic {
3896 Solver* solver, IntVar* objective,
bool maximize, int64_t step,
3897 const std::vector<IntVar*>& vars,
double penalty_factor,
3898 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
3899 get_equivalent_pairs,
3900 bool reset_penalties_on_new_best_solution);
3901 ~GuidedLocalSearch()
override {}
3902 bool AcceptDelta(Assignment* delta, Assignment* deltadelta)
override;
3903 void ApplyDecision(Decision* d)
override;
3904 bool AtSolution()
override;
3905 void EnterSearch()
override;
3906 bool LocalOptimum()
override;
3907 virtual int64_t AssignmentElementPenalty(
int index)
const = 0;
3908 virtual int64_t AssignmentPenalty(int64_t var, int64_t value)
const = 0;
3909 virtual int64_t Evaluate(
const Assignment* delta, int64_t current_penalty,
3910 bool incremental) = 0;
3911 virtual IntExpr* MakeElementPenalty(
int index) = 0;
3912 std::string DebugString()
const override {
return "Guided Local Search"; }
3918 template <
typename T,
typename IndexType =
int64_t>
3921 explicit DirtyArray(IndexType size)
3922 : base_data_(size), modified_data_(size), touched_(size) {}
3925 void Set(IndexType i,
const T& value) {
3926 modified_data_[
i] = value;
3930 void SetAll(
const T& value) {
3931 for (IndexType i = 0;
i < modified_data_.size(); ++
i) {
3936 T Get(IndexType i)
const {
return modified_data_[
i]; }
3940 for (
const IndexType index : touched_.PositionsSetAtLeastOnce()) {
3941 base_data_[index] = modified_data_[index];
3943 touched_.ResetAllToFalse();
3947 for (
const IndexType index : touched_.PositionsSetAtLeastOnce()) {
3948 modified_data_[index] = base_data_[index];
3950 touched_.ResetAllToFalse();
3954 int NumSetValues()
const {
3955 return touched_.NumberOfSetCallsWithDifferentArguments();
3959 std::vector<T> base_data_;
3960 std::vector<T> modified_data_;
3961 SparseBitset<IndexType> touched_;
3964 int64_t GetValue(int64_t index)
const {
3967 IntVar* GetVar(int64_t index)
const {
3970 void AddVars(
const std::vector<IntVar*>& vars);
3971 int NumPrimaryVars()
const {
return num_vars_; }
3972 int GetLocalIndexFromVar(IntVar* var)
const {
3973 const int var_index = var->index();
3974 return (var_index < var_index_to_local_index_.size())
3975 ? var_index_to_local_index_[var_index]
3978 void ResetPenalties();
3980 IntVar* penalized_objective_;
3981 Assignment::IntContainer assignment_;
3982 int64_t assignment_penalized_value_;
3983 int64_t old_penalized_value_;
3984 const int num_vars_;
3985 std::vector<int> var_index_to_local_index_;
3986 const double penalty_factor_;
3988 DirtyArray<int64_t> penalized_values_;
3990 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
3991 get_equivalent_pairs_;
3992 const bool reset_penalties_on_new_best_solution_;
3995template <
typename P>
3996GuidedLocalSearch<P>::GuidedLocalSearch(
3997 Solver* solver, IntVar* objective,
bool maximize, int64_t step,
3998 const std::vector<IntVar*>& vars,
double penalty_factor,
3999 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4000 get_equivalent_pairs,
4001 bool reset_penalties_on_new_best_solution)
4002 : Metaheuristic(solver, {maximize}, {objective}, {step}),
4003 penalized_objective_(
nullptr),
4004 assignment_penalized_value_(0),
4005 old_penalized_value_(0),
4006 num_vars_(vars.size()),
4007 penalty_factor_(penalty_factor),
4008 penalties_(vars.size()),
4009 penalized_values_(vars.size()),
4010 incremental_(
false),
4011 get_equivalent_pairs_(std::move(get_equivalent_pairs)),
4012 reset_penalties_on_new_best_solution_(
4013 reset_penalties_on_new_best_solution) {
4017template <
typename P>
4018void GuidedLocalSearch<P>::AddVars(
const std::vector<IntVar*>& vars) {
4019 const int offset = assignment_.Size();
4020 if (vars.empty())
return;
4021 assignment_.Resize(offset + vars.size());
4022 for (
int i = 0;
i < vars.size(); ++
i) {
4023 assignment_.AddAtPosition(vars[i], offset + i);
4025 const int max_var_index =
4026 (*std::max_element(vars.begin(), vars.end(), [](
IntVar* a,
IntVar* b) {
4027 return a->index() < b->index();
4029 if (max_var_index >= var_index_to_local_index_.size()) {
4030 var_index_to_local_index_.resize(max_var_index + 1, -1);
4032 for (
int i = 0;
i < vars.size(); ++
i) {
4033 var_index_to_local_index_[vars[
i]->index()] = offset +
i;
4044template <
typename P>
4045void GuidedLocalSearch<P>::ApplyDecision(
Decision*
const d) {
4046 if (d == solver()->balancing_decision()) {
4049 assignment_penalized_value_ = 0;
4050 if (penalties_.HasPenalties()) {
4054 std::vector<IntVar*> elements;
4055 for (
int i = 0;
i < num_vars_; ++
i) {
4056 elements.push_back(MakeElementPenalty(i)->Var());
4057 const int64_t penalty = AssignmentElementPenalty(i);
4058 penalized_values_.Set(i, penalty);
4059 assignment_penalized_value_ =
4060 CapAdd(assignment_penalized_value_, penalty);
4062 solver()->SaveAndSetValue(
4063 reinterpret_cast<void**
>(&penalized_objective_),
4064 reinterpret_cast<void*
>(solver()->MakeSum(elements)->Var()));
4066 penalized_values_.Commit();
4067 old_penalized_value_ = assignment_penalized_value_;
4068 incremental_ =
false;
4069 IntExpr* max_pen_exp = solver()->MakeDifference(
4070 CapSub(CurrentInternalValue(0), Step(0)), penalized_objective_);
4073 ->MakeMax(max_pen_exp,
CapSub(BestInternalValue(0), Step(0)))
4075 solver()->AddConstraint(
4076 solver()->MakeLessOrEqual(MinimizationVar(0), max_exp));
4078 penalized_objective_ =
nullptr;
4079 const int64_t
bound =
4080 (CurrentInternalValue(0) < std::numeric_limits<int64_t>::max())
4081 ?
CapSub(CurrentInternalValue(0), Step(0))
4082 : CurrentInternalValue(0);
4083 MinimizationVar(0)->SetMax(bound);
4087template <
typename P>
4088void GuidedLocalSearch<P>::ResetPenalties() {
4089 assignment_penalized_value_ = 0;
4090 old_penalized_value_ = 0;
4091 penalized_values_.SetAll(0);
4092 penalized_values_.Commit();
4096template <
typename P>
4097bool GuidedLocalSearch<P>::AtSolution() {
4098 const int64_t old_best = BestInternalValue(0);
4102 if (penalized_objective_ !=
nullptr && penalized_objective_->Bound()) {
4107 if (reset_penalties_on_new_best_solution_ &&
4108 old_best != BestInternalValue(0)) {
4110 DCHECK_EQ(CurrentInternalValue(0), BestInternalValue(0));
4113 SetCurrentInternalValue(
4114 0,
CapAdd(CurrentInternalValue(0), penalized_objective_->Value()));
4117 assignment_.Store();
4121template <
typename P>
4122void GuidedLocalSearch<P>::EnterSearch() {
4123 Metaheuristic::EnterSearch();
4124 solver()->SetUseFastLocalSearch(
true);
4125 penalized_objective_ =
nullptr;
4131template <
typename P>
4132bool GuidedLocalSearch<P>::AcceptDelta(
Assignment* delta,
4134 if (delta ==
nullptr && deltadelta ==
nullptr)
return true;
4135 if (!penalties_.HasPenalties()) {
4136 return Metaheuristic::AcceptDelta(delta, deltadelta);
4138 int64_t penalty = 0;
4139 if (!deltadelta->Empty()) {
4140 if (!incremental_) {
4141 DCHECK_EQ(penalized_values_.NumSetValues(), 0);
4142 penalty = Evaluate(delta, assignment_penalized_value_,
true);
4144 penalty = Evaluate(deltadelta, old_penalized_value_,
true);
4146 incremental_ =
true;
4149 penalized_values_.Revert();
4151 incremental_ =
false;
4152 DCHECK_EQ(penalized_values_.NumSetValues(), 0);
4153 penalty = Evaluate(delta, assignment_penalized_value_,
false);
4155 old_penalized_value_ = penalty;
4156 if (!delta->HasObjective()) {
4157 delta->AddObjective(ObjectiveVar(0));
4159 if (delta->Objective() == ObjectiveVar(0)) {
4160 const int64_t
bound =
4161 std::max(
CapSub(
CapSub(CurrentInternalValue(0), Step(0)), penalty),
4162 CapSub(BestInternalValue(0), Step(0)));
4164 delta->SetObjectiveMin(std::max(
CapOpp(bound), delta->ObjectiveMin()));
4166 delta->SetObjectiveMax(std::min(bound, delta->ObjectiveMax()));
4174template <
typename P>
4175bool GuidedLocalSearch<P>::LocalOptimum() {
4176 solver()->SetUseFastLocalSearch(
false);
4177 std::vector<double> utilities(num_vars_);
4178 double max_utility = -std::numeric_limits<double>::infinity();
4179 for (
int var = 0; var < num_vars_; ++var) {
4181 if (!element.Bound()) {
4185 const int64_t value = element.Value();
4188 const int64_t cost = (value != var) ? AssignmentPenalty(var, value) : 0;
4189 const double utility = cost / (penalties_.GetPenalty({var, value}) + 1.0);
4190 utilities[var] = utility;
4191 if (utility > max_utility) max_utility = utility;
4193 for (
int var = 0; var < num_vars_; ++var) {
4194 if (utilities[var] == max_utility) {
4196 DCHECK(element.Bound());
4197 const int64_t value = element.Value();
4198 if (get_equivalent_pairs_ ==
nullptr) {
4199 penalties_.IncrementPenalty({var, value});
4201 for (
const auto [other_var, other_value] :
4202 get_equivalent_pairs_(var, value)) {
4203 penalties_.IncrementPenalty({other_var, other_value});
4208 SetCurrentInternalValue(0, std::numeric_limits<int64_t>::max());
4212template <
typename P>
4213class BinaryGuidedLocalSearch :
public GuidedLocalSearch<P> {
4215 BinaryGuidedLocalSearch(
4216 Solver* solver, IntVar* objective,
4217 std::function<int64_t(int64_t, int64_t)> objective_function,
4218 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
4219 double penalty_factor,
4220 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4221 get_equivalent_pairs,
4222 bool reset_penalties_on_new_best_solution);
4223 ~BinaryGuidedLocalSearch()
override {}
4224 IntExpr* MakeElementPenalty(
int index)
override;
4225 int64_t AssignmentElementPenalty(
int index)
const override;
4226 int64_t AssignmentPenalty(int64_t var, int64_t value)
const override;
4227 int64_t Evaluate(
const Assignment* delta, int64_t current_penalty,
4228 bool incremental)
override;
4231 int64_t PenalizedValue(int64_t i, int64_t j)
const;
4232 std::function<int64_t(int64_t, int64_t)> objective_function_;
4235template <
typename P>
4236BinaryGuidedLocalSearch<P>::BinaryGuidedLocalSearch(
4238 std::function<int64_t(int64_t, int64_t)> objective_function,
bool maximize,
4239 int64_t step,
const std::vector<IntVar*>& vars,
double penalty_factor,
4240 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4241 get_equivalent_pairs,
4242 bool reset_penalties_on_new_best_solution)
4243 : GuidedLocalSearch<P>(solver, objective, maximize, step, vars,
4244 penalty_factor, std::move(get_equivalent_pairs),
4245 reset_penalties_on_new_best_solution),
4246 objective_function_(std::move(objective_function)) {
4247 solver->SetGuidedLocalSearchPenaltyCallback(
4248 [
this](int64_t i, int64_t j, int64_t) {
return PenalizedValue(i, j); });
4251template <
typename P>
4252IntExpr* BinaryGuidedLocalSearch<P>::MakeElementPenalty(
int index) {
4253 return this->solver()->MakeElement(
4254 [
this, index](int64_t i) {
return PenalizedValue(index, i); },
4255 this->GetVar(index));
4258template <
typename P>
4259int64_t BinaryGuidedLocalSearch<P>::AssignmentElementPenalty(
int index)
const {
4260 return PenalizedValue(index, this->GetValue(index));
4263template <
typename P>
4264int64_t BinaryGuidedLocalSearch<P>::AssignmentPenalty(int64_t var,
4265 int64_t value)
const {
4266 return objective_function_(var, value);
4269template <
typename P>
4270int64_t BinaryGuidedLocalSearch<P>::Evaluate(
const Assignment* delta,
4271 int64_t current_penalty,
4273 int64_t penalty = current_penalty;
4275 for (
const IntVarElement& new_element : container.elements()) {
4276 const int index = this->GetLocalIndexFromVar(new_element.Var());
4277 if (index == -1)
continue;
4278 penalty =
CapSub(penalty, this->penalized_values_.Get(index));
4279 if (new_element.Activated()) {
4280 const int64_t new_penalty = PenalizedValue(index, new_element.Value());
4281 penalty =
CapAdd(penalty, new_penalty);
4283 this->penalized_values_.Set(index, new_penalty);
4291template <
typename P>
4292int64_t BinaryGuidedLocalSearch<P>::PenalizedValue(int64_t i, int64_t j)
const {
4293 const int64_t penalty = this->penalties_.GetPenalty({
i, j});
4295 if (penalty == 0)
return 0;
4296 const double penalized_value_fp =
4297 this->penalty_factor_ * penalty * objective_function_(i, j);
4298 const int64_t penalized_value =
4299 (penalized_value_fp <= std::numeric_limits<int64_t>::max())
4300 ?
static_cast<int64_t
>(penalized_value_fp)
4301 : std::numeric_limits<int64_t>::max();
4302 return penalized_value;
4305template <
typename P>
4306class TernaryGuidedLocalSearch :
public GuidedLocalSearch<P> {
4308 TernaryGuidedLocalSearch(
4309 Solver* solver, IntVar* objective,
4310 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
4311 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
4312 const std::vector<IntVar*>& secondary_vars,
double penalty_factor,
4313 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4314 get_equivalent_pairs,
4315 bool reset_penalties_on_new_best_solution);
4316 ~TernaryGuidedLocalSearch()
override {}
4317 IntExpr* MakeElementPenalty(
int index)
override;
4318 int64_t AssignmentElementPenalty(
int index)
const override;
4319 int64_t AssignmentPenalty(int64_t var, int64_t value)
const override;
4320 int64_t Evaluate(
const Assignment* delta, int64_t current_penalty,
4321 bool incremental)
override;
4324 int64_t PenalizedValue(int64_t i, int64_t j, int64_t k)
const;
4326 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function_;
4327 std::vector<int> secondary_values_;
4330template <
typename P>
4331TernaryGuidedLocalSearch<P>::TernaryGuidedLocalSearch(
4333 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
4334 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
4335 const std::vector<IntVar*>& secondary_vars,
double penalty_factor,
4336 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4337 get_equivalent_pairs,
4338 bool reset_penalties_on_new_best_solution)
4339 : GuidedLocalSearch<P>(solver, objective, maximize, step, vars,
4340 penalty_factor, std::move(get_equivalent_pairs),
4341 reset_penalties_on_new_best_solution),
4342 objective_function_(std::move(objective_function)),
4343 secondary_values_(this->NumPrimaryVars(), -1) {
4344 this->AddVars(secondary_vars);
4345 solver->SetGuidedLocalSearchPenaltyCallback(
4346 [
this](int64_t i, int64_t j, int64_t k) {
4347 return PenalizedValue(i, j, k);
4351template <
typename P>
4352IntExpr* TernaryGuidedLocalSearch<P>::MakeElementPenalty(
int index) {
4353 Solver*
const solver = this->solver();
4355 solver->AddConstraint(solver->MakeLightElement(
4356 [
this, index](int64_t j, int64_t k) {
4357 return PenalizedValue(index, j, k);
4359 var, this->GetVar(index), this->GetVar(this->NumPrimaryVars() + index)));
4363template <
typename P>
4364int64_t TernaryGuidedLocalSearch<P>::AssignmentElementPenalty(
int index)
const {
4365 return PenalizedValue(index, this->GetValue(index),
4366 this->GetValue(this->NumPrimaryVars() + index));
4369template <
typename P>
4370int64_t TernaryGuidedLocalSearch<P>::AssignmentPenalty(int64_t var,
4371 int64_t value)
const {
4372 return objective_function_(var, value,
4373 this->GetValue(this->NumPrimaryVars() + var));
4376template <
typename P>
4377int64_t TernaryGuidedLocalSearch<P>::Evaluate(
const Assignment* delta,
4378 int64_t current_penalty,
4380 int64_t penalty = current_penalty;
4385 for (
const IntVarElement& new_element : container.elements()) {
4386 const int index = this->GetLocalIndexFromVar(new_element.Var());
4387 if (index != -1 && index < this->NumPrimaryVars()) {
4388 secondary_values_[index] = -1;
4391 for (
const IntVarElement& new_element : container.elements()) {
4392 const int index = this->GetLocalIndexFromVar(new_element.Var());
4393 if (!new_element.Activated())
continue;
4394 if (index != -1 && index >= this->NumPrimaryVars()) {
4395 secondary_values_[index - this->NumPrimaryVars()] = new_element.Value();
4398 for (
const IntVarElement& new_element : container.elements()) {
4399 const int index = this->GetLocalIndexFromVar(new_element.Var());
4401 if (index == -1 || index >= this->NumPrimaryVars()) {
4404 penalty =
CapSub(penalty, this->penalized_values_.Get(index));
4406 if (new_element.Activated() && secondary_values_[index] != -1) {
4407 const int64_t new_penalty =
4408 PenalizedValue(index, new_element.Value(), secondary_values_[index]);
4409 penalty =
CapAdd(penalty, new_penalty);
4411 this->penalized_values_.Set(index, new_penalty);
4419template <
typename P>
4420int64_t TernaryGuidedLocalSearch<P>::PenalizedValue(int64_t i, int64_t j,
4422 const int64_t penalty = this->penalties_.GetPenalty({
i, j});
4424 if (penalty == 0)
return 0;
4425 const double penalized_value_fp =
4426 this->penalty_factor_ * penalty * objective_function_(i, j, k);
4427 const int64_t penalized_value =
4428 (penalized_value_fp < std::numeric_limits<int64_t>::max())
4429 ?
static_cast<int64_t
>(penalized_value_fp)
4430 : std::numeric_limits<int64_t>::max();
4431 return penalized_value;
4436 bool maximize,
IntVar*
const objective,
4438 const std::vector<IntVar*>& vars,
double penalty_factor,
4439 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4440 get_equivalent_pairs,
4441 bool reset_penalties_on_new_best_solution) {
4442 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
4443 return RevAlloc(
new BinaryGuidedLocalSearch<GuidedLocalSearchPenaltiesMap>(
4444 this, objective, std::move(objective_function), maximize, step, vars,
4445 penalty_factor, std::move(get_equivalent_pairs),
4446 reset_penalties_on_new_best_solution));
4449 new BinaryGuidedLocalSearch<GuidedLocalSearchPenaltiesTable>(
4450 this, objective, std::move(objective_function), maximize, step,
4451 vars, penalty_factor, std::move(get_equivalent_pairs),
4452 reset_penalties_on_new_best_solution));
4457 bool maximize,
IntVar*
const objective,
4459 const std::vector<IntVar*>& vars,
4460 const std::vector<IntVar*>& secondary_vars,
double penalty_factor,
4461 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4462 get_equivalent_pairs,
4463 bool reset_penalties_on_new_best_solution) {
4464 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
4465 return RevAlloc(
new TernaryGuidedLocalSearch<GuidedLocalSearchPenaltiesMap>(
4466 this, objective, std::move(objective_function), maximize, step, vars,
4467 secondary_vars, penalty_factor, std::move(get_equivalent_pairs),
4468 reset_penalties_on_new_best_solution));
4471 new TernaryGuidedLocalSearch<GuidedLocalSearchPenaltiesTable>(
4472 this, objective, std::move(objective_function), maximize, step,
4473 vars, secondary_vars, penalty_factor,
4474 std::move(get_equivalent_pairs),
4475 reset_penalties_on_new_best_solution));
4508 if (crossed_ ||
Check()) {
4514void SearchLimit::TopPeriodicCheck() {
4515 if (
solver()->TopLevelSearch() !=
solver()->ActiveSearch()) {
4524 int64_t
solutions,
bool smart_time_check,
4527 duration_limit_(time),
4528 solver_time_at_limit_start_(s->Now()),
4529 last_time_elapsed_(
absl::ZeroDuration()),
4532 smart_time_check_(smart_time_check),
4534 branches_offset_(0),
4536 failures_offset_(0),
4538 solutions_offset_(0),
4539 cumulative_(cumulative) {}
4554 duration_limit_ = regular->duration_limit_;
4555 branches_ = regular->branches_;
4556 failures_ = regular->failures_;
4557 solutions_ = regular->solutions_;
4558 smart_time_check_ = regular->smart_time_check_;
4559 cumulative_ = regular->cumulative_;
4573 return s->
branches() - branches_offset_ >= branches_ ||
4574 s->
failures() - failures_offset_ >= failures_ || CheckTime(offset) ||
4575 s->
solutions() - solutions_offset_ >= solutions_;
4580 int64_t progress = GetPercent(s->
branches(), branches_offset_, branches_);
4581 progress = std::max(progress,
4582 GetPercent(s->
failures(), failures_offset_, failures_));
4583 progress = std::max(
4584 progress, GetPercent(s->
solutions(), solutions_offset_, solutions_));
4586 progress = std::max(progress, (100 * TimeElapsed()) /
duration_limit());
4595 solver_time_at_limit_start_ = s->
Now();
4596 last_time_elapsed_ = absl::ZeroDuration();
4606 branches_ -= s->
branches() - branches_offset_;
4607 failures_ -= s->
failures() - failures_offset_;
4608 duration_limit_ -= s->
Now() - solver_time_at_limit_start_;
4609 solutions_ -= s->
solutions() - solutions_offset_;
4616 duration_limit_ = time;
4629 return absl::StrFormat(
4630 "RegularLimit(crossed = %i, duration_limit = %s, "
4631 "branches = %d, failures = %d, solutions = %d cumulative = %s",
4633 solutions_, (cumulative_ ?
"true" :
"false"));
4651bool RegularLimit::CheckTime(absl::Duration offset) {
4655absl::Duration RegularLimit::TimeElapsed() {
4656 const int64_t kMaxSkip = 100;
4657 const int64_t kCheckWarmupIterations = 100;
4660 next_check_ <= check_count_) {
4661 Solver*
const s =
solver();
4662 absl::Duration elapsed = s->Now() - solver_time_at_limit_start_;
4663 if (smart_time_check_ && check_count_ > kCheckWarmupIterations &&
4664 elapsed > absl::ZeroDuration()) {
4666 check_count_ * absl::FDivDuration(duration_limit_, elapsed));
4668 std::min(check_count_ + kMaxSkip, estimated_check_count_at_limit);
4670 last_time_elapsed_ = elapsed;
4672 return last_time_elapsed_;
4676 return MakeLimit(time, std::numeric_limits<int64_t>::max(),
4677 std::numeric_limits<int64_t>::max(),
4678 std::numeric_limits<int64_t>::max(),
4684 std::numeric_limits<int64_t>::max(),
4685 std::numeric_limits<int64_t>::max(),
4690 return MakeLimit(absl::InfiniteDuration(),
4691 std::numeric_limits<int64_t>::max(),
failures,
4692 std::numeric_limits<int64_t>::max(),
4697 return MakeLimit(absl::InfiniteDuration(),
4698 std::numeric_limits<int64_t>::max(),
4699 std::numeric_limits<int64_t>::max(),
solutions,
4705 bool smart_time_check,
bool cumulative) {
4707 smart_time_check, cumulative);
4712 bool smart_time_check,
bool cumulative) {
4714 smart_time_check, cumulative));
4718 return MakeLimit(proto.
time() == std::numeric_limits<int64_t>::max()
4719 ? absl::InfiniteDuration()
4720 : absl::Milliseconds(proto.
time()),
4727 proto.
set_time(std::numeric_limits<int64_t>::max());
4728 proto.
set_branches(std::numeric_limits<int64_t>::max());
4729 proto.
set_failures(std::numeric_limits<int64_t>::max());
4740 double objective_scaling_factor,
double objective_offset,
4741 double improvement_rate_coefficient,
4742 int improvement_rate_solutions_distance)
4744 std::vector<bool>{maximize},
4745 std::vector<double>{objective_scaling_factor},
4746 std::vector<double>{objective_offset},
4747 improvement_rate_coefficient,
4748 improvement_rate_solutions_distance) {}
4752 std::vector<bool> maximize, std::vector<double> objective_scaling_factors,
4753 std::vector<double> objective_offsets,
double improvement_rate_coefficient,
4754 int improvement_rate_solutions_distance)
4756 objective_vars_(
std::move(objective_vars)),
4757 maximize_(
std::move(maximize)),
4758 objective_scaling_factors_(
std::move(objective_scaling_factors)),
4759 objective_offsets_(
std::move(objective_offsets)),
4760 improvement_rate_coefficient_(improvement_rate_coefficient),
4761 improvement_rate_solutions_distance_(improvement_rate_solutions_distance),
4762 best_objectives_(objective_vars_.size()),
4763 improvements_(objective_vars_.size()),
4764 thresholds_(objective_vars_.size(),
4765 std::numeric_limits<double>::infinity()) {
4777 for (
int i = 0; i < objective_vars_.size(); ++i) {
4778 best_objectives_[i] = std::numeric_limits<double>::infinity();
4779 improvements_[i].clear();
4780 thresholds_[i] = std::numeric_limits<double>::infinity();
4782 objective_updated_ =
false;
4783 gradient_stage_ =
true;
4789 objective_vars_ = improv->objective_vars_;
4790 maximize_ = improv->maximize_;
4791 objective_scaling_factors_ = improv->objective_scaling_factors_;
4792 objective_offsets_ = improv->objective_offsets_;
4793 improvement_rate_coefficient_ = improv->improvement_rate_coefficient_;
4794 improvement_rate_solutions_distance_ =
4795 improv->improvement_rate_solutions_distance_;
4796 improvements_ = improv->improvements_;
4797 thresholds_ = improv->thresholds_;
4798 best_objectives_ = improv->best_objectives_;
4799 objective_updated_ = improv->objective_updated_;
4800 gradient_stage_ = improv->gradient_stage_;
4805 solver(), objective_vars_, maximize_, objective_scaling_factors_,
4806 objective_offsets_, improvement_rate_coefficient_,
4807 improvement_rate_solutions_distance_));
4811 if (!objective_updated_) {
4814 objective_updated_ =
false;
4816 std::vector<double> improvement_rates(improvements_.size());
4817 for (
int i = 0; i < improvements_.size(); ++i) {
4818 if (improvements_[i].size() <= improvement_rate_solutions_distance_) {
4822 const auto [cur_obj, cur_neighbors] = improvements_[i].back();
4823 const auto [prev_obj, prev_neighbors] = improvements_[i].front();
4824 DCHECK_GT(cur_neighbors, prev_neighbors);
4825 improvement_rates[i] =
4826 (prev_obj - cur_obj) / (cur_neighbors - prev_neighbors);
4827 if (gradient_stage_)
continue;
4828 const double scaled_improvement_rate =
4829 improvement_rate_coefficient_ * improvement_rates[i];
4830 if (scaled_improvement_rate < thresholds_[i]) {
4832 }
else if (scaled_improvement_rate > thresholds_[i]) {
4836 if (gradient_stage_ && std::lexicographical_compare(
4837 improvement_rates.begin(), improvement_rates.end(),
4838 thresholds_.begin(), thresholds_.end())) {
4839 thresholds_ = std::move(improvement_rates);
4845 std::vector<double> scaled_new_objectives(objective_vars_.size());
4846 for (
int i = 0; i < objective_vars_.size(); ++i) {
4847 const int64_t new_objective =
4848 objective_vars_[i] !=
nullptr && objective_vars_[i]->Bound()
4849 ? objective_vars_[i]->Min()
4850 : (maximize_[i] ?
solver()
4858 scaled_new_objectives[i] = (maximize_[i] ? -objective_scaling_factors_[i]
4859 : objective_scaling_factors_[i]) *
4860 (new_objective + objective_offsets_[i]);
4862 const bool is_improvement = std::lexicographical_compare(
4863 scaled_new_objectives.begin(), scaled_new_objectives.end(),
4864 best_objectives_.begin(), best_objectives_.end());
4865 if (gradient_stage_ && !is_improvement) {
4866 gradient_stage_ =
false;
4869 for (
int i = 0; i < objective_vars_.size(); ++i) {
4870 if (thresholds_[i] == std::numeric_limits<double>::infinity()) {
4871 thresholds_[i] = -1;
4876 if (is_improvement) {
4877 objective_updated_ =
true;
4878 for (
int i = 0; i < objective_vars_.size(); ++i) {
4879 improvements_[i].push_back(
4880 std::make_pair(scaled_new_objectives[i],
solver()->neighbors()));
4884 if (improvements_[i].size() - 1 > improvement_rate_solutions_distance_) {
4885 improvements_[i].pop_front();
4887 DCHECK_LE(improvements_[i].size() - 1,
4888 improvement_rate_solutions_distance_);
4890 best_objectives_ = std::move(scaled_new_objectives);
4896 IntVar* objective_var,
bool maximize,
double objective_scaling_factor,
4897 double objective_offset,
double improvement_rate_coefficient,
4898 int improvement_rate_solutions_distance) {
4900 this, objective_var, maximize, objective_scaling_factor, objective_offset,
4901 improvement_rate_coefficient, improvement_rate_solutions_distance));
4905 std::vector<IntVar*> objective_vars, std::vector<bool> maximize,
4906 std::vector<double> objective_scaling_factors,
4907 std::vector<double> objective_offsets,
double improvement_rate_coefficient,
4908 int improvement_rate_solutions_distance) {
4910 this, std::move(objective_vars), std::move(maximize),
4911 std::move(objective_scaling_factors), std::move(objective_offsets),
4912 improvement_rate_coefficient, improvement_rate_solutions_distance));
4920 :
SearchLimit(limit_1->solver()), limit_1_(limit_1), limit_2_(limit_2) {
4921 CHECK(limit_1 !=
nullptr);
4922 CHECK(limit_2 !=
nullptr);
4924 <<
"Illegal arguments: cannot combines limits that belong to different "
4925 <<
"solvers, because the reversible allocations could delete one and "
4926 <<
"not the other.";
4929 bool CheckWithOffset(absl::Duration offset)
override {
4932 const bool check_1 = limit_1_->CheckWithOffset(offset);
4933 const bool check_2 = limit_2_->CheckWithOffset(offset);
4934 return check_1 || check_2;
4937 void Init()
override {
4942 void Copy(
const SearchLimit*
const)
override {
4943 LOG(FATAL) <<
"Not implemented.";
4946 SearchLimit* MakeClone()
const override {
4948 return solver()->MakeLimit(limit_1_->MakeClone(), limit_2_->MakeClone());
4951 void EnterSearch()
override {
4952 limit_1_->EnterSearch();
4953 limit_2_->EnterSearch();
4955 void BeginNextDecision(DecisionBuilder*
const b)
override {
4956 limit_1_->BeginNextDecision(b);
4957 limit_2_->BeginNextDecision(b);
4959 void PeriodicCheck()
override {
4960 limit_1_->PeriodicCheck();
4961 limit_2_->PeriodicCheck();
4963 void RefuteDecision(Decision*
const d)
override {
4964 limit_1_->RefuteDecision(d);
4965 limit_2_->RefuteDecision(d);
4967 std::string DebugString()
const override {
4968 return absl::StrCat(
"OR limit (", limit_1_->DebugString(),
" OR ",
4969 limit_2_->DebugString(),
")");
4973 SearchLimit*
const limit_1_;
4974 SearchLimit*
const limit_2_;
4980 return RevAlloc(
new ORLimit(limit_1, limit_2));
4986 CustomLimit(
Solver* s, std::function<
bool()> limiter);
4987 bool CheckWithOffset(absl::Duration offset)
override;
4988 void Init()
override;
4993 std::function<bool()> limiter_;
4996CustomLimit::CustomLimit(Solver*
const s, std::function<
bool()> limiter)
4997 : SearchLimit(s), limiter_(
std::move(limiter)) {}
4999bool CustomLimit::CheckWithOffset(absl::Duration) {
5001 if (limiter_)
return limiter_();
5005void CustomLimit::Init() {}
5007void CustomLimit::Copy(
const SearchLimit*
const limit) {
5008 const CustomLimit*
const custom =
5009 reinterpret_cast<const CustomLimit* const
>(limit);
5010 limiter_ = custom->limiter_;
5013SearchLimit* CustomLimit::MakeClone()
const {
5014 return solver()->RevAlloc(
new CustomLimit(solver(), limiter_));
5019 return RevAlloc(
new CustomLimit(
this, std::move(limiter)));
5028 CHECK(db !=
nullptr);
5031 SolveOnce(DecisionBuilder*
const db,
5032 const std::vector<SearchMonitor*>& monitors)
5033 : db_(db), monitors_(monitors) {
5034 CHECK(db !=
nullptr);
5037 ~SolveOnce()
override {}
5039 Decision*
Next(Solver* s)
override {
5040 bool res = s->SolveAndCommit(db_, monitors_);
5047 std::string DebugString()
const override {
5048 return absl::StrFormat(
"SolveOnce(%s)", db_->
DebugString());
5051 void Accept(ModelVisitor*
const visitor)
const override {
5056 DecisionBuilder*
const db_;
5057 std::vector<SearchMonitor*> monitors_;
5062 return RevAlloc(
new SolveOnce(db));
5067 std::vector<SearchMonitor*> monitors;
5068 monitors.push_back(monitor1);
5069 return RevAlloc(
new SolveOnce(db, monitors));
5075 std::vector<SearchMonitor*> monitors;
5076 monitors.push_back(monitor1);
5077 monitors.push_back(monitor2);
5078 return RevAlloc(
new SolveOnce(db, monitors));
5085 std::vector<SearchMonitor*> monitors;
5086 monitors.push_back(monitor1);
5087 monitors.push_back(monitor2);
5088 monitors.push_back(monitor3);
5089 return RevAlloc(
new SolveOnce(db, monitors));
5097 std::vector<SearchMonitor*> monitors;
5098 monitors.push_back(monitor1);
5099 monitors.push_back(monitor2);
5100 monitors.push_back(monitor3);
5101 monitors.push_back(monitor4);
5102 return RevAlloc(
new SolveOnce(db, monitors));
5106 DecisionBuilder*
const db,
const std::vector<SearchMonitor*>& monitors) {
5107 return RevAlloc(
new SolveOnce(db, monitors));
5116 bool maximize, int64_t step)
5119 maximize_(maximize),
5121 collector_(nullptr) {
5122 CHECK(db !=
nullptr);
5128 NestedOptimize(DecisionBuilder*
const db, Assignment*
const solution,
5129 bool maximize, int64_t step,
5130 const std::vector<SearchMonitor*>& monitors)
5132 solution_(solution),
5133 maximize_(maximize),
5135 monitors_(monitors),
5136 collector_(nullptr) {
5137 CHECK(db !=
nullptr);
5138 CHECK(solution !=
nullptr);
5139 CHECK(solution->HasObjective());
5143 void AddMonitors() {
5144 Solver*
const solver = solution_->
solver();
5145 collector_ = solver->MakeLastSolutionCollector(solution_);
5146 monitors_.push_back(collector_);
5147 OptimizeVar*
const optimize =
5148 solver->MakeOptimize(maximize_, solution_->
Objective(), step_);
5149 monitors_.push_back(optimize);
5152 Decision*
Next(Solver* solver)
override {
5153 solver->Solve(db_, monitors_);
5161 std::string DebugString()
const override {
5162 return absl::StrFormat(
"NestedOptimize(db = %s, maximize = %d, step = %d)",
5166 void Accept(ModelVisitor*
const visitor)
const override {
5171 DecisionBuilder*
const db_;
5172 Assignment*
const solution_;
5173 const bool maximize_;
5174 const int64_t step_;
5175 std::vector<SearchMonitor*> monitors_;
5176 SolutionCollector* collector_;
5182 bool maximize, int64_t step) {
5188 bool maximize, int64_t step,
5190 std::vector<SearchMonitor*> monitors;
5191 monitors.push_back(monitor1);
5192 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5197 bool maximize, int64_t step,
5200 std::vector<SearchMonitor*> monitors;
5201 monitors.push_back(monitor1);
5202 monitors.push_back(monitor2);
5203 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5208 bool maximize, int64_t step,
5212 std::vector<SearchMonitor*> monitors;
5213 monitors.push_back(monitor1);
5214 monitors.push_back(monitor2);
5215 monitors.push_back(monitor3);
5216 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5223 std::vector<SearchMonitor*> monitors;
5224 monitors.push_back(monitor1);
5225 monitors.push_back(monitor2);
5226 monitors.push_back(monitor3);
5227 monitors.push_back(monitor4);
5228 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5233 int64_t step,
const std::vector<SearchMonitor*>& monitors) {
5234 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5241int64_t NextLuby(
int i) {
5243 DCHECK_LT(i, std::numeric_limits<int32_t>::max());
5249 while (power < (i + 1)) {
5252 if (power == i + 1) {
5255 return NextLuby(i - (power / 2) + 1);
5258class LubyRestart :
public SearchMonitor {
5260 LubyRestart(Solver*
const s,
int scale_factor)
5262 scale_factor_(scale_factor),
5265 next_step_(scale_factor) {
5266 CHECK_GE(scale_factor, 1);
5269 ~LubyRestart()
override {}
5271 void BeginFail()
override {
5272 if (++current_fails_ >= next_step_) {
5274 next_step_ = NextLuby(++iteration_) * scale_factor_;
5275 solver()->RestartCurrentSearch();
5279 void Install()
override { ListenToEvent(Solver::MonitorEvent::kBeginFail); }
5281 std::string DebugString()
const override {
5282 return absl::StrFormat(
"LubyRestart(%i)", scale_factor_);
5286 const int scale_factor_;
5288 int64_t current_fails_;
5294 return RevAlloc(
new LubyRestart(
this, scale_factor));
5302 ConstantRestart(
Solver*
const s,
int frequency)
5303 :
SearchMonitor(s), frequency_(frequency), current_fails_(0) {
5304 CHECK_GE(frequency, 1);
5307 ~ConstantRestart()
override {}
5309 void BeginFail()
override {
5310 if (++current_fails_ >= frequency_) {
5312 solver()->RestartCurrentSearch();
5316 void Install()
override { ListenToEvent(Solver::MonitorEvent::kBeginFail); }
5318 std::string DebugString()
const override {
5319 return absl::StrFormat(
"ConstantRestart(%i)", frequency_);
5323 const int frequency_;
5324 int64_t current_fails_;
5329 return RevAlloc(
new ConstantRestart(
this, frequency));
5352 const std::vector<SymmetryBreaker*>& visitors)
5354 visitors_(visitors),
5355 clauses_(visitors.size()),
5356 decisions_(visitors.size()),
5357 directions_(visitors.size()) {
5358 for (
int i = 0; i < visitors_.size(); ++i) {
5359 visitors_[i]->set_symmetry_manager_and_index(
this, i);
5367 for (
int i = 0; i < visitors_.size(); ++i) {
5368 const void*
const last = clauses_[i].Last();
5370 if (last != clauses_[i].Last()) {
5372 decisions_[i].Push(
solver(), d);
5373 directions_[i].Push(
solver(),
false);
5380 for (
int i = 0; i < visitors_.size(); ++i) {
5381 if (decisions_[i].Last() !=
nullptr && decisions_[i].LastValue() == d) {
5394 std::vector<IntVar*> guard;
5399 IntVar*
const term = *tmp;
5401 if (term->
Max() == 0) {
5405 if (term->
Min() == 0) {
5406 DCHECK_EQ(1, term->
Max());
5408 guard.push_back(term);
5414 guard.push_back(clauses_[index].LastValue());
5415 directions_[index].SetLastValue(
true);
5422 DCHECK(ct !=
nullptr);
5423 solver()->AddConstraint(ct);
5427 clauses_[visitor->index_in_symmetry_manager()].Push(
solver(), term);
5430 std::string
DebugString()
const override {
return "SymmetryManager"; }
5433 const std::vector<SymmetryBreaker*> visitors_;
5434 std::vector<SimpleRevFIFO<IntVar*>> clauses_;
5435 std::vector<SimpleRevFIFO<Decision*>> decisions_;
5436 std::vector<SimpleRevFIFO<bool>> directions_;
5443 CHECK(var !=
nullptr);
5446 symmetry_manager()->AddTermToClause(
this, term);
5450 IntVar*
const var, int64_t value) {
5451 CHECK(var !=
nullptr);
5454 symmetry_manager()->AddTermToClause(
this, term);
5458 IntVar*
const var, int64_t value) {
5459 CHECK(var !=
nullptr);
5462 symmetry_manager()->AddTermToClause(
this, term);
5468 const std::vector<SymmetryBreaker*>& visitors) {
5473 std::vector<SymmetryBreaker*> visitors;
5474 visitors.push_back(v1);
5480 std::vector<SymmetryBreaker*> visitors;
5481 visitors.push_back(v1);
5482 visitors.push_back(v2);
5489 std::vector<SymmetryBreaker*> visitors;
5490 visitors.push_back(v1);
5491 visitors.push_back(v2);
5492 visitors.push_back(v3);
5500 std::vector<SymmetryBreaker*> visitors;
5501 visitors.push_back(v1);
5502 visitors.push_back(v2);
5503 visitors.push_back(v3);
5504 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.
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
void set_branches(::int64_t value)
void set_failures(::int64_t value)
::int64_t branches() const
bool smart_time_check() const
void set_solutions(::int64_t value)
void set_smart_time_check(bool value)
void set_time(::int64_t value)
void set_cumulative(bool value)
::int64_t failures() const
::int64_t solutions() const
absl::Duration duration_limit() const
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 --—
std::string MemoryUsage()
Returns the current thread's total memory usage in an human-readable string.
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