27#include "absl/container/flat_hash_map.h"
28#include "absl/flags/flag.h"
29#include "absl/log/check.h"
30#include "absl/random/distributions.h"
31#include "absl/strings/str_cat.h"
32#include "absl/strings/str_format.h"
33#include "absl/strings/str_join.h"
34#include "absl/strings/string_view.h"
35#include "absl/time/time.h"
43#include "ortools/constraint_solver/search_limit.pb.h"
49 "Use sparse implementation to store Guided Local Search penalties");
51 "Whether search related logging should be "
53ABSL_FLAG(int64_t, cp_large_domain_no_splitting_limit, 0xFFFFF,
54 "Size limit to allow holes in variables from the strategy.");
60 std::string vars_name, std::vector<double> scaling_factors,
61 std::vector<double> offsets,
62 std::function<std::string()> display_callback,
63 bool display_on_new_solutions_only,
int period)
68 vars_name_(
std::move(vars_name)),
69 scaling_factors_(
std::move(scaling_factors)),
70 offsets_(
std::move(offsets)),
71 display_callback_(
std::move(display_callback)),
72 display_on_new_solutions_only_(display_on_new_solutions_only),
77 min_right_depth_(
std::numeric_limits<int32_t>::
max()),
79 sliding_min_depth_(0),
80 sliding_max_depth_(0) {}
87 const std::string buffer =
88 absl::StrFormat(
"Start search (%s)", MemoryUsage());
91 min_right_depth_ = std::numeric_limits<int32_t>::max();
102 const std::string buffer = absl::StrFormat(
103 "End search (time = %d ms, branches = %d, failures = %d, %s, speed = %d "
105 ms, branches,
solver()->failures(), MemoryUsage(), branches * 1000 / ms);
112 std::string obj_str =
"";
113 std::vector<int64_t> current;
114 bool objective_updated =
false;
115 const auto scaled_str = [
this](
const std::vector<int64_t>& values) {
116 std::vector<std::string> value_strings(values.size());
117 for (
int i = 0; i < values.size(); ++i) {
118 if (scaling_factors_[i] != 1.0 || offsets_[i] != 0.0) {
120 absl::StrFormat(
"%d (%.8lf)", values[i],
121 scaling_factors_[i] * (values[i] + offsets_[i]));
123 value_strings[i] = absl::StrCat(values[i]);
126 return absl::StrJoin(value_strings,
", ");
128 bool all_vars_bound = !vars_.empty();
130 all_vars_bound &=
var->Bound();
132 if (all_vars_bound) {
134 current.push_back(
var->Value());
135 objective_updated =
true;
137 absl::StrAppend(&obj_str,
138 vars_name_.empty() ?
"" : absl::StrCat(vars_name_,
" = "),
139 scaled_str(current),
", ");
141 current.push_back(
solver()->GetOrCreateLocalSearchState()->ObjectiveMin());
142 absl::StrAppend(&obj_str,
"objective = ", scaled_str(current),
", ");
143 objective_updated =
true;
145 if (objective_updated) {
146 if (!objective_min_.empty() &&
147 std::lexicographical_compare(objective_min_.begin(),
148 objective_min_.end(), current.begin(),
150 absl::StrAppend(&obj_str,
151 vars_name_.empty() ?
"" : absl::StrCat(vars_name_,
" "),
152 "minimum = ", scaled_str(objective_min_),
", ");
155 objective_min_ = current;
157 if (!objective_max_.empty() &&
158 std::lexicographical_compare(current.begin(), current.end(),
159 objective_max_.begin(),
160 objective_max_.end())) {
161 absl::StrAppend(&obj_str,
162 vars_name_.empty() ?
"" : absl::StrCat(vars_name_,
" "),
163 "maximum = ", scaled_str(objective_max_),
", ");
165 objective_max_ = current;
169 absl::StrAppendFormat(&log,
170 "Solution #%d (%stime = %d ms, branches = %d,"
171 " failures = %d, depth = %d",
172 nsol_++, obj_str, timer_->
GetInMs(),
174 if (!
solver()->SearchContext().empty()) {
175 absl::StrAppendFormat(&log,
", %s",
solver()->SearchContext());
177 if (
solver()->accepted_neighbors() != neighbors_offset_) {
178 absl::StrAppendFormat(&log,
179 ", neighbors = %d, filtered neighbors = %d,"
180 " accepted neighbors = %d",
182 solver()->accepted_neighbors());
184 absl::StrAppendFormat(&log,
", %s", MemoryUsage());
187 absl::StrAppendFormat(&log,
", limit = %d%%", progress);
189 if (display_callback_) {
190 absl::StrAppendFormat(&log,
", %s", display_callback_());
202 std::string buffer = absl::StrFormat(
203 "Finished search tree (time = %d ms, branches = %d,"
206 if (
solver()->neighbors() != 0) {
207 absl::StrAppendFormat(&buffer,
208 ", neighbors = %d, filtered neighbors = %d,"
209 " accepted neigbors = %d",
211 solver()->accepted_neighbors());
213 absl::StrAppendFormat(&buffer,
", %s", MemoryUsage());
214 if (!display_on_new_solutions_only_ && display_callback_) {
215 absl::StrAppendFormat(&buffer,
", %s", display_callback_());
224 if (
b % period_ == 0 &&
b > 0) {
230 min_right_depth_ = std::min(min_right_depth_,
solver()->SearchDepth());
236 absl::StrFormat(
"%d branches, %d ms, %d failures",
solver()->branches(),
238 if (min_right_depth_ != std::numeric_limits<int32_t>::max() &&
241 absl::StrAppendFormat(&buffer,
", tree pos=%d/%d/%d minref=%d max=%d",
242 sliding_min_depth_, depth, sliding_max_depth_,
243 min_right_depth_, max_depth_);
244 sliding_min_depth_ = depth;
245 sliding_max_depth_ = depth;
247 if (!objective_min_.empty() &&
248 objective_min_[0] != std::numeric_limits<int64_t>::max() &&
249 objective_max_[0] != std::numeric_limits<int64_t>::min()) {
250 const std::string
name =
251 vars_name_.empty() ?
"" : absl::StrCat(
" ", vars_name_);
252 absl::StrAppendFormat(&buffer,
255 name, objective_min_[0],
name, objective_max_[0]);
259 absl::StrAppendFormat(&buffer,
", limit = %d%%", progress);
266 sliding_min_depth_ = std::min(current_depth, sliding_min_depth_);
267 sliding_max_depth_ = std::max(current_depth, sliding_max_depth_);
268 max_depth_ = std::max(current_depth, max_depth_);
274 const int64_t
delta = std::max<int64_t>(timer_->
GetInMs() - tick_, 0);
275 const std::string buffer = absl::StrFormat(
276 "Root node processed (time = %d ms, constraints = %d, %s)",
delta,
277 solver()->constraints(), MemoryUsage());
282 if (absl::GetFlag(FLAGS_cp_log_to_vlog)) {
289std::string SearchLog::MemoryUsage() {
290 static const int64_t kDisplayThreshold = 2;
291 static const int64_t kKiloByte = 1024;
292 static const int64_t kMegaByte = kKiloByte * kKiloByte;
293 static const int64_t kGigaByte = kMegaByte * kKiloByte;
295 if (memory_usage > kDisplayThreshold * kGigaByte) {
296 return absl::StrFormat(
"memory used = %.2lf GB",
297 memory_usage * 1.0 / kGigaByte);
298 }
else if (memory_usage > kDisplayThreshold * kMegaByte) {
299 return absl::StrFormat(
"memory used = %.2lf MB",
300 memory_usage * 1.0 / kMegaByte);
301 }
else if (memory_usage > kDisplayThreshold * kKiloByte) {
302 return absl::StrFormat(
"memory used = %2lf KB",
303 memory_usage * 1.0 / kKiloByte);
305 return absl::StrFormat(
"memory used = %d", memory_usage);
310 return MakeSearchLog(branch_period, std::vector<IntVar*>{},
nullptr);
318 int branch_period, std::function<std::string()> display_callback) {
320 std::move(display_callback));
325 std::function<std::string()> display_callback) {
327 std::move(display_callback));
331 int branch_period, std::vector<IntVar*> vars,
332 std::function<std::string()> display_callback) {
334 std::move(display_callback),
true,
344 std::function<std::string()> display_callback) {
346 std::vector<double> scaling_factors(vars.size(), 1.0);
347 std::vector<double> offsets(vars.size(), 0.0);
349 this, std::move(vars), opt_var->
Name(), std::move(scaling_factors),
350 std::move(offsets), std::move(display_callback),
true, branch_period));
355 <<
"Either variables are empty or objective is nullptr.";
356 std::vector<IntVar*> vars =
parameters.objective !=
nullptr
359 std::vector<double> scaling_factors =
parameters.scaling_factors;
360 scaling_factors.resize(vars.size(), 1.0);
361 std::vector<double> offsets =
parameters.offsets;
362 offsets.resize(vars.size(), 0.0);
364 this, std::move(vars),
"", std::move(scaling_factors), std::move(offsets),
373 SearchTrace(
Solver*
const s,
const std::string& prefix)
375 ~SearchTrace()
override {}
377 void EnterSearch()
override {
378 LOG(INFO) << prefix_ <<
" EnterSearch(" << solver()->
SolveDepth() <<
")";
380 void RestartSearch()
override {
381 LOG(INFO) << prefix_ <<
" RestartSearch(" << solver()->
SolveDepth() <<
")";
383 void ExitSearch()
override {
384 LOG(INFO) << prefix_ <<
" ExitSearch(" << solver()->
SolveDepth() <<
")";
386 void BeginNextDecision(DecisionBuilder*
const b)
override {
387 LOG(INFO) << prefix_ <<
" BeginNextDecision(" <<
b <<
") ";
389 void EndNextDecision(DecisionBuilder*
const b, Decision*
const d)
override {
391 LOG(INFO) << prefix_ <<
" EndNextDecision(" <<
b <<
", " << d <<
") ";
393 LOG(INFO) << prefix_ <<
" EndNextDecision(" <<
b <<
") ";
396 void ApplyDecision(Decision*
const d)
override {
397 LOG(INFO) << prefix_ <<
" ApplyDecision(" << d <<
") ";
399 void RefuteDecision(Decision*
const d)
override {
400 LOG(INFO) << prefix_ <<
" RefuteDecision(" << d <<
") ";
402 void AfterDecision(Decision*
const d,
bool apply)
override {
403 LOG(INFO) << prefix_ <<
" AfterDecision(" << d <<
", " << apply <<
") ";
405 void BeginFail()
override {
406 LOG(INFO) << prefix_ <<
" BeginFail(" << solver()->
SearchDepth() <<
")";
408 void EndFail()
override {
409 LOG(INFO) << prefix_ <<
" EndFail(" << solver()->
SearchDepth() <<
")";
411 void BeginInitialPropagation()
override {
412 LOG(INFO) << prefix_ <<
" BeginInitialPropagation()";
414 void EndInitialPropagation()
override {
415 LOG(INFO) << prefix_ <<
" EndInitialPropagation()";
417 bool AtSolution()
override {
418 LOG(INFO) << prefix_ <<
" AtSolution()";
421 bool AcceptSolution()
override {
422 LOG(INFO) << prefix_ <<
" AcceptSolution()";
425 void NoMoreSolutions()
override {
426 LOG(INFO) << prefix_ <<
" NoMoreSolutions()";
429 std::string DebugString()
const override {
return "SearchTrace"; }
432 const std::string prefix_;
437 return RevAlloc(
new SearchTrace(
this, prefix));
444 AtSolutionCallback(
Solver*
const solver, std::function<
void()>
callback)
446 ~AtSolutionCallback()
override {}
447 bool AtSolution()
override;
448 void Install()
override;
451 const std::function<void()> callback_;
454bool AtSolutionCallback::AtSolution() {
459void AtSolutionCallback::Install() {
460 ListenToEvent(Solver::MonitorEvent::kAtSolution);
466 return RevAlloc(
new AtSolutionCallback(
this, std::move(
callback)));
472 EnterSearchCallback(
Solver*
const solver, std::function<
void()>
callback)
474 ~EnterSearchCallback()
override {}
475 void EnterSearch()
override;
476 void Install()
override;
479 const std::function<void()> callback_;
482void EnterSearchCallback::EnterSearch() { callback_(); }
484void EnterSearchCallback::Install() {
485 ListenToEvent(Solver::MonitorEvent::kEnterSearch);
491 return RevAlloc(
new EnterSearchCallback(
this, std::move(
callback)));
497 ExitSearchCallback(
Solver*
const solver, std::function<
void()>
callback)
499 ~ExitSearchCallback()
override {}
500 void ExitSearch()
override;
501 void Install()
override;
504 const std::function<void()> callback_;
507void ExitSearchCallback::ExitSearch() { callback_(); }
509void ExitSearchCallback::Install() {
510 ListenToEvent(Solver::MonitorEvent::kExitSearch);
516 return RevAlloc(
new ExitSearchCallback(
this, std::move(
callback)));
524 CompositeDecisionBuilder();
525 explicit CompositeDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs);
526 ~CompositeDecisionBuilder()
override;
528 void AppendMonitors(
Solver* solver,
529 std::vector<SearchMonitor*>* monitors)
override;
536CompositeDecisionBuilder::CompositeDecisionBuilder() {}
538CompositeDecisionBuilder::CompositeDecisionBuilder(
539 const std::vector<DecisionBuilder*>& dbs) {
540 for (
int i = 0;
i < dbs.size(); ++
i) {
545CompositeDecisionBuilder::~CompositeDecisionBuilder() {}
547void CompositeDecisionBuilder::Add(DecisionBuilder*
const db) {
553void CompositeDecisionBuilder::AppendMonitors(
554 Solver*
const solver, std::vector<SearchMonitor*>*
const monitors) {
555 for (DecisionBuilder*
const db :
builders_) {
556 db->AppendMonitors(solver, monitors);
560void CompositeDecisionBuilder::Accept(ModelVisitor*
const visitor)
const {
561 for (DecisionBuilder*
const db :
builders_) {
570class ComposeDecisionBuilder :
public CompositeDecisionBuilder {
572 ComposeDecisionBuilder();
573 explicit ComposeDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs);
574 ~ComposeDecisionBuilder()
override;
575 Decision*
Next(Solver* s)
override;
576 std::string DebugString()
const override;
582ComposeDecisionBuilder::ComposeDecisionBuilder() : start_index_(0) {}
584ComposeDecisionBuilder::ComposeDecisionBuilder(
585 const std::vector<DecisionBuilder*>& dbs)
586 : CompositeDecisionBuilder(dbs), start_index_(0) {}
588ComposeDecisionBuilder::~ComposeDecisionBuilder() {}
590Decision* ComposeDecisionBuilder::Next(Solver*
const s) {
592 for (
int i = start_index_;
i <
size; ++
i) {
595 s->SaveAndSetValue(&start_index_, i);
599 s->SaveAndSetValue(&start_index_,
size);
603std::string ComposeDecisionBuilder::DebugString()
const {
604 return absl::StrFormat(
"ComposeDecisionBuilder(%s)",
611 ComposeDecisionBuilder* c = RevAlloc(
new ComposeDecisionBuilder());
620 ComposeDecisionBuilder* c = RevAlloc(
new ComposeDecisionBuilder());
631 ComposeDecisionBuilder* c = RevAlloc(
new ComposeDecisionBuilder());
640 if (dbs.size() == 1) {
643 return RevAlloc(
new ComposeDecisionBuilder(dbs));
649class ClosureDecision :
public Decision {
652 : apply_(
std::move(apply)), refute_(
std::move(refute)) {}
653 ~ClosureDecision()
override {}
655 void Apply(Solver*
const s)
override { apply_(s); }
657 void Refute(Solver*
const s)
override { refute_(s); }
659 std::string DebugString()
const override {
return "ClosureDecision"; }
662 Solver::Action apply_;
663 Solver::Action refute_;
668 return RevAlloc(
new ClosureDecision(std::move(apply), std::move(refute)));
675class TryDecisionBuilder;
677class TryDecision :
public Decision {
679 explicit TryDecision(TryDecisionBuilder* try_builder);
680 ~TryDecision()
override;
681 void Apply(
Solver* solver)
override;
682 void Refute(
Solver* solver)
override;
683 std::string DebugString()
const override {
return "TryDecision"; }
686 TryDecisionBuilder*
const try_builder_;
689class TryDecisionBuilder :
public CompositeDecisionBuilder {
691 TryDecisionBuilder();
692 explicit TryDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs);
693 ~TryDecisionBuilder()
override;
694 Decision*
Next(Solver* solver)
override;
695 std::string DebugString()
const override;
696 void AdvanceToNextBuilder(Solver* solver);
699 TryDecision try_decision_;
700 int current_builder_;
701 bool start_new_builder_;
704TryDecision::TryDecision(TryDecisionBuilder*
const try_builder)
705 : try_builder_(try_builder) {}
707TryDecision::~TryDecision() {}
709void TryDecision::Apply(Solver*
const) {}
711void TryDecision::Refute(Solver*
const solver) {
712 try_builder_->AdvanceToNextBuilder(solver);
715TryDecisionBuilder::TryDecisionBuilder()
716 : CompositeDecisionBuilder(),
718 current_builder_(-1),
719 start_new_builder_(
true) {}
721TryDecisionBuilder::TryDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs)
722 : CompositeDecisionBuilder(dbs),
724 current_builder_(-1),
725 start_new_builder_(
true) {}
727TryDecisionBuilder::~TryDecisionBuilder() {}
729Decision* TryDecisionBuilder::Next(Solver*
const solver) {
730 if (current_builder_ < 0) {
731 solver->SaveAndSetValue(¤t_builder_, 0);
732 start_new_builder_ =
true;
734 if (start_new_builder_) {
735 start_new_builder_ =
false;
736 return &try_decision_;
738 return builders_[current_builder_]->Next(solver);
742std::string TryDecisionBuilder::DebugString()
const {
743 return absl::StrFormat(
"TryDecisionBuilder(%s)",
747void TryDecisionBuilder::AdvanceToNextBuilder(Solver*
const solver) {
749 start_new_builder_ =
true;
750 if (current_builder_ >=
builders_.size()) {
759 TryDecisionBuilder* try_db = RevAlloc(
new TryDecisionBuilder());
768 TryDecisionBuilder* try_db = RevAlloc(
new TryDecisionBuilder());
779 TryDecisionBuilder* try_db = RevAlloc(
new TryDecisionBuilder());
788 return RevAlloc(
new TryDecisionBuilder(dbs));
796class BaseVariableAssignmentSelector :
public BaseObject {
798 BaseVariableAssignmentSelector(
Solver* solver,
799 const std::vector<IntVar*>& vars)
805 ~BaseVariableAssignmentSelector()
override {}
807 virtual int64_t SelectValue(
const IntVar* v, int64_t
id) = 0;
810 virtual int64_t ChooseVariable() = 0;
812 int64_t ChooseVariableWrapper() {
815 if (!
vars_[i]->Bound()) {
824 if (!
vars_[i]->Bound()) {
829 return ChooseVariable();
832 void Accept(ModelVisitor*
const visitor)
const {
833 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
834 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
836 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
839 const std::vector<IntVar*>& vars()
const {
return vars_; }
842 Solver*
const solver_;
850int64_t ChooseFirstUnbound(Solver*,
const std::vector<IntVar*>& vars,
851 int64_t first_unbound, int64_t last_unbound) {
852 for (int64_t
i = first_unbound;
i <= last_unbound; ++
i) {
853 if (!vars[
i]->Bound()) {
862int64_t ChooseMinSizeLowestMin(Solver*,
const std::vector<IntVar*>& vars,
863 int64_t first_unbound, int64_t last_unbound) {
864 uint64_t best_size = std::numeric_limits<uint64_t>::max();
865 int64_t best_min = std::numeric_limits<int64_t>::max();
866 int64_t best_index = -1;
867 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
868 IntVar*
const var = vars[
i];
870 if (
var->Size() < best_size ||
871 (
var->Size() == best_size &&
var->Min() < best_min)) {
872 best_size =
var->Size();
873 best_min =
var->Min();
883int64_t ChooseMinSizeHighestMin(Solver*,
const std::vector<IntVar*>& vars,
884 int64_t first_unbound, int64_t last_unbound) {
885 uint64_t best_size = std::numeric_limits<uint64_t>::max();
886 int64_t best_min = std::numeric_limits<int64_t>::min();
887 int64_t best_index = -1;
888 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
889 IntVar*
const var = vars[
i];
891 if (
var->Size() < best_size ||
892 (
var->Size() == best_size &&
var->Min() > best_min)) {
893 best_size =
var->Size();
894 best_min =
var->Min();
904int64_t ChooseMinSizeLowestMax(Solver*,
const std::vector<IntVar*>& vars,
905 int64_t first_unbound, int64_t last_unbound) {
906 uint64_t best_size = std::numeric_limits<uint64_t>::max();
907 int64_t best_max = std::numeric_limits<int64_t>::max();
908 int64_t best_index = -1;
909 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
910 IntVar*
const var = vars[
i];
912 if (
var->Size() < best_size ||
913 (
var->Size() == best_size &&
var->Max() < best_max)) {
914 best_size =
var->Size();
915 best_max =
var->Max();
925int64_t ChooseMinSizeHighestMax(Solver*,
const std::vector<IntVar*>& vars,
926 int64_t first_unbound, int64_t last_unbound) {
927 uint64_t best_size = std::numeric_limits<uint64_t>::max();
928 int64_t best_max = std::numeric_limits<int64_t>::min();
929 int64_t best_index = -1;
930 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
931 IntVar*
const var = vars[
i];
933 if (
var->Size() < best_size ||
934 (
var->Size() == best_size &&
var->Max() > best_max)) {
935 best_size =
var->Size();
936 best_max =
var->Max();
946int64_t ChooseLowestMin(Solver*,
const std::vector<IntVar*>& vars,
947 int64_t first_unbound, int64_t last_unbound) {
948 int64_t best_min = std::numeric_limits<int64_t>::max();
949 int64_t best_index = -1;
950 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
951 IntVar*
const var = vars[
i];
953 if (
var->Min() < best_min) {
954 best_min =
var->Min();
964int64_t ChooseHighestMax(Solver*,
const std::vector<IntVar*>& vars,
965 int64_t first_unbound, int64_t last_unbound) {
966 int64_t best_max = std::numeric_limits<int64_t>::min();
967 int64_t best_index = -1;
968 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
969 IntVar*
const var = vars[
i];
971 if (
var->Max() > best_max) {
972 best_max =
var->Max();
982int64_t ChooseMinSize(Solver*,
const std::vector<IntVar*>& vars,
983 int64_t first_unbound, int64_t last_unbound) {
984 uint64_t best_size = std::numeric_limits<uint64_t>::max();
985 int64_t best_index = -1;
986 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
987 IntVar*
const var = vars[
i];
989 if (
var->Size() < best_size) {
990 best_size =
var->Size();
1000int64_t ChooseMaxSize(Solver*,
const std::vector<IntVar*>& vars,
1001 int64_t first_unbound, int64_t last_unbound) {
1002 uint64_t best_size = 0;
1003 int64_t best_index = -1;
1004 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
1005 IntVar*
const var = vars[
i];
1006 if (!
var->Bound()) {
1007 if (
var->Size() > best_size) {
1008 best_size =
var->Size();
1018class HighestRegretSelectorOnMin :
public BaseObject {
1020 explicit HighestRegretSelectorOnMin(
const std::vector<IntVar*>& vars)
1021 : iterators_(vars.
size()) {
1022 for (int64_t i = 0;
i < vars.size(); ++
i) {
1023 iterators_[
i] = vars[
i]->MakeDomainIterator(
true);
1026 ~HighestRegretSelectorOnMin()
override{};
1027 int64_t Choose(Solver* s,
const std::vector<IntVar*>& vars,
1028 int64_t first_unbound, int64_t last_unbound);
1029 std::string DebugString()
const override {
return "MaxRegretSelector"; }
1031 int64_t ComputeRegret(IntVar*
var, int64_t
index)
const {
1032 DCHECK(!
var->Bound());
1033 const int64_t vmin =
var->Min();
1034 IntVarIterator*
const iterator = iterators_[
index];
1037 return iterator->Value() - vmin;
1041 std::vector<IntVarIterator*> iterators_;
1044int64_t HighestRegretSelectorOnMin::Choose(Solver*
const,
1045 const std::vector<IntVar*>& vars,
1046 int64_t first_unbound,
1047 int64_t last_unbound) {
1048 int64_t best_regret = 0;
1050 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
1051 IntVar*
const var = vars[
i];
1052 if (!
var->Bound()) {
1053 const int64_t regret = ComputeRegret(
var, i);
1054 if (regret > best_regret) {
1055 best_regret = regret;
1065int64_t ChooseRandom(Solver* solver,
const std::vector<IntVar*>& vars,
1066 int64_t first_unbound, int64_t last_unbound) {
1067 const int64_t span = last_unbound - first_unbound + 1;
1068 const int64_t shift = solver->Rand32(span);
1069 for (int64_t i = 0;
i < span; ++
i) {
1070 const int64_t
index = (
i + shift) % span + first_unbound;
1071 if (!vars[
index]->Bound()) {
1080class CheapestVarSelector :
public BaseObject {
1082 explicit CheapestVarSelector(std::function<int64_t(int64_t)> var_evaluator)
1083 : var_evaluator_(
std::move(var_evaluator)) {}
1084 ~CheapestVarSelector()
override{};
1085 int64_t Choose(Solver* s,
const std::vector<IntVar*>& vars,
1086 int64_t first_unbound, int64_t last_unbound);
1087 std::string DebugString()
const override {
return "CheapestVarSelector"; }
1090 std::function<int64_t(int64_t)> var_evaluator_;
1093int64_t CheapestVarSelector::Choose(Solver*
const,
1094 const std::vector<IntVar*>& vars,
1095 int64_t first_unbound,
1096 int64_t last_unbound) {
1097 int64_t best_eval = std::numeric_limits<int64_t>::max();
1099 for (int64_t i = first_unbound;
i <= last_unbound; ++
i) {
1100 if (!vars[i]->Bound()) {
1101 const int64_t eval = var_evaluator_(i);
1102 if (eval < best_eval) {
1114class PathSelector :
public BaseObject {
1116 PathSelector() : first_(
std::numeric_limits<int64_t>::
max()) {}
1117 ~PathSelector()
override{};
1118 int64_t Choose(Solver* s,
const std::vector<IntVar*>& vars);
1119 std::string DebugString()
const override {
return "ChooseNextOnPath"; }
1122 bool UpdateIndex(
const std::vector<IntVar*>& vars, int64_t*
index)
const;
1123 bool FindPathStart(
const std::vector<IntVar*>& vars, int64_t*
index)
const;
1125 Rev<int64_t> first_;
1128int64_t PathSelector::Choose(Solver*
const s,
1129 const std::vector<IntVar*>& vars) {
1130 int64_t
index = first_.Value();
1131 if (!UpdateIndex(vars, &
index)) {
1135 while (vars[
index]->Bound()) {
1137 if (!UpdateIndex(vars, &
index)) {
1141 if (count >= vars.size() &&
1142 !FindPathStart(vars, &
index)) {
1146 first_.SetValue(s,
index);
1150bool PathSelector::UpdateIndex(
const std::vector<IntVar*>& vars,
1151 int64_t*
index)
const {
1152 if (*
index >= vars.size()) {
1153 if (!FindPathStart(vars,
index)) {
1166bool PathSelector::FindPathStart(
const std::vector<IntVar*>& vars,
1167 int64_t*
index)
const {
1169 for (int64_t i = vars.size() - 1; i >= 0; --i) {
1170 if (vars[i]->Bound()) {
1171 const int64_t
next = vars[
i]->Value();
1172 if (
next < vars.size() && !vars[
next]->Bound()) {
1179 for (int64_t i = vars.size() - 1; i >= 0; --i) {
1180 if (!vars[i]->Bound()) {
1181 bool has_possible_prev =
false;
1182 for (int64_t j = 0; j < vars.size(); ++j) {
1183 if (vars[j]->Contains(i)) {
1184 has_possible_prev =
true;
1188 if (!has_possible_prev) {
1195 for (int64_t i = 0;
i < vars.size(); ++
i) {
1196 if (!vars[i]->Bound()) {
1206int64_t SelectMinValue(
const IntVar* v, int64_t) {
return v->Min(); }
1210int64_t SelectMaxValue(
const IntVar* v, int64_t) {
return v->Max(); }
1214int64_t SelectRandomValue(
const IntVar* v, int64_t) {
1215 const uint64_t span = v->Max() - v->Min() + 1;
1216 if (span > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {
1220 const uint64_t
size = v->Size();
1221 Solver*
const s = v->solver();
1222 if (
size > span / 4) {
1225 const int64_t
value = v->Min() + s->Rand64(span);
1226 if (v->Contains(
value)) {
1233 for (int64_t i = v->Min(); i <= v->Max(); ++
i) {
1234 if (v->Contains(i)) {
1242 for (int64_t i = v->Max(); i > v->Min(); --i) {
1243 if (v->Contains(i)) {
1257int64_t SelectCenterValue(
const IntVar* v, int64_t) {
1258 const int64_t vmin = v->Min();
1259 const int64_t vmax = v->Max();
1260 if (vmax - vmin > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {
1264 const int64_t mid = (vmin + vmax) / 2;
1265 if (v->Contains(mid)) {
1268 const int64_t diameter = vmax - mid;
1269 for (int64_t i = 1;
i <= diameter; ++
i) {
1270 if (v->Contains(mid - i)) {
1273 if (v->Contains(mid + i)) {
1282int64_t SelectSplitValue(
const IntVar* v, int64_t) {
1283 const int64_t vmin = v->Min();
1284 const int64_t vmax = v->Max();
1285 const uint64_t
delta = vmax - vmin;
1286 const int64_t mid = vmin +
delta / 2;
1292class CheapestValueSelector :
public BaseObject {
1294 CheapestValueSelector(std::function<int64_t(int64_t, int64_t)> eval,
1295 std::function<int64_t(int64_t)> tie_breaker)
1296 : eval_(
std::move(eval)), tie_breaker_(
std::move(tie_breaker)) {}
1297 ~CheapestValueSelector()
override {}
1298 int64_t Select(
const IntVar* v, int64_t
id);
1299 std::string DebugString()
const override {
return "CheapestValue"; }
1302 std::function<int64_t(int64_t, int64_t)> eval_;
1303 std::function<int64_t(int64_t)> tie_breaker_;
1304 std::vector<int64_t> cache_;
1307int64_t CheapestValueSelector::Select(
const IntVar* v, int64_t
id) {
1309 int64_t best = std::numeric_limits<int64_t>::max();
1310 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(
false));
1311 for (
const int64_t i : InitAndGetValues(it.get())) {
1312 int64_t eval = eval_(
id, i);
1316 cache_.push_back(i);
1317 }
else if (eval == best) {
1318 cache_.push_back(i);
1321 DCHECK_GT(cache_.size(), 0);
1322 if (tie_breaker_ ==
nullptr || cache_.size() == 1) {
1323 return cache_.back();
1325 return cache_[tie_breaker_(cache_.size())];
1337class BestValueByComparisonSelector :
public BaseObject {
1339 explicit BestValueByComparisonSelector(
1340 Solver::VariableValueComparator comparator)
1341 : comparator_(
std::move(comparator)) {}
1342 ~BestValueByComparisonSelector()
override {}
1343 int64_t Select(
const IntVar* v, int64_t
id);
1344 std::string DebugString()
const override {
1345 return "BestValueByComparisonSelector";
1349 Solver::VariableValueComparator comparator_;
1352int64_t BestValueByComparisonSelector::Select(
const IntVar* v, int64_t
id) {
1353 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(
false));
1356 int64_t best_value = it->Value();
1357 for (it->Next(); it->Ok(); it->Next()) {
1358 const int64_t candidate_value = it->Value();
1359 if (comparator_(
id, candidate_value, best_value)) {
1360 best_value = candidate_value;
1368class VariableAssignmentSelector :
public BaseVariableAssignmentSelector {
1370 VariableAssignmentSelector(Solver* solver,
const std::vector<IntVar*>& vars,
1371 Solver::VariableIndexSelector var_selector,
1372 Solver::VariableValueSelector value_selector,
1373 const std::string&
name)
1374 : BaseVariableAssignmentSelector(solver, vars),
1375 var_selector_(
std::move(var_selector)),
1376 value_selector_(
std::move(value_selector)),
1378 ~VariableAssignmentSelector()
override {}
1379 int64_t SelectValue(
const IntVar*
var, int64_t
id)
override {
1380 return value_selector_(
var,
id);
1382 int64_t ChooseVariable()
override {
1386 std::string DebugString()
const override;
1389 Solver::VariableIndexSelector var_selector_;
1390 Solver::VariableValueSelector value_selector_;
1391 const std::string name_;
1394std::string VariableAssignmentSelector::DebugString()
const {
1400class BaseEvaluatorSelector :
public BaseVariableAssignmentSelector {
1402 BaseEvaluatorSelector(Solver* solver,
const std::vector<IntVar*>& vars,
1403 std::function<int64_t(int64_t, int64_t)> evaluator);
1404 ~BaseEvaluatorSelector()
override {}
1409 Element(int64_t i, int64_t j) :
var(
i),
value(j) {}
1414 std::string DebugStringInternal(absl::string_view
name)
const {
1418 std::function<int64_t(int64_t, int64_t)> evaluator_;
1421BaseEvaluatorSelector::BaseEvaluatorSelector(
1422 Solver* solver,
const std::vector<IntVar*>& vars,
1423 std::function<int64_t(int64_t, int64_t)> evaluator)
1424 : BaseVariableAssignmentSelector(solver, vars),
1425 evaluator_(
std::move(evaluator)) {}
1429class DynamicEvaluatorSelector :
public BaseEvaluatorSelector {
1431 DynamicEvaluatorSelector(Solver* solver,
const std::vector<IntVar*>& vars,
1432 std::function<int64_t(int64_t, int64_t)> evaluator,
1433 std::function<int64_t(int64_t)> tie_breaker);
1434 ~DynamicEvaluatorSelector()
override {}
1435 int64_t SelectValue(
const IntVar*
var, int64_t
id)
override;
1436 int64_t ChooseVariable()
override;
1437 std::string DebugString()
const override;
1441 std::function<int64_t(int64_t)> tie_breaker_;
1442 std::vector<Element> cache_;
1445DynamicEvaluatorSelector::DynamicEvaluatorSelector(
1446 Solver* solver,
const std::vector<IntVar*>& vars,
1447 std::function<int64_t(int64_t, int64_t)> evaluator,
1448 std::function<int64_t(int64_t)> tie_breaker)
1449 : BaseEvaluatorSelector(solver, vars,
std::move(evaluator)),
1451 tie_breaker_(
std::move(tie_breaker)) {}
1453int64_t DynamicEvaluatorSelector::SelectValue(
const IntVar*, int64_t) {
1454 return cache_[first_].value;
1457int64_t DynamicEvaluatorSelector::ChooseVariable() {
1458 int64_t best_evaluation = std::numeric_limits<int64_t>::max();
1460 for (int64_t i = 0;
i <
vars_.size(); ++
i) {
1462 if (!
var->Bound()) {
1463 std::unique_ptr<IntVarIterator> it(
var->MakeDomainIterator(
false));
1464 for (
const int64_t j : InitAndGetValues(it.get())) {
1466 if (
value < best_evaluation) {
1467 best_evaluation =
value;
1469 cache_.push_back(Element(i, j));
1470 }
else if (
value == best_evaluation && tie_breaker_) {
1471 cache_.push_back(Element(i, j));
1477 if (cache_.empty()) {
1481 if (tie_breaker_ ==
nullptr || cache_.size() == 1) {
1483 return cache_.front().var;
1485 first_ = tie_breaker_(cache_.size());
1486 return cache_[first_].var;
1490std::string DynamicEvaluatorSelector::DebugString()
const {
1491 return DebugStringInternal(
"AssignVariablesOnDynamicEvaluator");
1496class StaticEvaluatorSelector :
public BaseEvaluatorSelector {
1498 StaticEvaluatorSelector(
1499 Solver* solver,
const std::vector<IntVar*>& vars,
1500 const std::function<int64_t(int64_t, int64_t)>& evaluator);
1501 ~StaticEvaluatorSelector()
override {}
1502 int64_t SelectValue(
const IntVar*
var, int64_t
id)
override;
1503 int64_t ChooseVariable()
override;
1504 std::string DebugString()
const override;
1509 explicit Compare(std::function<int64_t(int64_t, int64_t)> evaluator)
1510 : evaluator_(
std::move(evaluator)) {}
1511 bool operator()(
const Element& lhs,
const Element& rhs)
const {
1512 const int64_t value_lhs =
Value(lhs);
1513 const int64_t value_rhs =
Value(rhs);
1514 return value_lhs < value_rhs ||
1515 (value_lhs == value_rhs &&
1516 (lhs.var < rhs.var ||
1517 (lhs.var == rhs.var && lhs.value < rhs.value)));
1519 int64_t
Value(
const Element& element)
const {
1520 return evaluator_(element.var, element.value);
1524 std::function<int64_t(int64_t, int64_t)> evaluator_;
1528 std::vector<Element> elements_;
1532StaticEvaluatorSelector::StaticEvaluatorSelector(
1533 Solver* solver,
const std::vector<IntVar*>& vars,
1534 const std::function<int64_t(int64_t, int64_t)>& evaluator)
1535 : BaseEvaluatorSelector(solver, vars, evaluator),
1539int64_t StaticEvaluatorSelector::SelectValue(
const IntVar*, int64_t) {
1540 return elements_[first_].value;
1543int64_t StaticEvaluatorSelector::ChooseVariable() {
1546 int64_t element_size = 0;
1547 for (int64_t i = 0;
i <
vars_.size(); ++
i) {
1548 if (!
vars_[i]->Bound()) {
1549 element_size +=
vars_[
i]->Size();
1552 elements_.resize(element_size);
1554 for (
int i = 0;
i <
vars_.size(); ++
i) {
1556 if (!
var->Bound()) {
1557 std::unique_ptr<IntVarIterator> it(
var->MakeDomainIterator(
false));
1558 for (
const int64_t
value : InitAndGetValues(it.get())) {
1559 elements_[count++] = Element(i,
value);
1564 std::sort(elements_.begin(), elements_.end(), comp_);
1565 solver_->SaveAndSetValue<int64_t>(&first_, 0);
1567 for (int64_t i = first_;
i < elements_.size(); ++
i) {
1568 const Element& element = elements_[
i];
1569 IntVar*
const var =
vars_[element.var];
1570 if (!
var->Bound() &&
var->Contains(element.value)) {
1571 solver_->SaveAndSetValue(&first_, i);
1575 solver_->SaveAndSetValue(&first_,
static_cast<int64_t
>(elements_.size()));
1579std::string StaticEvaluatorSelector::DebugString()
const {
1580 return DebugStringInternal(
"AssignVariablesOnStaticEvaluator");
1585class AssignOneVariableValue :
public Decision {
1587 AssignOneVariableValue(IntVar* v, int64_t val);
1588 ~AssignOneVariableValue()
override {}
1589 void Apply(Solver* s)
override;
1590 void Refute(Solver* s)
override;
1591 std::string DebugString()
const override;
1592 void Accept(DecisionVisitor*
const visitor)
const override {
1593 visitor->VisitSetVariableValue(var_, value_);
1601AssignOneVariableValue::AssignOneVariableValue(IntVar*
const v, int64_t val)
1602 : var_(v), value_(val) {}
1604std::string AssignOneVariableValue::DebugString()
const {
1605 return absl::StrFormat(
"[%s == %d] or [%s != %d]", var_->DebugString(),
1606 value_, var_->DebugString(), value_);
1609void AssignOneVariableValue::Apply(Solver*
const) { var_->SetValue(value_); }
1611void AssignOneVariableValue::Refute(Solver*
const) {
1612 var_->RemoveValue(value_);
1617 return RevAlloc(
new AssignOneVariableValue(
var, val));
1623class AssignOneVariableValueOrFail :
public Decision {
1625 AssignOneVariableValueOrFail(
IntVar* v, int64_t
value);
1626 ~AssignOneVariableValueOrFail()
override {}
1627 void Apply(Solver* s)
override;
1628 void Refute(Solver* s)
override;
1629 std::string DebugString()
const override;
1630 void Accept(DecisionVisitor*
const visitor)
const override {
1631 visitor->VisitSetVariableValue(var_, value_);
1636 const int64_t value_;
1639AssignOneVariableValueOrFail::AssignOneVariableValueOrFail(IntVar*
const v,
1641 : var_(v), value_(
value) {}
1643std::string AssignOneVariableValueOrFail::DebugString()
const {
1644 return absl::StrFormat(
"[%s == %d] or fail", var_->
DebugString(), value_);
1647void AssignOneVariableValueOrFail::Apply(Solver*
const) {
1651void AssignOneVariableValueOrFail::Refute(Solver*
const s) { s->Fail(); }
1656 return RevAlloc(
new AssignOneVariableValueOrFail(
var,
value));
1662class AssignOneVariableValueDoNothing :
public Decision {
1664 AssignOneVariableValueDoNothing(
IntVar*
const v, int64_t
value)
1665 : var_(v), value_(
value) {}
1666 ~AssignOneVariableValueDoNothing()
override {}
1667 void Apply(Solver*
const)
override { var_->
SetValue(value_); }
1668 void Refute(Solver*
const)
override {}
1669 std::string DebugString()
const override {
1670 return absl::StrFormat(
"[%s == %d] or []", var_->
DebugString(), value_);
1672 void Accept(DecisionVisitor*
const visitor)
const override {
1673 visitor->VisitSetVariableValue(var_, value_);
1678 const int64_t value_;
1685 return RevAlloc(
new AssignOneVariableValueDoNothing(
var,
value));
1691class SplitOneVariable :
public Decision {
1693 SplitOneVariable(
IntVar* v, int64_t val,
bool start_with_lower_half);
1694 ~SplitOneVariable()
override {}
1695 void Apply(Solver* s)
override;
1696 void Refute(Solver* s)
override;
1697 std::string DebugString()
const override;
1698 void Accept(DecisionVisitor*
const visitor)
const override {
1699 visitor->VisitSplitVariableDomain(var_, value_, start_with_lower_half_);
1704 const int64_t value_;
1705 const bool start_with_lower_half_;
1708SplitOneVariable::SplitOneVariable(IntVar*
const v, int64_t val,
1709 bool start_with_lower_half)
1710 : var_(v), value_(val), start_with_lower_half_(start_with_lower_half) {}
1712std::string SplitOneVariable::DebugString()
const {
1713 if (start_with_lower_half_) {
1714 return absl::StrFormat(
"[%s <= %d]", var_->
DebugString(), value_);
1716 return absl::StrFormat(
"[%s >= %d]", var_->
DebugString(), value_);
1720void SplitOneVariable::Apply(Solver*
const) {
1721 if (start_with_lower_half_) {
1724 var_->
SetMin(value_ + 1);
1728void SplitOneVariable::Refute(Solver*
const) {
1729 if (start_with_lower_half_) {
1730 var_->
SetMin(value_ + 1);
1738 bool start_with_lower_half) {
1739 return RevAlloc(
new SplitOneVariable(
var, val, start_with_lower_half));
1744 return MakeSplitVariableDomain(
var,
value,
true);
1749 return MakeSplitVariableDomain(
var,
value,
false);
1755class AssignVariablesValues :
public Decision {
1761 enum class RefutationBehavior { kForbidAssignment, kDoNothing, kFail };
1762 AssignVariablesValues(
1763 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values,
1764 RefutationBehavior refutation = RefutationBehavior::kForbidAssignment);
1765 ~AssignVariablesValues()
override {}
1766 void Apply(Solver* s)
override;
1767 void Refute(Solver* s)
override;
1768 std::string DebugString()
const override;
1769 void Accept(DecisionVisitor*
const visitor)
const override {
1770 for (
int i = 0;
i <
vars_.size(); ++
i) {
1771 visitor->VisitSetVariableValue(
vars_[i], values_[i]);
1775 virtual void Accept(ModelVisitor*
const visitor)
const {
1776 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
1777 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1779 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
1783 const std::vector<IntVar*>
vars_;
1784 const std::vector<int64_t> values_;
1785 const RefutationBehavior refutation_;
1788AssignVariablesValues::AssignVariablesValues(
const std::vector<IntVar*>& vars,
1789 const std::vector<int64_t>& values,
1790 RefutationBehavior refutation)
1791 :
vars_(vars), values_(values), refutation_(refutation) {}
1793std::string AssignVariablesValues::DebugString()
const {
1795 if (
vars_.empty()) out +=
"do nothing";
1796 for (
int i = 0;
i <
vars_.size(); ++
i) {
1797 absl::StrAppendFormat(&out,
"[%s == %d]",
vars_[i]->DebugString(),
1800 switch (refutation_) {
1801 case RefutationBehavior::kForbidAssignment:
1802 out +=
" or forbid assignment";
1804 case RefutationBehavior::kDoNothing:
1805 out +=
" or do nothing";
1807 case RefutationBehavior::kFail:
1814void AssignVariablesValues::Apply(Solver*
const) {
1815 if (
vars_.empty())
return;
1816 vars_[0]->FreezeQueue();
1817 for (
int i = 0;
i <
vars_.size(); ++
i) {
1818 vars_[
i]->SetValue(values_[i]);
1820 vars_[0]->UnfreezeQueue();
1823void AssignVariablesValues::Refute(Solver*
const s) {
1824 switch (refutation_) {
1825 case RefutationBehavior::kForbidAssignment: {
1826 std::vector<IntVar*> terms;
1827 for (
int i = 0;
i <
vars_.size(); ++
i) {
1828 IntVar* term = s->MakeBoolVar();
1829 s->AddConstraint(s->MakeIsDifferentCstCt(
vars_[i], values_[i], term));
1830 terms.push_back(term);
1832 s->AddConstraint(s->MakeSumGreaterOrEqual(terms, 1));
1835 case RefutationBehavior::kDoNothing: {
1838 case RefutationBehavior::kFail: {
1847 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1848 CHECK_EQ(vars.size(), values.size());
1849 return RevAlloc(
new AssignVariablesValues(
1851 AssignVariablesValues::RefutationBehavior::kForbidAssignment));
1855 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1856 CHECK_EQ(vars.size(), values.size());
1857 return RevAlloc(
new AssignVariablesValues(
1858 vars, values, AssignVariablesValues::RefutationBehavior::kDoNothing));
1862 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1863 CHECK_EQ(vars.size(), values.size());
1864 return RevAlloc(
new AssignVariablesValues(
1865 vars, values, AssignVariablesValues::RefutationBehavior::kFail));
1879 BaseAssignVariables(BaseVariableAssignmentSelector*
const selector, Mode mode)
1880 : selector_(selector),
mode_(mode) {}
1882 ~BaseAssignVariables()
override;
1883 Decision*
Next(Solver* s)
override;
1884 std::string DebugString()
const override;
1885 static BaseAssignVariables* MakePhase(
1886 Solver* s,
const std::vector<IntVar*>& vars,
1887 Solver::VariableIndexSelector var_selector,
1888 Solver::VariableValueSelector value_selector,
1889 const std::string& value_selector_name, BaseAssignVariables::Mode mode);
1891 static Solver::VariableIndexSelector MakeVariableSelector(
1892 Solver*
const s,
const std::vector<IntVar*>& vars,
1893 Solver::IntVarStrategy str) {
1895 case Solver::INT_VAR_DEFAULT:
1896 case Solver::INT_VAR_SIMPLE:
1897 case Solver::CHOOSE_FIRST_UNBOUND:
1898 return ChooseFirstUnbound;
1899 case Solver::CHOOSE_RANDOM:
1900 return ChooseRandom;
1901 case Solver::CHOOSE_MIN_SIZE_LOWEST_MIN:
1902 return ChooseMinSizeLowestMin;
1903 case Solver::CHOOSE_MIN_SIZE_HIGHEST_MIN:
1904 return ChooseMinSizeHighestMin;
1905 case Solver::CHOOSE_MIN_SIZE_LOWEST_MAX:
1906 return ChooseMinSizeLowestMax;
1907 case Solver::CHOOSE_MIN_SIZE_HIGHEST_MAX:
1908 return ChooseMinSizeHighestMax;
1909 case Solver::CHOOSE_LOWEST_MIN:
1910 return ChooseLowestMin;
1911 case Solver::CHOOSE_HIGHEST_MAX:
1912 return ChooseHighestMax;
1913 case Solver::CHOOSE_MIN_SIZE:
1914 return ChooseMinSize;
1915 case Solver::CHOOSE_MAX_SIZE:
1916 return ChooseMaxSize;
1917 case Solver::CHOOSE_MAX_REGRET_ON_MIN: {
1918 HighestRegretSelectorOnMin*
const selector =
1919 s->RevAlloc(
new HighestRegretSelectorOnMin(vars));
1920 return [selector](Solver* solver,
const std::vector<IntVar*>& vars,
1921 int first_unbound,
int last_unbound) {
1922 return selector->Choose(solver, vars, first_unbound, last_unbound);
1925 case Solver::CHOOSE_PATH: {
1926 PathSelector*
const selector = s->RevAlloc(
new PathSelector());
1927 return [selector](Solver* solver,
const std::vector<IntVar*>& vars, int,
1928 int) {
return selector->Choose(solver, vars); };
1931 LOG(FATAL) <<
"Unknown int var strategy " << str;
1936 static Solver::VariableValueSelector MakeValueSelector(
1937 Solver*
const, Solver::IntValueStrategy val_str) {
1939 case Solver::INT_VALUE_DEFAULT:
1940 case Solver::INT_VALUE_SIMPLE:
1941 case Solver::ASSIGN_MIN_VALUE:
1942 return SelectMinValue;
1943 case Solver::ASSIGN_MAX_VALUE:
1944 return SelectMaxValue;
1945 case Solver::ASSIGN_RANDOM_VALUE:
1946 return SelectRandomValue;
1947 case Solver::ASSIGN_CENTER_VALUE:
1948 return SelectCenterValue;
1949 case Solver::SPLIT_LOWER_HALF:
1950 return SelectSplitValue;
1951 case Solver::SPLIT_UPPER_HALF:
1952 return SelectSplitValue;
1954 LOG(FATAL) <<
"Unknown int value strategy " << val_str;
1959 void Accept(ModelVisitor*
const visitor)
const override {
1960 selector_->Accept(visitor);
1964 BaseVariableAssignmentSelector*
const selector_;
1968BaseAssignVariables::~BaseAssignVariables() {}
1970Decision* BaseAssignVariables::Next(Solver*
const s) {
1971 const std::vector<IntVar*>& vars = selector_->vars();
1972 int id = selector_->ChooseVariableWrapper();
1973 if (
id >= 0 &&
id < vars.size()) {
1974 IntVar*
const var = vars[id];
1975 const int64_t
value = selector_->SelectValue(
var,
id);
1978 return s->RevAlloc(
new AssignOneVariableValue(
var,
value));
1980 return s->RevAlloc(
new SplitOneVariable(
var,
value,
true));
1982 return s->RevAlloc(
new SplitOneVariable(
var,
value,
false));
1988std::string BaseAssignVariables::DebugString()
const {
1989 return selector_->DebugString();
1992BaseAssignVariables* BaseAssignVariables::MakePhase(
1993 Solver*
const s,
const std::vector<IntVar*>& vars,
1996 const std::string& value_selector_name, BaseAssignVariables::Mode mode) {
1997 BaseVariableAssignmentSelector*
const selector =
1998 s->RevAlloc(
new VariableAssignmentSelector(
1999 s, vars, std::move(var_selector), std::move(value_selector),
2000 value_selector_name));
2001 return s->RevAlloc(
new BaseAssignVariables(selector, mode));
2009 return "ChooseFirstUnbound";
2011 return "ChooseRandom";
2013 return "ChooseMinSizeLowestMin";
2015 return "ChooseMinSizeHighestMin";
2017 return "ChooseMinSizeLowestMax";
2019 return "ChooseMinSizeHighestMax";
2021 return "ChooseLowestMin";
2023 return "ChooseHighestMax";
2025 return "ChooseMinSize";
2027 return "ChooseMaxSize;";
2029 return "HighestRegretSelectorOnMin";
2031 return "PathSelector";
2033 LOG(FATAL) <<
"Unknown int var strategy " << var_str;
2043 return "SelectMinValue";
2045 return "SelectMaxValue";
2047 return "SelectRandomValue";
2049 return "SelectCenterValue";
2051 return "SelectSplitValue";
2053 return "SelectSplitValue";
2055 LOG(FATAL) <<
"Unknown int value strategy " << val_str;
2062 return ChooseVariableName(var_str) +
"_" + SelectValueName(val_str);
2069 std::vector<IntVar*> vars(1);
2071 return MakePhase(vars, var_str, val_str);
2077 std::vector<IntVar*> vars(2);
2080 return MakePhase(vars, var_str, val_str);
2087 std::vector<IntVar*> vars(3);
2091 return MakePhase(vars, var_str, val_str);
2098 std::vector<IntVar*> vars(4);
2103 return MakePhase(vars, var_str, val_str);
2107 BaseAssignVariables::Mode mode = BaseAssignVariables::ASSIGN;
2109 mode = BaseAssignVariables::SPLIT_LOWER;
2111 mode = BaseAssignVariables::SPLIT_UPPER;
2120 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2122 BaseAssignVariables::MakeValueSelector(
this, val_str);
2123 const std::string
name = BuildHeuristicsName(var_str, val_str);
2124 return BaseAssignVariables::MakePhase(
2125 this, vars, var_selector, value_selector,
name,
ChooseMode(val_str));
2131 CHECK(var_evaluator !=
nullptr);
2132 CheapestVarSelector*
const var_selector =
2133 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2135 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2136 int first_unbound,
int last_unbound) {
2137 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2140 BaseAssignVariables::MakeValueSelector(
this, val_str);
2141 const std::string
name =
"ChooseCheapestVariable_" + SelectValueName(val_str);
2142 return BaseAssignVariables::MakePhase(
2143 this, vars, choose_variable, select_value,
name,
ChooseMode(val_str));
2150 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2151 CheapestValueSelector*
const value_selector =
2152 RevAlloc(
new CheapestValueSelector(std::move(value_evaluator),
nullptr));
2154 [value_selector](
const IntVar*
var, int64_t id) {
2155 return value_selector->Select(
var,
id);
2157 const std::string
name = ChooseVariableName(var_str) +
"_SelectCheapestValue";
2158 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2160 BaseAssignVariables::ASSIGN);
2167 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2168 BestValueByComparisonSelector*
const value_selector = RevAlloc(
2169 new BestValueByComparisonSelector(std::move(var_val1_val2_comparator)));
2171 [value_selector](
const IntVar*
var, int64_t id) {
2172 return value_selector->Select(
var,
id);
2174 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2175 select_value,
"CheapestValue",
2176 BaseAssignVariables::ASSIGN);
2182 CheapestVarSelector*
const var_selector =
2183 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2185 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2186 int first_unbound,
int last_unbound) {
2187 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2189 CheapestValueSelector* value_selector =
2190 RevAlloc(
new CheapestValueSelector(std::move(value_evaluator),
nullptr));
2192 [value_selector](
const IntVar*
var, int64_t id) {
2193 return value_selector->Select(
var,
id);
2195 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2196 select_value,
"CheapestValue",
2197 BaseAssignVariables::ASSIGN);
2205 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2206 CheapestValueSelector* value_selector = RevAlloc(
new CheapestValueSelector(
2207 std::move(value_evaluator), std::move(tie_breaker)));
2209 [value_selector](
const IntVar*
var, int64_t id) {
2210 return value_selector->Select(
var,
id);
2212 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2213 select_value,
"CheapestValue",
2214 BaseAssignVariables::ASSIGN);
2221 CheapestVarSelector*
const var_selector =
2222 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2224 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2225 int first_unbound,
int last_unbound) {
2226 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2228 CheapestValueSelector* value_selector = RevAlloc(
new CheapestValueSelector(
2229 std::move(value_evaluator), std::move(tie_breaker)));
2231 [value_selector](
const IntVar*
var, int64_t id) {
2232 return value_selector->Select(
var,
id);
2234 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2235 select_value,
"CheapestValue",
2236 BaseAssignVariables::ASSIGN);
2242 return MakePhase(vars, std::move(eval),
nullptr, str);
2249 BaseVariableAssignmentSelector* selector =
nullptr;
2253 selector = RevAlloc(
new StaticEvaluatorSelector(
this, vars, eval));
2257 selector = RevAlloc(
new DynamicEvaluatorSelector(
this, vars, eval,
2258 std::move(tie_breaker)));
2263 new BaseAssignVariables(selector, BaseAssignVariables::ASSIGN));
2271 AssignVariablesFromAssignment(
const Assignment*
const assignment,
2273 const std::vector<IntVar*>& vars)
2274 : assignment_(assignment), db_(db),
vars_(vars), iter_(0) {}
2276 ~AssignVariablesFromAssignment()
override {}
2278 Decision*
Next(Solver*
const s)
override {
2279 if (iter_ <
vars_.size()) {
2280 IntVar*
const var =
vars_[iter_++];
2282 new AssignOneVariableValue(
var, assignment_->
Value(
var)));
2284 return db_->
Next(s);
2288 void Accept(ModelVisitor*
const visitor)
const override {
2289 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
2290 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2292 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
2296 const Assignment*
const assignment_;
2297 DecisionBuilder*
const db_;
2298 const std::vector<IntVar*>
vars_;
2305 const std::vector<IntVar*>& vars) {
2306 return RevAlloc(
new AssignVariablesFromAssignment(assignment, db, vars));
2316 prototype_(assignment == nullptr ? nullptr : new
Assignment(assignment)) {
2336 const auto other_fields =
2338 if (fields != other_fields)
return fields < other_fields;
2340 DCHECK_EQ(other.
solution,
nullptr);
2343 for (
int i = 0; i <
solution->NumObjectives(); ++i) {
2346 if (
value != other_value)
return value < other_value;
2392 if (
prototype_ !=
nullptr && objective !=
nullptr) {
2448 CHECK_GE(n, 0) <<
"wrong index in solution getter";
2449 CHECK_LT(n,
solution_data_.size()) <<
"wrong index in solution getter";
2532 explicit FirstSolutionCollector(
Solver* s);
2533 ~FirstSolutionCollector()
override;
2534 void EnterSearch()
override;
2535 bool AtSolution()
override;
2536 void Install()
override;
2537 std::string DebugString()
const override;
2543FirstSolutionCollector::FirstSolutionCollector(Solver*
const s,
2544 const Assignment*
const a)
2547FirstSolutionCollector::FirstSolutionCollector(Solver*
const s)
2548 : SolutionCollector(s), done_(
false) {}
2550FirstSolutionCollector::~FirstSolutionCollector() {}
2552void FirstSolutionCollector::EnterSearch() {
2553 SolutionCollector::EnterSearch();
2557bool FirstSolutionCollector::AtSolution() {
2565void FirstSolutionCollector::Install() {
2566 SolutionCollector::Install();
2567 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2570std::string FirstSolutionCollector::DebugString()
const {
2571 if (prototype_ ==
nullptr) {
2572 return "FirstSolutionCollector()";
2574 return "FirstSolutionCollector(" + prototype_->DebugString() +
")";
2581 return RevAlloc(
new FirstSolutionCollector(
this, assignment));
2585 return RevAlloc(
new FirstSolutionCollector(
this));
2595 explicit LastSolutionCollector(
Solver* s);
2596 ~LastSolutionCollector()
override;
2597 bool AtSolution()
override;
2598 void Install()
override;
2599 std::string DebugString()
const override;
2602LastSolutionCollector::LastSolutionCollector(Solver*
const s,
2603 const Assignment*
const a)
2604 : SolutionCollector(s,
a) {}
2606LastSolutionCollector::LastSolutionCollector(Solver*
const s)
2607 : SolutionCollector(s) {}
2609LastSolutionCollector::~LastSolutionCollector() {}
2611bool LastSolutionCollector::AtSolution() {
2617void LastSolutionCollector::Install() {
2618 SolutionCollector::Install();
2619 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2622std::string LastSolutionCollector::DebugString()
const {
2623 if (prototype_ ==
nullptr) {
2624 return "LastSolutionCollector()";
2626 return "LastSolutionCollector(" + prototype_->DebugString() +
")";
2633 return RevAlloc(
new LastSolutionCollector(
this, assignment));
2637 return RevAlloc(
new LastSolutionCollector(
this));
2646 std::vector<bool> maximize);
2647 BestValueSolutionCollector(
Solver* solver, std::vector<bool> maximize);
2648 ~BestValueSolutionCollector()
override {}
2649 void EnterSearch()
override;
2650 bool AtSolution()
override;
2651 void Install()
override;
2652 std::string DebugString()
const override;
2655 void ResetBestObjective() {
2656 for (
int i = 0; i < maximize_.size(); ++i) {
2657 best_[i] = maximize_[i] ? std::numeric_limits<int64_t>::min()
2658 :
std::numeric_limits<int64_t>::
max();
2662 const std::vector<bool> maximize_;
2663 std::vector<int64_t> best_;
2666BestValueSolutionCollector::BestValueSolutionCollector(
2667 Solver* solver,
const Assignment* assignment, std::vector<bool> maximize)
2668 : SolutionCollector(solver, assignment),
2669 maximize_(
std::move(maximize)),
2670 best_(maximize_.
size()) {
2671 ResetBestObjective();
2674BestValueSolutionCollector::BestValueSolutionCollector(
2675 Solver* solver, std::vector<bool> maximize)
2676 : SolutionCollector(solver),
2677 maximize_(
std::move(maximize)),
2678 best_(maximize_.
size()) {
2679 ResetBestObjective();
2682void BestValueSolutionCollector::EnterSearch() {
2683 SolutionCollector::EnterSearch();
2684 ResetBestObjective();
2687bool BestValueSolutionCollector::AtSolution() {
2688 if (prototype_ !=
nullptr && prototype_->HasObjective()) {
2689 const int size = std::min(prototype_->NumObjectives(),
2690 static_cast<int>(maximize_.size()));
2693 bool is_improvement =
false;
2694 for (
int i = 0;
i <
size; ++
i) {
2695 const IntVar* objective = prototype_->ObjectiveFromIndex(i);
2697 maximize_[
i] ?
CapOpp(objective->Max()) : objective->Min();
2699 is_improvement =
true;
2705 if (solution_count() == 0 || is_improvement) {
2708 for (
int i = 0;
i <
size; ++
i) {
2709 best_[
i] = maximize_[
i]
2710 ?
CapOpp(prototype_->ObjectiveFromIndex(i)->Max())
2711 : prototype_->ObjectiveFromIndex(
i)->Min();
2718void BestValueSolutionCollector::Install() {
2719 SolutionCollector::Install();
2720 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2723std::string BestValueSolutionCollector::DebugString()
const {
2724 if (prototype_ ==
nullptr) {
2725 return "BestValueSolutionCollector()";
2727 return "BestValueSolutionCollector(" + prototype_->DebugString() +
")";
2733 const Assignment*
const assignment,
bool maximize) {
2734 return RevAlloc(
new BestValueSolutionCollector(
this, assignment, {maximize}));
2738 const Assignment* assignment, std::vector<bool> maximize) {
2740 new BestValueSolutionCollector(
this, assignment, std::move(maximize)));
2744 return RevAlloc(
new BestValueSolutionCollector(
this, {maximize}));
2748 std::vector<bool> maximize) {
2749 return RevAlloc(
new BestValueSolutionCollector(
this, std::move(maximize)));
2758 int solution_count, std::vector<bool> maximize);
2759 NBestValueSolutionCollector(
Solver* solver,
int solution_count,
2760 std::vector<bool> maximize);
2761 ~NBestValueSolutionCollector()
override { Clear(); }
2762 void EnterSearch()
override;
2763 void ExitSearch()
override;
2764 bool AtSolution()
override;
2765 void Install()
override;
2766 std::string DebugString()
const override;
2771 const std::vector<bool> maximize_;
2772 std::priority_queue<std::pair<std::vector<int64_t>, SolutionData>>
2774 const int solution_count_;
2777NBestValueSolutionCollector::NBestValueSolutionCollector(
2778 Solver* solver,
const Assignment* assignment,
int solution_count,
2779 std::vector<bool> maximize)
2780 : SolutionCollector(solver, assignment),
2781 maximize_(
std::move(maximize)),
2782 solution_count_(solution_count) {}
2784NBestValueSolutionCollector::NBestValueSolutionCollector(
2785 Solver* solver,
int solution_count, std::vector<bool> maximize)
2786 : SolutionCollector(solver),
2787 maximize_(
std::move(maximize)),
2788 solution_count_(solution_count) {}
2790void NBestValueSolutionCollector::EnterSearch() {
2791 SolutionCollector::EnterSearch();
2794 if (solution_count_ > 1) {
2795 solver()->SetUseFastLocalSearch(
false);
2800void NBestValueSolutionCollector::ExitSearch() {
2801 while (!solutions_pq_.empty()) {
2802 Push(solutions_pq_.top().second);
2803 solutions_pq_.pop();
2807bool NBestValueSolutionCollector::AtSolution() {
2808 if (prototype_ !=
nullptr && prototype_->HasObjective()) {
2809 const int size = std::min(prototype_->NumObjectives(),
2810 static_cast<int>(maximize_.size()));
2811 std::vector<int64_t> objective_values(
size);
2812 for (
int i = 0;
i <
size; ++
i) {
2813 objective_values[
i] =
2814 maximize_[
i] ?
CapOpp(prototype_->ObjectiveFromIndex(i)->Max())
2815 : prototype_->ObjectiveFromIndex(
i)->Min();
2817 if (solutions_pq_.size() < solution_count_) {
2819 {std::move(objective_values), BuildSolutionDataForCurrentState()});
2820 }
else if (!solutions_pq_.empty()) {
2821 const auto& [top_obj_value, top_sol_data] = solutions_pq_.top();
2822 if (std::lexicographical_compare(
2823 objective_values.begin(), objective_values.end(),
2824 top_obj_value.begin(), top_obj_value.end())) {
2825 FreeSolution(top_sol_data.solution);
2826 solutions_pq_.pop();
2828 {std::move(objective_values), BuildSolutionDataForCurrentState()});
2835void NBestValueSolutionCollector::Install() {
2836 SolutionCollector::Install();
2837 ListenToEvent(Solver::MonitorEvent::kExitSearch);
2838 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2841std::string NBestValueSolutionCollector::DebugString()
const {
2842 if (prototype_ ==
nullptr) {
2843 return "NBestValueSolutionCollector()";
2845 return "NBestValueSolutionCollector(" + prototype_->DebugString() +
")";
2849void NBestValueSolutionCollector::Clear() {
2850 while (!solutions_pq_.empty()) {
2851 delete solutions_pq_.top().second.solution;
2852 solutions_pq_.pop();
2859 const Assignment* assignment,
int solution_count,
bool maximize) {
2860 if (solution_count == 1) {
2861 return MakeBestValueSolutionCollector(assignment, maximize);
2863 return RevAlloc(
new NBestValueSolutionCollector(
this, assignment,
2864 solution_count, {maximize}));
2869 if (solution_count == 1) {
2870 return MakeBestValueSolutionCollector(maximize);
2873 new NBestValueSolutionCollector(
this, solution_count, {maximize}));
2877 const Assignment* assignment,
int solution_count,
2878 std::vector<bool> maximize) {
2879 if (solution_count == 1) {
2880 return MakeBestLexicographicValueSolutionCollector(assignment,
2881 std::move(maximize));
2883 return RevAlloc(
new NBestValueSolutionCollector(
2884 this, assignment, solution_count, std::move(maximize)));
2888 int solution_count, std::vector<bool> maximize) {
2889 if (solution_count == 1) {
2890 return MakeBestLexicographicValueSolutionCollector(std::move(maximize));
2892 return RevAlloc(
new NBestValueSolutionCollector(
this, solution_count,
2893 std::move(maximize)));
2902 explicit AllSolutionCollector(
Solver* s);
2903 ~AllSolutionCollector()
override;
2904 bool AtSolution()
override;
2905 void Install()
override;
2906 std::string DebugString()
const override;
2909AllSolutionCollector::AllSolutionCollector(Solver*
const s,
2910 const Assignment*
const a)
2911 : SolutionCollector(s,
a) {}
2913AllSolutionCollector::AllSolutionCollector(Solver*
const s)
2914 : SolutionCollector(s) {}
2916AllSolutionCollector::~AllSolutionCollector() {}
2918bool AllSolutionCollector::AtSolution() {
2923void AllSolutionCollector::Install() {
2924 SolutionCollector::Install();
2925 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2928std::string AllSolutionCollector::DebugString()
const {
2929 if (prototype_ ==
nullptr) {
2930 return "AllSolutionCollector()";
2932 return "AllSolutionCollector(" + prototype_->DebugString() +
")";
2939 return RevAlloc(
new AllSolutionCollector(
this, assignment));
2943 return RevAlloc(
new AllSolutionCollector(
this));
2949 const std::vector<bool>& maximize,
2950 std::vector<IntVar*> vars,
2951 std::vector<int64_t> steps)
2953 found_initial_solution_(false),
2954 objective_vars_(
std::move(vars)),
2955 minimization_vars_(objective_vars_),
2956 upper_bounds_(Size() + 1, nullptr),
2957 steps_(
std::move(steps)),
2958 best_values_(Size(),
std::numeric_limits<int64_t>::
max()),
2959 current_values_(Size(),
std::numeric_limits<int64_t>::
max()) {
2960 DCHECK_GT(
Size(), 0);
2961 DCHECK_EQ(objective_vars_.size(), steps_.size());
2962 DCHECK_EQ(objective_vars_.size(), maximize.size());
2963 DCHECK(std::all_of(steps_.begin(), steps_.end(),
2964 [](int64_t step) { return step > 0; }));
2965 for (
int i = 0; i <
Size(); ++i) {
2973 steps_.push_back(1);
2984 best_values_.assign(
Size(), std::numeric_limits<int64_t>::max());
2985 current_values_ = best_values_;
2989 for (
int i = 0; i <
Size(); ++i) {
2996 if (std::lexicographical_compare(current_values_.begin(),
2997 current_values_.end(), best_values_.begin(),
2998 best_values_.end())) {
2999 best_values_ = current_values_;
3006 if (
delta ==
nullptr)
return true;
3007 const bool delta_has_objective =
delta->HasObjective();
3008 if (!delta_has_objective) {
3013 for (
int i = 0; i <
Size(); ++i) {
3017 if (delta_has_objective) {
3018 obj_min = std::max(obj_min,
delta->ObjectiveMinFromIndex(i));
3020 if (
solver()->UseFastLocalSearch() &&
3021 i < local_search_state->NumObjectives()) {
3026 delta->SetObjectiveMinFromIndex(i, obj_min);
3029 if (delta_has_objective) {
3030 obj_max = std::min(obj_max,
delta->ObjectiveMaxFromIndex(i));
3032 if (
solver()->UseFastLocalSearch() &&
3033 i < local_search_state->NumObjectives()) {
3038 delta->SetObjectiveMaxFromIndex(i, obj_max);
3051 minimization_vars_);
3056 int num_values_at_max = 0;
3057 for (
int i = 0; i <
Size(); ++i) {
3059 DCHECK_EQ(num_values_at_max, 0);
3061 ++num_values_at_max;
3064 DCHECK(num_values_at_max == 0 || num_values_at_max ==
Size());
3065 return num_values_at_max <
Size();
3071 std::vector<IntVar*>{
var}, {step}) {}
3074 std::vector<IntVar*> vars, std::vector<int64_t> steps)
3078 if (
solver()->SearchDepth() == 0) {
3099 for (
int i = 0; i <
Size(); ++i) {
3103 if (!minimization_var->
Bound())
return true;
3104 const int64_t
value = minimization_var->
Value();
3121 for (
int i = 0; i <
Size(); ++i) {
3122 absl::StrAppendFormat(
3123 &out,
"%s%s(%s, step = %d, best = %d)", i == 0 ?
"" :
"; ",
3124 Maximize(i) ?
"MaximizeVar" :
"MinimizeVar",
3144 std::vector<IntVar*> variables,
3145 std::vector<int64_t> steps) {
3147 std::move(variables), std::move(steps)));
3153 WeightedOptimizeVar(
Solver* solver,
bool maximize,
3154 const std::vector<IntVar*>& sub_objectives,
3155 const std::vector<int64_t>& weights, int64_t step)
3157 solver->MakeScalProd(sub_objectives, weights)->Var(), step),
3158 sub_objectives_(sub_objectives),
3160 CHECK_EQ(sub_objectives.size(), weights.size());
3163 ~WeightedOptimizeVar()
override {}
3164 std::string Name()
const override;
3167 const std::vector<IntVar*> sub_objectives_;
3168 const std::vector<int64_t> weights_;
3171std::string WeightedOptimizeVar::Name()
const {
return "weighted objective"; }
3175 bool maximize,
const std::vector<IntVar*>& sub_objectives,
3176 const std::vector<int64_t>& weights, int64_t step) {
3178 new WeightedOptimizeVar(
this, maximize, sub_objectives, weights, step));
3182 const std::vector<IntVar*>& sub_objectives,
3183 const std::vector<int64_t>& weights, int64_t step) {
3185 new WeightedOptimizeVar(
this,
false, sub_objectives, weights, step));
3189 const std::vector<IntVar*>& sub_objectives,
3190 const std::vector<int64_t>& weights, int64_t step) {
3192 new WeightedOptimizeVar(
this,
true, sub_objectives, weights, step));
3196 bool maximize,
const std::vector<IntVar*>& sub_objectives,
3197 const std::vector<int>& weights, int64_t step) {
3198 return MakeWeightedOptimize(maximize, sub_objectives,
ToInt64Vector(weights),
3203 const std::vector<IntVar*>& sub_objectives,
const std::vector<int>& weights,
3205 return MakeWeightedMinimize(sub_objectives,
ToInt64Vector(weights), step);
3209 const std::vector<IntVar*>& sub_objectives,
const std::vector<int>& weights,
3211 return MakeWeightedMaximize(sub_objectives,
ToInt64Vector(weights), step);
3219 Metaheuristic(
Solver* solver,
const std::vector<bool>& maximize,
3220 std::vector<IntVar*> objectives, std::vector<int64_t> steps);
3221 ~Metaheuristic()
override {}
3223 void EnterSearch()
override;
3224 void RefuteDecision(Decision* d)
override;
3227Metaheuristic::Metaheuristic(Solver* solver,
const std::vector<bool>& maximize,
3228 std::vector<IntVar*> objectives,
3229 std::vector<int64_t> steps)
3230 : ObjectiveMonitor(solver, maximize,
std::move(objectives),
3231 std::move(steps)) {}
3233void Metaheuristic::EnterSearch() {
3234 ObjectiveMonitor::EnterSearch();
3237 solver()->SetUseFastLocalSearch(
false);
3240void Metaheuristic::RefuteDecision(Decision*) {
3241 for (
int i = 0;
i < Size(); ++
i) {
3251class TabuSearch :
public Metaheuristic {
3253 TabuSearch(Solver* solver,
const std::vector<bool>& maximize,
3254 std::vector<IntVar*> objectives, std::vector<int64_t> steps,
3255 const std::vector<IntVar*>& vars, int64_t keep_tenure,
3256 int64_t forbid_tenure,
double tabu_factor);
3257 ~TabuSearch()
override {}
3258 void EnterSearch()
override;
3259 void ApplyDecision(Decision* d)
override;
3260 bool AtSolution()
override;
3261 bool LocalOptimum()
override;
3264 std::string DebugString()
const override {
return "Tabu Search"; }
3272 typedef std::list<VarValue> TabuList;
3274 virtual std::vector<IntVar*> CreateTabuVars();
3275 const TabuList& forbid_tabu_list() {
return forbid_tabu_list_; }
3279 void AgeList(int64_t tenure, TabuList* list);
3281 int64_t TabuLimit()
const {
3282 return (synced_keep_tabu_list_.size() + synced_forbid_tabu_list_.size()) *
3286 const std::vector<IntVar*>
vars_;
3287 Assignment::IntContainer assignment_container_;
3288 std::vector<int64_t> last_values_;
3289 TabuList keep_tabu_list_;
3290 TabuList synced_keep_tabu_list_;
3291 int64_t keep_tenure_;
3292 TabuList forbid_tabu_list_;
3293 TabuList synced_forbid_tabu_list_;
3294 int64_t forbid_tenure_;
3295 double tabu_factor_;
3299TabuSearch::TabuSearch(Solver* solver,
const std::vector<bool>& maximize,
3300 std::vector<IntVar*> objectives,
3301 std::vector<int64_t> steps,
3302 const std::vector<IntVar*>& vars, int64_t keep_tenure,
3303 int64_t forbid_tenure,
double tabu_factor)
3304 : Metaheuristic(solver, maximize,
std::move(objectives),
std::move(steps)),
3306 last_values_(Size(),
std::numeric_limits<int64_t>::
max()),
3307 keep_tenure_(keep_tenure),
3308 forbid_tenure_(forbid_tenure),
3309 tabu_factor_(tabu_factor),
3317void TabuSearch::EnterSearch() {
3318 Metaheuristic::EnterSearch();
3319 solver()->SetUseFastLocalSearch(
true);
3323void TabuSearch::ApplyDecision(Decision*
const d) {
3324 Solver*
const s = solver();
3325 if (d == s->balancing_decision()) {
3329 synced_keep_tabu_list_ = keep_tabu_list_;
3330 synced_forbid_tabu_list_ = forbid_tabu_list_;
3331 Constraint* tabu_ct =
nullptr;
3335 const std::vector<IntVar*> tabu_vars = CreateTabuVars();
3336 if (!tabu_vars.empty()) {
3337 IntVar* tabu_var = s->MakeIsGreaterOrEqualCstVar(
3338 s->MakeSum(tabu_vars)->Var(), TabuLimit());
3341 IntVar* aspiration = MakeMinimizationVarsLessOrEqualWithStepsStatus(
3342 [
this](
int i) {
return BestInternalValue(i); });
3343 tabu_ct = s->MakeSumGreaterOrEqual({aspiration, tabu_var}, int64_t{1});
3346 if (tabu_ct !=
nullptr) s->AddConstraint(tabu_ct);
3349 if (CurrentInternalValuesAreConstraining()) {
3350 MakeMinimizationVarsLessOrEqualWithSteps(
3351 [
this](
int i) {
return CurrentInternalValue(i); });
3354 if (found_initial_solution_) {
3355 Constraint* plateau_ct =
nullptr;
3357 plateau_ct = s->MakeNonEquality(MinimizationVar(0), last_values_[0]);
3359 std::vector<IntVar*> plateau_vars(Size());
3360 for (
int i = 0;
i < Size(); ++
i) {
3362 s->MakeIsEqualCstVar(MinimizationVar(i), last_values_[i]);
3364 plateau_ct = s->MakeSumLessOrEqual(plateau_vars, Size() - 1);
3366 s->AddConstraint(plateau_ct);
3370std::vector<IntVar*> TabuSearch::CreateTabuVars() {
3371 Solver*
const s = solver();
3379 std::vector<IntVar*> tabu_vars;
3380 for (
const auto [
var_index,
value, unused_stamp] : keep_tabu_list_) {
3381 tabu_vars.push_back(s->MakeIsEqualCstVar(vars(
var_index),
value));
3383 for (
const auto [
var_index,
value, unused_stamp] : forbid_tabu_list_) {
3384 tabu_vars.push_back(s->MakeIsDifferentCstVar(vars(
var_index),
value));
3389bool TabuSearch::AtSolution() {
3390 if (!ObjectiveMonitor::AtSolution()) {
3393 for (
int i = 0;
i < Size(); ++
i) {
3394 last_values_[
i] = CurrentInternalValue(i);
3402 const int64_t old_value = assignment_container_.Element(
index).Value();
3403 const int64_t new_value =
var->Value();
3404 if (old_value != new_value) {
3405 if (keep_tenure_ > 0) {
3406 keep_tabu_list_.push_front({
index, new_value, stamp_});
3408 if (forbid_tenure_ > 0) {
3409 forbid_tabu_list_.push_front({
index, old_value, stamp_});
3414 assignment_container_.Store();
3419bool TabuSearch::LocalOptimum() {
3420 solver()->SetUseFastLocalSearch(
false);
3422 for (
int i = 0;
i < Size(); ++
i) {
3423 SetCurrentInternalValue(i, std::numeric_limits<int64_t>::max());
3425 return found_initial_solution_;
3428bool TabuSearch::AcceptDelta(Assignment*
delta, Assignment* deltadelta) {
3429 if (
delta ==
nullptr)
return true;
3430 if (!Metaheuristic::AcceptDelta(
delta, deltadelta))
return false;
3431 if (synced_keep_tabu_list_.empty() && synced_forbid_tabu_list_.empty()) {
3434 const Assignment::IntContainer& delta_container =
delta->IntVarContainer();
3436 for (
const IntVarElement& element : delta_container.elements()) {
3437 if (!element.Bound())
return true;
3439 int num_respected = 0;
3441 auto get_value = [
this, &delta_container](
int var_index) {
3442 const IntVarElement* element =
3443 delta_container.ElementPtrOrNull(vars(
var_index));
3444 return (element !=
nullptr)
3446 : assignment_container_.Element(
var_index).Value();
3448 for (
const auto [
var_index,
value, unused_stamp] : synced_keep_tabu_list_) {
3453 for (
const auto [
var_index,
value, unused_stamp] : synced_forbid_tabu_list_) {
3458 const int64_t tabu_limit = TabuLimit();
3459 if (num_respected >= tabu_limit)
return true;
3464 delta->SetObjectiveMinFromIndex(0,
CapAdd(BestInternalValue(0), Step(0)));
3466 delta->SetObjectiveMaxFromIndex(0,
CapSub(BestInternalValue(0), Step(0)));
3469 for (
int i = 0;
i < Size(); ++
i) {
3471 delta->SetObjectiveMinFromIndex(i, BestInternalValue(i));
3473 delta->SetObjectiveMaxFromIndex(i, BestInternalValue(i));
3481void TabuSearch::AcceptNeighbor() {
3487void TabuSearch::AgeList(int64_t tenure, TabuList* list) {
3488 while (!list->empty() && list->back().stamp < stamp_ - tenure) {
3493void TabuSearch::AgeLists() {
3494 AgeList(keep_tenure_, &keep_tabu_list_);
3495 AgeList(forbid_tenure_, &forbid_tabu_list_);
3499class GenericTabuSearch :
public TabuSearch {
3501 GenericTabuSearch(Solver* solver,
bool maximize, IntVar* objective,
3502 int64_t step,
const std::vector<IntVar*>& vars,
3503 int64_t forbid_tenure)
3504 : TabuSearch(solver, {maximize}, {objective}, {step}, vars, 0,
3505 forbid_tenure, 1) {}
3506 std::string DebugString()
const override {
return "Generic Tabu Search"; }
3509 std::vector<IntVar*> CreateTabuVars()
override;
3512std::vector<IntVar*> GenericTabuSearch::CreateTabuVars() {
3513 Solver*
const s = solver();
3517 std::vector<IntVar*> forbid_values;
3518 for (
const auto [
var_index,
value, unused_stamp] : forbid_tabu_list()) {
3519 forbid_values.push_back(s->MakeIsDifferentCstVar(vars(
var_index),
value));
3521 std::vector<IntVar*> tabu_vars;
3522 if (!forbid_values.empty()) {
3523 tabu_vars.push_back(s->MakeIsGreaterCstVar(s->MakeSum(forbid_values), 0));
3532 const std::vector<IntVar*>& vars,
3533 int64_t keep_tenure,
3534 int64_t forbid_tenure,
3535 double tabu_factor) {
3536 return RevAlloc(
new TabuSearch(
this, {maximize}, {objective}, {step}, vars,
3537 keep_tenure, forbid_tenure, tabu_factor));
3541 const std::vector<bool>& maximize, std::vector<IntVar*> objectives,
3542 std::vector<int64_t> steps,
const std::vector<IntVar*>& vars,
3543 int64_t keep_tenure, int64_t forbid_tenure,
double tabu_factor) {
3544 return RevAlloc(
new TabuSearch(
this, maximize, std::move(objectives),
3545 std::move(steps), vars, keep_tenure,
3546 forbid_tenure, tabu_factor));
3550 bool maximize,
IntVar*
const v, int64_t step,
3551 const std::vector<IntVar*>& tabu_vars, int64_t forbid_tenure) {
3553 new GenericTabuSearch(
this, maximize, v, step, tabu_vars, forbid_tenure));
3559class SimulatedAnnealing :
public Metaheuristic {
3561 SimulatedAnnealing(
Solver* solver,
const std::vector<bool>& maximize,
3562 std::vector<IntVar*> objectives,
3563 std::vector<int64_t> steps,
3564 std::vector<int64_t> initial_temperatures);
3565 ~SimulatedAnnealing()
override {}
3566 void ApplyDecision(Decision* d)
override;
3567 bool LocalOptimum()
override;
3568 void AcceptNeighbor()
override;
3569 std::string DebugString()
const override {
return "Simulated Annealing"; }
3572 double Temperature(
int index)
const {
3573 return iteration_ > 0
3574 ? (1.0 * temperature0_[
index]) / iteration_
3578 const std::vector<int64_t> temperature0_;
3583SimulatedAnnealing::SimulatedAnnealing(
3584 Solver* solver,
const std::vector<bool>& maximize,
3585 std::vector<IntVar*> objectives, std::vector<int64_t> steps,
3586 std::vector<int64_t> initial_temperatures)
3587 : Metaheuristic(solver, maximize,
std::move(objectives),
std::move(steps)),
3588 temperature0_(
std::move(initial_temperatures)),
3605void SimulatedAnnealing::ApplyDecision(Decision*
const d) {
3606 Solver*
const s = solver();
3607 if (d == s->balancing_decision()) {
3610 if (CurrentInternalValuesAreConstraining()) {
3611 MakeMinimizationVarsLessOrEqualWithSteps([
this](
int i) {
3612 const double rand_double = absl::Uniform<double>(rand_, 0.0, 1.0);
3613#if defined(_MSC_VER) || defined(__ANDROID__)
3614 const double rand_log2_double = log(rand_double) / log(2.0L);
3616 const double rand_log2_double = log2(rand_double);
3618 const int64_t energy_bound = Temperature(i) * rand_log2_double;
3621 return CapSub(CurrentInternalValue(i), energy_bound);
3626bool SimulatedAnnealing::LocalOptimum() {
3627 for (
int i = 0;
i < Size(); ++
i) {
3628 SetCurrentInternalValue(i, std::numeric_limits<int64_t>::max());
3631 if (!found_initial_solution_)
return false;
3632 for (
int i = 0;
i < Size(); ++
i) {
3633 if (Temperature(i) <= 0)
return false;
3638void SimulatedAnnealing::AcceptNeighbor() {
3639 if (iteration_ > 0) {
3647 int64_t initial_temperature) {
3648 return RevAlloc(
new SimulatedAnnealing(
this, {maximize}, {v}, {step},
3649 {initial_temperature}));
3653 const std::vector<bool>& maximize, std::vector<IntVar*> vars,
3654 std::vector<int64_t> steps, std::vector<int64_t> initial_temperatures) {
3655 return RevAlloc(
new SimulatedAnnealing(
this, maximize, std::move(vars),
3657 std::move(initial_temperatures)));
3667class GuidedLocalSearchPenaltiesTable {
3673 explicit GuidedLocalSearchPenaltiesTable(
int num_vars);
3674 bool HasPenalties()
const {
return has_values_; }
3675 void IncrementPenalty(
const VarValue& var_value);
3676 int64_t GetPenalty(
const VarValue& var_value)
const;
3680 std::vector<std::vector<int64_t>> penalties_;
3684GuidedLocalSearchPenaltiesTable::GuidedLocalSearchPenaltiesTable(
int num_vars)
3685 : penalties_(num_vars), has_values_(
false) {}
3687void GuidedLocalSearchPenaltiesTable::IncrementPenalty(
3688 const VarValue& var_value) {
3689 std::vector<int64_t>& var_penalties = penalties_[var_value.var];
3690 const int64_t
value = var_value.value;
3691 if (
value >= var_penalties.size()) {
3692 var_penalties.resize(
value + 1, 0);
3694 ++var_penalties[
value];
3698void GuidedLocalSearchPenaltiesTable::Reset() {
3699 has_values_ =
false;
3700 for (
int i = 0;
i < penalties_.size(); ++
i) {
3701 penalties_[
i].clear();
3705int64_t GuidedLocalSearchPenaltiesTable::GetPenalty(
3706 const VarValue& var_value)
const {
3707 const std::vector<int64_t>& var_penalties = penalties_[var_value.var];
3708 const int64_t
value = var_value.value;
3709 return (
value >= var_penalties.size()) ? 0 : var_penalties[
value];
3713class GuidedLocalSearchPenaltiesMap {
3719 friend bool operator==(
const VarValue& lhs,
const VarValue& rhs) {
3720 return lhs.var == rhs.var && lhs.value == rhs.value;
3722 template <
typename H>
3724 return H::combine(std::move(h), var_value.var, var_value.value);
3727 explicit GuidedLocalSearchPenaltiesMap(
int num_vars);
3728 bool HasPenalties()
const {
return (!penalties_.empty()); }
3729 void IncrementPenalty(
const VarValue& var_value);
3730 int64_t GetPenalty(
const VarValue& var_value)
const;
3735 absl::flat_hash_map<VarValue, int64_t> penalties_;
3738GuidedLocalSearchPenaltiesMap::GuidedLocalSearchPenaltiesMap(
int num_vars)
3739 : penalized_(num_vars,
false) {}
3741void GuidedLocalSearchPenaltiesMap::IncrementPenalty(
3742 const VarValue& var_value) {
3743 ++penalties_[var_value];
3744 penalized_.
Set(var_value.var,
true);
3747void GuidedLocalSearchPenaltiesMap::Reset() {
3752int64_t GuidedLocalSearchPenaltiesMap::GetPenalty(
3753 const VarValue& var_value)
const {
3754 return (penalized_.
Get(var_value.var))
3759template <
typename P>
3760class GuidedLocalSearch :
public Metaheuristic {
3762 GuidedLocalSearch(Solver* solver, IntVar* objective,
bool maximize,
3763 int64_t step,
const std::vector<IntVar*>& vars,
3764 double penalty_factor,
3765 bool reset_penalties_on_new_best_solution);
3766 ~GuidedLocalSearch()
override {}
3768 void ApplyDecision(Decision* d)
override;
3769 bool AtSolution()
override;
3770 void EnterSearch()
override;
3771 bool LocalOptimum()
override;
3772 virtual int64_t AssignmentElementPenalty(
int index)
const = 0;
3773 virtual int64_t AssignmentPenalty(int64_t
var, int64_t
value)
const = 0;
3774 virtual int64_t Evaluate(
const Assignment*
delta, int64_t current_penalty,
3775 bool incremental) = 0;
3776 virtual IntExpr* MakeElementPenalty(
int index) = 0;
3777 std::string DebugString()
const override {
return "Guided Local Search"; }
3783 template <
typename T,
typename IndexType =
int64_t>
3786 explicit DirtyArray(IndexType
size)
3787 : base_data_(
size), modified_data_(
size), touched_(
size) {}
3790 void Set(IndexType i,
const T&
value) {
3791 modified_data_[
i] =
value;
3795 void SetAll(
const T&
value) {
3796 for (IndexType i = 0;
i < modified_data_.size(); ++
i) {
3801 T Get(IndexType i)
const {
return modified_data_[
i]; }
3805 for (
const IndexType
index : touched_.PositionsSetAtLeastOnce()) {
3808 touched_.SparseClearAll();
3812 for (
const IndexType
index : touched_.PositionsSetAtLeastOnce()) {
3815 touched_.SparseClearAll();
3819 int NumSetValues()
const {
3820 return touched_.NumberOfSetCallsWithDifferentArguments();
3824 std::vector<T> base_data_;
3825 std::vector<T> modified_data_;
3826 SparseBitset<IndexType> touched_;
3829 int64_t GetValue(int64_t
index)
const {
3832 IntVar* GetVar(int64_t
index)
const {
3835 void AddVars(
const std::vector<IntVar*>& vars);
3836 int NumPrimaryVars()
const {
return num_vars_; }
3837 int GetLocalIndexFromVar(IntVar*
var)
const {
3843 void ResetPenalties();
3846 Assignment::IntContainer assignment_;
3858template <
typename P>
3860 Solver* solver, IntVar* objective,
bool maximize, int64_t step,
3861 const std::vector<IntVar*>& vars,
double penalty_factor,
3862 bool reset_penalties_on_new_best_solution)
3863 : Metaheuristic(solver, {maximize}, {objective}, {step}),
3869 penalties_(vars.size()),
3873 reset_penalties_on_new_best_solution) {
3877template <
typename P>
3878void GuidedLocalSearch<P>::AddVars(
const std::vector<IntVar*>& vars) {
3879 const int offset = assignment_.Size();
3880 if (vars.empty())
return;
3881 assignment_.Resize(offset + vars.size());
3882 for (
int i = 0;
i < vars.size(); ++
i) {
3883 assignment_.AddAtPosition(vars[i], offset + i);
3885 const int max_var_index =
3886 (*std::max_element(vars.begin(), vars.end(), [](IntVar*
a, IntVar*
b) {
3887 return a->index() < b->index();
3892 for (
int i = 0;
i < vars.size(); ++
i) {
3904template <
typename P>
3905void GuidedLocalSearch<P>::ApplyDecision(Decision*
const d) {
3906 if (d == solver()->balancing_decision()) {
3910 if (penalties_.HasPenalties()) {
3914 std::vector<IntVar*> elements;
3916 elements.push_back(MakeElementPenalty(i)->Var());
3917 const int64_t penalty = AssignmentElementPenalty(i);
3927 IntExpr* max_pen_exp = solver()->MakeDifference(
3931 ->MakeMax(max_pen_exp,
CapSub(BestInternalValue(0), Step(0)))
3933 solver()->AddConstraint(
3934 solver()->MakeLessOrEqual(MinimizationVar(0), max_exp));
3937 const int64_t
bound =
3938 (CurrentInternalValue(0) < std::numeric_limits<int64_t>::max())
3939 ?
CapSub(CurrentInternalValue(0), Step(0))
3940 : CurrentInternalValue(0);
3941 MinimizationVar(0)->SetMax(
bound);
3945template <
typename P>
3946void GuidedLocalSearch<P>::ResetPenalties() {
3954template <
typename P>
3955bool GuidedLocalSearch<P>::AtSolution() {
3956 const int64_t old_best = BestInternalValue(0);
3957 if (!ObjectiveMonitor::AtSolution()) {
3966 old_best != BestInternalValue(0)) {
3968 DCHECK_EQ(CurrentInternalValue(0), BestInternalValue(0));
3971 SetCurrentInternalValue(
3975 assignment_.Store();
3979template <
typename P>
3980void GuidedLocalSearch<P>::EnterSearch() {
3981 Metaheuristic::EnterSearch();
3982 solver()->SetUseFastLocalSearch(
true);
3989template <
typename P>
3990bool GuidedLocalSearch<P>::AcceptDelta(Assignment*
delta,
3991 Assignment* deltadelta) {
3992 if (
delta ==
nullptr && deltadelta ==
nullptr)
return true;
3993 if (!penalties_.HasPenalties()) {
3994 return Metaheuristic::AcceptDelta(
delta, deltadelta);
3996 int64_t penalty = 0;
3997 if (!deltadelta->Empty()) {
4014 if (!
delta->HasObjective()) {
4015 delta->AddObjective(ObjectiveVar(0));
4017 if (
delta->Objective() == ObjectiveVar(0)) {
4018 const int64_t
bound =
4019 std::max(
CapSub(
CapSub(CurrentInternalValue(0), Step(0)), penalty),
4020 CapSub(BestInternalValue(0), Step(0)));
4032template <
typename P>
4033bool GuidedLocalSearch<P>::LocalOptimum() {
4034 solver()->SetUseFastLocalSearch(
false);
4035 std::vector<double> utilities(
num_vars_);
4036 double max_utility = -std::numeric_limits<double>::infinity();
4038 const IntVarElement& element = assignment_.Element(
var);
4039 if (!element.Bound()) {
4043 const int64_t
value = element.Value();
4047 const double utility = cost / (penalties_.GetPenalty({
var,
value}) + 1.0);
4048 utilities[
var] = utility;
4049 if (utility > max_utility) max_utility = utility;
4052 if (utilities[
var] == max_utility) {
4053 const IntVarElement& element = assignment_.Element(
var);
4054 DCHECK(element.Bound());
4055 penalties_.IncrementPenalty({
var, element.Value()});
4058 SetCurrentInternalValue(0, std::numeric_limits<int64_t>::max());
4062template <
typename P>
4063class BinaryGuidedLocalSearch :
public GuidedLocalSearch<P> {
4065 BinaryGuidedLocalSearch(
4066 Solver* solver, IntVar* objective,
4067 std::function<int64_t(int64_t, int64_t)> objective_function,
4068 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
4069 double penalty_factor,
bool reset_penalties_on_new_best_solution);
4070 ~BinaryGuidedLocalSearch()
override {}
4071 IntExpr* MakeElementPenalty(
int index)
override;
4072 int64_t AssignmentElementPenalty(
int index)
const override;
4073 int64_t AssignmentPenalty(int64_t
var, int64_t
value)
const override;
4074 int64_t Evaluate(
const Assignment*
delta, int64_t current_penalty,
4075 bool incremental)
override;
4078 int64_t PenalizedValue(int64_t i, int64_t j)
const;
4079 std::function<int64_t(int64_t, int64_t)> objective_function_;
4082template <
typename P>
4083BinaryGuidedLocalSearch<P>::BinaryGuidedLocalSearch(
4084 Solver*
const solver, IntVar*
const objective,
4085 std::function<int64_t(int64_t, int64_t)> objective_function,
bool maximize,
4086 int64_t step,
const std::vector<IntVar*>& vars,
double penalty_factor,
4087 bool reset_penalties_on_new_best_solution)
4088 : GuidedLocalSearch<P>(solver, objective, maximize, step, vars,
4090 reset_penalties_on_new_best_solution),
4091 objective_function_(
std::move(objective_function)) {}
4093template <
typename P>
4094IntExpr* BinaryGuidedLocalSearch<P>::MakeElementPenalty(
int index) {
4095 return this->solver()->MakeElement(
4096 [
this,
index](int64_t i) {
return PenalizedValue(
index, i); },
4097 this->GetVar(
index));
4100template <
typename P>
4101int64_t BinaryGuidedLocalSearch<P>::AssignmentElementPenalty(
int index)
const {
4102 return PenalizedValue(
index, this->GetValue(
index));
4105template <
typename P>
4106int64_t BinaryGuidedLocalSearch<P>::AssignmentPenalty(int64_t
var,
4107 int64_t
value)
const {
4108 return objective_function_(
var,
value);
4111template <
typename P>
4112int64_t BinaryGuidedLocalSearch<P>::Evaluate(
const Assignment*
delta,
4113 int64_t current_penalty,
4115 int64_t penalty = current_penalty;
4116 const Assignment::IntContainer& container =
delta->IntVarContainer();
4117 for (
const IntVarElement& new_element : container.elements()) {
4118 const int index = this->GetLocalIndexFromVar(new_element.Var());
4119 if (
index == -1)
continue;
4121 if (new_element.Activated()) {
4122 const int64_t new_penalty = PenalizedValue(
index, new_element.Value());
4123 penalty =
CapAdd(penalty, new_penalty);
4133template <
typename P>
4134int64_t BinaryGuidedLocalSearch<P>::PenalizedValue(int64_t i, int64_t j)
const {
4135 const int64_t penalty = this->penalties_.GetPenalty({
i, j});
4137 if (penalty == 0)
return 0;
4138 const double penalized_value_fp =
4140 const int64_t penalized_value =
4141 (penalized_value_fp <= std::numeric_limits<int64_t>::max())
4142 ?
static_cast<int64_t
>(penalized_value_fp)
4143 : std::numeric_limits<int64_t>::max();
4144 return penalized_value;
4147template <
typename P>
4148class TernaryGuidedLocalSearch :
public GuidedLocalSearch<P> {
4150 TernaryGuidedLocalSearch(
4151 Solver* solver, IntVar* objective,
4152 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
4153 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
4154 const std::vector<IntVar*>& secondary_vars,
double penalty_factor,
4155 bool reset_penalties_on_new_best_solution);
4156 ~TernaryGuidedLocalSearch()
override {}
4157 IntExpr* MakeElementPenalty(
int index)
override;
4158 int64_t AssignmentElementPenalty(
int index)
const override;
4159 int64_t AssignmentPenalty(int64_t
var, int64_t
value)
const override;
4160 int64_t Evaluate(
const Assignment*
delta, int64_t current_penalty,
4161 bool incremental)
override;
4164 int64_t PenalizedValue(int64_t i, int64_t j, int64_t k)
const;
4166 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function_;
4167 std::vector<int> secondary_values_;
4170template <
typename P>
4171TernaryGuidedLocalSearch<P>::TernaryGuidedLocalSearch(
4172 Solver*
const solver, IntVar*
const objective,
4173 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
4174 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
4175 const std::vector<IntVar*>& secondary_vars,
double penalty_factor,
4176 bool reset_penalties_on_new_best_solution)
4177 : GuidedLocalSearch<P>(solver, objective, maximize, step, vars,
4179 reset_penalties_on_new_best_solution),
4180 objective_function_(
std::move(objective_function)),
4181 secondary_values_(this->NumPrimaryVars(), -1) {
4182 this->AddVars(secondary_vars);
4185template <
typename P>
4186IntExpr* TernaryGuidedLocalSearch<P>::MakeElementPenalty(
int index) {
4187 Solver*
const solver = this->solver();
4189 solver->AddConstraint(solver->MakeLightElement(
4190 [
this,
index](int64_t j, int64_t k) {
4191 return PenalizedValue(index, j, k);
4193 var, this->GetVar(
index), this->GetVar(this->NumPrimaryVars() +
index)));
4197template <
typename P>
4198int64_t TernaryGuidedLocalSearch<P>::AssignmentElementPenalty(
int index)
const {
4199 return PenalizedValue(
index, this->GetValue(
index),
4200 this->GetValue(this->NumPrimaryVars() +
index));
4203template <
typename P>
4204int64_t TernaryGuidedLocalSearch<P>::AssignmentPenalty(int64_t
var,
4205 int64_t
value)
const {
4206 return objective_function_(
var,
value,
4207 this->GetValue(this->NumPrimaryVars() +
var));
4210template <
typename P>
4211int64_t TernaryGuidedLocalSearch<P>::Evaluate(
const Assignment*
delta,
4212 int64_t current_penalty,
4214 int64_t penalty = current_penalty;
4215 const Assignment::IntContainer& container =
delta->IntVarContainer();
4219 for (
const IntVarElement& new_element : container.elements()) {
4220 const int index = this->GetLocalIndexFromVar(new_element.Var());
4222 secondary_values_[
index] = -1;
4225 for (
const IntVarElement& new_element : container.elements()) {
4226 const int index = this->GetLocalIndexFromVar(new_element.Var());
4227 if (!new_element.Activated())
continue;
4228 if (
index != -1 &&
index >= this->NumPrimaryVars()) {
4229 secondary_values_[
index - this->NumPrimaryVars()] = new_element.Value();
4232 for (
const IntVarElement& new_element : container.elements()) {
4233 const int index = this->GetLocalIndexFromVar(new_element.Var());
4235 if (
index == -1 ||
index >= this->NumPrimaryVars()) {
4240 if (new_element.Activated() && secondary_values_[
index] != -1) {
4241 const int64_t new_penalty =
4242 PenalizedValue(
index, new_element.Value(), secondary_values_[
index]);
4243 penalty =
CapAdd(penalty, new_penalty);
4253template <
typename P>
4254int64_t TernaryGuidedLocalSearch<P>::PenalizedValue(int64_t i, int64_t j,
4256 const int64_t penalty = this->penalties_.GetPenalty({
i, j});
4258 if (penalty == 0)
return 0;
4259 const double penalized_value_fp =
4261 const int64_t penalized_value =
4262 (penalized_value_fp < std::numeric_limits<int64_t>::max())
4263 ?
static_cast<int64_t
>(penalized_value_fp)
4264 : std::numeric_limits<int64_t>::max();
4265 return penalized_value;
4270 bool maximize,
IntVar*
const objective,
4272 const std::vector<IntVar*>& vars,
double penalty_factor,
4273 bool reset_penalties_on_new_best_solution) {
4274 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
4275 return RevAlloc(
new BinaryGuidedLocalSearch<GuidedLocalSearchPenaltiesMap>(
4276 this, objective, std::move(objective_function), maximize, step, vars,
4277 penalty_factor, reset_penalties_on_new_best_solution));
4280 new BinaryGuidedLocalSearch<GuidedLocalSearchPenaltiesTable>(
4281 this, objective, std::move(objective_function), maximize, step,
4282 vars, penalty_factor, reset_penalties_on_new_best_solution));
4287 bool maximize,
IntVar*
const objective,
4289 const std::vector<IntVar*>& vars,
4290 const std::vector<IntVar*>& secondary_vars,
double penalty_factor,
4291 bool reset_penalties_on_new_best_solution) {
4292 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
4293 return RevAlloc(
new TernaryGuidedLocalSearch<GuidedLocalSearchPenaltiesMap>(
4294 this, objective, std::move(objective_function), maximize, step, vars,
4295 secondary_vars, penalty_factor, reset_penalties_on_new_best_solution));
4298 new TernaryGuidedLocalSearch<GuidedLocalSearchPenaltiesTable>(
4299 this, objective, std::move(objective_function), maximize, step,
4300 vars, secondary_vars, penalty_factor,
4301 reset_penalties_on_new_best_solution));
4309SearchLimit::~SearchLimit() {}
4311void SearchLimit::Install() {
4312 ListenToEvent(Solver::MonitorEvent::kEnterSearch);
4313 ListenToEvent(Solver::MonitorEvent::kBeginNextDecision);
4314 ListenToEvent(Solver::MonitorEvent::kPeriodicCheck);
4315 ListenToEvent(Solver::MonitorEvent::kRefuteDecision);
4318void SearchLimit::EnterSearch() {
4333void SearchLimit::PeriodicCheck() {
4334 if (crossed_ || Check()) {
4340void SearchLimit::TopPeriodicCheck() {
4341 if (solver()->TopLevelSearch() != solver()->ActiveSearch()) {
4342 solver()->TopPeriodicCheck();
4349 int64_t branches, int64_t failures,
4350 int64_t solutions,
bool smart_time_check,
4353 duration_limit_(
time),
4354 solver_time_at_limit_start_(s->Now()),
4355 last_time_elapsed_(
absl::ZeroDuration()),
4358 smart_time_check_(smart_time_check),
4359 branches_(branches),
4360 branches_offset_(0),
4361 failures_(failures),
4362 failures_offset_(0),
4363 solutions_(solutions),
4364 solutions_offset_(0),
4365 cumulative_(cumulative) {}
4380 duration_limit_ = regular->duration_limit_;
4381 branches_ = regular->branches_;
4382 failures_ = regular->failures_;
4383 solutions_ = regular->solutions_;
4384 smart_time_check_ = regular->smart_time_check_;
4385 cumulative_ = regular->cumulative_;
4399 return s->
branches() - branches_offset_ >= branches_ ||
4400 s->
failures() - failures_offset_ >= failures_ || CheckTime(offset) ||
4401 s->
solutions() - solutions_offset_ >= solutions_;
4406 int64_t progress = GetPercent(s->
branches(), branches_offset_, branches_);
4407 progress = std::max(progress,
4408 GetPercent(s->
failures(), failures_offset_, failures_));
4409 progress = std::max(
4410 progress, GetPercent(s->
solutions(), solutions_offset_, solutions_));
4412 progress = std::max(progress, (100 * TimeElapsed()) /
duration_limit());
4421 solver_time_at_limit_start_ = s->
Now();
4422 last_time_elapsed_ = absl::ZeroDuration();
4432 branches_ -= s->
branches() - branches_offset_;
4433 failures_ -= s->
failures() - failures_offset_;
4434 duration_limit_ -= s->
Now() - solver_time_at_limit_start_;
4435 solutions_ -= s->
solutions() - solutions_offset_;
4440 int64_t failures, int64_t solutions) {
4442 duration_limit_ =
time;
4455 return absl::StrFormat(
4456 "RegularLimit(crossed = %i, duration_limit = %s, "
4457 "branches = %d, failures = %d, solutions = %d cumulative = %s",
4459 solutions_, (cumulative_ ?
"true" :
"false"));
4477bool RegularLimit::CheckTime(absl::Duration offset) {
4481absl::Duration RegularLimit::TimeElapsed() {
4482 const int64_t kMaxSkip = 100;
4483 const int64_t kCheckWarmupIterations = 100;
4486 next_check_ <= check_count_) {
4487 Solver*
const s =
solver();
4488 absl::Duration elapsed = s->Now() - solver_time_at_limit_start_;
4489 if (smart_time_check_ && check_count_ > kCheckWarmupIterations &&
4490 elapsed > absl::ZeroDuration()) {
4492 check_count_ * absl::FDivDuration(duration_limit_, elapsed));
4494 std::min(check_count_ + kMaxSkip, estimated_check_count_at_limit);
4496 last_time_elapsed_ = elapsed;
4498 return last_time_elapsed_;
4503 std::numeric_limits<int64_t>::max(),
4504 std::numeric_limits<int64_t>::max(),
4510 std::numeric_limits<int64_t>::max(),
4511 std::numeric_limits<int64_t>::max(),
4516 return MakeLimit(absl::InfiniteDuration(),
4517 std::numeric_limits<int64_t>::max(),
failures,
4518 std::numeric_limits<int64_t>::max(),
4523 return MakeLimit(absl::InfiniteDuration(),
4524 std::numeric_limits<int64_t>::max(),
4525 std::numeric_limits<int64_t>::max(),
solutions,
4530 int64_t failures, int64_t solutions,
4531 bool smart_time_check,
bool cumulative) {
4533 smart_time_check, cumulative);
4537 int64_t failures, int64_t solutions,
4538 bool smart_time_check,
bool cumulative) {
4540 smart_time_check, cumulative));
4544 return MakeLimit(
proto.time() == std::numeric_limits<int64_t>::max()
4545 ? absl::InfiniteDuration()
4546 : absl::Milliseconds(
proto.time()),
4548 proto.smart_time_check(),
proto.cumulative());
4552 RegularLimitParameters
proto;
4553 proto.set_time(std::numeric_limits<int64_t>::max());
4554 proto.set_branches(std::numeric_limits<int64_t>::max());
4555 proto.set_failures(std::numeric_limits<int64_t>::max());
4556 proto.set_solutions(std::numeric_limits<int64_t>::max());
4557 proto.set_smart_time_check(
false);
4558 proto.set_cumulative(
false);
4566 double objective_scaling_factor,
double objective_offset,
4567 double improvement_rate_coefficient,
4568 int improvement_rate_solutions_distance)
4570 std::vector<bool>{maximize},
4571 std::vector<double>{objective_scaling_factor},
4572 std::vector<double>{objective_offset},
4573 improvement_rate_coefficient,
4574 improvement_rate_solutions_distance) {}
4577 Solver* solver, std::vector<IntVar*> objective_vars,
4578 std::vector<bool> maximize, std::vector<double> objective_scaling_factors,
4579 std::vector<double> objective_offsets,
double improvement_rate_coefficient,
4580 int improvement_rate_solutions_distance)
4582 objective_vars_(
std::move(objective_vars)),
4583 maximize_(
std::move(maximize)),
4584 objective_scaling_factors_(
std::move(objective_scaling_factors)),
4585 objective_offsets_(
std::move(objective_offsets)),
4586 improvement_rate_coefficient_(improvement_rate_coefficient),
4587 improvement_rate_solutions_distance_(improvement_rate_solutions_distance),
4588 best_objectives_(objective_vars_.
size()),
4589 improvements_(objective_vars_.
size()),
4590 thresholds_(objective_vars_.
size(),
4591 std::numeric_limits<double>::infinity()) {
4603 for (
int i = 0; i < objective_vars_.size(); ++i) {
4604 best_objectives_[i] = std::numeric_limits<double>::infinity();
4605 improvements_[i].clear();
4606 thresholds_[i] = std::numeric_limits<double>::infinity();
4608 objective_updated_ =
false;
4609 gradient_stage_ =
true;
4615 objective_vars_ = improv->objective_vars_;
4616 maximize_ = improv->maximize_;
4617 objective_scaling_factors_ = improv->objective_scaling_factors_;
4618 objective_offsets_ = improv->objective_offsets_;
4619 improvement_rate_coefficient_ = improv->improvement_rate_coefficient_;
4620 improvement_rate_solutions_distance_ =
4621 improv->improvement_rate_solutions_distance_;
4622 improvements_ = improv->improvements_;
4623 thresholds_ = improv->thresholds_;
4624 best_objectives_ = improv->best_objectives_;
4625 objective_updated_ = improv->objective_updated_;
4626 gradient_stage_ = improv->gradient_stage_;
4631 solver(), objective_vars_, maximize_, objective_scaling_factors_,
4632 objective_offsets_, improvement_rate_coefficient_,
4633 improvement_rate_solutions_distance_));
4637 if (!objective_updated_) {
4640 objective_updated_ =
false;
4642 std::vector<double> improvement_rates(improvements_.size());
4643 for (
int i = 0; i < improvements_.size(); ++i) {
4644 if (improvements_[i].
size() <= improvement_rate_solutions_distance_) {
4648 const auto [cur_obj, cur_neighbors] = improvements_[i].back();
4649 const auto [prev_obj, prev_neighbors] = improvements_[i].front();
4650 DCHECK_GT(cur_neighbors, prev_neighbors);
4651 improvement_rates[i] =
4652 (prev_obj - cur_obj) / (cur_neighbors - prev_neighbors);
4653 if (gradient_stage_)
continue;
4654 const double scaled_improvement_rate =
4655 improvement_rate_coefficient_ * improvement_rates[i];
4656 if (scaled_improvement_rate < thresholds_[i]) {
4658 }
else if (scaled_improvement_rate > thresholds_[i]) {
4662 if (gradient_stage_ && std::lexicographical_compare(
4663 improvement_rates.begin(), improvement_rates.end(),
4664 thresholds_.begin(), thresholds_.end())) {
4665 thresholds_ = std::move(improvement_rates);
4671 std::vector<double> scaled_new_objectives(objective_vars_.size());
4672 for (
int i = 0; i < objective_vars_.size(); ++i) {
4673 const int64_t new_objective =
4674 objective_vars_[i] !=
nullptr && objective_vars_[i]->Bound()
4675 ? objective_vars_[i]->Min()
4676 : (maximize_[i] ?
solver()
4684 scaled_new_objectives[i] = (maximize_[i] ? -objective_scaling_factors_[i]
4685 : objective_scaling_factors_[i]) *
4686 (new_objective + objective_offsets_[i]);
4688 const bool is_improvement = std::lexicographical_compare(
4689 scaled_new_objectives.begin(), scaled_new_objectives.end(),
4690 best_objectives_.begin(), best_objectives_.end());
4691 if (gradient_stage_ && !is_improvement) {
4692 gradient_stage_ =
false;
4695 for (
int i = 0; i < objective_vars_.size(); ++i) {
4696 if (thresholds_[i] == std::numeric_limits<double>::infinity()) {
4697 thresholds_[i] = -1;
4702 if (is_improvement) {
4703 objective_updated_ =
true;
4704 for (
int i = 0; i < objective_vars_.size(); ++i) {
4705 improvements_[i].push_back(
4706 std::make_pair(scaled_new_objectives[i],
solver()->neighbors()));
4710 if (improvements_[i].
size() - 1 > improvement_rate_solutions_distance_) {
4711 improvements_[i].pop_front();
4713 DCHECK_LE(improvements_[i].
size() - 1,
4714 improvement_rate_solutions_distance_);
4716 best_objectives_ = std::move(scaled_new_objectives);
4722 IntVar* objective_var,
bool maximize,
double objective_scaling_factor,
4723 double objective_offset,
double improvement_rate_coefficient,
4724 int improvement_rate_solutions_distance) {
4726 this, objective_var, maximize, objective_scaling_factor, objective_offset,
4727 improvement_rate_coefficient, improvement_rate_solutions_distance));
4731 std::vector<IntVar*> objective_vars, std::vector<bool> maximize,
4732 std::vector<double> objective_scaling_factors,
4733 std::vector<double> objective_offsets,
double improvement_rate_coefficient,
4734 int improvement_rate_solutions_distance) {
4736 this, std::move(objective_vars), std::move(maximize),
4737 std::move(objective_scaling_factors), std::move(objective_offsets),
4738 improvement_rate_coefficient, improvement_rate_solutions_distance));
4746 :
SearchLimit(limit_1->solver()), limit_1_(limit_1), limit_2_(limit_2) {
4747 CHECK(limit_1 !=
nullptr);
4748 CHECK(limit_2 !=
nullptr);
4750 <<
"Illegal arguments: cannot combines limits that belong to different "
4751 <<
"solvers, because the reversible allocations could delete one and "
4752 <<
"not the other.";
4755 bool CheckWithOffset(absl::Duration offset)
override {
4758 const bool check_1 = limit_1_->CheckWithOffset(offset);
4759 const bool check_2 = limit_2_->CheckWithOffset(offset);
4760 return check_1 || check_2;
4763 void Init()
override {
4768 void Copy(
const SearchLimit*
const)
override {
4769 LOG(FATAL) <<
"Not implemented.";
4772 SearchLimit* MakeClone()
const override {
4774 return solver()->MakeLimit(limit_1_->MakeClone(), limit_2_->MakeClone());
4777 void EnterSearch()
override {
4778 limit_1_->EnterSearch();
4779 limit_2_->EnterSearch();
4781 void BeginNextDecision(DecisionBuilder*
const b)
override {
4782 limit_1_->BeginNextDecision(
b);
4783 limit_2_->BeginNextDecision(
b);
4785 void PeriodicCheck()
override {
4786 limit_1_->PeriodicCheck();
4787 limit_2_->PeriodicCheck();
4789 void RefuteDecision(Decision*
const d)
override {
4790 limit_1_->RefuteDecision(d);
4791 limit_2_->RefuteDecision(d);
4793 std::string DebugString()
const override {
4794 return absl::StrCat(
"OR limit (", limit_1_->DebugString(),
" OR ",
4795 limit_2_->DebugString(),
")");
4799 SearchLimit*
const limit_1_;
4800 SearchLimit*
const limit_2_;
4806 return RevAlloc(
new ORLimit(limit_1, limit_2));
4812 CustomLimit(
Solver* s, std::function<
bool()> limiter);
4813 bool CheckWithOffset(absl::Duration offset)
override;
4814 void Init()
override;
4819 std::function<bool()> limiter_;
4822CustomLimit::CustomLimit(Solver*
const s, std::function<
bool()> limiter)
4823 : SearchLimit(s), limiter_(
std::move(limiter)) {}
4825bool CustomLimit::CheckWithOffset(absl::Duration) {
4827 if (limiter_)
return limiter_();
4831void CustomLimit::Init() {}
4833void CustomLimit::Copy(
const SearchLimit*
const limit) {
4834 const CustomLimit*
const custom =
4835 reinterpret_cast<const CustomLimit* const
>(limit);
4836 limiter_ = custom->limiter_;
4839SearchLimit* CustomLimit::MakeClone()
const {
4840 return solver()->RevAlloc(
new CustomLimit(solver(), limiter_));
4845 return RevAlloc(
new CustomLimit(
this, std::move(limiter)));
4854 CHECK(db !=
nullptr);
4857 SolveOnce(DecisionBuilder*
const db,
4858 const std::vector<SearchMonitor*>& monitors)
4859 : db_(db), monitors_(monitors) {
4860 CHECK(db !=
nullptr);
4863 ~SolveOnce()
override {}
4865 Decision*
Next(Solver* s)
override {
4866 bool res = s->SolveAndCommit(db_, monitors_);
4873 std::string DebugString()
const override {
4874 return absl::StrFormat(
"SolveOnce(%s)", db_->
DebugString());
4877 void Accept(ModelVisitor*
const visitor)
const override {
4882 DecisionBuilder*
const db_;
4883 std::vector<SearchMonitor*> monitors_;
4888 return RevAlloc(
new SolveOnce(db));
4893 std::vector<SearchMonitor*> monitors;
4894 monitors.push_back(monitor1);
4895 return RevAlloc(
new SolveOnce(db, monitors));
4901 std::vector<SearchMonitor*> monitors;
4902 monitors.push_back(monitor1);
4903 monitors.push_back(monitor2);
4904 return RevAlloc(
new SolveOnce(db, monitors));
4911 std::vector<SearchMonitor*> monitors;
4912 monitors.push_back(monitor1);
4913 monitors.push_back(monitor2);
4914 monitors.push_back(monitor3);
4915 return RevAlloc(
new SolveOnce(db, monitors));
4923 std::vector<SearchMonitor*> monitors;
4924 monitors.push_back(monitor1);
4925 monitors.push_back(monitor2);
4926 monitors.push_back(monitor3);
4927 monitors.push_back(monitor4);
4928 return RevAlloc(
new SolveOnce(db, monitors));
4932 DecisionBuilder*
const db,
const std::vector<SearchMonitor*>& monitors) {
4933 return RevAlloc(
new SolveOnce(db, monitors));
4942 bool maximize, int64_t step)
4945 maximize_(maximize),
4947 collector_(nullptr) {
4948 CHECK(db !=
nullptr);
4954 NestedOptimize(DecisionBuilder*
const db, Assignment*
const solution,
4955 bool maximize, int64_t step,
4956 const std::vector<SearchMonitor*>& monitors)
4959 maximize_(maximize),
4961 monitors_(monitors),
4962 collector_(nullptr) {
4963 CHECK(db !=
nullptr);
4969 void AddMonitors() {
4970 Solver*
const solver = solution_->
solver();
4971 collector_ = solver->MakeLastSolutionCollector(solution_);
4972 monitors_.push_back(collector_);
4973 OptimizeVar*
const optimize =
4974 solver->MakeOptimize(maximize_, solution_->
Objective(), step_);
4975 monitors_.push_back(optimize);
4978 Decision*
Next(Solver* solver)
override {
4979 solver->Solve(db_, monitors_);
4987 std::string DebugString()
const override {
4988 return absl::StrFormat(
"NestedOptimize(db = %s, maximize = %d, step = %d)",
4992 void Accept(ModelVisitor*
const visitor)
const override {
4997 DecisionBuilder*
const db_;
4998 Assignment*
const solution_;
4999 const bool maximize_;
5000 const int64_t step_;
5001 std::vector<SearchMonitor*> monitors_;
5002 SolutionCollector* collector_;
5008 bool maximize, int64_t step) {
5009 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step));
5014 bool maximize, int64_t step,
5016 std::vector<SearchMonitor*> monitors;
5017 monitors.push_back(monitor1);
5018 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5023 bool maximize, int64_t step,
5026 std::vector<SearchMonitor*> monitors;
5027 monitors.push_back(monitor1);
5028 monitors.push_back(monitor2);
5029 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5034 bool maximize, int64_t step,
5038 std::vector<SearchMonitor*> monitors;
5039 monitors.push_back(monitor1);
5040 monitors.push_back(monitor2);
5041 monitors.push_back(monitor3);
5042 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5049 std::vector<SearchMonitor*> monitors;
5050 monitors.push_back(monitor1);
5051 monitors.push_back(monitor2);
5052 monitors.push_back(monitor3);
5053 monitors.push_back(monitor4);
5054 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5059 int64_t step,
const std::vector<SearchMonitor*>& monitors) {
5060 return RevAlloc(
new NestedOptimize(db,
solution, maximize, step, monitors));
5067int64_t NextLuby(
int i) {
5069 DCHECK_LT(i, std::numeric_limits<int32_t>::max());
5075 while (power < (i + 1)) {
5078 if (power == i + 1) {
5081 return NextLuby(i - (power / 2) + 1);
5084class LubyRestart :
public SearchMonitor {
5086 LubyRestart(Solver*
const s,
int scale_factor)
5088 scale_factor_(scale_factor),
5091 next_step_(scale_factor) {
5092 CHECK_GE(scale_factor, 1);
5095 ~LubyRestart()
override {}
5097 void BeginFail()
override {
5098 if (++current_fails_ >= next_step_) {
5100 next_step_ = NextLuby(++iteration_) * scale_factor_;
5101 solver()->RestartCurrentSearch();
5105 void Install()
override { ListenToEvent(Solver::MonitorEvent::kBeginFail); }
5107 std::string DebugString()
const override {
5108 return absl::StrFormat(
"LubyRestart(%i)", scale_factor_);
5112 const int scale_factor_;
5114 int64_t current_fails_;
5120 return RevAlloc(
new LubyRestart(
this, scale_factor));
5128 ConstantRestart(
Solver*
const s,
int frequency)
5129 :
SearchMonitor(s), frequency_(frequency), current_fails_(0) {
5130 CHECK_GE(frequency, 1);
5133 ~ConstantRestart()
override {}
5135 void BeginFail()
override {
5136 if (++current_fails_ >= frequency_) {
5138 solver()->RestartCurrentSearch();
5142 void Install()
override { ListenToEvent(Solver::MonitorEvent::kBeginFail); }
5144 std::string DebugString()
const override {
5145 return absl::StrFormat(
"ConstantRestart(%i)", frequency_);
5149 const int frequency_;
5150 int64_t current_fails_;
5155 return RevAlloc(
new ConstantRestart(
this, frequency));
5178 const std::vector<SymmetryBreaker*>& visitors)
5180 visitors_(visitors),
5181 clauses_(visitors.
size()),
5182 decisions_(visitors.
size()),
5183 directions_(visitors.
size()) {
5184 for (
int i = 0; i < visitors_.size(); ++i) {
5185 visitors_[i]->set_symmetry_manager_and_index(
this, i);
5193 for (
int i = 0; i < visitors_.size(); ++i) {
5194 const void*
const last = clauses_[i].Last();
5196 if (last != clauses_[i].Last()) {
5198 decisions_[i].Push(solver(), d);
5199 directions_[i].Push(solver(),
false);
5206 for (
int i = 0; i < visitors_.size(); ++i) {
5207 if (decisions_[i].Last() !=
nullptr && decisions_[i].LastValue() == d) {
5220 std::vector<IntVar*> guard;
5225 IntVar*
const term = *tmp;
5227 if (term->
Max() == 0) {
5231 if (term->
Min() == 0) {
5232 DCHECK_EQ(1, term->
Max());
5234 guard.push_back(term);
5240 guard.push_back(clauses_[
index].LastValue());
5241 directions_[
index].SetLastValue(
true);
5246 ct = solver()->MakeEquality(solver()->MakeMin(guard),
Zero());
5248 DCHECK(
ct !=
nullptr);
5249 solver()->AddConstraint(
ct);
5253 clauses_[visitor->index_in_symmetry_manager()].Push(solver(), term);
5256 std::string
DebugString()
const override {
return "SymmetryManager"; }
5259 const std::vector<SymmetryBreaker*> visitors_;
5260 std::vector<SimpleRevFIFO<IntVar*>> clauses_;
5261 std::vector<SimpleRevFIFO<Decision*>> decisions_;
5262 std::vector<SimpleRevFIFO<bool>> directions_;
5269 CHECK(
var !=
nullptr);
5272 symmetry_manager()->AddTermToClause(
this, term);
5277 CHECK(
var !=
nullptr);
5280 symmetry_manager()->AddTermToClause(
this, term);
5285 CHECK(
var !=
nullptr);
5288 symmetry_manager()->AddTermToClause(
this, term);
5294 const std::vector<SymmetryBreaker*>& visitors) {
5299 std::vector<SymmetryBreaker*> visitors;
5300 visitors.push_back(v1);
5301 return MakeSymmetryManager(visitors);
5306 std::vector<SymmetryBreaker*> visitors;
5307 visitors.push_back(v1);
5308 visitors.push_back(v2);
5309 return MakeSymmetryManager(visitors);
5315 std::vector<SymmetryBreaker*> visitors;
5316 visitors.push_back(v1);
5317 visitors.push_back(v2);
5318 visitors.push_back(v3);
5319 return MakeSymmetryManager(visitors);
5326 std::vector<SymmetryBreaker*> visitors;
5327 visitors.push_back(v1);
5328 visitors.push_back(v2);
5329 visitors.push_back(v3);
5330 visitors.push_back(v4);
5331 return MakeSymmetryManager(visitors);
const std::vector< IntVar * > vars_
const E & Element(const V *const var) const
int64_t Value(const IntVar *var) const
int64_t ObjectiveValueFromIndex(int index) const
int64_t ObjectiveMinFromIndex(int index) const
IntVar * Objective() const
int64_t ObjectiveMaxFromIndex(int index) const
int64_t ObjectiveValue() const
bool Get(uint32_t index) const
void Set(uint32_t index, bool value)
void Clear()
Clears all bits in the bitmap.
virtual Decision * Next(Solver *s)=0
virtual void Accept(ModelVisitor *visitor) const
std::string DebugString() const override
-------— Decision Builder -------—
virtual void Accept(DecisionVisitor *visitor) const
Accepts the given visitor.
GuidedLocalSearch(SetCoverInvariant *inv)
bool CheckWithOffset(absl::Duration offset) override
~ImprovementSearchLimit() override
ImprovementSearchLimit(Solver *solver, IntVar *objective_var, bool maximize, double objective_scaling_factor, double objective_offset, double improvement_rate_coefficient, int improvement_rate_solutions_distance)
--— Improvement Search Limit --—
void Init() override
This method is called when the search limit is initialized.
void Install() override
A search monitors adds itself on the active search.
void Copy(const SearchLimit *limit) override
bool AtSolution() override
SearchLimit * MakeClone() const override
Allocates a clone of the limit.
virtual void SetValue(int64_t v)
This method sets the value of the expression.
virtual bool Bound() const
Returns true if the min and the max of the expression are equal.
virtual void SetMax(int64_t m)=0
virtual int64_t Min() const =0
virtual void SetMin(int64_t m)=0
virtual IntVar * Var()=0
Creates a variable from the expression.
virtual int64_t Max() const =0
virtual int64_t Value() const =0
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[]
Base objective monitor class. All metaheuristics derive from this.
bool CurrentInternalValuesAreConstraining() const
IntVar * MinimizationVar(int index) const
const std::vector< IntVar * > & objective_vars() const
void MakeMinimizationVarsLessOrEqualWithSteps(const T &upper_bounds)
int64_t BestInternalValue(int index) const
bool found_initial_solution_
int64_t CurrentInternalValue(int index) const
bool AcceptDelta(Assignment *delta, Assignment *deltadelta) override
IntVar * ObjectiveVar(int index) const
void Accept(ModelVisitor *visitor) const override
Accepts the given model visitor.
int64_t BestValue(int index) const
bool AtSolution() override
int64_t Step(int index) const
ObjectiveMonitor(Solver *solver, const std::vector< bool > &maximize, std::vector< IntVar * > vars, std::vector< int64_t > steps)
-------— Objective Management -------—
bool Maximize(int index) const
void EnterSearch() override
Beginning of the search.
void BeginNextDecision(DecisionBuilder *db) override
Internal methods.
void RefuteDecision(Decision *d) override
Before refuting the decision.
bool AtSolution() override
OptimizeVar(Solver *solver, bool maximize, IntVar *var, int64_t step)
std::string DebugString() const override
bool AcceptSolution() override
virtual std::string Name() const
std::string DebugString() const override
absl::Duration duration_limit() const
SearchLimit * MakeClone() const override
Allocates a clone of the limit.
bool IsUncheckedSolutionLimitReached() override
void Install() override
A search monitors adds itself on the active search.
bool CheckWithOffset(absl::Duration offset) override
int64_t wall_time() const
void Init() override
This method is called when the search limit is initialized.
int64_t solutions() const
int ProgressPercent() override
std::string DebugString() const override
void Accept(ModelVisitor *visitor) const override
Accepts the given model visitor.
void ExitSearch() override
End of the search.
void Copy(const SearchLimit *limit) override
void UpdateLimits(absl::Duration time, int64_t branches, int64_t failures, int64_t solutions)
RegularLimit * MakeIdenticalClone() const
Base class of all search limits.
bool crossed() const
Returns true if the limit has been crossed.
void Install() override
A search monitors adds itself on the active search.
void BeginFail() override
Just when the failure occurs.
void NoMoreSolutions() override
When the search tree is finished.
virtual void OutputLine(const std::string &line)
bool AtSolution() override
void AcceptUncheckedNeighbor() override
After accepting an unchecked neighbor during local search.
SearchLog(Solver *solver, std::vector< IntVar * > vars, std::string vars_name, std::vector< double > scaling_factors, std::vector< double > offsets, std::function< std::string()> display_callback, bool display_on_new_solutions_only, int period)
-------— Search Log ------—
void EndInitialPropagation() override
After the initial propagation.
void BeginInitialPropagation() override
Before the initial propagation.
void RefuteDecision(Decision *decision) override
Before refuting the decision.
void ExitSearch() override
End of the search.
std::string DebugString() const override
void EnterSearch() override
Beginning of the search.
void ApplyDecision(Decision *decision) override
Before applying the decision.
A search monitor is a simple set of callbacks to monitor all search events.
static constexpr int kNoProgress
void ListenToEvent(Solver::MonitorEvent event)
This iterator is not stable with respect to deletion.
int64_t branches(int n) const
Returns the number of branches when the nth solution was found.
SolutionData BuildSolutionDataForCurrentState()
void AddObjectives(const std::vector< IntVar * > &objectives)
const std::vector< int > & ForwardSequence(int n, SequenceVar *var) const
int64_t objective_value(int n) const
Returns the objective value of the nth solution.
~SolutionCollector() override
void Add(IntVar *var)
Add API.
std::vector< std::unique_ptr< Assignment > > solution_pool_
int64_t PerformedValue(int n, IntervalVar *var) const
This is a shortcut to get the PerformedValue of 'var' in the nth solution.
void EnterSearch() override
Beginning of the search.
void FreeSolution(Assignment *solution)
void Push(const SolutionData &data)
void PopSolution()
Remove and delete the last popped solution.
const std::vector< int > & Unperformed(int n, SequenceVar *var) const
void AddObjective(IntVar *objective)
bool has_solution() const
Returns whether any solutions were stored during the search.
void check_index(int n) const
int solution_count() const
Returns how many solutions were stored during the search.
void Install() override
A search monitors adds itself on the active search.
int64_t wall_time(int n) const
Returns the wall time in ms for the nth solution.
void PushSolution()
Push the current state as a new solution.
int64_t DurationValue(int n, IntervalVar *var) const
This is a shortcut to get the DurationValue of 'var' in the nth solution.
int64_t ObjectiveValueFromIndex(int n, int index) const
Returns the value of the index-th objective of the nth solution.
int64_t failures(int n) const
const std::vector< int > & BackwardSequence(int n, SequenceVar *var) const
int64_t StartValue(int n, IntervalVar *var) const
This is a shortcut to get the StartValue of 'var' in the nth solution.
SolutionCollector(Solver *solver, const Assignment *assignment)
-------— Solution Collectors --------—
Assignment * solution(int n) const
Returns the nth solution.
int64_t Value(int n, IntVar *var) const
This is a shortcut to get the Value of 'var' in the nth solution.
std::vector< Assignment * > recycle_solutions_
std::vector< SolutionData > solution_data_
std::unique_ptr< Assignment > prototype_
Assignment * last_solution_or_null() const
Returns the last solution if there are any, nullptr otherwise.
int64_t EndValue(int n, IntervalVar *var) const
This is a shortcut to get the EndValue of 'var' in the nth solution.
For the time being, Solver is neither MT_SAFE nor MT_HOT.
std::function< int64_t(const IntVar *v, int64_t id)> VariableValueSelector
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)
ABSL_MUST_USE_RESULT RegularLimit * MakeFailuresLimit(int64_t failures)
std::function< void(Solver *)> Action
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.
DecisionBuilder * MakePhase(const std::vector< IntVar * > &vars, IntVarStrategy var_str, IntValueStrategy val_str)
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)
IntExpr * MakeOpposite(IntExpr *expr)
-expr
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).
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)
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)
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
std::function< int64_t(int64_t, int64_t, int64_t)> IndexEvaluator3
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)
DecisionBuilder * MakeDecisionBuilderFromAssignment(Assignment *assignment, DecisionBuilder *db, const std::vector< IntVar * > &vars)
int64_t wall_time() const
ABSL_MUST_USE_RESULT RegularLimit * MakeBranchesLimit(int64_t branches)
SearchMonitor * MakeSearchLog(int branch_period)
ObjectiveMonitor * MakeSimulatedAnnealing(bool maximize, IntVar *v, int64_t step, int64_t initial_temperature)
OptimizeVar * MakeMinimize(IntVar *v, int64_t step)
Creates a minimization objective.
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)
std::function< bool(int64_t, int64_t, int64_t)> VariableValueComparator
ConstraintSolverParameters parameters() const
Stored Parameters.
Assignment * GetOrCreateLocalSearchState()
std::function< int64_t(Solver *solver, const std::vector< IntVar * > &vars, int64_t first_unbound, int64_t last_unbound)> VariableIndexSelector
void set_optimization_direction(OptimizationDirection direction)
@ 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)
std::function< int64_t(int64_t)> IndexEvaluator1
Callback typedefs.
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.
std::function< int64_t(int64_t, int64_t)> IndexEvaluator2
IntVar * MakeIntConst(int64_t val, const std::string &name)
IntConst will create a constant expression.
static int64_t MemoryUsage()
Current memory usage in bytes.
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)
void AddIntegerVariableGreaterOrEqualValueClause(IntVar *var, int64_t value)
void AddIntegerVariableLessOrEqualValueClause(IntVar *var, int64_t value)
void AddIntegerVariableEqualValueClause(IntVar *var, int64_t value)
--— Symmetry Breaker --—
-------— Symmetry Breaking -------—
void EndNextDecision(DecisionBuilder *const, Decision *const d) override
After calling DecisionBuilder::Next, along with the returned decision.
void CheckSymmetries(int index)
void RefuteDecision(Decision *d) override
Before refuting the decision.
void AddTermToClause(SymmetryBreaker *const visitor, IntVar *const term)
~SymmetryManager() override
SymmetryManager(Solver *const s, const std::vector< SymmetryBreaker * > &visitors)
std::string DebugString() const override
CpModelProto proto
The output proto.
const std::string name
A name for logging purposes.
const MapUtilMappedT< Collection > & FindWithDefault(const Collection &collection, const KeyType &key, const MapUtilMappedT< Collection > &value)
For infeasible and unbounded see Not checked if options check_solutions_if_inf_or_unbounded and the If options first_solution_only is false
problem is infeasible or unbounded (default).
H AbslHashValue(H h, const IndicatorConstraint &constraint)
std::function< int64_t(const Model &)> Value(IntegerVariable v)
This checks that the variable is fixed.
In SWIG mode, we don't want anything besides these top-level includes.
LinearRange operator==(const LinearExpr &lhs, const LinearExpr &rhs)
int64_t CapAdd(int64_t x, int64_t y)
std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)
Join v[i]->DebugString().
void AcceptNeighbor(Search *search)
Notifies the search that a neighbor has been accepted by local search.
int64_t CapSub(int64_t x, int64_t y)
std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)
--— Vector manipulations --—
BaseAssignVariables::Mode ChooseMode(Solver::IntValueStrategy val_str)
int64_t CapOpp(int64_t v)
Note(user): -kint64min != kint64max, but kint64max == ~kint64min.
bool AcceptDelta(Search *search, Assignment *delta, Assignment *deltadelta)
int64_t assignment_penalized_value_
const double penalty_factor_
std::vector< DecisionBuilder * > builders_
std::vector< int > var_index_to_local_index_
DirtyArray< int64_t > penalized_values_
const bool reset_penalties_on_new_best_solution_
ABSL_FLAG(bool, cp_use_sparse_gls_penalties, false, "Use sparse implementation to store Guided Local Search penalties")
IntVar * penalized_objective_
std::vector< IntVar * > vars_
Rev< int64_t > first_unbound_
Rev< int64_t > last_unbound_
std::function< int64_t(int64_t, int64_t)> evaluator_
int64_t old_penalized_value_
int64_t ObjectiveValue() const
bool operator<(const SolutionData &other) const
int64_t ObjectiveValueFromIndex(int index) const
Creates a search monitor from logging parameters.
double objective_value
The value objective_vector^T * (solution - center_point).
static const int64_t kint64max