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_]->AtLocalOptimum();
3019 enabled_monitors_[active_monitor_] =
false;
3021 if (++num_local_optimum_ >= local_optimum_limit_ || !ok) {
3022 monitors_[active_monitor_]->set_active(
false);
3023 int next_active_monitor = (active_monitor_ + 1) % monitors_.size();
3024 while (!enabled_monitors_[next_active_monitor]) {
3025 if (next_active_monitor == active_monitor_)
return false;
3026 next_active_monitor = (active_monitor_ + 1) % monitors_.size();
3028 active_monitor_ = next_active_monitor;
3029 monitors_[active_monitor_]->set_active(
true);
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) {
3223 explicit ApplyBoundDecisionBuilder(
OptimizeVar* optimize_var)
3224 : optimize_var_(optimize_var) {}
3225 ~ApplyBoundDecisionBuilder()
override =
default;
3226 Decision*
Next(Solver*)
override {
3227 optimize_var_->ApplyBound();
3232 OptimizeVar* optimize_var_;
3237 if (!
solver()->SolveAndCommit(
3238 solver()->RevAlloc(
new ApplyBoundDecisionBuilder(
this)))) {
3239 if (on_optimal_found_) {
3257 for (
int i = 0; i <
Size(); ++i) {
3261 if (!minimization_var->
Bound())
return true;
3262 const int64_t value = minimization_var->
Value();
3279 for (
int i = 0; i <
Size(); ++i) {
3280 absl::StrAppendFormat(
3281 &out,
"%s%s(%s, step = %d, best = %d)", i == 0 ?
"" :
"; ",
3282 Maximize(i) ?
"MaximizeVar" :
"MinimizeVar",
3302 std::vector<IntVar*> variables,
3303 std::vector<int64_t> steps) {
3305 std::move(variables), std::move(steps)));
3311 WeightedOptimizeVar(
Solver* solver,
bool maximize,
3312 const std::vector<IntVar*>& sub_objectives,
3313 const std::vector<int64_t>& weights, int64_t step)
3315 solver->MakeScalProd(sub_objectives, weights)->Var(), step),
3316 sub_objectives_(sub_objectives),
3318 CHECK_EQ(sub_objectives.size(), weights.size());
3321 ~WeightedOptimizeVar()
override {}
3322 std::string Name()
const override;
3325 const std::vector<IntVar*> sub_objectives_;
3326 const std::vector<int64_t> weights_;
3329std::string WeightedOptimizeVar::Name()
const {
return "weighted objective"; }
3333 bool maximize,
const std::vector<IntVar*>& sub_objectives,
3334 const std::vector<int64_t>& weights, int64_t step) {
3336 new WeightedOptimizeVar(
this, maximize, sub_objectives, weights, step));
3340 const std::vector<IntVar*>& sub_objectives,
3341 const std::vector<int64_t>& weights, int64_t step) {
3343 new WeightedOptimizeVar(
this,
false, sub_objectives, weights, step));
3347 const std::vector<IntVar*>& sub_objectives,
3348 const std::vector<int64_t>& weights, int64_t step) {
3350 new WeightedOptimizeVar(
this,
true, sub_objectives, weights, step));
3354 bool maximize,
const std::vector<IntVar*>& sub_objectives,
3355 const std::vector<int>& weights, int64_t step) {
3361 const std::vector<IntVar*>& sub_objectives,
const std::vector<int>& weights,
3367 const std::vector<IntVar*>& sub_objectives,
const std::vector<int>& weights,
3377 Metaheuristic(
Solver* solver,
const std::vector<bool>& maximize,
3378 std::vector<IntVar*> objectives, std::vector<int64_t> steps);
3379 ~Metaheuristic()
override {}
3381 void EnterSearch()
override;
3382 void RefuteDecision(Decision* d)
override;
3385Metaheuristic::Metaheuristic(Solver* solver,
const std::vector<bool>& maximize,
3386 std::vector<IntVar*> objectives,
3387 std::vector<int64_t> steps)
3388 : ObjectiveMonitor(solver, maximize, std::move(objectives),
3389 std::move(steps)) {}
3391void Metaheuristic::EnterSearch() {
3392 ObjectiveMonitor::EnterSearch();
3395 solver()->SetUseFastLocalSearch(
false);
3398void Metaheuristic::RefuteDecision(Decision*) {
3399 for (
int i = 0;
i < Size(); ++
i) {
3400 const int64_t objective_value = MinimizationVar(i)->Min();
3401 if (objective_value > BestInternalValue(i))
break;
3402 if (objective_value <=
CapSub(BestInternalValue(i), Step(i)))
return;
3409class TabuSearch :
public Metaheuristic {
3411 TabuSearch(Solver* solver,
const std::vector<bool>& maximize,
3412 std::vector<IntVar*> objectives, std::vector<int64_t> steps,
3413 const std::vector<IntVar*>& vars, int64_t keep_tenure,
3414 int64_t forbid_tenure,
double tabu_factor);
3415 ~TabuSearch()
override {}
3416 void EnterSearch()
override;
3417 void ApplyDecision(Decision* d)
override;
3418 bool AtSolution()
override;
3419 bool AcceptSolution()
override;
3420 bool AtLocalOptimum()
override;
3421 bool AcceptDelta(Assignment* delta, Assignment* deltadelta)
override;
3423 void BeginNextDecision(DecisionBuilder*
const)
override {
3424 if (stop_search_) solver()->Fail();
3426 void RefuteDecision(Decision*
const d)
override {
3427 Metaheuristic::RefuteDecision(d);
3428 if (stop_search_) solver()->Fail();
3430 std::string DebugString()
const override {
return "Tabu Search"; }
3438 typedef std::list<VarValue> TabuList;
3440 virtual std::vector<IntVar*> CreateTabuVars();
3441 const TabuList& forbid_tabu_list() {
return forbid_tabu_list_; }
3442 IntVar* vars(
int index)
const {
return vars_[index]; }
3445 void AgeList(int64_t tenure, TabuList* list);
3447 int64_t TabuLimit()
const {
3448 return (synced_keep_tabu_list_.size() + synced_forbid_tabu_list_.size()) *
3452 const std::vector<IntVar*> vars_;
3453 Assignment::IntContainer assignment_container_;
3454 bool has_stored_assignment_ =
false;
3455 std::vector<int64_t> last_values_;
3456 TabuList keep_tabu_list_;
3457 TabuList synced_keep_tabu_list_;
3458 int64_t keep_tenure_;
3459 TabuList forbid_tabu_list_;
3460 TabuList synced_forbid_tabu_list_;
3461 int64_t forbid_tenure_;
3462 double tabu_factor_;
3464 int64_t solution_count_ = 0;
3465 bool stop_search_ =
false;
3466 std::vector<int64_t> delta_values_;
3467 SparseBitset<> delta_vars_;
3468 std::vector<int> var_index_to_index_;
3471TabuSearch::TabuSearch(Solver* solver,
const std::vector<bool>& maximize,
3472 std::vector<IntVar*> objectives,
3473 std::vector<int64_t> steps,
3474 const std::vector<IntVar*>& vars, int64_t keep_tenure,
3475 int64_t forbid_tenure,
double tabu_factor)
3476 : Metaheuristic(solver, maximize, std::move(objectives), std::move(steps)),
3478 last_values_(Size(), std::numeric_limits<int64_t>::max()),
3479 keep_tenure_(keep_tenure),
3480 forbid_tenure_(forbid_tenure),
3481 tabu_factor_(tabu_factor),
3483 delta_values_(vars.size(), 0),
3484 delta_vars_(vars.size()) {
3485 for (
int index = 0; index < vars_.size(); ++index) {
3486 assignment_container_.FastAdd(vars_[index]);
3487 DCHECK_EQ(vars_[index], assignment_container_.Element(index).Var());
3488 const int var_index = vars_[index]->index();
3489 if (var_index >= var_index_to_index_.size()) {
3490 var_index_to_index_.resize(var_index + 1, -1);
3492 var_index_to_index_[var_index] = index;
3496void TabuSearch::EnterSearch() {
3497 Metaheuristic::EnterSearch();
3498 solver()->SetUseFastLocalSearch(
true);
3500 has_stored_assignment_ =
false;
3501 solution_count_ = 0;
3502 stop_search_ =
false;
3505void TabuSearch::ApplyDecision(Decision*
const d) {
3506 Solver*
const s = solver();
3507 if (d == s->balancing_decision()) {
3511 synced_keep_tabu_list_ = keep_tabu_list_;
3512 synced_forbid_tabu_list_ = forbid_tabu_list_;
3513 Constraint* tabu_ct =
nullptr;
3517 const std::vector<IntVar*> tabu_vars = CreateTabuVars();
3518 if (!tabu_vars.empty()) {
3519 IntVar* tabu_var = s->MakeIsGreaterOrEqualCstVar(
3520 s->MakeSum(tabu_vars)->Var(), TabuLimit());
3523 IntVar* aspiration = MakeMinimizationVarsLessOrEqualWithStepsStatus(
3524 [
this](
int i) {
return BestInternalValue(i); });
3525 tabu_ct = s->MakeSumGreaterOrEqual({aspiration, tabu_var}, int64_t{1});
3528 if (tabu_ct !=
nullptr) s->AddConstraint(tabu_ct);
3531 if (CurrentInternalValuesAreConstraining()) {
3532 MakeMinimizationVarsLessOrEqualWithSteps(
3533 [
this](
int i) {
return CurrentInternalValue(i); });
3537bool TabuSearch::AcceptSolution() {
3539 if (found_initial_solution_) {
3540 for (
int i = 0;
i < Size(); ++
i) {
3541 if (last_values_[i] != MinimizationVar(i)->Min()) {
3550std::vector<IntVar*> TabuSearch::CreateTabuVars() {
3551 Solver*
const s = solver();
3559 std::vector<IntVar*> tabu_vars;
3560 for (
const auto [var_index, value, unused_stamp] : keep_tabu_list_) {
3561 tabu_vars.push_back(s->MakeIsEqualCstVar(vars(var_index), value));
3563 for (
const auto [var_index, value, unused_stamp] : forbid_tabu_list_) {
3564 tabu_vars.push_back(s->MakeIsDifferentCstVar(vars(var_index), value));
3569bool TabuSearch::AtSolution() {
3571 if (!ObjectiveMonitor::AtSolution()) {
3574 for (
int i = 0;
i < Size(); ++
i) {
3575 last_values_[
i] = CurrentInternalValue(i);
3580 if (0 != stamp_ && has_stored_assignment_) {
3581 for (
int index = 0; index < vars_.size(); ++index) {
3582 IntVar* var = vars(index);
3583 const int64_t old_value = assignment_container_.
Element(index).
Value();
3584 const int64_t new_value = var->Value();
3585 if (old_value != new_value) {
3586 if (keep_tenure_ > 0) {
3587 keep_tabu_list_.push_front({index, new_value, stamp_});
3589 if (forbid_tenure_ > 0) {
3590 forbid_tabu_list_.push_front({index, old_value, stamp_});
3595 assignment_container_.
Store();
3596 has_stored_assignment_ =
true;
3601bool TabuSearch::AtLocalOptimum() {
3602 solver()->SetUseFastLocalSearch(
false);
3605 if (stamp_ > 0 && solution_count_ == 0 && keep_tabu_list_.empty() &&
3606 forbid_tabu_list_.empty()) {
3607 stop_search_ =
true;
3609 solution_count_ = 0;
3611 for (
int i = 0;
i < Size(); ++
i) {
3612 SetCurrentInternalValue(i, std::numeric_limits<int64_t>::max());
3614 return found_initial_solution_;
3617bool TabuSearch::AcceptDelta(Assignment* delta, Assignment* deltadelta) {
3618 if (delta ==
nullptr)
return true;
3619 if (!Metaheuristic::AcceptDelta(delta, deltadelta))
return false;
3620 if (synced_keep_tabu_list_.empty() && synced_forbid_tabu_list_.empty()) {
3623 const Assignment::IntContainer& delta_container = delta->IntVarContainer();
3625 for (
const IntVarElement& element : delta_container.elements()) {
3626 if (!element.Bound())
return true;
3629 for (
const IntVarElement& element : delta_container.elements()) {
3630 const int var_index = element.Var()->index();
3631 if (var_index >= var_index_to_index_.size())
continue;
3632 const int index = var_index_to_index_[var_index];
3633 if (index == -1)
continue;
3634 delta_values_[index] = element.Value();
3635 delta_vars_.
Set(index);
3637 int num_respected = 0;
3638 auto get_value = [
this](
int var_index) {
3639 return delta_vars_[var_index]
3640 ? delta_values_[var_index]
3643 const int64_t tabu_limit = TabuLimit();
3644 for (
const auto [var_index, value, unused_stamp] : synced_keep_tabu_list_) {
3645 if (get_value(var_index) == value) {
3646 if (++num_respected >= tabu_limit)
return true;
3649 for (
const auto [var_index, value, unused_stamp] : synced_forbid_tabu_list_) {
3650 if (get_value(var_index) != value) {
3651 if (++num_respected >= tabu_limit)
return true;
3654 if (num_respected >= tabu_limit)
return true;
3659 delta->SetObjectiveMinFromIndex(0,
CapAdd(BestInternalValue(0), Step(0)));
3661 delta->SetObjectiveMaxFromIndex(0,
CapSub(BestInternalValue(0), Step(0)));
3664 for (
int i = 0;
i < Size(); ++
i) {
3666 delta->SetObjectiveMinFromIndex(i, BestInternalValue(i));
3668 delta->SetObjectiveMaxFromIndex(i, BestInternalValue(i));
3676void TabuSearch::AcceptNeighbor() {
3682void TabuSearch::AgeList(int64_t tenure, TabuList* list) {
3683 while (!list->empty() && list->back().stamp < stamp_ - tenure) {
3688void TabuSearch::AgeLists() {
3689 AgeList(keep_tenure_, &keep_tabu_list_);
3690 AgeList(forbid_tenure_, &forbid_tabu_list_);
3694class GenericTabuSearch :
public TabuSearch {
3696 GenericTabuSearch(Solver* solver,
bool maximize, IntVar* objective,
3697 int64_t step,
const std::vector<IntVar*>& vars,
3698 int64_t forbid_tenure)
3699 : TabuSearch(solver, {maximize}, {objective}, {step}, vars, 0,
3700 forbid_tenure, 1) {}
3701 std::string DebugString()
const override {
return "Generic Tabu Search"; }
3704 std::vector<IntVar*> CreateTabuVars()
override;
3707std::vector<IntVar*> GenericTabuSearch::CreateTabuVars() {
3708 Solver*
const s = solver();
3712 std::vector<IntVar*> forbid_values;
3713 for (
const auto [var_index, value, unused_stamp] : forbid_tabu_list()) {
3714 forbid_values.push_back(s->MakeIsDifferentCstVar(vars(var_index), value));
3716 std::vector<IntVar*> tabu_vars;
3717 if (!forbid_values.empty()) {
3718 tabu_vars.push_back(s->MakeIsGreaterCstVar(s->MakeSum(forbid_values), 0));
3727 const std::vector<IntVar*>& vars,
3728 int64_t keep_tenure,
3729 int64_t forbid_tenure,
3730 double tabu_factor) {
3731 return RevAlloc(
new TabuSearch(
this, {maximize}, {objective}, {step}, vars,
3732 keep_tenure, forbid_tenure, tabu_factor));
3736 const std::vector<bool>& maximize, std::vector<IntVar*> objectives,
3737 std::vector<int64_t> steps,
const std::vector<IntVar*>& vars,
3738 int64_t keep_tenure, int64_t forbid_tenure,
double tabu_factor) {
3739 return RevAlloc(
new TabuSearch(
this, maximize, std::move(objectives),
3740 std::move(steps), vars, keep_tenure,
3741 forbid_tenure, tabu_factor));
3745 bool maximize,
IntVar*
const v, int64_t step,
3746 const std::vector<IntVar*>& tabu_vars, int64_t forbid_tenure) {
3748 new GenericTabuSearch(
this, maximize, v, step, tabu_vars, forbid_tenure));
3754class SimulatedAnnealing :
public Metaheuristic {
3756 SimulatedAnnealing(
Solver* solver,
const std::vector<bool>& maximize,
3757 std::vector<IntVar*> objectives,
3758 std::vector<int64_t> steps,
3759 std::vector<int64_t> initial_temperatures);
3760 ~SimulatedAnnealing()
override {}
3761 void ApplyDecision(Decision* d)
override;
3762 bool AtLocalOptimum()
override;
3763 void AcceptNeighbor()
override;
3764 std::string DebugString()
const override {
return "Simulated Annealing"; }
3767 double Temperature(
int index)
const {
3768 return iteration_ > 0
3769 ? (1.0 * temperature0_[index]) / iteration_
3773 const std::vector<int64_t> temperature0_;
3778SimulatedAnnealing::SimulatedAnnealing(
3779 Solver* solver,
const std::vector<bool>& maximize,
3780 std::vector<IntVar*> objectives, std::vector<int64_t> steps,
3781 std::vector<int64_t> initial_temperatures)
3782 : Metaheuristic(solver, maximize, std::move(objectives), std::move(steps)),
3783 temperature0_(std::move(initial_temperatures)),
3800void SimulatedAnnealing::ApplyDecision(
Decision*
const d) {
3801 Solver*
const s = solver();
3802 if (d == s->balancing_decision()) {
3805 if (CurrentInternalValuesAreConstraining()) {
3806 MakeMinimizationVarsLessOrEqualWithSteps([
this](
int i) {
3807 const double rand_double = absl::Uniform<double>(rand_, 0.0, 1.0);
3808#if defined(_MSC_VER) || defined(__ANDROID__)
3809 const double rand_log2_double = log(rand_double) / log(2.0L);
3811 const double rand_log2_double = log2(rand_double);
3813 const int64_t energy_bound = Temperature(i) * rand_log2_double;
3816 return CapSub(CurrentInternalValue(i), energy_bound);
3821bool SimulatedAnnealing::AtLocalOptimum() {
3822 for (
int i = 0;
i < Size(); ++
i) {
3823 SetCurrentInternalValue(i, std::numeric_limits<int64_t>::max());
3826 if (!found_initial_solution_)
return false;
3827 for (
int i = 0;
i < Size(); ++
i) {
3828 if (Temperature(i) <= 0)
return false;
3833void SimulatedAnnealing::AcceptNeighbor() {
3834 if (iteration_ > 0) {
3842 int64_t initial_temperature) {
3843 return RevAlloc(
new SimulatedAnnealing(
this, {maximize}, {v}, {step},
3844 {initial_temperature}));
3848 const std::vector<bool>& maximize, std::vector<IntVar*> vars,
3849 std::vector<int64_t> steps, std::vector<int64_t> initial_temperatures) {
3850 return RevAlloc(
new SimulatedAnnealing(
this, maximize, std::move(vars),
3852 std::move(initial_temperatures)));
3862class GuidedLocalSearchPenaltiesTable {
3868 explicit GuidedLocalSearchPenaltiesTable(
int num_vars);
3869 bool HasPenalties()
const {
return has_values_; }
3870 void IncrementPenalty(
const VarValue& var_value);
3871 int64_t GetPenalty(
const VarValue& var_value)
const;
3875 std::vector<std::vector<int64_t>> penalties_;
3879GuidedLocalSearchPenaltiesTable::GuidedLocalSearchPenaltiesTable(
int num_vars)
3880 : penalties_(num_vars), has_values_(
false) {}
3882void GuidedLocalSearchPenaltiesTable::IncrementPenalty(
3883 const VarValue& var_value) {
3884 std::vector<int64_t>& var_penalties = penalties_[var_value.var];
3885 const int64_t value = var_value.value;
3886 if (value >= var_penalties.size()) {
3887 var_penalties.resize(value + 1, 0);
3889 ++var_penalties[value];
3893void GuidedLocalSearchPenaltiesTable::Reset() {
3894 has_values_ =
false;
3895 for (
int i = 0;
i < penalties_.size(); ++
i) {
3896 penalties_[
i].clear();
3900int64_t GuidedLocalSearchPenaltiesTable::GetPenalty(
3901 const VarValue& var_value)
const {
3902 const std::vector<int64_t>& var_penalties = penalties_[var_value.var];
3903 const int64_t value = var_value.value;
3904 return (value >= var_penalties.size()) ? 0 : var_penalties[value];
3908class GuidedLocalSearchPenaltiesMap {
3914 friend bool operator==(
const VarValue& lhs,
const VarValue& rhs) {
3915 return lhs.var == rhs.var && lhs.value == rhs.value;
3917 template <
typename H>
3919 return H::combine(std::move(h), var_value.var, var_value.value);
3922 explicit GuidedLocalSearchPenaltiesMap(
int num_vars);
3923 bool HasPenalties()
const {
return (!penalties_.empty()); }
3924 void IncrementPenalty(
const VarValue& var_value);
3925 int64_t GetPenalty(
const VarValue& var_value)
const;
3930 absl::flat_hash_map<VarValue, int64_t> penalties_;
3933GuidedLocalSearchPenaltiesMap::GuidedLocalSearchPenaltiesMap(
int num_vars)
3934 : penalized_(num_vars,
false) {}
3936void GuidedLocalSearchPenaltiesMap::IncrementPenalty(
3937 const VarValue& var_value) {
3938 ++penalties_[var_value];
3939 penalized_.
Set(var_value.var,
true);
3942void GuidedLocalSearchPenaltiesMap::Reset() {
3947int64_t GuidedLocalSearchPenaltiesMap::GetPenalty(
3948 const VarValue& var_value)
const {
3949 return (penalized_.
Get(var_value.var))
3954template <
typename P>
3955class GuidedLocalSearch :
public Metaheuristic {
3958 Solver* solver, IntVar* objective,
bool maximize, int64_t step,
3959 const std::vector<IntVar*>& vars,
double penalty_factor,
3960 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
3961 get_equivalent_pairs,
3962 bool reset_penalties_on_new_best_solution);
3963 ~GuidedLocalSearch()
override {}
3964 bool AcceptDelta(Assignment* delta, Assignment* deltadelta)
override;
3965 void ApplyDecision(Decision* d)
override;
3966 bool AtSolution()
override;
3967 void EnterSearch()
override;
3968 bool AtLocalOptimum()
override;
3969 virtual int64_t AssignmentElementPenalty(
int index)
const = 0;
3970 virtual int64_t AssignmentPenalty(int64_t var, int64_t value)
const = 0;
3971 virtual int64_t Evaluate(
const Assignment* delta, int64_t current_penalty,
3972 bool incremental) = 0;
3973 virtual IntExpr* MakeElementPenalty(
int index) = 0;
3974 std::string DebugString()
const override {
return "Guided Local Search"; }
3980 template <
typename T,
typename IndexType =
int64_t>
3983 explicit DirtyArray(IndexType size)
3984 : base_data_(size), modified_data_(size), touched_(size) {}
3987 void Set(IndexType i,
const T& value) {
3988 modified_data_[
i] = value;
3992 void SetAll(
const T& value) {
3993 for (IndexType i = 0;
i < modified_data_.size(); ++
i) {
3998 T Get(IndexType i)
const {
return modified_data_[
i]; }
4002 for (
const IndexType index : touched_.PositionsSetAtLeastOnce()) {
4003 base_data_[index] = modified_data_[index];
4005 touched_.ResetAllToFalse();
4009 for (
const IndexType index : touched_.PositionsSetAtLeastOnce()) {
4010 modified_data_[index] = base_data_[index];
4012 touched_.ResetAllToFalse();
4016 int NumSetValues()
const {
4017 return touched_.NumberOfSetCallsWithDifferentArguments();
4021 std::vector<T> base_data_;
4022 std::vector<T> modified_data_;
4023 SparseBitset<IndexType> touched_;
4026 int64_t GetValue(int64_t index)
const {
4029 IntVar* GetVar(int64_t index)
const {
4032 void AddVars(
const std::vector<IntVar*>& vars);
4033 int NumPrimaryVars()
const {
return num_vars_; }
4034 int GetLocalIndexFromVar(IntVar* var)
const {
4035 const int var_index = var->index();
4036 return (var_index < var_index_to_local_index_.size())
4037 ? var_index_to_local_index_[var_index]
4040 void ResetPenalties();
4042 IntVar* penalized_objective_;
4043 Assignment::IntContainer assignment_;
4044 int64_t assignment_penalized_value_;
4045 int64_t old_penalized_value_;
4046 const int num_vars_;
4047 std::vector<int> var_index_to_local_index_;
4048 const double penalty_factor_;
4050 DirtyArray<int64_t> penalized_values_;
4052 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4053 get_equivalent_pairs_;
4054 const bool reset_penalties_on_new_best_solution_;
4057template <
typename P>
4058GuidedLocalSearch<P>::GuidedLocalSearch(
4059 Solver* solver, IntVar* objective,
bool maximize, int64_t step,
4060 const std::vector<IntVar*>& vars,
double penalty_factor,
4061 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4062 get_equivalent_pairs,
4063 bool reset_penalties_on_new_best_solution)
4064 : Metaheuristic(solver, {maximize}, {objective}, {step}),
4065 penalized_objective_(
nullptr),
4066 assignment_penalized_value_(0),
4067 old_penalized_value_(0),
4068 num_vars_(vars.size()),
4069 penalty_factor_(penalty_factor),
4070 penalties_(vars.size()),
4071 penalized_values_(vars.size()),
4072 incremental_(
false),
4073 get_equivalent_pairs_(std::move(get_equivalent_pairs)),
4074 reset_penalties_on_new_best_solution_(
4075 reset_penalties_on_new_best_solution) {
4079template <
typename P>
4080void GuidedLocalSearch<P>::AddVars(
const std::vector<IntVar*>& vars) {
4081 const int offset = assignment_.Size();
4082 if (vars.empty())
return;
4083 assignment_.Resize(offset + vars.size());
4084 for (
int i = 0;
i < vars.size(); ++
i) {
4085 assignment_.AddAtPosition(vars[i], offset + i);
4087 const int max_var_index =
4088 (*std::max_element(vars.begin(), vars.end(), [](
IntVar* a,
IntVar* b) {
4089 return a->index() < b->index();
4091 if (max_var_index >= var_index_to_local_index_.size()) {
4092 var_index_to_local_index_.resize(max_var_index + 1, -1);
4094 for (
int i = 0;
i < vars.size(); ++
i) {
4095 var_index_to_local_index_[vars[
i]->index()] = offset +
i;
4106template <
typename P>
4107void GuidedLocalSearch<P>::ApplyDecision(
Decision*
const d) {
4108 if (d == solver()->balancing_decision()) {
4111 assignment_penalized_value_ = 0;
4112 if (penalties_.HasPenalties()) {
4116 std::vector<IntVar*> elements;
4117 for (
int i = 0;
i < num_vars_; ++
i) {
4118 elements.push_back(MakeElementPenalty(i)->Var());
4119 const int64_t penalty = AssignmentElementPenalty(i);
4120 penalized_values_.Set(i, penalty);
4121 assignment_penalized_value_ =
4122 CapAdd(assignment_penalized_value_, penalty);
4124 solver()->SaveAndSetValue(
4125 reinterpret_cast<void**
>(&penalized_objective_),
4126 reinterpret_cast<void*
>(solver()->MakeSum(elements)->Var()));
4128 penalized_values_.Commit();
4129 old_penalized_value_ = assignment_penalized_value_;
4130 incremental_ =
false;
4131 IntExpr* max_pen_exp = solver()->MakeDifference(
4132 CapSub(CurrentInternalValue(0), Step(0)), penalized_objective_);
4135 ->MakeMax(max_pen_exp,
CapSub(BestInternalValue(0), Step(0)))
4137 solver()->AddConstraint(
4138 solver()->MakeLessOrEqual(MinimizationVar(0), max_exp));
4140 penalized_objective_ =
nullptr;
4141 const int64_t
bound =
4142 (CurrentInternalValue(0) < std::numeric_limits<int64_t>::max())
4143 ?
CapSub(CurrentInternalValue(0), Step(0))
4144 : CurrentInternalValue(0);
4145 MinimizationVar(0)->SetMax(bound);
4149template <
typename P>
4150void GuidedLocalSearch<P>::ResetPenalties() {
4151 assignment_penalized_value_ = 0;
4152 old_penalized_value_ = 0;
4153 penalized_values_.SetAll(0);
4154 penalized_values_.Commit();
4158template <
typename P>
4159bool GuidedLocalSearch<P>::AtSolution() {
4160 const int64_t old_best = BestInternalValue(0);
4164 if (penalized_objective_ !=
nullptr && penalized_objective_->Bound()) {
4169 if (reset_penalties_on_new_best_solution_ &&
4170 old_best != BestInternalValue(0)) {
4172 DCHECK_EQ(CurrentInternalValue(0), BestInternalValue(0));
4175 SetCurrentInternalValue(
4176 0,
CapAdd(CurrentInternalValue(0), penalized_objective_->Value()));
4179 assignment_.Store();
4183template <
typename P>
4184void GuidedLocalSearch<P>::EnterSearch() {
4185 Metaheuristic::EnterSearch();
4186 solver()->SetUseFastLocalSearch(
true);
4187 penalized_objective_ =
nullptr;
4193template <
typename P>
4194bool GuidedLocalSearch<P>::AcceptDelta(
Assignment* delta,
4196 if (delta ==
nullptr && deltadelta ==
nullptr)
return true;
4197 if (!penalties_.HasPenalties()) {
4198 return Metaheuristic::AcceptDelta(delta, deltadelta);
4200 int64_t penalty = 0;
4201 if (!deltadelta->Empty()) {
4202 if (!incremental_) {
4203 DCHECK_EQ(penalized_values_.NumSetValues(), 0);
4204 penalty = Evaluate(delta, assignment_penalized_value_,
true);
4206 penalty = Evaluate(deltadelta, old_penalized_value_,
true);
4208 incremental_ =
true;
4211 penalized_values_.Revert();
4213 incremental_ =
false;
4214 DCHECK_EQ(penalized_values_.NumSetValues(), 0);
4215 penalty = Evaluate(delta, assignment_penalized_value_,
false);
4217 old_penalized_value_ = penalty;
4218 if (!delta->HasObjective()) {
4219 delta->AddObjective(ObjectiveVar(0));
4221 if (delta->Objective() == ObjectiveVar(0)) {
4222 const int64_t
bound =
4223 std::max(
CapSub(
CapSub(CurrentInternalValue(0), Step(0)), penalty),
4224 CapSub(BestInternalValue(0), Step(0)));
4226 delta->SetObjectiveMin(std::max(
CapOpp(bound), delta->ObjectiveMin()));
4228 delta->SetObjectiveMax(std::min(bound, delta->ObjectiveMax()));
4236template <
typename P>
4237bool GuidedLocalSearch<P>::AtLocalOptimum() {
4238 solver()->SetUseFastLocalSearch(
false);
4239 std::vector<double> utilities(num_vars_);
4240 double max_utility = -std::numeric_limits<double>::infinity();
4241 for (
int var = 0; var < num_vars_; ++var) {
4243 if (!element.Bound()) {
4247 const int64_t value = element.Value();
4250 const int64_t cost = (value != var) ? AssignmentPenalty(var, value) : 0;
4251 const double utility = cost / (penalties_.GetPenalty({var, value}) + 1.0);
4252 utilities[var] = utility;
4253 if (utility > max_utility) max_utility = utility;
4255 for (
int var = 0; var < num_vars_; ++var) {
4256 if (utilities[var] == max_utility) {
4258 DCHECK(element.Bound());
4259 const int64_t value = element.Value();
4260 if (get_equivalent_pairs_ ==
nullptr) {
4261 penalties_.IncrementPenalty({var, value});
4263 for (
const auto [other_var, other_value] :
4264 get_equivalent_pairs_(var, value)) {
4265 penalties_.IncrementPenalty({other_var, other_value});
4270 SetCurrentInternalValue(0, std::numeric_limits<int64_t>::max());
4274template <
typename P>
4275class BinaryGuidedLocalSearch :
public GuidedLocalSearch<P> {
4277 BinaryGuidedLocalSearch(
4278 Solver* solver, IntVar* objective,
4279 std::function<int64_t(int64_t, int64_t)> objective_function,
4280 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
4281 double penalty_factor,
4282 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4283 get_equivalent_pairs,
4284 bool reset_penalties_on_new_best_solution);
4285 ~BinaryGuidedLocalSearch()
override {}
4286 IntExpr* MakeElementPenalty(
int index)
override;
4287 int64_t AssignmentElementPenalty(
int index)
const override;
4288 int64_t AssignmentPenalty(int64_t var, int64_t value)
const override;
4289 int64_t Evaluate(
const Assignment* delta, int64_t current_penalty,
4290 bool incremental)
override;
4293 int64_t PenalizedValue(int64_t i, int64_t j)
const;
4294 std::function<int64_t(int64_t, int64_t)> objective_function_;
4297template <
typename P>
4298BinaryGuidedLocalSearch<P>::BinaryGuidedLocalSearch(
4300 std::function<int64_t(int64_t, int64_t)> objective_function,
bool maximize,
4301 int64_t step,
const std::vector<IntVar*>& vars,
double penalty_factor,
4302 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4303 get_equivalent_pairs,
4304 bool reset_penalties_on_new_best_solution)
4305 : GuidedLocalSearch<P>(solver, objective, maximize, step, vars,
4306 penalty_factor, std::move(get_equivalent_pairs),
4307 reset_penalties_on_new_best_solution),
4308 objective_function_(std::move(objective_function)) {
4309 solver->SetGuidedLocalSearchPenaltyCallback(
4310 [
this](int64_t i, int64_t j, int64_t) {
return PenalizedValue(i, j); });
4313template <
typename P>
4314IntExpr* BinaryGuidedLocalSearch<P>::MakeElementPenalty(
int index) {
4315 return this->solver()->MakeElement(
4316 [
this, index](int64_t i) {
return PenalizedValue(index, i); },
4317 this->GetVar(index));
4320template <
typename P>
4321int64_t BinaryGuidedLocalSearch<P>::AssignmentElementPenalty(
int index)
const {
4322 return PenalizedValue(index, this->GetValue(index));
4325template <
typename P>
4326int64_t BinaryGuidedLocalSearch<P>::AssignmentPenalty(int64_t var,
4327 int64_t value)
const {
4328 return objective_function_(var, value);
4331template <
typename P>
4332int64_t BinaryGuidedLocalSearch<P>::Evaluate(
const Assignment* delta,
4333 int64_t current_penalty,
4335 int64_t penalty = current_penalty;
4337 for (
const IntVarElement& new_element : container.elements()) {
4338 const int index = this->GetLocalIndexFromVar(new_element.Var());
4339 if (index == -1)
continue;
4340 penalty =
CapSub(penalty, this->penalized_values_.Get(index));
4341 if (new_element.Activated()) {
4342 const int64_t new_penalty = PenalizedValue(index, new_element.Value());
4343 penalty =
CapAdd(penalty, new_penalty);
4345 this->penalized_values_.Set(index, new_penalty);
4353template <
typename P>
4354int64_t BinaryGuidedLocalSearch<P>::PenalizedValue(int64_t i, int64_t j)
const {
4355 const int64_t penalty = this->penalties_.GetPenalty({
i, j});
4357 if (penalty == 0)
return 0;
4358 const double penalized_value_fp =
4359 this->penalty_factor_ * penalty * objective_function_(i, j);
4360 const int64_t penalized_value =
4361 (penalized_value_fp <= std::numeric_limits<int64_t>::max())
4362 ?
static_cast<int64_t
>(penalized_value_fp)
4363 : std::numeric_limits<int64_t>::max();
4364 return penalized_value;
4367template <
typename P>
4368class TernaryGuidedLocalSearch :
public GuidedLocalSearch<P> {
4370 TernaryGuidedLocalSearch(
4371 Solver* solver, IntVar* objective,
4372 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
4373 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
4374 const std::vector<IntVar*>& secondary_vars,
double penalty_factor,
4375 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4376 get_equivalent_pairs,
4377 bool reset_penalties_on_new_best_solution);
4378 ~TernaryGuidedLocalSearch()
override {}
4379 IntExpr* MakeElementPenalty(
int index)
override;
4380 int64_t AssignmentElementPenalty(
int index)
const override;
4381 int64_t AssignmentPenalty(int64_t var, int64_t value)
const override;
4382 int64_t Evaluate(
const Assignment* delta, int64_t current_penalty,
4383 bool incremental)
override;
4386 int64_t PenalizedValue(int64_t i, int64_t j, int64_t k)
const;
4388 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function_;
4389 std::vector<int> secondary_values_;
4392template <
typename P>
4393TernaryGuidedLocalSearch<P>::TernaryGuidedLocalSearch(
4395 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
4396 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
4397 const std::vector<IntVar*>& secondary_vars,
double penalty_factor,
4398 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4399 get_equivalent_pairs,
4400 bool reset_penalties_on_new_best_solution)
4401 : GuidedLocalSearch<P>(solver, objective, maximize, step, vars,
4402 penalty_factor, std::move(get_equivalent_pairs),
4403 reset_penalties_on_new_best_solution),
4404 objective_function_(std::move(objective_function)),
4405 secondary_values_(this->NumPrimaryVars(), -1) {
4406 this->AddVars(secondary_vars);
4407 solver->SetGuidedLocalSearchPenaltyCallback(
4408 [
this](int64_t i, int64_t j, int64_t k) {
4409 return PenalizedValue(i, j, k);
4413template <
typename P>
4414IntExpr* TernaryGuidedLocalSearch<P>::MakeElementPenalty(
int index) {
4415 Solver*
const solver = this->solver();
4417 solver->AddConstraint(solver->MakeLightElement(
4418 [
this, index](int64_t j, int64_t k) {
4419 return PenalizedValue(index, j, k);
4421 var, this->GetVar(index), this->GetVar(this->NumPrimaryVars() + index)));
4425template <
typename P>
4426int64_t TernaryGuidedLocalSearch<P>::AssignmentElementPenalty(
int index)
const {
4427 return PenalizedValue(index, this->GetValue(index),
4428 this->GetValue(this->NumPrimaryVars() + index));
4431template <
typename P>
4432int64_t TernaryGuidedLocalSearch<P>::AssignmentPenalty(int64_t var,
4433 int64_t value)
const {
4434 return objective_function_(var, value,
4435 this->GetValue(this->NumPrimaryVars() + var));
4438template <
typename P>
4439int64_t TernaryGuidedLocalSearch<P>::Evaluate(
const Assignment* delta,
4440 int64_t current_penalty,
4442 int64_t penalty = current_penalty;
4447 for (
const IntVarElement& new_element : container.elements()) {
4448 const int index = this->GetLocalIndexFromVar(new_element.Var());
4449 if (index != -1 && index < this->NumPrimaryVars()) {
4450 secondary_values_[index] = -1;
4453 for (
const IntVarElement& new_element : container.elements()) {
4454 const int index = this->GetLocalIndexFromVar(new_element.Var());
4455 if (!new_element.Activated())
continue;
4456 if (index != -1 && index >= this->NumPrimaryVars()) {
4457 secondary_values_[index - this->NumPrimaryVars()] = new_element.Value();
4460 for (
const IntVarElement& new_element : container.elements()) {
4461 const int index = this->GetLocalIndexFromVar(new_element.Var());
4463 if (index == -1 || index >= this->NumPrimaryVars()) {
4466 penalty =
CapSub(penalty, this->penalized_values_.Get(index));
4468 if (new_element.Activated() && secondary_values_[index] != -1) {
4469 const int64_t new_penalty =
4470 PenalizedValue(index, new_element.Value(), secondary_values_[index]);
4471 penalty =
CapAdd(penalty, new_penalty);
4473 this->penalized_values_.Set(index, new_penalty);
4481template <
typename P>
4482int64_t TernaryGuidedLocalSearch<P>::PenalizedValue(int64_t i, int64_t j,
4484 const int64_t penalty = this->penalties_.GetPenalty({
i, j});
4486 if (penalty == 0)
return 0;
4487 const double penalized_value_fp =
4488 this->penalty_factor_ * penalty * objective_function_(i, j, k);
4489 const int64_t penalized_value =
4490 (penalized_value_fp < std::numeric_limits<int64_t>::max())
4491 ?
static_cast<int64_t
>(penalized_value_fp)
4492 : std::numeric_limits<int64_t>::max();
4493 return penalized_value;
4498 bool maximize,
IntVar*
const objective,
4500 const std::vector<IntVar*>& vars,
double penalty_factor,
4501 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4502 get_equivalent_pairs,
4503 bool reset_penalties_on_new_best_solution) {
4504 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
4505 return RevAlloc(
new BinaryGuidedLocalSearch<GuidedLocalSearchPenaltiesMap>(
4506 this, objective, std::move(objective_function), maximize, step, vars,
4507 penalty_factor, std::move(get_equivalent_pairs),
4508 reset_penalties_on_new_best_solution));
4511 new BinaryGuidedLocalSearch<GuidedLocalSearchPenaltiesTable>(
4512 this, objective, std::move(objective_function), maximize, step,
4513 vars, penalty_factor, std::move(get_equivalent_pairs),
4514 reset_penalties_on_new_best_solution));
4519 bool maximize,
IntVar*
const objective,
4521 const std::vector<IntVar*>& vars,
4522 const std::vector<IntVar*>& secondary_vars,
double penalty_factor,
4523 std::function<std::vector<std::pair<int64_t, int64_t>>(int64_t, int64_t)>
4524 get_equivalent_pairs,
4525 bool reset_penalties_on_new_best_solution) {
4526 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
4527 return RevAlloc(
new TernaryGuidedLocalSearch<GuidedLocalSearchPenaltiesMap>(
4528 this, objective, std::move(objective_function), maximize, step, vars,
4529 secondary_vars, penalty_factor, std::move(get_equivalent_pairs),
4530 reset_penalties_on_new_best_solution));
4533 new TernaryGuidedLocalSearch<GuidedLocalSearchPenaltiesTable>(
4534 this, objective, std::move(objective_function), maximize, step,
4535 vars, secondary_vars, penalty_factor,
4536 std::move(get_equivalent_pairs),
4537 reset_penalties_on_new_best_solution));
4570 if (crossed_ ||
Check()) {
4576void SearchLimit::TopPeriodicCheck() {
4577 if (
solver()->TopLevelSearch() !=
solver()->ActiveSearch()) {
4586 int64_t
solutions,
bool smart_time_check,
4589 duration_limit_(time),
4590 solver_time_at_limit_start_(s->Now()),
4591 last_time_elapsed_(
absl::ZeroDuration()),
4594 smart_time_check_(smart_time_check),
4596 branches_offset_(0),
4598 failures_offset_(0),
4600 solutions_offset_(0),
4601 cumulative_(cumulative) {}
4616 duration_limit_ = regular->duration_limit_;
4617 branches_ = regular->branches_;
4618 failures_ = regular->failures_;
4619 solutions_ = regular->solutions_;
4620 smart_time_check_ = regular->smart_time_check_;
4621 cumulative_ = regular->cumulative_;
4635 return s->
branches() - branches_offset_ >= branches_ ||
4636 s->
failures() - failures_offset_ >= failures_ || CheckTime(offset) ||
4637 s->
solutions() - solutions_offset_ >= solutions_;
4642 int64_t progress = GetPercent(s->
branches(), branches_offset_, branches_);
4643 progress = std::max(progress,
4644 GetPercent(s->
failures(), failures_offset_, failures_));
4645 progress = std::max(
4646 progress, GetPercent(s->
solutions(), solutions_offset_, solutions_));
4648 progress = std::max(progress, (100 * TimeElapsed()) /
duration_limit());
4657 solver_time_at_limit_start_ = s->
Now();
4658 last_time_elapsed_ = absl::ZeroDuration();
4668 branches_ -= s->
branches() - branches_offset_;
4669 failures_ -= s->
failures() - failures_offset_;
4670 duration_limit_ -= s->
Now() - solver_time_at_limit_start_;
4671 solutions_ -= s->
solutions() - solutions_offset_;
4678 duration_limit_ = time;
4691 return absl::StrFormat(
4692 "RegularLimit(crossed = %i, duration_limit = %s, "
4693 "branches = %d, failures = %d, solutions = %d cumulative = %s",
4695 solutions_, (cumulative_ ?
"true" :
"false"));
4713bool RegularLimit::CheckTime(absl::Duration offset) {
4717absl::Duration RegularLimit::TimeElapsed() {
4718 const int64_t kMaxSkip = 100;
4719 const int64_t kCheckWarmupIterations = 100;
4722 next_check_ <= check_count_) {
4723 Solver*
const s =
solver();
4724 absl::Duration elapsed = s->Now() - solver_time_at_limit_start_;
4725 if (smart_time_check_ && check_count_ > kCheckWarmupIterations &&
4726 elapsed > absl::ZeroDuration()) {
4728 check_count_ * absl::FDivDuration(duration_limit_, elapsed));
4730 std::min(check_count_ + kMaxSkip, estimated_check_count_at_limit);
4732 last_time_elapsed_ = elapsed;
4734 return last_time_elapsed_;
4738 return MakeLimit(time, std::numeric_limits<int64_t>::max(),
4739 std::numeric_limits<int64_t>::max(),
4740 std::numeric_limits<int64_t>::max(),
4746 std::numeric_limits<int64_t>::max(),
4747 std::numeric_limits<int64_t>::max(),
4752 return MakeLimit(absl::InfiniteDuration(),
4753 std::numeric_limits<int64_t>::max(),
failures,
4754 std::numeric_limits<int64_t>::max(),
4759 return MakeLimit(absl::InfiniteDuration(),
4760 std::numeric_limits<int64_t>::max(),
4761 std::numeric_limits<int64_t>::max(),
solutions,
4767 bool smart_time_check,
bool cumulative) {
4769 smart_time_check, cumulative);
4774 bool smart_time_check,
bool cumulative) {
4776 smart_time_check, cumulative));
4780 return MakeLimit(proto.
time() == std::numeric_limits<int64_t>::max()
4781 ? absl::InfiniteDuration()
4782 : absl::Milliseconds(proto.
time()),
4789 proto.
set_time(std::numeric_limits<int64_t>::max());
4790 proto.
set_branches(std::numeric_limits<int64_t>::max());
4791 proto.
set_failures(std::numeric_limits<int64_t>::max());
4802 double objective_scaling_factor,
double objective_offset,
4803 double improvement_rate_coefficient,
4804 int improvement_rate_solutions_distance)
4806 std::vector<bool>{maximize},
4807 std::vector<double>{objective_scaling_factor},
4808 std::vector<double>{objective_offset},
4809 improvement_rate_coefficient,
4810 improvement_rate_solutions_distance) {}
4814 std::vector<bool> maximize, std::vector<double> objective_scaling_factors,
4815 std::vector<double> objective_offsets,
double improvement_rate_coefficient,
4816 int improvement_rate_solutions_distance)
4818 objective_vars_(
std::move(objective_vars)),
4819 maximize_(
std::move(maximize)),
4820 objective_scaling_factors_(
std::move(objective_scaling_factors)),
4821 objective_offsets_(
std::move(objective_offsets)),
4822 improvement_rate_coefficient_(improvement_rate_coefficient),
4823 improvement_rate_solutions_distance_(improvement_rate_solutions_distance),
4824 best_objectives_(objective_vars_.size()),
4825 improvements_(objective_vars_.size()),
4826 thresholds_(objective_vars_.size(),
4827 std::numeric_limits<double>::infinity()) {
4839 for (
int i = 0; i < objective_vars_.size(); ++i) {
4840 best_objectives_[i] = std::numeric_limits<double>::infinity();
4841 improvements_[i].clear();
4842 thresholds_[i] = std::numeric_limits<double>::infinity();
4844 objective_updated_ =
false;
4845 gradient_stage_ =
true;
4851 objective_vars_ = improv->objective_vars_;
4852 maximize_ = improv->maximize_;
4853 objective_scaling_factors_ = improv->objective_scaling_factors_;
4854 objective_offsets_ = improv->objective_offsets_;
4855 improvement_rate_coefficient_ = improv->improvement_rate_coefficient_;
4856 improvement_rate_solutions_distance_ =
4857 improv->improvement_rate_solutions_distance_;
4858 improvements_ = improv->improvements_;
4859 thresholds_ = improv->thresholds_;
4860 best_objectives_ = improv->best_objectives_;
4861 objective_updated_ = improv->objective_updated_;
4862 gradient_stage_ = improv->gradient_stage_;
4867 solver(), objective_vars_, maximize_, objective_scaling_factors_,
4868 objective_offsets_, improvement_rate_coefficient_,
4869 improvement_rate_solutions_distance_));
4873 if (!objective_updated_) {
4876 objective_updated_ =
false;
4878 std::vector<double> improvement_rates(improvements_.size());
4879 for (
int i = 0; i < improvements_.size(); ++i) {
4880 if (improvements_[i].size() <= improvement_rate_solutions_distance_) {
4884 const auto [cur_obj, cur_neighbors] = improvements_[i].back();
4885 const auto [prev_obj, prev_neighbors] = improvements_[i].front();
4886 DCHECK_GT(cur_neighbors, prev_neighbors);
4887 improvement_rates[i] =
4888 (prev_obj - cur_obj) / (cur_neighbors - prev_neighbors);
4889 if (gradient_stage_)
continue;
4890 const double scaled_improvement_rate =
4891 improvement_rate_coefficient_ * improvement_rates[i];
4892 if (scaled_improvement_rate < thresholds_[i]) {
4894 }
else if (scaled_improvement_rate > thresholds_[i]) {
4898 if (gradient_stage_ && std::lexicographical_compare(
4899 improvement_rates.begin(), improvement_rates.end(),
4900 thresholds_.begin(), thresholds_.end())) {
4901 thresholds_ = std::move(improvement_rates);
4907 std::vector<double> scaled_new_objectives(objective_vars_.size());
4908 for (
int i = 0; i < objective_vars_.size(); ++i) {
4909 const int64_t new_objective =
4910 objective_vars_[i] !=
nullptr && objective_vars_[i]->Bound()
4911 ? objective_vars_[i]->Min()
4912 : (maximize_[i] ?
solver()
4920 scaled_new_objectives[i] = (maximize_[i] ? -objective_scaling_factors_[i]
4921 : objective_scaling_factors_[i]) *
4922 (new_objective + objective_offsets_[i]);
4924 const bool is_improvement = std::lexicographical_compare(
4925 scaled_new_objectives.begin(), scaled_new_objectives.end(),
4926 best_objectives_.begin(), best_objectives_.end());
4927 if (gradient_stage_ && !is_improvement) {
4928 gradient_stage_ =
false;
4931 for (
int i = 0; i < objective_vars_.size(); ++i) {
4932 if (thresholds_[i] == std::numeric_limits<double>::infinity()) {
4933 thresholds_[i] = -1;
4938 if (is_improvement) {
4939 objective_updated_ =
true;
4940 for (
int i = 0; i < objective_vars_.size(); ++i) {
4941 improvements_[i].push_back(
4942 std::make_pair(scaled_new_objectives[i],
solver()->neighbors()));
4946 if (improvements_[i].size() - 1 > improvement_rate_solutions_distance_) {
4947 improvements_[i].pop_front();
4949 DCHECK_LE(improvements_[i].size() - 1,
4950 improvement_rate_solutions_distance_);
4952 best_objectives_ = std::move(scaled_new_objectives);
4958 IntVar* objective_var,
bool maximize,
double objective_scaling_factor,
4959 double objective_offset,
double improvement_rate_coefficient,
4960 int improvement_rate_solutions_distance) {
4962 this, objective_var, maximize, objective_scaling_factor, objective_offset,
4963 improvement_rate_coefficient, improvement_rate_solutions_distance));
4967 std::vector<IntVar*> objective_vars, std::vector<bool> maximize,
4968 std::vector<double> objective_scaling_factors,
4969 std::vector<double> objective_offsets,
double improvement_rate_coefficient,
4970 int improvement_rate_solutions_distance) {
4972 this, std::move(objective_vars), std::move(maximize),
4973 std::move(objective_scaling_factors), std::move(objective_offsets),
4974 improvement_rate_coefficient, improvement_rate_solutions_distance));
4982 :
SearchLimit(limit_1->solver()), limit_1_(limit_1), limit_2_(limit_2) {
4983 CHECK(limit_1 !=
nullptr);
4984 CHECK(limit_2 !=
nullptr);
4986 <<
"Illegal arguments: cannot combines limits that belong to different "
4987 <<
"solvers, because the reversible allocations could delete one and "
4988 <<
"not the other.";
4991 bool CheckWithOffset(absl::Duration offset)
override {
4994 const bool check_1 = limit_1_->CheckWithOffset(offset);
4995 const bool check_2 = limit_2_->CheckWithOffset(offset);
4996 return check_1 || check_2;
4999 void Init()
override {
5004 void Copy(
const SearchLimit*
const)
override {
5005 LOG(FATAL) <<
"Not implemented.";
5008 SearchLimit* MakeClone()
const override {
5010 return solver()->MakeLimit(limit_1_->MakeClone(), limit_2_->MakeClone());
5013 void EnterSearch()
override {
5014 limit_1_->EnterSearch();
5015 limit_2_->EnterSearch();
5017 void BeginNextDecision(DecisionBuilder*
const b)
override {
5018 limit_1_->BeginNextDecision(b);
5019 limit_2_->BeginNextDecision(b);
5021 void PeriodicCheck()
override {
5022 limit_1_->PeriodicCheck();
5023 limit_2_->PeriodicCheck();
5025 void RefuteDecision(Decision*
const d)
override {
5026 limit_1_->RefuteDecision(d);
5027 limit_2_->RefuteDecision(d);
5029 std::string DebugString()
const override {
5030 return absl::StrCat(
"OR limit (", limit_1_->DebugString(),
" OR ",
5031 limit_2_->DebugString(),
")");
5035 SearchLimit*
const limit_1_;
5036 SearchLimit*
const limit_2_;
5042 return RevAlloc(
new ORLimit(limit_1, limit_2));
5048 CustomLimit(
Solver* s, std::function<
bool()> limiter);
5049 bool CheckWithOffset(absl::Duration offset)
override;
5050 void Init()
override;
5055 std::function<bool()> limiter_;
5058CustomLimit::CustomLimit(Solver*
const s, std::function<
bool()> limiter)
5059 : SearchLimit(s), limiter_(
std::move(limiter)) {}
5061bool CustomLimit::CheckWithOffset(absl::Duration) {
5063 if (limiter_)
return limiter_();
5067void CustomLimit::Init() {}
5069void CustomLimit::Copy(
const SearchLimit*
const limit) {
5070 const CustomLimit*
const custom =
5071 reinterpret_cast<const CustomLimit* const
>(limit);
5072 limiter_ = custom->limiter_;
5075SearchLimit* CustomLimit::MakeClone()
const {
5076 return solver()->RevAlloc(
new CustomLimit(solver(), limiter_));
5081 return RevAlloc(
new CustomLimit(
this, std::move(limiter)));
5090 CHECK(db !=
nullptr);
5093 SolveOnce(DecisionBuilder*
const db,
5094 const std::vector<SearchMonitor*>& monitors)
5095 : db_(db), monitors_(monitors) {
5096 CHECK(db !=
nullptr);
5099 ~SolveOnce()
override {}
5101 Decision*
Next(Solver* s)
override {
5102 bool res = s->SolveAndCommit(db_, monitors_);
5109 std::string DebugString()
const override {
5110 return absl::StrFormat(
"SolveOnce(%s)", db_->
DebugString());
5113 void Accept(ModelVisitor*
const visitor)
const override {
5118 DecisionBuilder*
const db_;
5119 std::vector<SearchMonitor*> monitors_;
5124 return RevAlloc(
new SolveOnce(db));
5129 std::vector<SearchMonitor*> monitors;
5130 monitors.push_back(monitor1);
5131 return RevAlloc(
new SolveOnce(db, monitors));
5137 std::vector<SearchMonitor*> monitors;
5138 monitors.push_back(monitor1);
5139 monitors.push_back(monitor2);
5140 return RevAlloc(
new SolveOnce(db, monitors));
5147 std::vector<SearchMonitor*> monitors;
5148 monitors.push_back(monitor1);
5149 monitors.push_back(monitor2);
5150 monitors.push_back(monitor3);
5151 return RevAlloc(
new SolveOnce(db, monitors));
5159 std::vector<SearchMonitor*> monitors;
5160 monitors.push_back(monitor1);
5161 monitors.push_back(monitor2);
5162 monitors.push_back(monitor3);
5163 monitors.push_back(monitor4);
5164 return RevAlloc(
new SolveOnce(db, monitors));
5168 DecisionBuilder*
const db,
const std::vector<SearchMonitor*>& monitors) {
5169 return RevAlloc(
new SolveOnce(db, monitors));
5178 bool maximize, int64_t step)
5181 maximize_(maximize),
5183 collector_(nullptr) {
5184 CHECK(db !=
nullptr);
5190 NestedOptimize(DecisionBuilder*
const db, Assignment*
const solution,
5191 bool maximize, int64_t step,
5192 const std::vector<SearchMonitor*>& monitors)
5194 solution_(solution),
5195 maximize_(maximize),
5197 monitors_(monitors),
5198 collector_(nullptr) {
5199 CHECK(db !=
nullptr);
5200 CHECK(solution !=
nullptr);
5201 CHECK(solution->HasObjective());
5205 void AddMonitors() {
5206 Solver*
const solver = solution_->
solver();
5207 collector_ = solver->MakeLastSolutionCollector(solution_);
5208 monitors_.push_back(collector_);
5209 OptimizeVar*
const optimize =
5210 solver->MakeOptimize(maximize_, solution_->
Objective(), step_);
5211 monitors_.push_back(optimize);
5214 Decision*
Next(Solver* solver)
override {
5215 solver->Solve(db_, monitors_);
5223 std::string DebugString()
const override {
5224 return absl::StrFormat(
"NestedOptimize(db = %s, maximize = %d, step = %d)",
5228 void Accept(ModelVisitor*
const visitor)
const override {
5233 DecisionBuilder*
const db_;
5234 Assignment*
const solution_;
5235 const bool maximize_;
5236 const int64_t step_;
5237 std::vector<SearchMonitor*> monitors_;
5238 SolutionCollector* collector_;
5244 bool maximize, int64_t step) {
5250 bool maximize, int64_t step,
5252 std::vector<SearchMonitor*> monitors;
5253 monitors.push_back(monitor1);
5254 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5259 bool maximize, int64_t step,
5262 std::vector<SearchMonitor*> monitors;
5263 monitors.push_back(monitor1);
5264 monitors.push_back(monitor2);
5265 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5270 bool maximize, int64_t step,
5274 std::vector<SearchMonitor*> monitors;
5275 monitors.push_back(monitor1);
5276 monitors.push_back(monitor2);
5277 monitors.push_back(monitor3);
5278 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5285 std::vector<SearchMonitor*> monitors;
5286 monitors.push_back(monitor1);
5287 monitors.push_back(monitor2);
5288 monitors.push_back(monitor3);
5289 monitors.push_back(monitor4);
5290 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5295 int64_t step,
const std::vector<SearchMonitor*>& monitors) {
5296 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5303int64_t NextLuby(
int i) {
5305 DCHECK_LT(i, std::numeric_limits<int32_t>::max());
5311 while (power < (i + 1)) {
5314 if (power == i + 1) {
5317 return NextLuby(i - (power / 2) + 1);
5320class LubyRestart :
public SearchMonitor {
5322 LubyRestart(Solver*
const s,
int scale_factor)
5324 scale_factor_(scale_factor),
5327 next_step_(scale_factor) {
5328 CHECK_GE(scale_factor, 1);
5331 ~LubyRestart()
override {}
5333 void BeginFail()
override {
5334 if (++current_fails_ >= next_step_) {
5336 next_step_ = NextLuby(++iteration_) * scale_factor_;
5337 solver()->RestartCurrentSearch();
5341 void Install()
override { ListenToEvent(Solver::MonitorEvent::kBeginFail); }
5343 std::string DebugString()
const override {
5344 return absl::StrFormat(
"LubyRestart(%i)", scale_factor_);
5348 const int scale_factor_;
5350 int64_t current_fails_;
5356 return RevAlloc(
new LubyRestart(
this, scale_factor));
5364 ConstantRestart(
Solver*
const s,
int frequency)
5365 :
SearchMonitor(s), frequency_(frequency), current_fails_(0) {
5366 CHECK_GE(frequency, 1);
5369 ~ConstantRestart()
override {}
5371 void BeginFail()
override {
5372 if (++current_fails_ >= frequency_) {
5374 solver()->RestartCurrentSearch();
5378 void Install()
override { ListenToEvent(Solver::MonitorEvent::kBeginFail); }
5380 std::string DebugString()
const override {
5381 return absl::StrFormat(
"ConstantRestart(%i)", frequency_);
5385 const int frequency_;
5386 int64_t current_fails_;
5391 return RevAlloc(
new ConstantRestart(
this, frequency));
5414 const std::vector<SymmetryBreaker*>& visitors)
5416 visitors_(visitors),
5417 clauses_(visitors.size()),
5418 decisions_(visitors.size()),
5419 directions_(visitors.size()) {
5420 for (
int i = 0; i < visitors_.size(); ++i) {
5421 visitors_[i]->set_symmetry_manager_and_index(
this, i);
5429 for (
int i = 0; i < visitors_.size(); ++i) {
5430 const void*
const last = clauses_[i].Last();
5432 if (last != clauses_[i].Last()) {
5434 decisions_[i].Push(
solver(), d);
5435 directions_[i].Push(
solver(),
false);
5442 for (
int i = 0; i < visitors_.size(); ++i) {
5443 if (decisions_[i].Last() !=
nullptr && decisions_[i].LastValue() == d) {
5456 std::vector<IntVar*> guard;
5461 IntVar*
const term = *tmp;
5463 if (term->
Max() == 0) {
5467 if (term->
Min() == 0) {
5468 DCHECK_EQ(1, term->
Max());
5470 guard.push_back(term);
5476 guard.push_back(clauses_[index].LastValue());
5477 directions_[index].SetLastValue(
true);
5484 DCHECK(ct !=
nullptr);
5485 solver()->AddConstraint(ct);
5489 clauses_[visitor->index_in_symmetry_manager()].Push(
solver(), term);
5492 std::string
DebugString()
const override {
return "SymmetryManager"; }
5495 const std::vector<SymmetryBreaker*> visitors_;
5496 std::vector<SimpleRevFIFO<IntVar*>> clauses_;
5497 std::vector<SimpleRevFIFO<Decision*>> decisions_;
5498 std::vector<SimpleRevFIFO<bool>> directions_;
5505 CHECK(var !=
nullptr);
5508 symmetry_manager()->AddTermToClause(
this, term);
5512 IntVar*
const var, int64_t value) {
5513 CHECK(var !=
nullptr);
5516 symmetry_manager()->AddTermToClause(
this, term);
5520 IntVar*
const var, int64_t value) {
5521 CHECK(var !=
nullptr);
5524 symmetry_manager()->AddTermToClause(
this, term);
5530 const std::vector<SymmetryBreaker*>& visitors) {
5535 std::vector<SymmetryBreaker*> visitors;
5536 visitors.push_back(v1);
5542 std::vector<SymmetryBreaker*> visitors;
5543 visitors.push_back(v1);
5544 visitors.push_back(v2);
5551 std::vector<SymmetryBreaker*> visitors;
5552 visitors.push_back(v1);
5553 visitors.push_back(v2);
5554 visitors.push_back(v3);
5562 std::vector<SymmetryBreaker*> visitors;
5563 visitors.push_back(v1);
5564 visitors.push_back(v2);
5565 visitors.push_back(v3);
5566 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)
virtual Decision * Next(Solver *s)=0
virtual void Accept(ModelVisitor *visitor) const
std::string DebugString() const override
virtual void Accept(DecisionVisitor *visitor) const
Accepts the given visitor.
bool CheckWithOffset(absl::Duration offset) override
~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)
void Init() override
This method is called when the search limit is initialized.
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 * > & minimization_vars() const
const std::vector< IntVar * > & objective_vars() const
int64_t Step(int index) const override
int Size() const override
void MakeMinimizationVarsLessOrEqualWithSteps(const T &upper_bounds)
bool found_initial_solution_
int64_t CurrentInternalValue(int index) const
bool Maximize(int index) const override
bool AcceptDelta(Assignment *delta, Assignment *deltadelta) override
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
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)
void Copy(const SearchLimit *limit) override
void UpdateLimits(absl::Duration time, int64_t branches, int64_t failures, int64_t solutions)
RegularLimit * MakeIdenticalClone() const
bool AcceptDelta(Assignment *delta, Assignment *deltadelta) override
void EnterSearch() override
Beginning of the search.
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 AtLocalOptimum() 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.
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.
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)
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.
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)
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.
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)
Phases on IntVar arrays.
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)
Creates a Simulated Annealing monitor.
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()
Returns (or creates) an assignment representing the state of local search.
@ ASSIGN_MAX_VALUE
Selects the max value of the selected variable.
@ INT_VALUE_DEFAULT
The default behavior is ASSIGN_MIN_VALUE.
@ INT_VALUE_SIMPLE
The simple selection is ASSIGN_MIN_VALUE.
@ ASSIGN_MIN_VALUE
Selects the min value of the selected variable.
@ ASSIGN_RANDOM_VALUE
Selects randomly one of the possible values of the selected variable.
OptimizeVar * MakeLexicographicOptimize(std::vector< bool > maximize, std::vector< IntVar * > variables, std::vector< int64_t > steps)
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 Set(IntegerType index)
void AddIntegerVariableGreaterOrEqualValueClause(IntVar *var, int64_t value)
void AddIntegerVariableLessOrEqualValueClause(IntVar *var, int64_t value)
void AddIntegerVariableEqualValueClause(IntVar *var, int64_t value)
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
H AbslHashValue(H h, std::shared_ptr< Variable > i)
dual_gradient T(y - `dual_solution`) class DiagonalTrustRegionProblemFromQp
std::function< int64_t(const Model &)> Value(IntegerVariable v)
int64_t CapAdd(int64_t x, int64_t y)
std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
void AcceptNeighbor(Search *search)
int64_t CapSub(int64_t x, int64_t y)
std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)
std::string MemoryUsage()
BaseAssignVariables::Mode ChooseMode(Solver::IntValueStrategy val_str)
int64_t CapOpp(int64_t v)
bool AcceptDelta(Search *search, Assignment *delta, Assignment *deltadelta)
ABSL_FLAG(bool, cp_use_sparse_gls_penalties, false, "Use sparse implementation to store Guided Local Search penalties")
int64_t ObjectiveValue() const
bool operator<(const SolutionData &other) const
int64_t ObjectiveValueFromIndex(int index) const
Creates a search monitor from logging parameters.
static const int64_t kint64max