25 #include "absl/base/casts.h"
26 #include "absl/container/flat_hash_map.h"
27 #include "absl/memory/memory.h"
28 #include "absl/strings/str_cat.h"
29 #include "absl/strings/str_format.h"
30 #include "absl/strings/str_join.h"
31 #include "absl/time/time.h"
48 "Use sparse implementation to store Guided Local Search penalties");
50 "Whether search related logging should be "
52 ABSL_FLAG(int64_t, cp_large_domain_no_splitting_limit, 0xFFFFF,
53 "Size limit to allow holes in variables from the strategy.");
59 double scaling_factor,
double offset,
60 std::function<std::string()> display_callback,
61 bool display_on_new_solutions_only,
int period)
67 scaling_factor_(scaling_factor),
69 display_callback_(std::move(display_callback)),
70 display_on_new_solutions_only_(display_on_new_solutions_only),
73 objective_min_(std::numeric_limits<int64_t>::
max()),
74 objective_max_(std::numeric_limits<int64_t>::
min()),
75 min_right_depth_(std::numeric_limits<int32_t>::
max()),
77 sliding_min_depth_(0),
78 sliding_max_depth_(0) {
79 CHECK(obj ==
nullptr ||
var ==
nullptr)
80 <<
"Either var or obj need to be nullptr.";
88 const std::string buffer =
89 absl::StrFormat(
"Start search (%s)", MemoryUsage());
97 int64_t ms = timer_->GetInMs();
101 const std::string buffer = absl::StrFormat(
102 "End search (time = %d ms, branches = %d, failures = %d, %s, speed = %d "
104 ms, branches,
solver()->failures(), MemoryUsage(), branches * 1000 / ms);
111 std::string obj_str =
"";
113 bool objective_updated =
false;
114 const auto scaled_str = [
this](int64_t
value) {
115 if (scaling_factor_ != 1.0 || offset_ != 0.0) {
116 return absl::StrFormat(
"%d (%.8lf)",
value,
117 scaling_factor_ * (
value + offset_));
119 return absl::StrCat(
value);
122 if (obj_ !=
nullptr && obj_->
Var()->
Bound()) {
124 obj_str = obj_->
Print();
125 objective_updated =
true;
126 }
else if (var_ !=
nullptr && var_->
Bound()) {
127 current = var_->
Value();
128 absl::StrAppend(&obj_str, scaled_str(current),
", ");
129 objective_updated =
true;
132 absl::StrAppend(&obj_str, scaled_str(current),
", ");
133 objective_updated =
true;
135 if (objective_updated) {
136 if (current > objective_min_) {
137 absl::StrAppend(&obj_str,
138 "objective minimum = ", scaled_str(objective_min_),
", ");
140 objective_min_ = current;
142 if (current < objective_max_) {
143 absl::StrAppend(&obj_str,
144 "objective maximum = ", scaled_str(objective_max_),
", ");
146 objective_max_ = current;
150 absl::StrAppendFormat(&log,
151 "Solution #%d (%stime = %d ms, branches = %d,"
152 " failures = %d, depth = %d",
153 nsol_++, obj_str, timer_->GetInMs(),
155 if (!
solver()->SearchContext().empty()) {
156 absl::StrAppendFormat(&log,
", %s",
solver()->SearchContext());
158 if (
solver()->neighbors() != 0) {
159 absl::StrAppendFormat(&log,
160 ", neighbors = %d, filtered neighbors = %d,"
161 " accepted neighbors = %d",
163 solver()->accepted_neighbors());
165 absl::StrAppendFormat(&log,
", %s", MemoryUsage());
168 absl::StrAppendFormat(&log,
", limit = %d%%", progress);
170 if (display_callback_) {
171 absl::StrAppendFormat(&log,
", %s", display_callback_());
183 std::string buffer = absl::StrFormat(
184 "Finished search tree (time = %d ms, branches = %d,"
186 timer_->GetInMs(),
solver()->branches(),
solver()->failures());
187 if (
solver()->neighbors() != 0) {
188 absl::StrAppendFormat(&buffer,
189 ", neighbors = %d, filtered neighbors = %d,"
190 " accepted neigbors = %d",
192 solver()->accepted_neighbors());
194 absl::StrAppendFormat(&buffer,
", %s", MemoryUsage());
195 if (!display_on_new_solutions_only_ && display_callback_) {
196 absl::StrAppendFormat(&buffer,
", %s", display_callback_());
205 if (
b % period_ == 0 &&
b > 0) {
211 min_right_depth_ =
std::min(min_right_depth_,
solver()->SearchDepth());
217 absl::StrFormat(
"%d branches, %d ms, %d failures",
solver()->branches(),
218 timer_->GetInMs(),
solver()->failures());
222 absl::StrAppendFormat(&buffer,
", tree pos=%d/%d/%d minref=%d max=%d",
223 sliding_min_depth_, depth, sliding_max_depth_,
224 min_right_depth_, max_depth_);
225 sliding_min_depth_ = depth;
226 sliding_max_depth_ = depth;
228 if (obj_ !=
nullptr &&
231 absl::StrAppendFormat(&buffer,
232 ", objective minimum = %d"
233 ", objective maximum = %d",
234 objective_min_, objective_max_);
238 absl::StrAppendFormat(&buffer,
", limit = %d%%", progress);
245 sliding_min_depth_ =
std::min(current_depth, sliding_min_depth_);
246 sliding_max_depth_ =
std::max(current_depth, sliding_max_depth_);
247 max_depth_ =
std::max(current_depth, max_depth_);
253 const int64_t
delta = std::max<int64_t>(timer_->GetInMs() - tick_, 0);
254 const std::string buffer = absl::StrFormat(
255 "Root node processed (time = %d ms, constraints = %d, %s)",
delta,
256 solver()->constraints(), MemoryUsage());
261 if (absl::GetFlag(FLAGS_cp_log_to_vlog)) {
268 std::string SearchLog::MemoryUsage() {
269 static const int64_t kDisplayThreshold = 2;
270 static const int64_t kKiloByte = 1024;
271 static const int64_t kMegaByte = kKiloByte * kKiloByte;
272 static const int64_t kGigaByte = kMegaByte * kKiloByte;
274 if (memory_usage > kDisplayThreshold * kGigaByte) {
275 return absl::StrFormat(
"memory used = %.2lf GB",
276 memory_usage * 1.0 / kGigaByte);
277 }
else if (memory_usage > kDisplayThreshold * kMegaByte) {
278 return absl::StrFormat(
"memory used = %.2lf MB",
279 memory_usage * 1.0 / kMegaByte);
280 }
else if (memory_usage > kDisplayThreshold * kKiloByte) {
281 return absl::StrFormat(
"memory used = %2lf KB",
282 memory_usage * 1.0 / kKiloByte);
284 return absl::StrFormat(
"memory used = %d", memory_usage);
297 int branch_period, std::function<std::string()> display_callback) {
299 std::move(display_callback));
304 std::function<std::string()> display_callback) {
306 std::move(display_callback),
true,
317 std::function<std::string()> display_callback) {
319 std::move(display_callback),
true,
335 SearchTrace(
Solver*
const s,
const std::string& prefix)
337 ~SearchTrace()
override {}
339 void EnterSearch()
override {
340 LOG(
INFO) << prefix_ <<
" EnterSearch(" << solver()->SolveDepth() <<
")";
342 void RestartSearch()
override {
343 LOG(
INFO) << prefix_ <<
" RestartSearch(" << solver()->SolveDepth() <<
")";
345 void ExitSearch()
override {
346 LOG(
INFO) << prefix_ <<
" ExitSearch(" << solver()->SolveDepth() <<
")";
348 void BeginNextDecision(DecisionBuilder*
const b)
override {
349 LOG(
INFO) << prefix_ <<
" BeginNextDecision(" <<
b <<
") ";
351 void EndNextDecision(DecisionBuilder*
const b, Decision*
const d)
override {
353 LOG(
INFO) << prefix_ <<
" EndNextDecision(" <<
b <<
", " << d <<
") ";
355 LOG(
INFO) << prefix_ <<
" EndNextDecision(" <<
b <<
") ";
358 void ApplyDecision(Decision*
const d)
override {
359 LOG(
INFO) << prefix_ <<
" ApplyDecision(" << d <<
") ";
361 void RefuteDecision(Decision*
const d)
override {
362 LOG(
INFO) << prefix_ <<
" RefuteDecision(" << d <<
") ";
364 void AfterDecision(Decision*
const d,
bool apply)
override {
365 LOG(
INFO) << prefix_ <<
" AfterDecision(" << d <<
", " << apply <<
") ";
367 void BeginFail()
override {
368 LOG(
INFO) << prefix_ <<
" BeginFail(" << solver()->SearchDepth() <<
")";
370 void EndFail()
override {
371 LOG(
INFO) << prefix_ <<
" EndFail(" << solver()->SearchDepth() <<
")";
373 void BeginInitialPropagation()
override {
374 LOG(
INFO) << prefix_ <<
" BeginInitialPropagation()";
376 void EndInitialPropagation()
override {
377 LOG(
INFO) << prefix_ <<
" EndInitialPropagation()";
379 bool AtSolution()
override {
380 LOG(
INFO) << prefix_ <<
" AtSolution()";
383 bool AcceptSolution()
override {
384 LOG(
INFO) << prefix_ <<
" AcceptSolution()";
387 void NoMoreSolutions()
override {
388 LOG(
INFO) << prefix_ <<
" NoMoreSolutions()";
391 std::string DebugString()
const override {
return "SearchTrace"; }
394 const std::string prefix_;
399 return RevAlloc(
new SearchTrace(
this, prefix));
406 AtSolutionCallback(
Solver*
const solver, std::function<
void()>
callback)
408 ~AtSolutionCallback()
override {}
409 bool AtSolution()
override;
412 const std::function<void()> callback_;
415 bool AtSolutionCallback::AtSolution() {
429 EnterSearchCallback(
Solver*
const solver, std::function<
void()>
callback)
431 ~EnterSearchCallback()
override {}
432 void EnterSearch()
override;
435 const std::function<void()> callback_;
438 void EnterSearchCallback::EnterSearch() { callback_(); }
449 ExitSearchCallback(
Solver*
const solver, std::function<
void()>
callback)
451 ~ExitSearchCallback()
override {}
452 void ExitSearch()
override;
455 const std::function<void()> callback_;
458 void ExitSearchCallback::ExitSearch() { callback_(); }
471 CompositeDecisionBuilder();
472 explicit CompositeDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs);
473 ~CompositeDecisionBuilder()
override;
475 void AppendMonitors(
Solver*
const solver,
476 std::vector<SearchMonitor*>*
const monitors)
override;
477 void Accept(
ModelVisitor*
const visitor)
const override;
483 CompositeDecisionBuilder::CompositeDecisionBuilder() {}
485 CompositeDecisionBuilder::CompositeDecisionBuilder(
486 const std::vector<DecisionBuilder*>& dbs) {
487 for (
int i = 0; i < dbs.size(); ++i) {
492 CompositeDecisionBuilder::~CompositeDecisionBuilder() {}
494 void CompositeDecisionBuilder::Add(DecisionBuilder*
const db) {
500 void CompositeDecisionBuilder::AppendMonitors(
501 Solver*
const solver, std::vector<SearchMonitor*>*
const monitors) {
502 for (DecisionBuilder*
const db :
builders_) {
503 db->AppendMonitors(solver, monitors);
507 void CompositeDecisionBuilder::Accept(ModelVisitor*
const visitor)
const {
508 for (DecisionBuilder*
const db :
builders_) {
517 class ComposeDecisionBuilder :
public CompositeDecisionBuilder {
519 ComposeDecisionBuilder();
520 explicit ComposeDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs);
521 ~ComposeDecisionBuilder()
override;
522 Decision* Next(Solver*
const s)
override;
523 std::string DebugString()
const override;
529 ComposeDecisionBuilder::ComposeDecisionBuilder() : start_index_(0) {}
531 ComposeDecisionBuilder::ComposeDecisionBuilder(
532 const std::vector<DecisionBuilder*>& dbs)
533 : CompositeDecisionBuilder(dbs), start_index_(0) {}
535 ComposeDecisionBuilder::~ComposeDecisionBuilder() {}
537 Decision* ComposeDecisionBuilder::Next(Solver*
const s) {
539 for (
int i = start_index_; i < size; ++i) {
542 s->SaveAndSetValue(&start_index_, i);
546 s->SaveAndSetValue(&start_index_, size);
550 std::string ComposeDecisionBuilder::DebugString()
const {
551 return absl::StrFormat(
"ComposeDecisionBuilder(%s)",
558 ComposeDecisionBuilder* c = RevAlloc(
new ComposeDecisionBuilder());
567 ComposeDecisionBuilder* c = RevAlloc(
new ComposeDecisionBuilder());
578 ComposeDecisionBuilder* c = RevAlloc(
new ComposeDecisionBuilder());
587 if (dbs.size() == 1) {
590 return RevAlloc(
new ComposeDecisionBuilder(dbs));
596 class ClosureDecision :
public Decision {
599 : apply_(std::move(apply)), refute_(std::move(refute)) {}
600 ~ClosureDecision()
override {}
602 void Apply(Solver*
const s)
override { apply_(s); }
604 void Refute(Solver*
const s)
override { refute_(s); }
606 std::string
DebugString()
const override {
return "ClosureDecision"; }
609 Solver::Action apply_;
610 Solver::Action refute_;
615 return RevAlloc(
new ClosureDecision(std::move(apply), std::move(refute)));
622 class TryDecisionBuilder;
624 class TryDecision :
public Decision {
626 explicit TryDecision(TryDecisionBuilder*
const try_builder);
627 ~TryDecision()
override;
630 std::string
DebugString()
const override {
return "TryDecision"; }
633 TryDecisionBuilder*
const try_builder_;
636 class TryDecisionBuilder :
public CompositeDecisionBuilder {
638 TryDecisionBuilder();
639 explicit TryDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs);
640 ~TryDecisionBuilder()
override;
641 Decision* Next(Solver*
const solver)
override;
642 std::string DebugString()
const override;
643 void AdvanceToNextBuilder(Solver*
const solver);
646 TryDecision try_decision_;
647 int current_builder_;
648 bool start_new_builder_;
651 TryDecision::TryDecision(TryDecisionBuilder*
const try_builder)
652 : try_builder_(try_builder) {}
654 TryDecision::~TryDecision() {}
656 void TryDecision::Apply(Solver*
const solver) {}
658 void TryDecision::Refute(Solver*
const solver) {
659 try_builder_->AdvanceToNextBuilder(solver);
662 TryDecisionBuilder::TryDecisionBuilder()
663 : CompositeDecisionBuilder(),
665 current_builder_(-1),
666 start_new_builder_(true) {}
668 TryDecisionBuilder::TryDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs)
669 : CompositeDecisionBuilder(dbs),
671 current_builder_(-1),
672 start_new_builder_(true) {}
674 TryDecisionBuilder::~TryDecisionBuilder() {}
676 Decision* TryDecisionBuilder::Next(Solver*
const solver) {
677 if (current_builder_ < 0) {
678 solver->SaveAndSetValue(¤t_builder_, 0);
679 start_new_builder_ =
true;
681 if (start_new_builder_) {
682 start_new_builder_ =
false;
683 return &try_decision_;
685 return builders_[current_builder_]->Next(solver);
689 std::string TryDecisionBuilder::DebugString()
const {
690 return absl::StrFormat(
"TryDecisionBuilder(%s)",
694 void TryDecisionBuilder::AdvanceToNextBuilder(Solver*
const solver) {
696 start_new_builder_ =
true;
697 if (current_builder_ >=
builders_.size()) {
706 TryDecisionBuilder* try_db =
RevAlloc(
new TryDecisionBuilder());
715 TryDecisionBuilder* try_db =
RevAlloc(
new TryDecisionBuilder());
726 TryDecisionBuilder* try_db =
RevAlloc(
new TryDecisionBuilder());
735 return RevAlloc(
new TryDecisionBuilder(dbs));
743 class BaseVariableAssignmentSelector :
public BaseObject {
745 BaseVariableAssignmentSelector(
Solver* solver,
746 const std::vector<IntVar*>& vars)
752 ~BaseVariableAssignmentSelector()
override {}
754 virtual int64_t SelectValue(
const IntVar* v, int64_t
id) = 0;
757 virtual int64_t ChooseVariable() = 0;
759 int64_t ChooseVariableWrapper() {
762 if (!
vars_[i]->Bound()) {
771 if (!
vars_[i]->Bound()) {
776 return ChooseVariable();
779 void Accept(ModelVisitor*
const visitor)
const {
786 const std::vector<IntVar*>& vars()
const {
return vars_; }
797 int64_t ChooseFirstUnbound(Solver* solver,
const std::vector<IntVar*>& vars,
798 int64_t first_unbound, int64_t last_unbound) {
799 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
800 if (!vars[i]->Bound()) {
809 int64_t ChooseMinSizeLowestMin(Solver* solver,
const std::vector<IntVar*>& vars,
810 int64_t first_unbound, int64_t last_unbound) {
813 int64_t best_index = -1;
814 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
815 IntVar*
const var = vars[i];
817 if (
var->Size() < best_size ||
818 (
var->Size() == best_size &&
var->Min() < best_min)) {
819 best_size =
var->Size();
820 best_min =
var->Min();
830 int64_t ChooseMinSizeHighestMin(Solver* solver,
831 const std::vector<IntVar*>& vars,
832 int64_t first_unbound, int64_t last_unbound) {
835 int64_t best_index = -1;
836 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
837 IntVar*
const var = vars[i];
839 if (
var->Size() < best_size ||
840 (
var->Size() == best_size &&
var->Min() > best_min)) {
841 best_size =
var->Size();
842 best_min =
var->Min();
852 int64_t ChooseMinSizeLowestMax(Solver* solver,
const std::vector<IntVar*>& vars,
853 int64_t first_unbound, int64_t last_unbound) {
856 int64_t best_index = -1;
857 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
858 IntVar*
const var = vars[i];
860 if (
var->Size() < best_size ||
861 (
var->Size() == best_size &&
var->Max() < best_max)) {
862 best_size =
var->Size();
863 best_max =
var->Max();
873 int64_t ChooseMinSizeHighestMax(Solver* solver,
874 const std::vector<IntVar*>& vars,
875 int64_t first_unbound, int64_t last_unbound) {
878 int64_t best_index = -1;
879 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
880 IntVar*
const var = vars[i];
882 if (
var->Size() < best_size ||
883 (
var->Size() == best_size &&
var->Max() > best_max)) {
884 best_size =
var->Size();
885 best_max =
var->Max();
895 int64_t ChooseLowestMin(Solver* solver,
const std::vector<IntVar*>& vars,
896 int64_t first_unbound, int64_t last_unbound) {
898 int64_t best_index = -1;
899 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
900 IntVar*
const var = vars[i];
902 if (
var->Min() < best_min) {
903 best_min =
var->Min();
913 int64_t ChooseHighestMax(Solver* solver,
const std::vector<IntVar*>& vars,
914 int64_t first_unbound, int64_t last_unbound) {
916 int64_t best_index = -1;
917 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
918 IntVar*
const var = vars[i];
920 if (
var->Max() > best_max) {
921 best_max =
var->Max();
931 int64_t ChooseMinSize(Solver* solver,
const std::vector<IntVar*>& vars,
932 int64_t first_unbound, int64_t last_unbound) {
934 int64_t best_index = -1;
935 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
936 IntVar*
const var = vars[i];
938 if (
var->Size() < best_size) {
939 best_size =
var->Size();
949 int64_t ChooseMaxSize(Solver* solver,
const std::vector<IntVar*>& vars,
950 int64_t first_unbound, int64_t last_unbound) {
951 uint64_t best_size = 0;
952 int64_t best_index = -1;
953 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
954 IntVar*
const var = vars[i];
956 if (
var->Size() > best_size) {
957 best_size =
var->Size();
967 class HighestRegretSelectorOnMin :
public BaseObject {
969 explicit HighestRegretSelectorOnMin(
const std::vector<IntVar*>& vars)
971 for (int64_t i = 0; i < vars.size(); ++i) {
972 iterators_[i] = vars[i]->MakeDomainIterator(
true);
975 ~HighestRegretSelectorOnMin()
override {}
976 int64_t Choose(Solver*
const s,
const std::vector<IntVar*>& vars,
977 int64_t first_unbound, int64_t last_unbound);
978 std::string DebugString()
const override {
return "MaxRegretSelector"; }
980 int64_t ComputeRegret(IntVar*
var, int64_t
index)
const {
982 const int64_t vmin =
var->Min();
986 return iterator->Value() - vmin;
993 int64_t HighestRegretSelectorOnMin::Choose(Solver*
const s,
994 const std::vector<IntVar*>& vars,
995 int64_t first_unbound,
996 int64_t last_unbound) {
997 int64_t best_regret = 0;
999 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
1000 IntVar*
const var = vars[i];
1001 if (!
var->Bound()) {
1002 const int64_t regret = ComputeRegret(
var, i);
1003 if (regret > best_regret) {
1004 best_regret = regret;
1014 int64_t ChooseRandom(Solver* solver,
const std::vector<IntVar*>& vars,
1015 int64_t first_unbound, int64_t last_unbound) {
1016 const int64_t span = last_unbound - first_unbound + 1;
1017 const int64_t shift = solver->Rand32(span);
1018 for (int64_t i = 0; i < span; ++i) {
1019 const int64_t
index = (i + shift) % span + first_unbound;
1020 if (!vars[
index]->Bound()) {
1029 class CheapestVarSelector :
public BaseObject {
1031 explicit CheapestVarSelector(std::function<int64_t(int64_t)> var_evaluator)
1032 : var_evaluator_(std::move(var_evaluator)) {}
1033 ~CheapestVarSelector()
override {}
1034 int64_t Choose(Solver*
const s,
const std::vector<IntVar*>& vars,
1035 int64_t first_unbound, int64_t last_unbound);
1036 std::string DebugString()
const override {
return "CheapestVarSelector"; }
1039 std::function<int64_t(int64_t)> var_evaluator_;
1042 int64_t CheapestVarSelector::Choose(Solver*
const s,
1043 const std::vector<IntVar*>& vars,
1044 int64_t first_unbound,
1045 int64_t last_unbound) {
1048 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
1049 if (!vars[i]->Bound()) {
1050 const int64_t eval = var_evaluator_(i);
1051 if (eval < best_eval) {
1063 class PathSelector :
public BaseObject {
1065 PathSelector() : first_(std::numeric_limits<int64_t>::
max()) {}
1066 ~PathSelector()
override {}
1067 int64_t Choose(Solver*
const s,
const std::vector<IntVar*>& vars,
1068 int64_t first_unbound, int64_t last_unbound);
1069 std::string DebugString()
const override {
return "ChooseNextOnPath"; }
1072 bool UpdateIndex(
const std::vector<IntVar*>& vars, int64_t*
index)
const;
1073 bool FindPathStart(
const std::vector<IntVar*>& vars, int64_t*
index)
const;
1075 Rev<int64_t> first_;
1078 int64_t PathSelector::Choose(Solver*
const s,
const std::vector<IntVar*>& vars,
1079 int64_t first_unbound, int64_t last_unbound) {
1080 int64_t
index = first_.Value();
1081 if (!UpdateIndex(vars, &
index)) {
1085 while (vars[
index]->Bound()) {
1087 if (!UpdateIndex(vars, &
index)) {
1091 if (count >= vars.size() &&
1092 !FindPathStart(vars, &
index)) {
1096 first_.SetValue(s,
index);
1100 bool PathSelector::UpdateIndex(
const std::vector<IntVar*>& vars,
1101 int64_t*
index)
const {
1102 if (*
index >= vars.size()) {
1103 if (!FindPathStart(vars,
index)) {
1116 bool PathSelector::FindPathStart(
const std::vector<IntVar*>& vars,
1117 int64_t*
index)
const {
1119 for (int64_t i = vars.size() - 1; i >= 0; --i) {
1120 if (vars[i]->Bound()) {
1121 const int64_t
next = vars[i]->Value();
1122 if (
next < vars.size() && !vars[
next]->Bound()) {
1129 for (int64_t i = vars.size() - 1; i >= 0; --i) {
1130 if (!vars[i]->Bound()) {
1131 bool has_possible_prev =
false;
1132 for (int64_t j = 0; j < vars.size(); ++j) {
1133 if (vars[j]->Contains(i)) {
1134 has_possible_prev =
true;
1138 if (!has_possible_prev) {
1145 for (int64_t i = 0; i < vars.size(); ++i) {
1146 if (!vars[i]->Bound()) {
1156 int64_t SelectMinValue(
const IntVar* v, int64_t
id) {
return v->Min(); }
1160 int64_t SelectMaxValue(
const IntVar* v, int64_t
id) {
return v->Max(); }
1164 int64_t SelectRandomValue(
const IntVar* v, int64_t
id) {
1165 const uint64_t span = v->Max() - v->Min() + 1;
1166 if (span > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {
1170 const uint64_t size = v->Size();
1171 Solver*
const s = v->solver();
1172 if (size > span / 4) {
1175 const int64_t
value = v->Min() + s->Rand64(span);
1176 if (v->Contains(
value)) {
1181 int64_t
index = s->Rand64(size);
1182 if (
index <= size / 2) {
1183 for (int64_t i = v->Min(); i <= v->Max(); ++i) {
1184 if (v->Contains(i)) {
1192 for (int64_t i = v->Max(); i > v->Min(); --i) {
1193 if (v->Contains(i)) {
1207 int64_t SelectCenterValue(
const IntVar* v, int64_t
id) {
1208 const int64_t vmin = v->Min();
1209 const int64_t vmax = v->Max();
1210 if (vmax - vmin > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {
1214 const int64_t mid = (vmin + vmax) / 2;
1215 if (v->Contains(mid)) {
1218 const int64_t diameter = vmax - mid;
1219 for (int64_t i = 1; i <= diameter; ++i) {
1220 if (v->Contains(mid - i)) {
1223 if (v->Contains(mid + i)) {
1232 int64_t SelectSplitValue(
const IntVar* v, int64_t
id) {
1233 const int64_t vmin = v->Min();
1234 const int64_t vmax = v->Max();
1235 const uint64_t
delta = vmax - vmin;
1236 const int64_t mid = vmin +
delta / 2;
1242 class CheapestValueSelector :
public BaseObject {
1244 CheapestValueSelector(std::function<int64_t(int64_t, int64_t)> eval,
1245 std::function<int64_t(int64_t)> tie_breaker)
1246 : eval_(std::move(eval)), tie_breaker_(std::move(tie_breaker)) {}
1247 ~CheapestValueSelector()
override {}
1248 int64_t Select(
const IntVar* v, int64_t
id);
1249 std::string DebugString()
const override {
return "CheapestValue"; }
1252 std::function<int64_t(int64_t, int64_t)> eval_;
1253 std::function<int64_t(int64_t)> tie_breaker_;
1254 std::vector<int64_t> cache_;
1257 int64_t CheapestValueSelector::Select(
const IntVar* v, int64_t
id) {
1260 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(
false));
1261 for (
const int64_t i : InitAndGetValues(it.get())) {
1262 int64_t eval = eval_(
id, i);
1266 cache_.push_back(i);
1267 }
else if (eval == best) {
1268 cache_.push_back(i);
1272 if (tie_breaker_ ==
nullptr || cache_.size() == 1) {
1273 return cache_.back();
1275 return cache_[tie_breaker_(cache_.size())];
1287 class BestValueByComparisonSelector :
public BaseObject {
1289 explicit BestValueByComparisonSelector(
1291 : comparator_(std::move(comparator)) {}
1292 ~BestValueByComparisonSelector()
override {}
1293 int64_t Select(
const IntVar* v, int64_t
id);
1294 std::string DebugString()
const override {
1295 return "BestValueByComparisonSelector";
1302 int64_t BestValueByComparisonSelector::Select(
const IntVar* v, int64_t
id) {
1303 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(
false));
1306 int64_t best_value = it->Value();
1307 for (it->Next(); it->Ok(); it->Next()) {
1308 const int64_t candidate_value = it->Value();
1309 if (comparator_(
id, candidate_value, best_value)) {
1310 best_value = candidate_value;
1318 class VariableAssignmentSelector :
public BaseVariableAssignmentSelector {
1320 VariableAssignmentSelector(Solver* solver,
const std::vector<IntVar*>& vars,
1323 const std::string&
name)
1324 : BaseVariableAssignmentSelector(solver, vars),
1325 var_selector_(std::move(var_selector)),
1326 value_selector_(std::move(value_selector)),
1328 ~VariableAssignmentSelector()
override {}
1329 int64_t SelectValue(
const IntVar*
var, int64_t
id)
override {
1330 return value_selector_(
var,
id);
1332 int64_t ChooseVariable()
override {
1336 std::string DebugString()
const override;
1341 const std::string name_;
1344 std::string VariableAssignmentSelector::DebugString()
const {
1350 class BaseEvaluatorSelector :
public BaseVariableAssignmentSelector {
1352 BaseEvaluatorSelector(Solver* solver,
const std::vector<IntVar*>& vars,
1353 std::function<int64_t(int64_t, int64_t)> evaluator);
1354 ~BaseEvaluatorSelector()
override {}
1359 Element(int64_t i, int64_t j) :
var(i),
value(j) {}
1364 std::string DebugStringInternal(
const std::string&
name)
const {
1371 BaseEvaluatorSelector::BaseEvaluatorSelector(
1372 Solver* solver,
const std::vector<IntVar*>& vars,
1373 std::function<int64_t(int64_t, int64_t)> evaluator)
1374 : BaseVariableAssignmentSelector(solver, vars),
1379 class DynamicEvaluatorSelector :
public BaseEvaluatorSelector {
1381 DynamicEvaluatorSelector(Solver* solver,
const std::vector<IntVar*>& vars,
1382 std::function<int64_t(int64_t, int64_t)> evaluator,
1383 std::function<int64_t(int64_t)> tie_breaker);
1384 ~DynamicEvaluatorSelector()
override {}
1385 int64_t SelectValue(
const IntVar*
var, int64_t
id)
override;
1386 int64_t ChooseVariable()
override;
1387 std::string DebugString()
const override;
1391 std::function<int64_t(int64_t)> tie_breaker_;
1392 std::vector<Element> cache_;
1395 DynamicEvaluatorSelector::DynamicEvaluatorSelector(
1396 Solver* solver,
const std::vector<IntVar*>& vars,
1397 std::function<int64_t(int64_t, int64_t)> evaluator,
1398 std::function<int64_t(int64_t)> tie_breaker)
1399 : BaseEvaluatorSelector(solver, vars, std::move(evaluator)),
1401 tie_breaker_(std::move(tie_breaker)) {}
1403 int64_t DynamicEvaluatorSelector::SelectValue(
const IntVar*
var, int64_t
id) {
1404 return cache_[first_].value;
1407 int64_t DynamicEvaluatorSelector::ChooseVariable() {
1410 for (int64_t i = 0; i <
vars_.size(); ++i) {
1411 const IntVar*
const var =
vars_[i];
1412 if (!
var->Bound()) {
1413 std::unique_ptr<IntVarIterator> it(
var->MakeDomainIterator(
false));
1414 for (
const int64_t j : InitAndGetValues(it.get())) {
1416 if (
value < best_evaluation) {
1417 best_evaluation =
value;
1419 cache_.push_back(Element(i, j));
1420 }
else if (
value == best_evaluation && tie_breaker_) {
1421 cache_.push_back(Element(i, j));
1427 if (cache_.empty()) {
1431 if (tie_breaker_ ==
nullptr || cache_.size() == 1) {
1433 return cache_.front().var;
1435 first_ = tie_breaker_(cache_.size());
1436 return cache_[first_].var;
1440 std::string DynamicEvaluatorSelector::DebugString()
const {
1441 return DebugStringInternal(
"AssignVariablesOnDynamicEvaluator");
1446 class StaticEvaluatorSelector :
public BaseEvaluatorSelector {
1448 StaticEvaluatorSelector(
1449 Solver* solver,
const std::vector<IntVar*>& vars,
1450 const std::function<int64_t(int64_t, int64_t)>& evaluator);
1451 ~StaticEvaluatorSelector()
override {}
1452 int64_t SelectValue(
const IntVar*
var, int64_t
id)
override;
1453 int64_t ChooseVariable()
override;
1454 std::string DebugString()
const override;
1459 explicit Compare(std::function<int64_t(int64_t, int64_t)> evaluator)
1461 bool operator()(
const Element& lhs,
const Element& rhs)
const {
1462 const int64_t value_lhs =
Value(lhs);
1463 const int64_t value_rhs =
Value(rhs);
1464 return value_lhs < value_rhs ||
1465 (value_lhs == value_rhs &&
1466 (lhs.var < rhs.var ||
1467 (lhs.var == rhs.var && lhs.value < rhs.value)));
1469 int64_t
Value(
const Element& element)
const {
1470 return evaluator_(element.var, element.value);
1474 std::function<int64_t(int64_t, int64_t)>
evaluator_;
1478 std::vector<Element> elements_;
1482 StaticEvaluatorSelector::StaticEvaluatorSelector(
1483 Solver* solver,
const std::vector<IntVar*>& vars,
1484 const std::function<int64_t(int64_t, int64_t)>& evaluator)
1485 : BaseEvaluatorSelector(solver, vars, evaluator),
1489 int64_t StaticEvaluatorSelector::SelectValue(
const IntVar*
var, int64_t
id) {
1490 return elements_[first_].value;
1493 int64_t StaticEvaluatorSelector::ChooseVariable() {
1496 int64_t element_size = 0;
1497 for (int64_t i = 0; i <
vars_.size(); ++i) {
1498 if (!
vars_[i]->Bound()) {
1499 element_size +=
vars_[i]->Size();
1502 elements_.resize(element_size);
1504 for (
int i = 0; i <
vars_.size(); ++i) {
1505 const IntVar*
const var =
vars_[i];
1506 if (!
var->Bound()) {
1507 std::unique_ptr<IntVarIterator> it(
var->MakeDomainIterator(
false));
1508 for (
const int64_t
value : InitAndGetValues(it.get())) {
1509 elements_[count++] = Element(i,
value);
1514 std::sort(elements_.begin(), elements_.end(), comp_);
1515 solver_->SaveAndSetValue<int64_t>(&first_, 0);
1517 for (int64_t i = first_; i < elements_.size(); ++i) {
1518 const Element& element = elements_[i];
1519 IntVar*
const var =
vars_[element.var];
1520 if (!
var->Bound() &&
var->Contains(element.value)) {
1521 solver_->SaveAndSetValue(&first_, i);
1525 solver_->SaveAndSetValue(&first_,
static_cast<int64_t
>(elements_.size()));
1529 std::string StaticEvaluatorSelector::DebugString()
const {
1530 return DebugStringInternal(
"AssignVariablesOnStaticEvaluator");
1535 class AssignOneVariableValue :
public Decision {
1537 AssignOneVariableValue(IntVar*
const v, int64_t val);
1538 ~AssignOneVariableValue()
override {}
1539 void Apply(Solver*
const s)
override;
1540 void Refute(Solver*
const s)
override;
1541 std::string DebugString()
const override;
1542 void Accept(DecisionVisitor*
const visitor)
const override {
1543 visitor->VisitSetVariableValue(var_, value_);
1551 AssignOneVariableValue::AssignOneVariableValue(IntVar*
const v, int64_t val)
1552 : var_(v), value_(val) {}
1554 std::string AssignOneVariableValue::DebugString()
const {
1555 return absl::StrFormat(
"[%s == %d] or [%s != %d]", var_->DebugString(),
1556 value_, var_->DebugString(), value_);
1559 void AssignOneVariableValue::Apply(Solver*
const s) { var_->SetValue(value_); }
1561 void AssignOneVariableValue::Refute(Solver*
const s) {
1562 var_->RemoveValue(value_);
1567 return RevAlloc(
new AssignOneVariableValue(
var, val));
1573 class AssignOneVariableValueOrFail :
public Decision {
1575 AssignOneVariableValueOrFail(
IntVar*
const v, int64_t
value);
1576 ~AssignOneVariableValueOrFail()
override {}
1577 void Apply(Solver*
const s)
override;
1578 void Refute(Solver*
const s)
override;
1580 void Accept(DecisionVisitor*
const visitor)
const override {
1581 visitor->VisitSetVariableValue(var_, value_);
1586 const int64_t value_;
1589 AssignOneVariableValueOrFail::AssignOneVariableValueOrFail(IntVar*
const v,
1591 : var_(v), value_(
value) {}
1593 std::string AssignOneVariableValueOrFail::DebugString()
const {
1594 return absl::StrFormat(
"[%s == %d] or fail", var_->
DebugString(), value_);
1597 void AssignOneVariableValueOrFail::Apply(Solver*
const s) {
1601 void AssignOneVariableValueOrFail::Refute(Solver*
const s) { s->Fail(); }
1612 class AssignOneVariableValueDoNothing :
public Decision {
1614 AssignOneVariableValueDoNothing(
IntVar*
const v, int64_t
value)
1615 : var_(v), value_(
value) {}
1616 ~AssignOneVariableValueDoNothing()
override {}
1617 void Apply(Solver*
const s)
override { var_->SetValue(value_); }
1618 void Refute(Solver*
const s)
override {}
1619 std::string DebugString()
const override {
1620 return absl::StrFormat(
"[%s == %d] or []", var_->DebugString(), value_);
1622 void Accept(DecisionVisitor*
const visitor)
const override {
1623 visitor->VisitSetVariableValue(var_, value_);
1628 const int64_t value_;
1641 class SplitOneVariable :
public Decision {
1643 SplitOneVariable(
IntVar*
const v, int64_t val,
bool start_with_lower_half);
1644 ~SplitOneVariable()
override {}
1645 void Apply(Solver*
const s)
override;
1646 void Refute(Solver*
const s)
override;
1647 std::string DebugString()
const override;
1648 void Accept(DecisionVisitor*
const visitor)
const override {
1649 visitor->VisitSplitVariableDomain(var_, value_, start_with_lower_half_);
1654 const int64_t value_;
1655 const bool start_with_lower_half_;
1658 SplitOneVariable::SplitOneVariable(IntVar*
const v, int64_t val,
1659 bool start_with_lower_half)
1660 : var_(v), value_(val), start_with_lower_half_(start_with_lower_half) {}
1662 std::string SplitOneVariable::DebugString()
const {
1663 if (start_with_lower_half_) {
1664 return absl::StrFormat(
"[%s <= %d]", var_->
DebugString(), value_);
1666 return absl::StrFormat(
"[%s >= %d]", var_->
DebugString(), value_);
1670 void SplitOneVariable::Apply(Solver*
const s) {
1671 if (start_with_lower_half_) {
1674 var_->
SetMin(value_ + 1);
1678 void SplitOneVariable::Refute(Solver*
const s) {
1679 if (start_with_lower_half_) {
1680 var_->
SetMin(value_ + 1);
1688 bool start_with_lower_half) {
1689 return RevAlloc(
new SplitOneVariable(
var, val, start_with_lower_half));
1705 class AssignVariablesValues :
public Decision {
1707 AssignVariablesValues(
const std::vector<IntVar*>& vars,
1708 const std::vector<int64_t>& values);
1709 ~AssignVariablesValues()
override {}
1710 void Apply(Solver*
const s)
override;
1711 void Refute(Solver*
const s)
override;
1712 std::string DebugString()
const override;
1713 void Accept(DecisionVisitor*
const visitor)
const override {
1714 for (
int i = 0; i <
vars_.size(); ++i) {
1715 visitor->VisitSetVariableValue(
vars_[i], values_[i]);
1719 virtual void Accept(ModelVisitor*
const visitor)
const {
1727 const std::vector<IntVar*>
vars_;
1728 const std::vector<int64_t> values_;
1731 AssignVariablesValues::AssignVariablesValues(
const std::vector<IntVar*>& vars,
1732 const std::vector<int64_t>& values)
1733 :
vars_(vars), values_(values) {}
1735 std::string AssignVariablesValues::DebugString()
const {
1737 for (
int i = 0; i <
vars_.size(); ++i) {
1738 absl::StrAppendFormat(&out,
"[%s == %d]",
vars_[i]->DebugString(),
1744 void AssignVariablesValues::Apply(Solver*
const s) {
1745 for (
int i = 0; i <
vars_.size(); ++i) {
1746 vars_[i]->SetValue(values_[i]);
1750 void AssignVariablesValues::Refute(Solver*
const s) {
1751 std::vector<IntVar*> terms;
1752 for (
int i = 0; i <
vars_.size(); ++i) {
1753 IntVar* term = s->MakeBoolVar();
1754 s->MakeIsDifferentCstCt(
vars_[i], values_[i], term);
1755 terms.push_back(term);
1757 s->AddConstraint(s->MakeSumGreaterOrEqual(terms, 1));
1762 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1763 CHECK_EQ(vars.size(), values.size());
1764 return RevAlloc(
new AssignVariablesValues(vars, values));
1778 BaseAssignVariables(BaseVariableAssignmentSelector*
const selector, Mode mode)
1781 ~BaseAssignVariables()
override;
1782 Decision* Next(Solver*
const s)
override;
1783 std::string DebugString()
const override;
1784 static BaseAssignVariables* MakePhase(
1785 Solver*
const s,
const std::vector<IntVar*>& vars,
1788 const std::string& value_selector_name, BaseAssignVariables::Mode mode);
1791 Solver*
const s,
const std::vector<IntVar*>& vars,
1797 return ChooseFirstUnbound;
1799 return ChooseRandom;
1801 return ChooseMinSizeLowestMin;
1803 return ChooseMinSizeHighestMin;
1805 return ChooseMinSizeLowestMax;
1807 return ChooseMinSizeHighestMax;
1809 return ChooseLowestMin;
1811 return ChooseHighestMax;
1813 return ChooseMinSize;
1815 return ChooseMaxSize;
1817 HighestRegretSelectorOnMin*
const selector =
1818 s->RevAlloc(
new HighestRegretSelectorOnMin(vars));
1819 return [selector](Solver* solver,
const std::vector<IntVar*>& vars,
1820 int first_unbound,
int last_unbound) {
1821 return selector->Choose(solver, vars, first_unbound, last_unbound);
1825 PathSelector*
const selector = s->RevAlloc(
new PathSelector());
1826 return [selector](Solver* solver,
const std::vector<IntVar*>& vars,
1827 int first_unbound,
int last_unbound) {
1828 return selector->Choose(solver, vars, first_unbound, last_unbound);
1832 LOG(
FATAL) <<
"Unknown int var strategy " << str;
1843 return SelectMinValue;
1845 return SelectMaxValue;
1847 return SelectRandomValue;
1849 return SelectCenterValue;
1851 return SelectSplitValue;
1853 return SelectSplitValue;
1855 LOG(
FATAL) <<
"Unknown int value strategy " << val_str;
1860 void Accept(ModelVisitor*
const visitor)
const override {
1869 BaseAssignVariables::~BaseAssignVariables() {}
1871 Decision* BaseAssignVariables::Next(Solver*
const s) {
1872 const std::vector<IntVar*>& vars =
selector_->vars();
1873 int id =
selector_->ChooseVariableWrapper();
1874 if (
id >= 0 &&
id < vars.size()) {
1875 IntVar*
const var = vars[id];
1879 return s->RevAlloc(
new AssignOneVariableValue(
var,
value));
1881 return s->RevAlloc(
new SplitOneVariable(
var,
value,
true));
1883 return s->RevAlloc(
new SplitOneVariable(
var,
value,
false));
1889 std::string BaseAssignVariables::DebugString()
const {
1893 BaseAssignVariables* BaseAssignVariables::MakePhase(
1894 Solver*
const s,
const std::vector<IntVar*>& vars,
1897 const std::string& value_selector_name, BaseAssignVariables::Mode mode) {
1898 BaseVariableAssignmentSelector*
const selector =
1899 s->RevAlloc(
new VariableAssignmentSelector(
1900 s, vars, std::move(var_selector), std::move(value_selector),
1901 value_selector_name));
1902 return s->RevAlloc(
new BaseAssignVariables(selector, mode));
1910 return "ChooseFirstUnbound";
1912 return "ChooseRandom";
1914 return "ChooseMinSizeLowestMin";
1916 return "ChooseMinSizeHighestMin";
1918 return "ChooseMinSizeLowestMax";
1920 return "ChooseMinSizeHighestMax";
1922 return "ChooseLowestMin";
1924 return "ChooseHighestMax";
1926 return "ChooseMinSize";
1928 return "ChooseMaxSize;";
1930 return "HighestRegretSelectorOnMin";
1932 return "PathSelector";
1934 LOG(
FATAL) <<
"Unknown int var strategy " << var_str;
1944 return "SelectMinValue";
1946 return "SelectMaxValue";
1948 return "SelectRandomValue";
1950 return "SelectCenterValue";
1952 return "SelectSplitValue";
1954 return "SelectSplitValue";
1956 LOG(
FATAL) <<
"Unknown int value strategy " << val_str;
1963 return ChooseVariableName(var_str) +
"_" + SelectValueName(val_str);
1970 std::vector<IntVar*> vars(1);
1972 return MakePhase(vars, var_str, val_str);
1978 std::vector<IntVar*> vars(2);
1981 return MakePhase(vars, var_str, val_str);
1988 std::vector<IntVar*> vars(3);
1992 return MakePhase(vars, var_str, val_str);
1999 std::vector<IntVar*> vars(4);
2004 return MakePhase(vars, var_str, val_str);
2008 BaseAssignVariables::Mode mode = BaseAssignVariables::ASSIGN;
2010 mode = BaseAssignVariables::SPLIT_LOWER;
2012 mode = BaseAssignVariables::SPLIT_UPPER;
2021 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2023 BaseAssignVariables::MakeValueSelector(
this, val_str);
2024 const std::string
name = BuildHeuristicsName(var_str, val_str);
2025 return BaseAssignVariables::MakePhase(
2026 this, vars, var_selector, value_selector,
name,
ChooseMode(val_str));
2032 CHECK(var_evaluator !=
nullptr);
2033 CheapestVarSelector*
const var_selector =
2034 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2036 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2037 int first_unbound,
int last_unbound) {
2038 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2041 BaseAssignVariables::MakeValueSelector(
this, val_str);
2042 const std::string
name =
"ChooseCheapestVariable_" + SelectValueName(val_str);
2043 return BaseAssignVariables::MakePhase(
2044 this, vars, choose_variable, select_value,
name,
ChooseMode(val_str));
2051 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2052 CheapestValueSelector*
const value_selector =
2053 RevAlloc(
new CheapestValueSelector(std::move(value_evaluator),
nullptr));
2055 [value_selector](
const IntVar*
var, int64_t id) {
2056 return value_selector->Select(
var,
id);
2058 const std::string
name = ChooseVariableName(var_str) +
"_SelectCheapestValue";
2059 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2061 BaseAssignVariables::ASSIGN);
2068 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2069 BestValueByComparisonSelector*
const value_selector =
RevAlloc(
2070 new BestValueByComparisonSelector(std::move(var_val1_val2_comparator)));
2072 [value_selector](
const IntVar*
var, int64_t id) {
2073 return value_selector->Select(
var,
id);
2075 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2076 select_value,
"CheapestValue",
2077 BaseAssignVariables::ASSIGN);
2083 CheapestVarSelector*
const var_selector =
2084 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2086 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2087 int first_unbound,
int last_unbound) {
2088 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2090 CheapestValueSelector* value_selector =
2091 RevAlloc(
new CheapestValueSelector(std::move(value_evaluator),
nullptr));
2093 [value_selector](
const IntVar*
var, int64_t id) {
2094 return value_selector->Select(
var,
id);
2096 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2097 select_value,
"CheapestValue",
2098 BaseAssignVariables::ASSIGN);
2106 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2107 CheapestValueSelector* value_selector =
RevAlloc(
new CheapestValueSelector(
2108 std::move(value_evaluator), std::move(tie_breaker)));
2110 [value_selector](
const IntVar*
var, int64_t id) {
2111 return value_selector->Select(
var,
id);
2113 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2114 select_value,
"CheapestValue",
2115 BaseAssignVariables::ASSIGN);
2122 CheapestVarSelector*
const var_selector =
2123 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2125 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2126 int first_unbound,
int last_unbound) {
2127 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2129 CheapestValueSelector* value_selector =
RevAlloc(
new CheapestValueSelector(
2130 std::move(value_evaluator), std::move(tie_breaker)));
2132 [value_selector](
const IntVar*
var, int64_t id) {
2133 return value_selector->Select(
var,
id);
2135 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2136 select_value,
"CheapestValue",
2137 BaseAssignVariables::ASSIGN);
2143 return MakePhase(vars, std::move(eval),
nullptr, str);
2150 BaseVariableAssignmentSelector* selector =
nullptr;
2154 selector =
RevAlloc(
new StaticEvaluatorSelector(
this, vars, eval));
2158 selector =
RevAlloc(
new DynamicEvaluatorSelector(
this, vars, eval,
2159 std::move(tie_breaker)));
2164 new BaseAssignVariables(selector, BaseAssignVariables::ASSIGN));
2172 AssignVariablesFromAssignment(
const Assignment*
const assignment,
2174 const std::vector<IntVar*>& vars)
2175 : assignment_(assignment), db_(db),
vars_(vars), iter_(0) {}
2177 ~AssignVariablesFromAssignment()
override {}
2179 Decision* Next(Solver*
const s)
override {
2180 if (iter_ <
vars_.size()) {
2181 IntVar*
const var =
vars_[iter_++];
2183 new AssignOneVariableValue(
var, assignment_->Value(
var)));
2185 return db_->Next(s);
2189 void Accept(ModelVisitor*
const visitor)
const override {
2197 const Assignment*
const assignment_;
2198 DecisionBuilder*
const db_;
2199 const std::vector<IntVar*>
vars_;
2206 const std::vector<IntVar*>& vars) {
2207 return RevAlloc(
new AssignVariablesFromAssignment(assignment, db, vars));
2217 prototype_(assignment == nullptr ? nullptr : new
Assignment(assignment)) {
2225 delete data.solution;
2267 if (
prototype_ !=
nullptr && objective !=
nullptr) {
2274 delete data.solution;
2325 CHECK_GE(n, 0) <<
"wrong index in solution getter";
2398 explicit FirstSolutionCollector(
Solver*
const s);
2399 ~FirstSolutionCollector()
override;
2400 void EnterSearch()
override;
2401 bool AtSolution()
override;
2402 std::string DebugString()
const override;
2408 FirstSolutionCollector::FirstSolutionCollector(Solver*
const s,
2409 const Assignment*
const a)
2410 : SolutionCollector(s,
a), done_(false) {}
2412 FirstSolutionCollector::FirstSolutionCollector(Solver*
const s)
2413 : SolutionCollector(s), done_(false) {}
2415 FirstSolutionCollector::~FirstSolutionCollector() {}
2417 void FirstSolutionCollector::EnterSearch() {
2422 bool FirstSolutionCollector::AtSolution() {
2430 std::string FirstSolutionCollector::DebugString()
const {
2431 if (prototype_ ==
nullptr) {
2432 return "FirstSolutionCollector()";
2434 return "FirstSolutionCollector(" + prototype_->DebugString() +
")";
2441 return RevAlloc(
new FirstSolutionCollector(
this, assignment));
2445 return RevAlloc(
new FirstSolutionCollector(
this));
2455 explicit LastSolutionCollector(
Solver*
const s);
2456 ~LastSolutionCollector()
override;
2457 bool AtSolution()
override;
2458 std::string DebugString()
const override;
2461 LastSolutionCollector::LastSolutionCollector(Solver*
const s,
2462 const Assignment*
const a)
2463 : SolutionCollector(s,
a) {}
2465 LastSolutionCollector::LastSolutionCollector(Solver*
const s)
2466 : SolutionCollector(s) {}
2468 LastSolutionCollector::~LastSolutionCollector() {}
2470 bool LastSolutionCollector::AtSolution() {
2476 std::string LastSolutionCollector::DebugString()
const {
2477 if (prototype_ ==
nullptr) {
2478 return "LastSolutionCollector()";
2480 return "LastSolutionCollector(" + prototype_->DebugString() +
")";
2487 return RevAlloc(
new LastSolutionCollector(
this, assignment));
2491 return RevAlloc(
new LastSolutionCollector(
this));
2501 BestValueSolutionCollector(
Solver*
const s,
bool maximize);
2502 ~BestValueSolutionCollector()
override {}
2503 void EnterSearch()
override;
2504 bool AtSolution()
override;
2505 std::string DebugString()
const override;
2512 BestValueSolutionCollector::BestValueSolutionCollector(
2513 Solver*
const s,
const Assignment*
const a,
bool maximize)
2514 : SolutionCollector(s,
a),
2516 best_(maximize ? std::numeric_limits<int64_t>::
min()
2517 : std::numeric_limits<int64_t>::
max()) {}
2519 BestValueSolutionCollector::BestValueSolutionCollector(Solver*
const s,
2521 : SolutionCollector(s),
2523 best_(maximize ? std::numeric_limits<int64_t>::
min()
2524 : std::numeric_limits<int64_t>::
max()) {}
2526 void BestValueSolutionCollector::EnterSearch() {
2527 SolutionCollector::EnterSearch();
2529 : std::numeric_limits<int64_t>::
max();
2532 bool BestValueSolutionCollector::AtSolution() {
2533 if (prototype_ !=
nullptr) {
2534 const IntVar* objective = prototype_->Objective();
2535 if (objective !=
nullptr) {
2536 if (
maximize_ && (solution_count() == 0 || objective->Max() >
best_)) {
2539 best_ = objective->Max();
2541 (solution_count() == 0 || objective->Min() <
best_)) {
2544 best_ = objective->Min();
2551 std::string BestValueSolutionCollector::DebugString()
const {
2552 if (prototype_ ==
nullptr) {
2553 return "BestValueSolutionCollector()";
2555 return "BestValueSolutionCollector(" + prototype_->DebugString() +
")";
2561 const Assignment*
const assignment,
bool maximize) {
2562 return RevAlloc(
new BestValueSolutionCollector(
this, assignment, maximize));
2566 return RevAlloc(
new BestValueSolutionCollector(
this, maximize));
2574 NBestValueSolutionCollector(
Solver*
const solver,
2576 int solution_count,
bool maximize);
2577 NBestValueSolutionCollector(
Solver*
const solver,
int solution_count,
2579 ~NBestValueSolutionCollector()
override { Clear(); }
2593 NBestValueSolutionCollector::NBestValueSolutionCollector(
2594 Solver*
const solver,
const Assignment*
const assignment,
2595 int solution_count,
bool maximize)
2596 : SolutionCollector(solver, assignment),
2600 NBestValueSolutionCollector::NBestValueSolutionCollector(Solver*
const solver,
2603 : SolutionCollector(solver),
2607 void NBestValueSolutionCollector::EnterSearch() {
2608 SolutionCollector::EnterSearch();
2612 solver()->SetUseFastLocalSearch(
false);
2617 void NBestValueSolutionCollector::ExitSearch() {
2624 bool NBestValueSolutionCollector::AtSolution() {
2625 if (prototype_ !=
nullptr) {
2626 const IntVar* objective = prototype_->Objective();
2627 if (objective !=
nullptr) {
2628 const int64_t objective_value =
2632 {objective_value, BuildSolutionDataForCurrentState()});
2635 if (top.first > objective_value) {
2639 {objective_value, BuildSolutionDataForCurrentState()});
2647 std::string NBestValueSolutionCollector::DebugString()
const {
2648 if (prototype_ ==
nullptr) {
2649 return "NBestValueSolutionCollector()";
2651 return "NBestValueSolutionCollector(" + prototype_->DebugString() +
")";
2655 void NBestValueSolutionCollector::Clear() {
2665 const Assignment*
const assignment,
int solution_count,
bool maximize) {
2666 if (solution_count == 1) {
2667 return MakeBestValueSolutionCollector(assignment, maximize);
2669 return RevAlloc(
new NBestValueSolutionCollector(
this, assignment,
2670 solution_count, maximize));
2675 if (solution_count == 1) {
2676 return MakeBestValueSolutionCollector(maximize);
2679 new NBestValueSolutionCollector(
this, solution_count, maximize));
2689 explicit AllSolutionCollector(
Solver*
const s);
2690 ~AllSolutionCollector()
override;
2695 AllSolutionCollector::AllSolutionCollector(Solver*
const s,
2696 const Assignment*
const a)
2697 : SolutionCollector(s,
a) {}
2699 AllSolutionCollector::AllSolutionCollector(Solver*
const s)
2700 : SolutionCollector(s) {}
2702 AllSolutionCollector::~AllSolutionCollector() {}
2704 bool AllSolutionCollector::AtSolution() {
2709 std::string AllSolutionCollector::DebugString()
const {
2710 if (prototype_ ==
nullptr) {
2711 return "AllSolutionCollector()";
2713 return "AllSolutionCollector(" + prototype_->DebugString() +
")";
2720 return RevAlloc(
new AllSolutionCollector(
this, assignment));
2724 return RevAlloc(
new AllSolutionCollector(
this));
2734 best_(std::numeric_limits<int64_t>::
max()),
2736 found_initial_solution_(false) {
2760 if (
solver()->SearchDepth() == 0) {
2803 if (
delta !=
nullptr) {
2804 const bool delta_has_objective =
delta->HasObjective();
2805 if (!delta_has_objective) {
2812 const int64_t delta_min_objective =
2813 delta_has_objective ?
delta->ObjectiveMin()
2815 const int64_t min_objective =
2819 delta->SetObjectiveMin(
2823 const int64_t delta_max_objective =
2824 delta_has_objective ?
delta->ObjectiveMax()
2826 const int64_t max_objective =
2830 delta->SetObjectiveMax(
2839 return absl::StrFormat(
"objective value = %d, ",
var_->
Value());
2845 out =
"MaximizeVar(";
2847 out =
"MinimizeVar(";
2849 absl::StrAppendFormat(&out,
"%s, step = %d, best = %d)",
var_->
DebugString(),
2879 WeightedOptimizeVar(
Solver* solver,
bool maximize,
2880 const std::vector<IntVar*>& sub_objectives,
2881 const std::vector<int64_t>& weights, int64_t step)
2883 solver->MakeScalProd(sub_objectives, weights)->Var(), step),
2884 sub_objectives_(sub_objectives),
2886 CHECK_EQ(sub_objectives.size(), weights.size());
2889 ~WeightedOptimizeVar()
override {}
2890 std::string Print()
const override;
2893 const std::vector<IntVar*> sub_objectives_;
2894 const std::vector<int64_t> weights_;
2899 std::string WeightedOptimizeVar::Print()
const {
2901 result.append(
"\nWeighted Objective:\n");
2902 for (
int i = 0; i < sub_objectives_.size(); ++i) {
2903 absl::StrAppendFormat(&result,
"Variable %s,\tvalue %d,\tweight %d\n",
2904 sub_objectives_[i]->
name(),
2905 sub_objectives_[i]->
Value(), weights_[i]);
2912 bool maximize,
const std::vector<IntVar*>& sub_objectives,
2913 const std::vector<int64_t>& weights, int64_t step) {
2915 new WeightedOptimizeVar(
this, maximize, sub_objectives, weights, step));
2919 const std::vector<IntVar*>& sub_objectives,
2920 const std::vector<int64_t>& weights, int64_t step) {
2922 new WeightedOptimizeVar(
this,
false, sub_objectives, weights, step));
2926 const std::vector<IntVar*>& sub_objectives,
2927 const std::vector<int64_t>& weights, int64_t step) {
2929 new WeightedOptimizeVar(
this,
true, sub_objectives, weights, step));
2933 bool maximize,
const std::vector<IntVar*>& sub_objectives,
2934 const std::vector<int>& weights, int64_t step) {
2940 const std::vector<IntVar*>& sub_objectives,
const std::vector<int>& weights,
2946 const std::vector<IntVar*>& sub_objectives,
const std::vector<int>& weights,
2956 Metaheuristic(
Solver*
const solver,
bool maximize,
IntVar* objective,
2958 ~Metaheuristic()
override {}
2960 bool AtSolution()
override;
2961 void EnterSearch()
override;
2962 void RefuteDecision(Decision*
const d)
override;
2973 Metaheuristic::Metaheuristic(Solver*
const solver,
bool maximize,
2974 IntVar* objective, int64_t step)
2975 : SearchMonitor(solver),
2979 best_(std::numeric_limits<int64_t>::
max()),
2982 bool Metaheuristic::AtSolution() {
2992 void Metaheuristic::EnterSearch() {
2995 solver()->SetUseFastLocalSearch(
false);
3005 void Metaheuristic::RefuteDecision(Decision* d) {
3016 if (
delta !=
nullptr) {
3017 if (!
delta->HasObjective()) {
3022 delta->SetObjectiveMin(
3025 delta->SetObjectiveMax(
3035 class TabuSearch :
public Metaheuristic {
3037 TabuSearch(Solver*
const s,
bool maximize, IntVar* objective, int64_t step,
3038 const std::vector<IntVar*>& vars, int64_t keep_tenure,
3039 int64_t forbid_tenure,
double tabu_factor);
3040 ~TabuSearch()
override {}
3041 void EnterSearch()
override;
3042 void ApplyDecision(Decision* d)
override;
3043 bool AtSolution()
override;
3044 bool LocalOptimum()
override;
3046 std::string DebugString()
const override {
return "Tabu Search"; }
3050 VarValue(IntVar*
const var, int64_t
value, int64_t stamp)
3053 const int64_t value_;
3056 typedef std::list<VarValue> TabuList;
3058 virtual std::vector<IntVar*> CreateTabuVars();
3059 const TabuList& forbid_tabu_list() {
return forbid_tabu_list_; }
3062 void AgeList(int64_t tenure, TabuList* list);
3065 const std::vector<IntVar*>
vars_;
3066 Assignment assignment_;
3068 TabuList keep_tabu_list_;
3069 int64_t keep_tenure_;
3070 TabuList forbid_tabu_list_;
3071 int64_t forbid_tenure_;
3072 double tabu_factor_;
3074 bool found_initial_solution_;
3079 TabuSearch::TabuSearch(Solver*
const s,
bool maximize, IntVar* objective,
3080 int64_t step,
const std::vector<IntVar*>& vars,
3081 int64_t keep_tenure, int64_t forbid_tenure,
3083 : Metaheuristic(s, maximize, objective, step),
3086 last_(std::numeric_limits<int64_t>::
max()),
3087 keep_tenure_(keep_tenure),
3088 forbid_tenure_(forbid_tenure),
3089 tabu_factor_(tabu_factor),
3091 found_initial_solution_(false) {
3092 assignment_.Add(
vars_);
3095 void TabuSearch::EnterSearch() {
3096 Metaheuristic::EnterSearch();
3097 found_initial_solution_ =
false;
3100 void TabuSearch::ApplyDecision(Decision*
const d) {
3101 Solver*
const s = solver();
3102 if (d == s->balancing_decision()) {
3107 IntVar* aspiration = s->MakeBoolVar();
3109 s->AddConstraint(s->MakeIsGreaterOrEqualCstCt(
3116 IntVar* tabu_var =
nullptr;
3120 const std::vector<IntVar*> tabu_vars = CreateTabuVars();
3121 if (!tabu_vars.empty()) {
3122 tabu_var = s->MakeIsGreaterOrEqualCstVar(s->MakeSum(tabu_vars)->Var(),
3123 tabu_vars.size() * tabu_factor_);
3127 if (tabu_var !=
nullptr) {
3129 s->MakeGreaterOrEqual(s->MakeSum(aspiration, tabu_var), int64_t{1}));
3146 if (found_initial_solution_) {
3147 s->AddConstraint(s->MakeNonEquality(
objective_, last_));
3151 std::vector<IntVar*> TabuSearch::CreateTabuVars() {
3152 Solver*
const s = solver();
3160 std::vector<IntVar*> tabu_vars;
3161 for (
const VarValue& vv : keep_tabu_list_) {
3162 tabu_vars.push_back(s->MakeIsEqualCstVar(vv.var_, vv.value_));
3164 for (
const VarValue& vv : forbid_tabu_list_) {
3165 tabu_vars.push_back(s->MakeIsDifferentCstVar(vv.var_, vv.value_));
3170 bool TabuSearch::AtSolution() {
3171 if (!Metaheuristic::AtSolution()) {
3174 found_initial_solution_ =
true;
3180 for (
int i = 0; i <
vars_.size(); ++i) {
3182 const int64_t old_value = assignment_.Value(
var);
3183 const int64_t new_value =
var->Value();
3184 if (old_value != new_value) {
3185 if (keep_tenure_ > 0) {
3186 VarValue keep_value(
var, new_value,
stamp_);
3187 keep_tabu_list_.push_front(keep_value);
3189 if (forbid_tenure_ > 0) {
3190 VarValue forbid_value(
var, old_value,
stamp_);
3191 forbid_tabu_list_.push_front(forbid_value);
3196 assignment_.Store();
3201 bool TabuSearch::LocalOptimum() {
3208 return found_initial_solution_;
3217 void TabuSearch::AgeList(int64_t tenure, TabuList* list) {
3218 while (!list->empty() && list->back().stamp_ <
stamp_ - tenure) {
3223 void TabuSearch::AgeLists() {
3224 AgeList(keep_tenure_, &keep_tabu_list_);
3225 AgeList(forbid_tenure_, &forbid_tabu_list_);
3229 class GenericTabuSearch :
public TabuSearch {
3231 GenericTabuSearch(Solver*
const s,
bool maximize, IntVar* objective,
3232 int64_t step,
const std::vector<IntVar*>& vars,
3233 int64_t forbid_tenure)
3234 : TabuSearch(s, maximize, objective, step, vars, 0, forbid_tenure, 1) {}
3235 std::string DebugString()
const override {
return "Generic Tabu Search"; }
3238 std::vector<IntVar*> CreateTabuVars()
override;
3241 std::vector<IntVar*> GenericTabuSearch::CreateTabuVars() {
3242 Solver*
const s = solver();
3246 std::vector<IntVar*> forbid_values;
3247 for (
const VarValue& vv : forbid_tabu_list()) {
3248 forbid_values.push_back(s->MakeIsDifferentCstVar(vv.var_, vv.value_));
3250 std::vector<IntVar*> tabu_vars;
3251 if (!forbid_values.empty()) {
3252 tabu_vars.push_back(s->MakeIsGreaterCstVar(s->MakeSum(forbid_values), 0));
3261 const std::vector<IntVar*>& vars,
3262 int64_t keep_tenure,
3263 int64_t forbid_tenure,
3264 double tabu_factor) {
3265 return RevAlloc(
new TabuSearch(
this, maximize, v, step, vars, keep_tenure,
3266 forbid_tenure, tabu_factor));
3270 bool maximize,
IntVar*
const v, int64_t step,
3271 const std::vector<IntVar*>& tabu_vars, int64_t forbid_tenure) {
3273 new GenericTabuSearch(
this, maximize, v, step, tabu_vars, forbid_tenure));
3279 class SimulatedAnnealing :
public Metaheuristic {
3281 SimulatedAnnealing(
Solver*
const s,
bool maximize,
IntVar* objective,
3282 int64_t step, int64_t initial_temperature);
3283 ~SimulatedAnnealing()
override {}
3284 void EnterSearch()
override;
3285 void ApplyDecision(Decision* d)
override;
3286 bool AtSolution()
override;
3287 bool LocalOptimum()
override;
3289 std::string DebugString()
const override {
return "Simulated Annealing"; }
3292 double Temperature()
const;
3294 const int64_t temperature0_;
3297 bool found_initial_solution_;
3302 SimulatedAnnealing::SimulatedAnnealing(Solver*
const s,
bool maximize,
3303 IntVar* objective, int64_t step,
3304 int64_t initial_temperature)
3305 : Metaheuristic(s, maximize, objective, step),
3306 temperature0_(initial_temperature),
3309 found_initial_solution_(false) {}
3311 void SimulatedAnnealing::EnterSearch() {
3312 Metaheuristic::EnterSearch();
3313 found_initial_solution_ =
false;
3316 void SimulatedAnnealing::ApplyDecision(Decision*
const d) {
3317 Solver*
const s = solver();
3318 if (d == s->balancing_decision()) {
3321 const double rand_double = absl::Uniform<double>(rand_, 0.0, 1.0);
3322 #if defined(_MSC_VER) || defined(__ANDROID__)
3323 const double rand_log2_double = log(rand_double) / log(2.0L);
3325 const double rand_log2_double = log2(rand_double);
3327 const int64_t energy_bound = Temperature() * rand_log2_double;
3341 bool SimulatedAnnealing::AtSolution() {
3342 if (!Metaheuristic::AtSolution()) {
3345 found_initial_solution_ =
true;
3349 bool SimulatedAnnealing::LocalOptimum() {
3356 return found_initial_solution_ && Temperature() > 0;
3360 if (iteration_ > 0) {
3365 double SimulatedAnnealing::Temperature()
const {
3366 if (iteration_ > 0) {
3367 return (1.0 * temperature0_) / iteration_;
3376 int64_t initial_temperature) {
3378 new SimulatedAnnealing(
this, maximize, v, step, initial_temperature));
3383 typedef std::pair<int64_t, int64_t>
Arc;
3388 class GuidedLocalSearchPenalties {
3390 virtual ~GuidedLocalSearchPenalties() {}
3391 virtual bool HasValues()
const = 0;
3392 virtual void Increment(
const Arc& arc) = 0;
3393 virtual int64_t
Value(
const Arc& arc)
const = 0;
3394 virtual void Reset() = 0;
3398 class GuidedLocalSearchPenaltiesTable :
public GuidedLocalSearchPenalties {
3400 explicit GuidedLocalSearchPenaltiesTable(
int size);
3401 ~GuidedLocalSearchPenaltiesTable()
override {}
3402 bool HasValues()
const override {
return has_values_; }
3403 void Increment(
const Arc& arc)
override;
3404 int64_t
Value(
const Arc& arc)
const override;
3405 void Reset()
override;
3408 std::vector<std::vector<int64_t>> penalties_;
3412 GuidedLocalSearchPenaltiesTable::GuidedLocalSearchPenaltiesTable(
int size)
3413 : penalties_(size), has_values_(
false) {}
3415 void GuidedLocalSearchPenaltiesTable::Increment(
const Arc& arc) {
3416 std::vector<int64_t>& first_penalties = penalties_[arc.first];
3417 const int64_t second = arc.second;
3418 if (second >= first_penalties.size()) {
3419 first_penalties.resize(second + 1, 0);
3421 ++first_penalties[second];
3425 void GuidedLocalSearchPenaltiesTable::Reset() {
3426 has_values_ =
false;
3427 for (
int i = 0; i < penalties_.size(); ++i) {
3428 penalties_[i].clear();
3433 const std::vector<int64_t>& first_penalties = penalties_[arc.first];
3434 const int64_t second = arc.second;
3435 if (second >= first_penalties.size()) {
3438 return first_penalties[second];
3443 class GuidedLocalSearchPenaltiesMap :
public GuidedLocalSearchPenalties {
3445 explicit GuidedLocalSearchPenaltiesMap(
int size);
3446 ~GuidedLocalSearchPenaltiesMap()
override {}
3447 bool HasValues()
const override {
return (!penalties_.empty()); }
3448 void Increment(
const Arc& arc)
override;
3449 int64_t
Value(
const Arc& arc)
const override;
3450 void Reset()
override;
3454 absl::flat_hash_map<Arc, int64_t> penalties_;
3457 GuidedLocalSearchPenaltiesMap::GuidedLocalSearchPenaltiesMap(
int size)
3458 : penalized_(size,
false) {}
3460 void GuidedLocalSearchPenaltiesMap::Increment(
const Arc& arc) {
3462 penalized_.
Set(arc.first,
true);
3465 void GuidedLocalSearchPenaltiesMap::Reset() {
3471 if (penalized_.
Get(arc.first)) {
3477 class GuidedLocalSearch :
public Metaheuristic {
3479 GuidedLocalSearch(
Solver*
const s,
IntVar* objective,
bool maximize,
3480 int64_t step,
const std::vector<IntVar*>& vars,
3481 double penalty_factor);
3482 ~GuidedLocalSearch()
override {}
3484 void ApplyDecision(
Decision* d)
override;
3485 bool AtSolution()
override;
3486 void EnterSearch()
override;
3487 bool LocalOptimum()
override;
3488 virtual int64_t AssignmentElementPenalty(
const Assignment& assignment,
3490 virtual int64_t AssignmentPenalty(
const Assignment& assignment,
int index,
3493 int64_t
index,
int* container_index,
3494 int64_t* penalty) = 0;
3496 std::string DebugString()
const override {
return "Guided Local Search"; }
3500 bool operator()(
const std::pair<Arc, double>& i,
3501 const std::pair<Arc, double>& j) {
3502 return i.second > j.second;
3507 const int64_t*
const out_values,
bool cache_delta_values);
3510 Assignment assignment_;
3513 const std::vector<IntVar*>
vars_;
3516 std::unique_ptr<GuidedLocalSearchPenalties> penalties_;
3522 GuidedLocalSearch::GuidedLocalSearch(Solver*
const s, IntVar* objective,
3523 bool maximize, int64_t step,
3524 const std::vector<IntVar*>& vars,
3525 double penalty_factor)
3526 : Metaheuristic(s, maximize, objective, step),
3534 if (!vars.empty()) {
3536 assignment_.Add(
vars_);
3542 for (
int i = 0; i <
vars_.size(); ++i) {
3545 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
3546 penalties_ = absl::make_unique<GuidedLocalSearchPenaltiesMap>(
vars_.size());
3549 absl::make_unique<GuidedLocalSearchPenaltiesTable>(
vars_.size());
3560 void GuidedLocalSearch::ApplyDecision(Decision*
const d) {
3561 if (d == solver()->balancing_decision()) {
3565 if (penalties_->HasValues()) {
3569 std::vector<IntVar*> elements;
3570 for (
int i = 0; i <
vars_.size(); ++i) {
3571 elements.push_back(MakeElementPenalty(i)->Var());
3572 const int64_t penalty = AssignmentElementPenalty(assignment_, i);
3583 IntExpr* min_pen_exp =
3585 IntVar* min_exp = solver()->MakeMin(min_pen_exp,
best_ +
step_)->Var();
3586 solver()->AddConstraint(
3587 solver()->MakeGreaterOrEqual(
objective_, min_exp));
3589 IntExpr* max_pen_exp =
3591 IntVar* max_exp = solver()->MakeMax(max_pen_exp,
best_ -
step_)->Var();
3592 solver()->AddConstraint(solver()->MakeLessOrEqual(
objective_, max_exp));
3610 bool GuidedLocalSearch::AtSolution() {
3611 if (!Metaheuristic::AtSolution()) {
3617 assignment_.Store();
3621 void GuidedLocalSearch::EnterSearch() {
3622 Metaheuristic::EnterSearch();
3628 penalties_->Reset();
3634 if (
delta !=
nullptr || deltadelta !=
nullptr) {
3635 if (!penalties_->HasValues()) {
3638 int64_t penalty = 0;
3639 if (!deltadelta->Empty()) {
3650 for (
int i = 0; i <
vars_.size(); ++i) {
3660 if (!
delta->HasObjective()) {
3665 delta->SetObjectiveMin(
3668 delta->ObjectiveMin()));
3670 delta->SetObjectiveMax(
3673 delta->ObjectiveMax()));
3680 int64_t GuidedLocalSearch::Evaluate(
const Assignment*
delta,
3681 int64_t current_penalty,
3682 const int64_t*
const out_values,
3683 bool cache_delta_values) {
3684 int64_t penalty = current_penalty;
3685 const Assignment::IntContainer& container =
delta->IntVarContainer();
3686 const int size = container.Size();
3687 for (
int i = 0; i < size; ++i) {
3688 const IntVarElement& new_element = container.Element(i);
3689 IntVar*
var = new_element.Var();
3693 int64_t new_penalty = 0;
3694 if (EvaluateElementValue(container,
index, &i, &new_penalty)) {
3695 penalty =
CapAdd(penalty, new_penalty);
3696 if (cache_delta_values) {
3707 bool GuidedLocalSearch::LocalOptimum() {
3708 std::vector<std::pair<Arc, double>> utility(
vars_.size());
3709 for (
int i = 0; i <
vars_.size(); ++i) {
3710 if (!assignment_.Bound(
vars_[i])) {
3714 const int64_t var_value = assignment_.Value(
vars_[i]);
3715 const int64_t
value =
3716 (var_value != i) ? AssignmentPenalty(assignment_, i, var_value) : 0;
3717 const Arc arc(i, var_value);
3718 const int64_t penalty = penalties_->Value(arc);
3719 utility[i] = std::pair<Arc, double>(arc,
value / (penalty + 1.0));
3721 Comparator comparator;
3722 std::sort(utility.begin(), utility.end(), comparator);
3723 int64_t utility_value = utility[0].second;
3724 penalties_->Increment(utility[0].first);
3725 for (
int i = 1; i < utility.size() && utility_value == utility[i].second;
3727 penalties_->Increment(utility[i].first);
3737 class BinaryGuidedLocalSearch :
public GuidedLocalSearch {
3739 BinaryGuidedLocalSearch(
3740 Solver*
const solver, IntVar*
const objective,
3741 std::function<int64_t(int64_t, int64_t)> objective_function,
3742 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
3743 double penalty_factor);
3744 ~BinaryGuidedLocalSearch()
override {}
3745 IntExpr* MakeElementPenalty(
int index)
override;
3746 int64_t AssignmentElementPenalty(
const Assignment& assignment,
3747 int index)
override;
3748 int64_t AssignmentPenalty(
const Assignment& assignment,
int index,
3749 int64_t
next)
override;
3750 bool EvaluateElementValue(
const Assignment::IntContainer& container,
3751 int64_t
index,
int* container_index,
3752 int64_t* penalty)
override;
3755 int64_t PenalizedValue(int64_t i, int64_t j);
3756 std::function<int64_t(int64_t, int64_t)> objective_function_;
3759 BinaryGuidedLocalSearch::BinaryGuidedLocalSearch(
3760 Solver*
const solver, IntVar*
const objective,
3761 std::function<int64_t(int64_t, int64_t)> objective_function,
bool maximize,
3762 int64_t step,
const std::vector<IntVar*>& vars,
double penalty_factor)
3763 : GuidedLocalSearch(solver, objective, maximize, step, vars,
3765 objective_function_(std::move(objective_function)) {}
3767 IntExpr* BinaryGuidedLocalSearch::MakeElementPenalty(
int index) {
3768 return solver()->MakeElement(
3769 [
this,
index](int64_t i) {
return PenalizedValue(
index, i); },
3773 int64_t BinaryGuidedLocalSearch::AssignmentElementPenalty(
3774 const Assignment& assignment,
int index) {
3778 int64_t BinaryGuidedLocalSearch::AssignmentPenalty(
const Assignment& assignment,
3780 return objective_function_(
index,
next);
3783 bool BinaryGuidedLocalSearch::EvaluateElementValue(
3784 const Assignment::IntContainer& container, int64_t
index,
3785 int* container_index, int64_t* penalty) {
3786 const IntVarElement& element = container.Element(*container_index);
3787 if (element.Activated()) {
3788 *penalty = PenalizedValue(
index, element.Value());
3795 int64_t BinaryGuidedLocalSearch::PenalizedValue(int64_t i, int64_t j) {
3796 const Arc arc(i, j);
3797 const int64_t penalty = penalties_->Value(arc);
3799 const double penalized_value_fp =
3801 const int64_t penalized_value =
3803 ?
static_cast<int64_t
>(penalized_value_fp)
3806 return -penalized_value;
3808 return penalized_value;
3815 class TernaryGuidedLocalSearch :
public GuidedLocalSearch {
3817 TernaryGuidedLocalSearch(
3818 Solver*
const solver, IntVar*
const objective,
3819 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
3820 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
3821 const std::vector<IntVar*>& secondary_vars,
double penalty_factor);
3822 ~TernaryGuidedLocalSearch()
override {}
3823 IntExpr* MakeElementPenalty(
int index)
override;
3824 int64_t AssignmentElementPenalty(
const Assignment& assignment,
3825 int index)
override;
3826 int64_t AssignmentPenalty(
const Assignment& assignment,
int index,
3827 int64_t
next)
override;
3828 bool EvaluateElementValue(
const Assignment::IntContainer& container,
3829 int64_t
index,
int* container_index,
3830 int64_t* penalty)
override;
3833 int64_t PenalizedValue(int64_t i, int64_t j, int64_t k);
3834 int64_t GetAssignmentSecondaryValue(
const Assignment::IntContainer& container,
3835 int index,
int* container_index)
const;
3837 const std::vector<IntVar*> secondary_vars_;
3838 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function_;
3841 TernaryGuidedLocalSearch::TernaryGuidedLocalSearch(
3842 Solver*
const solver, IntVar*
const objective,
3843 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
3844 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
3845 const std::vector<IntVar*>& secondary_vars,
double penalty_factor)
3846 : GuidedLocalSearch(solver, objective, maximize, step, vars,
3848 secondary_vars_(secondary_vars),
3849 objective_function_(std::move(objective_function)) {
3850 if (!secondary_vars.empty()) {
3851 assignment_.Add(secondary_vars);
3855 IntExpr* TernaryGuidedLocalSearch::MakeElementPenalty(
int index) {
3856 return solver()->MakeElement(
3857 [
this,
index](int64_t i, int64_t j) {
3858 return PenalizedValue(
index, i, j);
3863 int64_t TernaryGuidedLocalSearch::AssignmentElementPenalty(
3864 const Assignment& assignment,
int index) {
3866 assignment.Value(secondary_vars_[
index]));
3869 int64_t TernaryGuidedLocalSearch::AssignmentPenalty(
3870 const Assignment& assignment,
int index, int64_t
next) {
3872 assignment.Value(secondary_vars_[
index]));
3875 bool TernaryGuidedLocalSearch::EvaluateElementValue(
3876 const Assignment::IntContainer& container, int64_t
index,
3877 int* container_index, int64_t* penalty) {
3878 const IntVarElement& element = container.Element(*container_index);
3879 if (element.Activated()) {
3880 *penalty = PenalizedValue(
3881 index, element.Value(),
3882 GetAssignmentSecondaryValue(container,
index, container_index));
3889 int64_t TernaryGuidedLocalSearch::PenalizedValue(int64_t i, int64_t j,
3891 const Arc arc(i, j);
3892 const int64_t penalty = penalties_->Value(arc);
3894 const double penalized_value_fp =
3896 const int64_t penalized_value =
3898 ?
static_cast<int64_t
>(penalized_value_fp)
3901 return -penalized_value;
3903 return penalized_value;
3910 int64_t TernaryGuidedLocalSearch::GetAssignmentSecondaryValue(
3911 const Assignment::IntContainer& container,
int index,
3912 int* container_index)
const {
3913 const IntVar* secondary_var = secondary_vars_[
index];
3914 int hint_index = *container_index + 1;
3915 if (hint_index > 0 && hint_index < container.Size() &&
3916 secondary_var == container.Element(hint_index).Var()) {
3917 *container_index = hint_index;
3918 return container.Element(hint_index).Value();
3920 return container.Element(secondary_var).Value();
3926 bool maximize,
IntVar*
const objective,
3928 const std::vector<IntVar*>& vars,
double penalty_factor) {
3929 return RevAlloc(
new BinaryGuidedLocalSearch(
3930 this, objective, std::move(objective_function), maximize, step, vars,
3935 bool maximize,
IntVar*
const objective,
3937 const std::vector<IntVar*>& vars,
3938 const std::vector<IntVar*>& secondary_vars,
double penalty_factor) {
3939 return RevAlloc(
new TernaryGuidedLocalSearch(
3940 this, objective, std::move(objective_function), maximize, step, vars,
3941 secondary_vars, penalty_factor));
3948 SearchLimit::~SearchLimit() {}
3950 void SearchLimit::EnterSearch() {
3965 void SearchLimit::PeriodicCheck() {
3966 if (crossed_ || Check()) {
3972 void SearchLimit::TopPeriodicCheck() {
3973 if (solver()->TopLevelSearch() != solver()->ActiveSearch()) {
3974 solver()->TopPeriodicCheck();
3981 int64_t branches, int64_t failures,
3982 int64_t solutions,
bool smart_time_check,
3985 duration_limit_(
time),
3986 solver_time_at_limit_start_(s->Now()),
3987 last_time_elapsed_(
absl::ZeroDuration()),
3990 smart_time_check_(smart_time_check),
3991 branches_(branches),
3992 branches_offset_(0),
3993 failures_(failures),
3994 failures_offset_(0),
3995 solutions_(solutions),
3996 solutions_offset_(0),
3997 cumulative_(cumulative) {}
4004 duration_limit_ = regular->duration_limit_;
4005 branches_ = regular->branches_;
4006 failures_ = regular->failures_;
4007 solutions_ = regular->solutions_;
4008 smart_time_check_ = regular->smart_time_check_;
4009 cumulative_ = regular->cumulative_;
4023 return s->
branches() - branches_offset_ >= branches_ ||
4024 s->
failures() - failures_offset_ >= failures_ || CheckTime() ||
4025 s->
solutions() - solutions_offset_ >= solutions_;
4030 int64_t progress = GetPercent(s->
branches(), branches_offset_, branches_);
4032 GetPercent(s->
failures(), failures_offset_, failures_));
4034 progress, GetPercent(s->
solutions(), solutions_offset_, solutions_));
4045 solver_time_at_limit_start_ = s->
Now();
4046 last_time_elapsed_ = absl::ZeroDuration();
4056 branches_ -= s->
branches() - branches_offset_;
4057 failures_ -= s->
failures() - failures_offset_;
4058 duration_limit_ -= s->
Now() - solver_time_at_limit_start_;
4059 solutions_ -= s->
solutions() - solutions_offset_;
4064 int64_t failures, int64_t solutions) {
4065 duration_limit_ =
time;
4078 return absl::StrFormat(
4079 "RegularLimit(crossed = %i, duration_limit = %s, "
4080 "branches = %d, failures = %d, solutions = %d cumulative = %s",
4082 solutions_, (cumulative_ ?
"true" :
"false"));
4100 bool RegularLimit::CheckTime() {
return TimeElapsed() >=
duration_limit(); }
4102 absl::Duration RegularLimit::TimeElapsed() {
4103 const int64_t kMaxSkip = 100;
4104 const int64_t kCheckWarmupIterations = 100;
4107 next_check_ <= check_count_) {
4108 Solver*
const s =
solver();
4109 absl::Duration elapsed = s->Now() - solver_time_at_limit_start_;
4110 if (smart_time_check_ && check_count_ > kCheckWarmupIterations &&
4111 elapsed > absl::ZeroDuration()) {
4113 check_count_ * absl::FDivDuration(duration_limit_, elapsed));
4115 std::min(check_count_ + kMaxSkip, estimated_check_count_at_limit);
4117 last_time_elapsed_ = elapsed;
4119 return last_time_elapsed_;
4137 return MakeLimit(absl::InfiniteDuration(),
4144 return MakeLimit(absl::InfiniteDuration(),
4151 int64_t failures, int64_t solutions,
4152 bool smart_time_check,
bool cumulative) {
4154 smart_time_check, cumulative);
4158 int64_t failures, int64_t solutions,
4159 bool smart_time_check,
bool cumulative) {
4161 smart_time_check, cumulative));
4166 ? absl::InfiniteDuration()
4167 : absl::Milliseconds(
proto.time()),
4169 proto.smart_time_check(),
proto.cumulative());
4173 RegularLimitParameters
proto;
4178 proto.set_smart_time_check(
false);
4179 proto.set_cumulative(
false);
4187 double objective_scaling_factor,
double objective_offset,
4188 double improvement_rate_coefficient,
4189 int improvement_rate_solutions_distance)
4191 objective_var_(objective_var),
4193 objective_scaling_factor_(objective_scaling_factor),
4194 objective_offset_(objective_offset),
4195 improvement_rate_coefficient_(improvement_rate_coefficient),
4196 improvement_rate_solutions_distance_(
4197 improvement_rate_solutions_distance) {
4204 best_objective_ = maximize_ ? -std::numeric_limits<double>::infinity()
4205 : std::numeric_limits<double>::infinity();
4206 threshold_ = std::numeric_limits<double>::infinity();
4207 objective_updated_ =
false;
4208 gradient_stage_ =
true;
4214 objective_var_ = improv->objective_var_;
4215 maximize_ = improv->maximize_;
4216 objective_scaling_factor_ = improv->objective_scaling_factor_;
4217 objective_offset_ = improv->objective_offset_;
4218 improvement_rate_coefficient_ = improv->improvement_rate_coefficient_;
4219 improvement_rate_solutions_distance_ =
4220 improv->improvement_rate_solutions_distance_;
4221 improvements_ = improv->improvements_;
4222 threshold_ = improv->threshold_;
4223 best_objective_ = improv->best_objective_;
4224 objective_updated_ = improv->objective_updated_;
4225 gradient_stage_ = improv->gradient_stage_;
4231 objective_var_, maximize_, objective_scaling_factor_, objective_offset_,
4232 improvement_rate_coefficient_, improvement_rate_solutions_distance_);
4236 if (!objective_updated_) {
4239 objective_updated_ =
false;
4241 if (improvements_.size() <= improvement_rate_solutions_distance_) {
4245 const std::pair<double, int64_t> cur = improvements_.back();
4246 const std::pair<double, int64_t> prev = improvements_.front();
4248 double improvement_rate =
4249 std::abs(prev.first - cur.first) / (cur.second - prev.second);
4250 if (gradient_stage_) {
4251 threshold_ = fmin(threshold_, improvement_rate);
4252 }
else if (improvement_rate_coefficient_ * improvement_rate < threshold_) {
4260 const int64_t new_objective =
4261 objective_var_ !=
nullptr && objective_var_->
Bound()
4262 ? objective_var_->
Value()
4267 const double scaled_new_objective =
4268 objective_scaling_factor_ * (new_objective + objective_offset_);
4270 const bool is_improvement = maximize_
4271 ? scaled_new_objective > best_objective_
4272 : scaled_new_objective < best_objective_;
4274 if (gradient_stage_ && !is_improvement) {
4275 gradient_stage_ =
false;
4278 if (threshold_ == std::numeric_limits<double>::infinity()) {
4283 if (is_improvement) {
4284 best_objective_ = scaled_new_objective;
4285 objective_updated_ =
true;
4286 improvements_.push_back(
4291 if (improvements_.size() - 1 > improvement_rate_solutions_distance_) {
4292 improvements_.pop_front();
4294 DCHECK_LE(improvements_.size() - 1, improvement_rate_solutions_distance_);
4301 IntVar* objective_var,
bool maximize,
double objective_scaling_factor,
4302 double objective_offset,
double improvement_rate_coefficient,
4303 int improvement_rate_solutions_distance) {
4305 this, objective_var, maximize, objective_scaling_factor, objective_offset,
4306 improvement_rate_coefficient, improvement_rate_solutions_distance));
4314 :
SearchLimit(limit_1->solver()), limit_1_(limit_1), limit_2_(limit_2) {
4315 CHECK(limit_1 !=
nullptr);
4316 CHECK(limit_2 !=
nullptr);
4318 <<
"Illegal arguments: cannot combines limits that belong to different "
4319 <<
"solvers, because the reversible allocations could delete one and "
4320 <<
"not the other.";
4323 bool Check()
override {
4326 const bool check_1 = limit_1_->Check();
4327 const bool check_2 = limit_2_->Check();
4328 return check_1 || check_2;
4331 void Init()
override {
4336 void Copy(
const SearchLimit*
const limit)
override {
4340 SearchLimit* MakeClone()
const override {
4342 return solver()->MakeLimit(limit_1_->MakeClone(), limit_2_->MakeClone());
4345 void EnterSearch()
override {
4346 limit_1_->EnterSearch();
4347 limit_2_->EnterSearch();
4349 void BeginNextDecision(DecisionBuilder*
const b)
override {
4350 limit_1_->BeginNextDecision(
b);
4351 limit_2_->BeginNextDecision(
b);
4353 void PeriodicCheck()
override {
4354 limit_1_->PeriodicCheck();
4355 limit_2_->PeriodicCheck();
4357 void RefuteDecision(Decision*
const d)
override {
4358 limit_1_->RefuteDecision(d);
4359 limit_2_->RefuteDecision(d);
4361 std::string DebugString()
const override {
4362 return absl::StrCat(
"OR limit (", limit_1_->DebugString(),
" OR ",
4363 limit_2_->DebugString(),
")");
4367 SearchLimit*
const limit_1_;
4368 SearchLimit*
const limit_2_;
4374 return RevAlloc(
new ORLimit(limit_1, limit_2));
4380 CustomLimit(
Solver*
const s, std::function<
bool()> limiter);
4381 bool Check()
override;
4382 void Init()
override;
4383 void Copy(
const SearchLimit*
const limit)
override;
4387 std::function<bool()> limiter_;
4390 CustomLimit::CustomLimit(Solver*
const s, std::function<
bool()> limiter)
4391 : SearchLimit(s), limiter_(std::move(limiter)) {}
4393 bool CustomLimit::Check() {
4394 if (limiter_)
return limiter_();
4398 void CustomLimit::Init() {}
4400 void CustomLimit::Copy(
const SearchLimit*
const limit) {
4401 const CustomLimit*
const custom =
4402 reinterpret_cast<const CustomLimit* const
>(limit);
4403 limiter_ = custom->limiter_;
4406 SearchLimit* CustomLimit::MakeClone()
const {
4407 return solver()->RevAlloc(
new CustomLimit(solver(), limiter_));
4412 return RevAlloc(
new CustomLimit(
this, std::move(limiter)));
4421 CHECK(db !=
nullptr);
4424 SolveOnce(DecisionBuilder*
const db,
4425 const std::vector<SearchMonitor*>& monitors)
4426 : db_(db), monitors_(monitors) {
4427 CHECK(db !=
nullptr);
4430 ~SolveOnce()
override {}
4432 Decision* Next(Solver* s)
override {
4433 bool res = s->SolveAndCommit(db_, monitors_);
4440 std::string DebugString()
const override {
4441 return absl::StrFormat(
"SolveOnce(%s)", db_->DebugString());
4444 void Accept(ModelVisitor*
const visitor)
const override {
4445 db_->Accept(visitor);
4449 DecisionBuilder*
const db_;
4450 std::vector<SearchMonitor*> monitors_;
4455 return RevAlloc(
new SolveOnce(db));
4460 std::vector<SearchMonitor*> monitors;
4461 monitors.push_back(monitor1);
4462 return RevAlloc(
new SolveOnce(db, monitors));
4468 std::vector<SearchMonitor*> monitors;
4469 monitors.push_back(monitor1);
4470 monitors.push_back(monitor2);
4471 return RevAlloc(
new SolveOnce(db, monitors));
4478 std::vector<SearchMonitor*> monitors;
4479 monitors.push_back(monitor1);
4480 monitors.push_back(monitor2);
4481 monitors.push_back(monitor3);
4482 return RevAlloc(
new SolveOnce(db, monitors));
4490 std::vector<SearchMonitor*> monitors;
4491 monitors.push_back(monitor1);
4492 monitors.push_back(monitor2);
4493 monitors.push_back(monitor3);
4494 monitors.push_back(monitor4);
4495 return RevAlloc(
new SolveOnce(db, monitors));
4499 DecisionBuilder*
const db,
const std::vector<SearchMonitor*>& monitors) {
4500 return RevAlloc(
new SolveOnce(db, monitors));
4509 bool maximize, int64_t step)
4511 solution_(solution),
4514 collector_(nullptr) {
4515 CHECK(db !=
nullptr);
4516 CHECK(solution !=
nullptr);
4521 NestedOptimize(DecisionBuilder*
const db, Assignment*
const solution,
4522 bool maximize, int64_t step,
4523 const std::vector<SearchMonitor*>& monitors)
4525 solution_(solution),
4528 monitors_(monitors),
4529 collector_(nullptr) {
4530 CHECK(db !=
nullptr);
4531 CHECK(solution !=
nullptr);
4532 CHECK(solution->HasObjective());
4536 void AddMonitors() {
4537 Solver*
const solver = solution_->solver();
4538 collector_ = solver->MakeLastSolutionCollector(solution_);
4539 monitors_.push_back(collector_);
4540 OptimizeVar*
const optimize =
4542 monitors_.push_back(optimize);
4545 Decision* Next(Solver* solver)
override {
4546 solver->Solve(db_, monitors_);
4547 if (collector_->solution_count() == 0) {
4550 collector_->solution(0)->Restore();
4554 std::string DebugString()
const override {
4555 return absl::StrFormat(
"NestedOptimize(db = %s, maximize = %d, step = %d)",
4559 void Accept(ModelVisitor*
const visitor)
const override {
4560 db_->Accept(visitor);
4564 DecisionBuilder*
const db_;
4565 Assignment*
const solution_;
4567 const int64_t
step_;
4568 std::vector<SearchMonitor*> monitors_;
4569 SolutionCollector* collector_;
4575 bool maximize, int64_t step) {
4576 return RevAlloc(
new NestedOptimize(db, solution, maximize, step));
4581 bool maximize, int64_t step,
4583 std::vector<SearchMonitor*> monitors;
4584 monitors.push_back(monitor1);
4585 return RevAlloc(
new NestedOptimize(db, solution, maximize, step, monitors));
4590 bool maximize, int64_t step,
4593 std::vector<SearchMonitor*> monitors;
4594 monitors.push_back(monitor1);
4595 monitors.push_back(monitor2);
4596 return RevAlloc(
new NestedOptimize(db, solution, maximize, step, monitors));
4601 bool maximize, int64_t step,
4605 std::vector<SearchMonitor*> monitors;
4606 monitors.push_back(monitor1);
4607 monitors.push_back(monitor2);
4608 monitors.push_back(monitor3);
4609 return RevAlloc(
new NestedOptimize(db, solution, maximize, step, monitors));
4616 std::vector<SearchMonitor*> monitors;
4617 monitors.push_back(monitor1);
4618 monitors.push_back(monitor2);
4619 monitors.push_back(monitor3);
4620 monitors.push_back(monitor4);
4621 return RevAlloc(
new NestedOptimize(db, solution, maximize, step, monitors));
4626 int64_t step,
const std::vector<SearchMonitor*>& monitors) {
4627 return RevAlloc(
new NestedOptimize(db, solution, maximize, step, monitors));
4634 int64_t NextLuby(
int i) {
4642 while (power < (i + 1)) {
4645 if (power == i + 1) {
4648 return NextLuby(i - (power / 2) + 1);
4651 class LubyRestart :
public SearchMonitor {
4653 LubyRestart(Solver*
const s,
int scale_factor)
4655 scale_factor_(scale_factor),
4658 next_step_(scale_factor) {
4662 ~LubyRestart()
override {}
4664 void BeginFail()
override {
4665 if (++current_fails_ >= next_step_) {
4667 next_step_ = NextLuby(++iteration_) * scale_factor_;
4668 solver()->RestartCurrentSearch();
4672 std::string DebugString()
const override {
4673 return absl::StrFormat(
"LubyRestart(%i)", scale_factor_);
4677 const int scale_factor_;
4679 int64_t current_fails_;
4685 return RevAlloc(
new LubyRestart(
this, scale_factor));
4693 ConstantRestart(
Solver*
const s,
int frequency)
4694 :
SearchMonitor(s), frequency_(frequency), current_fails_(0) {
4698 ~ConstantRestart()
override {}
4700 void BeginFail()
override {
4701 if (++current_fails_ >= frequency_) {
4703 solver()->RestartCurrentSearch();
4707 std::string DebugString()
const override {
4708 return absl::StrFormat(
"ConstantRestart(%i)", frequency_);
4712 const int frequency_;
4713 int64_t current_fails_;
4718 return RevAlloc(
new ConstantRestart(
this, frequency));
4741 const std::vector<SymmetryBreaker*>& visitors)
4743 visitors_(visitors),
4744 clauses_(visitors.size()),
4745 decisions_(visitors.size()),
4746 directions_(visitors.size()) {
4747 for (
int i = 0; i < visitors_.size(); ++i) {
4748 visitors_[i]->set_symmetry_manager_and_index(
this, i);
4756 for (
int i = 0; i < visitors_.size(); ++i) {
4757 const void*
const last = clauses_[i].Last();
4759 if (last != clauses_[i].Last()) {
4761 decisions_[i].Push(
solver(), d);
4762 directions_[i].Push(
solver(),
false);
4769 for (
int i = 0; i < visitors_.size(); ++i) {
4770 if (decisions_[i].Last() !=
nullptr && decisions_[i].LastValue() == d) {
4783 std::vector<IntVar*> guard;
4788 IntVar*
const term = *tmp;
4790 if (term->
Max() == 0) {
4794 if (term->
Min() == 0) {
4797 guard.push_back(term);
4803 guard.push_back(clauses_[
index].LastValue());
4804 directions_[
index].SetLastValue(
true);
4816 clauses_[visitor->index_in_symmetry_manager()].Push(
solver(), term);
4819 std::string
DebugString()
const override {
return "SymmetryManager"; }
4822 const std::vector<SymmetryBreaker*> visitors_;
4823 std::vector<SimpleRevFIFO<IntVar*>> clauses_;
4824 std::vector<SimpleRevFIFO<Decision*>> decisions_;
4825 std::vector<SimpleRevFIFO<bool>> directions_;
4857 const std::vector<SymmetryBreaker*>& visitors) {
4862 std::vector<SymmetryBreaker*> visitors;
4863 visitors.push_back(v1);
4869 std::vector<SymmetryBreaker*> visitors;
4870 visitors.push_back(v1);
4871 visitors.push_back(v2);
4878 std::vector<SymmetryBreaker*> visitors;
4879 visitors.push_back(v1);
4880 visitors.push_back(v2);
4881 visitors.push_back(v3);
4889 std::vector<SymmetryBreaker*> visitors;
4890 visitors.push_back(v1);
4891 visitors.push_back(v2);
4892 visitors.push_back(v3);
4893 visitors.push_back(v4);
#define DCHECK_LE(val1, val2)
#define CHECK_LT(val1, val2)
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
#define CHECK_GT(val1, val2)
#define DCHECK_GT(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
#define CHECK_LE(val1, val2)
#define DCHECK_EQ(val1, val2)
#define VLOG(verboselevel)
An Assignment is a variable -> domains mapping, used to report solutions to the user.
const std::vector< int > & Unperformed(const SequenceVar *const var) const
const std::vector< int > & BackwardSequence(const SequenceVar *const var) const
int64_t EndValue(const IntervalVar *const var) const
int64_t ObjectiveMax() const
int64_t StartValue(const IntervalVar *const var) const
int64_t PerformedValue(const IntervalVar *const var) const
int64_t ObjectiveValue() const
int64_t DurationValue(const IntervalVar *const var) const
const std::vector< int > & ForwardSequence(const SequenceVar *const var) const
bool HasObjective() const
int64_t ObjectiveMin() const
int64_t Value(const IntVar *const var) const
A BaseObject is the root of all reversibly allocated objects.
void Set(uint32_t index, bool value)
bool Get(uint32_t index) const
A constraint is the main modeling object.
A DecisionBuilder is responsible for creating the search tree.
A Decision represents a choice point in the search tree.
virtual void Accept(DecisionVisitor *const visitor) const
Accepts the given visitor.
virtual void Apply(Solver *const s)=0
Apply will be called first when the decision is executed.
virtual void Refute(Solver *const s)=0
Refute will be called after a backtrack.
std::string DebugString() const override
bool Check() override
This method is called to check the status of the limit.
void Init() override
This method is called when the search limit is initialized.
~ImprovementSearchLimit() override
void Copy(const SearchLimit *const limit) override
Copy a limit.
bool AtSolution() override
This method is called when a valid solution is found.
ImprovementSearchLimit(Solver *const s, IntVar *objective_var, bool maximize, double objective_scaling_factor, double objective_offset, double improvement_rate_coefficient, int improvement_rate_solutions_distance)
SearchLimit * MakeClone() const override
Allocates a clone of the limit.
The class IntExpr is the base of all integer expressions in constraint programming.
virtual bool Bound() const
Returns true if the min and the max of the expression are equal.
virtual void SetValue(int64_t v)
This method sets the value of the expression.
virtual int64_t Min() const =0
virtual void SetMax(int64_t m)=0
virtual void SetMin(int64_t m)=0
virtual int64_t Max() const =0
The class IntVar is a subset of IntExpr.
virtual int64_t Value() const =0
This method returns the value of the variable.
Interval variables are often used in scheduling.
static int64_t FastInt64Round(double x)
static const char kSolutionLimitArgument[]
static const char kObjectiveExtension[]
static const char kMaximizeArgument[]
virtual void VisitIntegerArgument(const std::string &arg_name, int64_t value)
Visit integer arguments.
static const char kTimeLimitArgument[]
static const char kBranchesLimitArgument[]
static const char kSmartTimeCheckArgument[]
virtual void BeginVisitExtension(const std::string &type)
virtual void EndVisitExtension(const std::string &type)
static const char kCumulativeArgument[]
static const char kStepArgument[]
static const char kVarsArgument[]
static const char kVariableGroupExtension[]
static const char kExpressionArgument[]
static const char kFailuresLimitArgument[]
virtual void VisitIntegerExpressionArgument(const std::string &arg_name, IntExpr *const argument)
Visit integer expression argument.
static const char kSearchLimitExtension[]
This class encapsulates an objective.
void EnterSearch() override
Beginning of the search.
void BeginNextDecision(DecisionBuilder *const db) override
Before calling DecisionBuilder::Next.
OptimizeVar(Solver *const s, bool maximize, IntVar *const a, int64_t step)
bool found_initial_solution_
IntVar * Var() const
Returns the variable that is optimized.
void Accept(ModelVisitor *const visitor) const override
Accepts the given model visitor.
bool AcceptSolution() override
This method is called when a solution is found.
virtual std::string Print() const
bool AtSolution() override
This method is called when a valid solution is found.
void RefuteDecision(Decision *const d) override
Before refuting the decision.
bool AcceptDelta(Assignment *delta, Assignment *deltadelta) override
Internal methods.
std::string DebugString() const override
std::string DebugString() const override
Usual limit based on wall_time, number of explored branches and number of failures in the search tree...
bool Check() override
This method is called to check the status of the limit.
absl::Duration duration_limit() const
bool IsUncheckedSolutionLimitReached() override
Returns true if the limit of solutions has been reached including unchecked solutions.
void UpdateLimits(absl::Duration time, int64_t branches, int64_t failures, int64_t solutions)
void Init() override
This method is called when the search limit is initialized.
void ExitSearch() override
End of the search.
int64_t wall_time() const
int ProgressPercent() override
Returns a percentage representing the propress of the search before reaching limits.
void Accept(ModelVisitor *const visitor) const override
Accepts the given model visitor.
void Copy(const SearchLimit *const limit) override
Copy a limit.
RegularLimit * MakeIdenticalClone() const
std::string DebugString() const override
int64_t solutions() const
SearchLimit * MakeClone() const override
Allocates a clone of the limit.
Base class of all search limits.
bool crossed() const
Returns true if the limit has been crossed.
The base class of all search logs that periodically outputs information when the search is running.
void BeginFail() override
Just when the failure occurs.
virtual void OutputLine(const std::string &line)
void EnterSearch() override
Beginning of the search.
void RefuteDecision(Decision *const decision) override
Before refuting the decision.
void ExitSearch() override
End of the search.
SearchLog(Solver *const s, OptimizeVar *const obj, IntVar *const var, double scaling_factor, double offset, std::function< std::string()> display_callback, bool display_on_new_solutions_only, int period)
void BeginInitialPropagation() override
Before the initial propagation.
void NoMoreSolutions() override
When the search tree is finished.
void ApplyDecision(Decision *const decision) override
Before applying the decision.
bool AtSolution() override
This method is called when a valid solution is found.
std::string DebugString() const override
void AcceptUncheckedNeighbor() override
After accepting an unchecked neighbor during local search.
void EndInitialPropagation() override
After the initial propagation.
A search monitor is a simple set of callbacks to monitor all search events.
virtual void ExitSearch()
End of the search.
static constexpr int kNoProgress
virtual bool AtSolution()
This method is called when a valid solution is found.
A sequence variable is a variable whose domain is a set of possible orderings of the interval variabl...
This iterator is not stable with respect to deletion.
This class represent a reversible FIFO structure.
This class is the root class of all solution collectors.
void check_index(int n) const
void EnterSearch() override
Beginning of the search.
~SolutionCollector() override
void Push(const SolutionData &data)
void PushSolution()
Push the current state as a new solution.
void AddObjective(IntVar *const objective)
std::vector< Assignment * > recycle_solutions_
std::vector< SolutionData > solution_data_
void Add(IntVar *const var)
Add API.
int solution_count() const
Returns how many solutions were stored during the search.
int64_t Value(int n, IntVar *const var) const
This is a shortcut to get the Value of 'var' in the nth solution.
const std::vector< int > & Unperformed(int n, SequenceVar *const var) const
This is a shortcut to get the list of unperformed of 'var' in the nth solution.
SolutionData BuildSolutionDataForCurrentState()
int64_t DurationValue(int n, IntervalVar *const var) const
This is a shortcut to get the DurationValue of 'var' in the nth solution.
int64_t StartValue(int n, IntervalVar *const var) const
This is a shortcut to get the StartValue of 'var' in the nth solution.
Assignment * solution(int n) const
Returns the nth solution.
int64_t EndValue(int n, IntervalVar *const var) const
This is a shortcut to get the EndValue of 'var' in the nth solution.
int64_t objective_value(int n) const
Returns the objective value of the nth solution.
int64_t wall_time(int n) const
Returns the wall time in ms for the nth solution.
int64_t branches(int n) const
Returns the number of branches when the nth solution was found.
int64_t PerformedValue(int n, IntervalVar *const var) const
This is a shortcut to get the PerformedValue of 'var' in the nth solution.
const std::vector< int > & ForwardSequence(int n, SequenceVar *const var) const
This is a shortcut to get the ForwardSequence of 'var' in the nth solution.
void FreeSolution(Assignment *solution)
int64_t failures(int n) const
Returns the number of failures encountered at the time of the nth solution.
std::unique_ptr< Assignment > prototype_
SolutionCollector(Solver *const solver, const Assignment *assignment)
void PopSolution()
Remove and delete the last popped solution.
std::string DebugString() const override
const std::vector< int > & BackwardSequence(int n, SequenceVar *const var) const
This is a shortcut to get the BackwardSequence of 'var' in the nth solution.
int64_t neighbors() const
The number of neighbors created.
SearchMonitor * MakeLubyRestart(int scale_factor)
This search monitor will restart the search periodically.
SolutionCollector * MakeAllSolutionCollector()
Collect all solutions of the search.
RegularLimit * MakeSolutionsLimit(int64_t solutions)
Creates a search limit that constrains the number of solutions found during the search.
OptimizeVar * MakeWeightedMinimize(const std::vector< IntVar * > &sub_objectives, const std::vector< int64_t > &weights, int64_t step)
Creates a minimization weighted objective.
SolutionCollector * MakeLastSolutionCollector()
Collect the last solution of the search.
Decision * MakeAssignVariableValueOrDoNothing(IntVar *const var, int64_t value)
SearchMonitor * MakeAtSolutionCallback(std::function< void()> callback)
int64_t branches() const
The number of branches explored since the creation of the solver.
SearchLimit * MakeCustomLimit(std::function< bool()> limiter)
Callback-based search limit.
Constraint * MakeEquality(IntExpr *const left, IntExpr *const right)
left == right
OptimizeVar * MakeOptimize(bool maximize, IntVar *const v, int64_t step)
Creates a objective with a given sense (true = maximization).
IntVar * MakeIsGreaterOrEqualCstVar(IntExpr *const var, int64_t value)
status var of (var >= value)
ConstraintSolverParameters parameters() const
Stored Parameters.
SearchMonitor * MakeSymmetryManager(const std::vector< SymmetryBreaker * > &visitors)
Symmetry Breaking.
RegularLimit * MakeFailuresLimit(int64_t failures)
Creates a search limit that constrains the number of failures that can happen when exploring the sear...
absl::Time Now() const
The 'absolute time' as seen by the solver.
std::function< int64_t(int64_t, int64_t, int64_t)> IndexEvaluator3
Assignment * GetOrCreateLocalSearchState()
Returns (or creates) an assignment representing the state of local search.
DecisionBuilder * MakeNestedOptimize(DecisionBuilder *const db, Assignment *const solution, bool maximize, int64_t step)
NestedOptimize will collapse a search tree described by a decision builder 'db' and a set of monitors...
DecisionBuilder * Try(DecisionBuilder *const db1, DecisionBuilder *const db2)
Creates a decision builder which will create a search tree where each decision builder is called from...
RegularLimit * MakeBranchesLimit(int64_t branches)
Creates a search limit that constrains the number of branches explored in the search tree.
OptimizeVar * MakeMaximize(IntVar *const v, int64_t step)
Creates a maximization objective.
SearchMonitor * MakeSearchLog(int branch_period)
The SearchMonitors below will display a periodic search log on LOG(INFO) every branch_period branches...
IntValueStrategy
This enum describes the strategy used to select the next variable value to set.
@ INT_VALUE_SIMPLE
The simple selection is ASSIGN_MIN_VALUE.
@ ASSIGN_CENTER_VALUE
Selects the first possible value which is the closest to the center of the domain of the selected var...
@ SPLIT_UPPER_HALF
Split the domain in two around the center, and choose the lower part first.
@ 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.
@ INT_VALUE_DEFAULT
The default behavior is ASSIGN_MIN_VALUE.
@ ASSIGN_MAX_VALUE
Selects the max value of the selected variable.
@ SPLIT_LOWER_HALF
Split the domain in two around the center, and choose the lower part first.
RegularLimit * MakeLimit(absl::Duration time, int64_t branches, int64_t failures, int64_t solutions, bool smart_time_check=false, bool cumulative=false)
Limits the search with the 'time', 'branches', 'failures' and 'solutions' limits.
std::function< int64_t(Solver *solver, const std::vector< IntVar * > &vars, int64_t first_unbound, int64_t last_unbound)> VariableIndexSelector
std::function< int64_t(int64_t, int64_t)> IndexEvaluator2
OptimizeVar * MakeMinimize(IntVar *const v, int64_t step)
Creates a minimization objective.
void AddConstraint(Constraint *const c)
Adds the constraint 'c' to the model.
Decision * MakeAssignVariablesValues(const std::vector< IntVar * > &vars, const std::vector< int64_t > &values)
DecisionBuilder * MakeSolveOnce(DecisionBuilder *const db)
SolveOnce will collapse a search tree described by a decision builder 'db' and a set of monitors and ...
int64_t wall_time() const
DEPRECATED: Use Now() instead.
OptimizeVar * MakeWeightedMaximize(const std::vector< IntVar * > &sub_objectives, const std::vector< int64_t > &weights, int64_t step)
Creates a maximization weigthed objective.
int SearchDepth() const
Gets the search depth of the current active search.
int64_t unchecked_solutions() const
The number of unchecked solutions found by local search.
int64_t failures() const
The number of failures encountered since the creation of the solver.
ImprovementSearchLimit * MakeImprovementLimit(IntVar *objective_var, bool maximize, double objective_scaling_factor, double objective_offset, double improvement_rate_coefficient, int improvement_rate_solutions_distance)
Limits the search based on the improvements of 'objective_var'.
SearchMonitor * MakeConstantRestart(int frequency)
This search monitor will restart the search periodically after 'frequency' failures.
EvaluatorStrategy
This enum is used by Solver::MakePhase to specify how to select variables and values during the searc...
@ CHOOSE_STATIC_GLOBAL_BEST
Pairs are compared at the first call of the selector, and results are cached.
@ CHOOSE_DYNAMIC_GLOBAL_BEST
Pairs are compared each time a variable is selected.
static int64_t MemoryUsage()
Current memory usage in bytes.
void set_optimization_direction(OptimizationDirection direction)
IntVar * MakeIsLessOrEqualCstVar(IntExpr *const var, int64_t value)
status var of (var <= value)
SearchMonitor * MakeSimulatedAnnealing(bool maximize, IntVar *const v, int64_t step, int64_t initial_temperature)
Creates a Simulated Annealing monitor.
RegularLimitParameters MakeDefaultRegularLimitParameters() const
Creates a regular limit proto containing default values.
RegularLimit * MakeTimeLimit(absl::Duration time)
Creates a search limit that constrains the running time.
SearchMonitor * MakeSearchTrace(const std::string &prefix)
Creates a search monitor that will trace precisely the behavior of the search.
int TopProgressPercent()
Returns a percentage representing the propress of the search before reaching the limits of the top-le...
T * RevAlloc(T *object)
Registers the given object as being reversible.
IntVarStrategy
This enum describes the strategy used to select the next branching variable at each node during the s...
@ CHOOSE_RANDOM
Randomly select one of the remaining unbound variables.
@ CHOOSE_MIN_SIZE
Among unbound variables, select the variable with the smallest size.
@ CHOOSE_FIRST_UNBOUND
Select the first unbound variable.
@ CHOOSE_PATH
Selects the next unbound variable on a path, the path being defined by the variables: var[i] correspo...
@ CHOOSE_HIGHEST_MAX
Among unbound variables, select the variable with the highest maximal value.
@ CHOOSE_MIN_SIZE_LOWEST_MIN
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ INT_VAR_DEFAULT
The default behavior is CHOOSE_FIRST_UNBOUND.
@ CHOOSE_MIN_SIZE_HIGHEST_MAX
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ CHOOSE_MAX_REGRET_ON_MIN
Among unbound variables, select the variable with the largest gap between the first and the second va...
@ CHOOSE_MIN_SIZE_HIGHEST_MIN
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ CHOOSE_MAX_SIZE
Among unbound variables, select the variable with the highest size.
@ INT_VAR_SIMPLE
The simple selection is CHOOSE_FIRST_UNBOUND.
@ CHOOSE_MIN_SIZE_LOWEST_MAX
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ CHOOSE_LOWEST_MIN
Among unbound variables, select the variable with the smallest minimal value.
DecisionBuilder * MakePhase(const std::vector< IntVar * > &vars, IntVarStrategy var_str, IntValueStrategy val_str)
Phases on IntVar arrays.
std::function< int64_t(const IntVar *v, int64_t id)> VariableValueSelector
SearchMonitor * MakeEnterSearchCallback(std::function< void()> callback)
--— Callback-based search monitors --—
std::function< void(Solver *)> Action
SolutionCollector * MakeFirstSolutionCollector()
Collect the first solution of the search.
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).
std::function< int64_t(int64_t)> IndexEvaluator1
Callback typedefs.
SearchMonitor * MakeExitSearchCallback(std::function< void()> callback)
Decision * MakeSplitVariableDomain(IntVar *const var, int64_t val, bool start_with_lower_half)
DecisionBuilder * MakeDecisionBuilderFromAssignment(Assignment *const assignment, DecisionBuilder *const db, const std::vector< IntVar * > &vars)
Returns a decision builder for which the left-most leaf corresponds to assignment,...
Decision * MakeVariableLessOrEqualValue(IntVar *const var, int64_t value)
IntVar * MakeIsEqualCstVar(IntExpr *const var, int64_t value)
status var of (var == value)
int64_t solutions() const
The number of solutions found since the start of the search.
std::function< bool(int64_t, int64_t, int64_t)> VariableValueComparator
Decision * MakeAssignVariableValueOrFail(IntVar *const var, int64_t value)
Decision * MakeVariableGreaterOrEqualValue(IntVar *const var, int64_t value)
A symmetry breaker is an object that will visit a decision and create the 'symmetrical' decision in r...
void AddIntegerVariableLessOrEqualValueClause(IntVar *const var, int64_t value)
void AddIntegerVariableEqualValueClause(IntVar *const var, int64_t value)
void AddIntegerVariableGreaterOrEqualValueClause(IntVar *const var, int64_t value)
void AddTermToClause(SymmetryBreaker *const visitor, IntVar *const term)
~SymmetryManager() override
void EndNextDecision(DecisionBuilder *const db, 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.
SymmetryManager(Solver *const s, const std::vector< SymmetryBreaker * > &visitors)
std::string DebugString() const override
std::vector< IntVarIterator * > iterators_
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
void STLDeleteElements(T *container)
bool FindCopy(const Collection &collection, const Key &key, Value *const value)
const Collection::value_type::second_type & FindWithDefault(const Collection &collection, const typename Collection::value_type::first_type &key, const typename Collection::value_type::second_type &value)
std::function< int64_t(const Model &)> Value(IntegerVariable v)
Collection of objects used to extend the Constraint Solver library.
int64_t CapAdd(int64_t x, int64_t y)
int64_t CapSub(int64_t x, int64_t y)
std::pair< int64_t, int64_t > Arc
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)
bool AcceptDelta(Search *const search, Assignment *delta, Assignment *deltadelta)
std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)
void AcceptNeighbor(Search *const search)
BaseAssignVariables::Mode ChooseMode(Solver::IntValueStrategy val_str)
std::priority_queue< std::pair< int64_t, SolutionData > > solutions_pq_
int64_t assignment_penalized_value_
const double penalty_factor_
std::vector< DecisionBuilder * > builders_
std::unique_ptr< int64_t[]> delta_cache_
BaseVariableAssignmentSelector *const selector_
std::unique_ptr< int64_t[]> current_penalized_values_
const int solution_count_
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_
absl::flat_hash_map< const IntVar *, int64_t > indices_
Creates a search monitor from logging parameters.