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"
44#include "ortools/constraint_solver/search_limit.pb.h"
48 "Use sparse implementation to store Guided Local Search penalties");
50 "Whether search related logging should be "
52ABSL_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)) {
268std::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_;
415bool AtSolutionCallback::AtSolution() {
429 EnterSearchCallback(
Solver*
const solver, std::function<
void()>
callback)
431 ~EnterSearchCallback()
override {}
432 void EnterSearch()
override;
435 const std::function<void()> callback_;
438void 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_;
458void 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;
483CompositeDecisionBuilder::CompositeDecisionBuilder() {}
485CompositeDecisionBuilder::CompositeDecisionBuilder(
486 const std::vector<DecisionBuilder*>& dbs) {
487 for (
int i = 0; i < dbs.size(); ++i) {
492CompositeDecisionBuilder::~CompositeDecisionBuilder() {}
494void CompositeDecisionBuilder::Add(DecisionBuilder*
const db) {
500void CompositeDecisionBuilder::AppendMonitors(
501 Solver*
const solver, std::vector<SearchMonitor*>*
const monitors) {
502 for (DecisionBuilder*
const db :
builders_) {
503 db->AppendMonitors(solver, monitors);
507void CompositeDecisionBuilder::Accept(ModelVisitor*
const visitor)
const {
508 for (DecisionBuilder*
const db :
builders_) {
517class 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;
529ComposeDecisionBuilder::ComposeDecisionBuilder() : start_index_(0) {}
531ComposeDecisionBuilder::ComposeDecisionBuilder(
532 const std::vector<DecisionBuilder*>& dbs)
533 : CompositeDecisionBuilder(dbs), start_index_(0) {}
535ComposeDecisionBuilder::~ComposeDecisionBuilder() {}
537Decision* 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);
550std::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));
596class 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)));
622class TryDecisionBuilder;
624class 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_;
636class 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_;
651TryDecision::TryDecision(TryDecisionBuilder*
const try_builder)
652 : try_builder_(try_builder) {}
654TryDecision::~TryDecision() {}
656void TryDecision::Apply(Solver*
const solver) {}
658void TryDecision::Refute(Solver*
const solver) {
659 try_builder_->AdvanceToNextBuilder(solver);
662TryDecisionBuilder::TryDecisionBuilder()
663 : CompositeDecisionBuilder(),
665 current_builder_(-1),
666 start_new_builder_(true) {}
668TryDecisionBuilder::TryDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs)
669 : CompositeDecisionBuilder(dbs),
671 current_builder_(-1),
672 start_new_builder_(true) {}
674TryDecisionBuilder::~TryDecisionBuilder() {}
676Decision* 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);
689std::string TryDecisionBuilder::DebugString()
const {
690 return absl::StrFormat(
"TryDecisionBuilder(%s)",
694void 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));
743class 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_; }
797int64_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()) {
809int64_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();
830int64_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();
852int64_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();
873int64_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();
895int64_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();
913int64_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();
931int64_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();
949int64_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();
967class 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;
993int64_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;
1014int64_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()) {
1029class 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_;
1042int64_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) {
1063class 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_;
1078int64_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);
1100bool PathSelector::UpdateIndex(
const std::vector<IntVar*>& vars,
1101 int64_t*
index)
const {
1102 if (*
index >= vars.size()) {
1103 if (!FindPathStart(vars,
index)) {
1116bool 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()) {
1156int64_t SelectMinValue(
const IntVar* v, int64_t
id) {
return v->Min(); }
1160int64_t SelectMaxValue(
const IntVar* v, int64_t
id) {
return v->Max(); }
1164int64_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)) {
1207int64_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)) {
1232int64_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;
1242class 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_;
1257int64_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())];
1287class 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";
1302int64_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;
1318class 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_;
1344std::string VariableAssignmentSelector::DebugString()
const {
1350class 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 {
1371BaseEvaluatorSelector::BaseEvaluatorSelector(
1372 Solver* solver,
const std::vector<IntVar*>& vars,
1373 std::function<int64_t(int64_t, int64_t)> evaluator)
1374 : BaseVariableAssignmentSelector(solver, vars),
1379class 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_;
1395DynamicEvaluatorSelector::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)) {}
1403int64_t DynamicEvaluatorSelector::SelectValue(
const IntVar*
var, int64_t
id) {
1404 return cache_[first_].value;
1407int64_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;
1440std::string DynamicEvaluatorSelector::DebugString()
const {
1441 return DebugStringInternal(
"AssignVariablesOnDynamicEvaluator");
1446class 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_;
1482StaticEvaluatorSelector::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),
1489int64_t StaticEvaluatorSelector::SelectValue(
const IntVar*
var, int64_t
id) {
1490 return elements_[first_].value;
1493int64_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()));
1529std::string StaticEvaluatorSelector::DebugString()
const {
1530 return DebugStringInternal(
"AssignVariablesOnStaticEvaluator");
1535class 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_);
1551AssignOneVariableValue::AssignOneVariableValue(IntVar*
const v, int64_t val)
1552 : var_(v), value_(val) {}
1554std::string AssignOneVariableValue::DebugString()
const {
1555 return absl::StrFormat(
"[%s == %d] or [%s != %d]", var_->DebugString(),
1556 value_, var_->DebugString(), value_);
1559void AssignOneVariableValue::Apply(Solver*
const s) { var_->SetValue(value_); }
1561void AssignOneVariableValue::Refute(Solver*
const s) {
1562 var_->RemoveValue(value_);
1567 return RevAlloc(
new AssignOneVariableValue(
var, val));
1573class 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_;
1589AssignOneVariableValueOrFail::AssignOneVariableValueOrFail(IntVar*
const v,
1591 : var_(v), value_(
value) {}
1593std::string AssignOneVariableValueOrFail::DebugString()
const {
1594 return absl::StrFormat(
"[%s == %d] or fail", var_->
DebugString(), value_);
1597void AssignOneVariableValueOrFail::Apply(Solver*
const s) {
1601void AssignOneVariableValueOrFail::Refute(Solver*
const s) { s->Fail(); }
1612class 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_;
1641class 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_;
1658SplitOneVariable::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) {}
1662std::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_);
1670void SplitOneVariable::Apply(Solver*
const s) {
1671 if (start_with_lower_half_) {
1674 var_->
SetMin(value_ + 1);
1678void 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));
1705class AssignVariablesValues :
public Decision {
1711 enum class RefutationBehavior { kForbidAssignment, kDoNothing, kFail };
1712 AssignVariablesValues(
1713 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values,
1714 RefutationBehavior refutation = RefutationBehavior::kForbidAssignment);
1715 ~AssignVariablesValues()
override {}
1716 void Apply(Solver*
const s)
override;
1717 void Refute(Solver*
const s)
override;
1718 std::string DebugString()
const override;
1719 void Accept(DecisionVisitor*
const visitor)
const override {
1720 for (
int i = 0; i <
vars_.size(); ++i) {
1721 visitor->VisitSetVariableValue(
vars_[i], values_[i]);
1725 virtual void Accept(ModelVisitor*
const visitor)
const {
1733 const std::vector<IntVar*>
vars_;
1734 const std::vector<int64_t> values_;
1735 const RefutationBehavior refutation_;
1738AssignVariablesValues::AssignVariablesValues(
const std::vector<IntVar*>& vars,
1739 const std::vector<int64_t>& values,
1740 RefutationBehavior refutation)
1741 :
vars_(vars), values_(values), refutation_(refutation) {}
1743std::string AssignVariablesValues::DebugString()
const {
1745 if (
vars_.empty()) out +=
"do nothing";
1746 for (
int i = 0; i <
vars_.size(); ++i) {
1747 absl::StrAppendFormat(&out,
"[%s == %d]",
vars_[i]->DebugString(),
1750 switch (refutation_) {
1751 case RefutationBehavior::kForbidAssignment:
1752 out +=
" or forbid assignment";
1754 case RefutationBehavior::kDoNothing:
1755 out +=
" or do nothing";
1757 case RefutationBehavior::kFail:
1764void AssignVariablesValues::Apply(Solver*
const s) {
1765 if (
vars_.empty())
return;
1766 vars_[0]->FreezeQueue();
1767 for (
int i = 0; i <
vars_.size(); ++i) {
1768 vars_[i]->SetValue(values_[i]);
1770 vars_[0]->UnfreezeQueue();
1773void AssignVariablesValues::Refute(Solver*
const s) {
1774 switch (refutation_) {
1775 case RefutationBehavior::kForbidAssignment: {
1776 std::vector<IntVar*> terms;
1777 for (
int i = 0; i <
vars_.size(); ++i) {
1778 IntVar* term = s->MakeBoolVar();
1779 s->AddConstraint(s->MakeIsDifferentCstCt(
vars_[i], values_[i], term));
1780 terms.push_back(term);
1782 s->AddConstraint(s->MakeSumGreaterOrEqual(terms, 1));
1785 case RefutationBehavior::kDoNothing: {
1788 case RefutationBehavior::kFail: {
1797 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1798 CHECK_EQ(vars.size(), values.size());
1799 return RevAlloc(
new AssignVariablesValues(
1801 AssignVariablesValues::RefutationBehavior::kForbidAssignment));
1805 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1806 CHECK_EQ(vars.size(), values.size());
1807 return RevAlloc(
new AssignVariablesValues(
1808 vars, values, AssignVariablesValues::RefutationBehavior::kDoNothing));
1812 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1813 CHECK_EQ(vars.size(), values.size());
1814 return RevAlloc(
new AssignVariablesValues(
1815 vars, values, AssignVariablesValues::RefutationBehavior::kFail));
1829 BaseAssignVariables(BaseVariableAssignmentSelector*
const selector, Mode mode)
1832 ~BaseAssignVariables()
override;
1833 Decision* Next(Solver*
const s)
override;
1834 std::string DebugString()
const override;
1835 static BaseAssignVariables* MakePhase(
1836 Solver*
const s,
const std::vector<IntVar*>& vars,
1839 const std::string& value_selector_name, BaseAssignVariables::Mode mode);
1842 Solver*
const s,
const std::vector<IntVar*>& vars,
1848 return ChooseFirstUnbound;
1850 return ChooseRandom;
1852 return ChooseMinSizeLowestMin;
1854 return ChooseMinSizeHighestMin;
1856 return ChooseMinSizeLowestMax;
1858 return ChooseMinSizeHighestMax;
1860 return ChooseLowestMin;
1862 return ChooseHighestMax;
1864 return ChooseMinSize;
1866 return ChooseMaxSize;
1868 HighestRegretSelectorOnMin*
const selector =
1869 s->RevAlloc(
new HighestRegretSelectorOnMin(vars));
1870 return [selector](Solver* solver,
const std::vector<IntVar*>& vars,
1871 int first_unbound,
int last_unbound) {
1872 return selector->Choose(solver, vars, first_unbound, last_unbound);
1876 PathSelector*
const selector = s->RevAlloc(
new PathSelector());
1877 return [selector](Solver* solver,
const std::vector<IntVar*>& vars,
1878 int first_unbound,
int last_unbound) {
1879 return selector->Choose(solver, vars, first_unbound, last_unbound);
1883 LOG(
FATAL) <<
"Unknown int var strategy " << str;
1894 return SelectMinValue;
1896 return SelectMaxValue;
1898 return SelectRandomValue;
1900 return SelectCenterValue;
1902 return SelectSplitValue;
1904 return SelectSplitValue;
1906 LOG(
FATAL) <<
"Unknown int value strategy " << val_str;
1911 void Accept(ModelVisitor*
const visitor)
const override {
1920BaseAssignVariables::~BaseAssignVariables() {}
1922Decision* BaseAssignVariables::Next(Solver*
const s) {
1923 const std::vector<IntVar*>& vars =
selector_->vars();
1924 int id =
selector_->ChooseVariableWrapper();
1925 if (
id >= 0 &&
id < vars.size()) {
1926 IntVar*
const var = vars[id];
1930 return s->RevAlloc(
new AssignOneVariableValue(
var,
value));
1932 return s->RevAlloc(
new SplitOneVariable(
var,
value,
true));
1934 return s->RevAlloc(
new SplitOneVariable(
var,
value,
false));
1940std::string BaseAssignVariables::DebugString()
const {
1944BaseAssignVariables* BaseAssignVariables::MakePhase(
1945 Solver*
const s,
const std::vector<IntVar*>& vars,
1948 const std::string& value_selector_name, BaseAssignVariables::Mode mode) {
1949 BaseVariableAssignmentSelector*
const selector =
1950 s->RevAlloc(
new VariableAssignmentSelector(
1951 s, vars, std::move(var_selector), std::move(value_selector),
1952 value_selector_name));
1953 return s->RevAlloc(
new BaseAssignVariables(selector, mode));
1961 return "ChooseFirstUnbound";
1963 return "ChooseRandom";
1965 return "ChooseMinSizeLowestMin";
1967 return "ChooseMinSizeHighestMin";
1969 return "ChooseMinSizeLowestMax";
1971 return "ChooseMinSizeHighestMax";
1973 return "ChooseLowestMin";
1975 return "ChooseHighestMax";
1977 return "ChooseMinSize";
1979 return "ChooseMaxSize;";
1981 return "HighestRegretSelectorOnMin";
1983 return "PathSelector";
1985 LOG(
FATAL) <<
"Unknown int var strategy " << var_str;
1995 return "SelectMinValue";
1997 return "SelectMaxValue";
1999 return "SelectRandomValue";
2001 return "SelectCenterValue";
2003 return "SelectSplitValue";
2005 return "SelectSplitValue";
2007 LOG(
FATAL) <<
"Unknown int value strategy " << val_str;
2014 return ChooseVariableName(var_str) +
"_" + SelectValueName(val_str);
2021 std::vector<IntVar*> vars(1);
2023 return MakePhase(vars, var_str, val_str);
2029 std::vector<IntVar*> vars(2);
2032 return MakePhase(vars, var_str, val_str);
2039 std::vector<IntVar*> vars(3);
2043 return MakePhase(vars, var_str, val_str);
2050 std::vector<IntVar*> vars(4);
2055 return MakePhase(vars, var_str, val_str);
2059 BaseAssignVariables::Mode mode = BaseAssignVariables::ASSIGN;
2061 mode = BaseAssignVariables::SPLIT_LOWER;
2063 mode = BaseAssignVariables::SPLIT_UPPER;
2072 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2074 BaseAssignVariables::MakeValueSelector(
this, val_str);
2075 const std::string
name = BuildHeuristicsName(var_str, val_str);
2076 return BaseAssignVariables::MakePhase(
2077 this, vars, var_selector, value_selector,
name,
ChooseMode(val_str));
2083 CHECK(var_evaluator !=
nullptr);
2084 CheapestVarSelector*
const var_selector =
2085 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2087 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2088 int first_unbound,
int last_unbound) {
2089 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2092 BaseAssignVariables::MakeValueSelector(
this, val_str);
2093 const std::string
name =
"ChooseCheapestVariable_" + SelectValueName(val_str);
2094 return BaseAssignVariables::MakePhase(
2095 this, vars, choose_variable, select_value,
name,
ChooseMode(val_str));
2102 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2103 CheapestValueSelector*
const value_selector =
2104 RevAlloc(
new CheapestValueSelector(std::move(value_evaluator),
nullptr));
2106 [value_selector](
const IntVar*
var, int64_t id) {
2107 return value_selector->Select(
var,
id);
2109 const std::string
name = ChooseVariableName(var_str) +
"_SelectCheapestValue";
2110 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2112 BaseAssignVariables::ASSIGN);
2119 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2120 BestValueByComparisonSelector*
const value_selector =
RevAlloc(
2121 new BestValueByComparisonSelector(std::move(var_val1_val2_comparator)));
2123 [value_selector](
const IntVar*
var, int64_t id) {
2124 return value_selector->Select(
var,
id);
2126 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2127 select_value,
"CheapestValue",
2128 BaseAssignVariables::ASSIGN);
2134 CheapestVarSelector*
const var_selector =
2135 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2137 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2138 int first_unbound,
int last_unbound) {
2139 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2141 CheapestValueSelector* value_selector =
2142 RevAlloc(
new CheapestValueSelector(std::move(value_evaluator),
nullptr));
2144 [value_selector](
const IntVar*
var, int64_t id) {
2145 return value_selector->Select(
var,
id);
2147 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2148 select_value,
"CheapestValue",
2149 BaseAssignVariables::ASSIGN);
2157 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2158 CheapestValueSelector* value_selector =
RevAlloc(
new CheapestValueSelector(
2159 std::move(value_evaluator), std::move(tie_breaker)));
2161 [value_selector](
const IntVar*
var, int64_t id) {
2162 return value_selector->Select(
var,
id);
2164 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2165 select_value,
"CheapestValue",
2166 BaseAssignVariables::ASSIGN);
2173 CheapestVarSelector*
const var_selector =
2174 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2176 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2177 int first_unbound,
int last_unbound) {
2178 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2180 CheapestValueSelector* value_selector =
RevAlloc(
new CheapestValueSelector(
2181 std::move(value_evaluator), std::move(tie_breaker)));
2183 [value_selector](
const IntVar*
var, int64_t id) {
2184 return value_selector->Select(
var,
id);
2186 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2187 select_value,
"CheapestValue",
2188 BaseAssignVariables::ASSIGN);
2194 return MakePhase(vars, std::move(eval),
nullptr, str);
2201 BaseVariableAssignmentSelector* selector =
nullptr;
2205 selector =
RevAlloc(
new StaticEvaluatorSelector(
this, vars, eval));
2209 selector =
RevAlloc(
new DynamicEvaluatorSelector(
this, vars, eval,
2210 std::move(tie_breaker)));
2215 new BaseAssignVariables(selector, BaseAssignVariables::ASSIGN));
2223 AssignVariablesFromAssignment(
const Assignment*
const assignment,
2225 const std::vector<IntVar*>& vars)
2226 : assignment_(assignment), db_(db),
vars_(vars), iter_(0) {}
2228 ~AssignVariablesFromAssignment()
override {}
2230 Decision* Next(Solver*
const s)
override {
2231 if (iter_ <
vars_.size()) {
2232 IntVar*
const var =
vars_[iter_++];
2234 new AssignOneVariableValue(
var, assignment_->Value(
var)));
2236 return db_->Next(s);
2240 void Accept(ModelVisitor*
const visitor)
const override {
2248 const Assignment*
const assignment_;
2249 DecisionBuilder*
const db_;
2250 const std::vector<IntVar*>
vars_;
2257 const std::vector<IntVar*>& vars) {
2258 return RevAlloc(
new AssignVariablesFromAssignment(assignment, db, vars));
2268 prototype_(assignment == nullptr ? nullptr : new
Assignment(assignment)) {
2276 delete data.solution;
2318 if (
prototype_ !=
nullptr && objective !=
nullptr) {
2325 delete data.solution;
2376 CHECK_GE(n, 0) <<
"wrong index in solution getter";
2449 explicit FirstSolutionCollector(
Solver*
const s);
2450 ~FirstSolutionCollector()
override;
2451 void EnterSearch()
override;
2452 bool AtSolution()
override;
2453 std::string DebugString()
const override;
2459FirstSolutionCollector::FirstSolutionCollector(Solver*
const s,
2460 const Assignment*
const a)
2461 : SolutionCollector(s,
a), done_(false) {}
2463FirstSolutionCollector::FirstSolutionCollector(Solver*
const s)
2464 : SolutionCollector(s), done_(false) {}
2466FirstSolutionCollector::~FirstSolutionCollector() {}
2468void FirstSolutionCollector::EnterSearch() {
2473bool FirstSolutionCollector::AtSolution() {
2481std::string FirstSolutionCollector::DebugString()
const {
2482 if (prototype_ ==
nullptr) {
2483 return "FirstSolutionCollector()";
2485 return "FirstSolutionCollector(" + prototype_->DebugString() +
")";
2492 return RevAlloc(
new FirstSolutionCollector(
this, assignment));
2496 return RevAlloc(
new FirstSolutionCollector(
this));
2506 explicit LastSolutionCollector(
Solver*
const s);
2507 ~LastSolutionCollector()
override;
2508 bool AtSolution()
override;
2509 std::string DebugString()
const override;
2512LastSolutionCollector::LastSolutionCollector(Solver*
const s,
2513 const Assignment*
const a)
2514 : SolutionCollector(s,
a) {}
2516LastSolutionCollector::LastSolutionCollector(Solver*
const s)
2517 : SolutionCollector(s) {}
2519LastSolutionCollector::~LastSolutionCollector() {}
2521bool LastSolutionCollector::AtSolution() {
2527std::string LastSolutionCollector::DebugString()
const {
2528 if (prototype_ ==
nullptr) {
2529 return "LastSolutionCollector()";
2531 return "LastSolutionCollector(" + prototype_->DebugString() +
")";
2538 return RevAlloc(
new LastSolutionCollector(
this, assignment));
2542 return RevAlloc(
new LastSolutionCollector(
this));
2552 BestValueSolutionCollector(
Solver*
const s,
bool maximize);
2553 ~BestValueSolutionCollector()
override {}
2554 void EnterSearch()
override;
2555 bool AtSolution()
override;
2556 std::string DebugString()
const override;
2563BestValueSolutionCollector::BestValueSolutionCollector(
2564 Solver*
const s,
const Assignment*
const a,
bool maximize)
2565 : SolutionCollector(s,
a),
2567 best_(maximize ?
std::numeric_limits<int64_t>::
min()
2568 :
std::numeric_limits<int64_t>::
max()) {}
2570BestValueSolutionCollector::BestValueSolutionCollector(Solver*
const s,
2572 : SolutionCollector(s),
2574 best_(maximize ?
std::numeric_limits<int64_t>::
min()
2575 :
std::numeric_limits<int64_t>::
max()) {}
2577void BestValueSolutionCollector::EnterSearch() {
2578 SolutionCollector::EnterSearch();
2580 :
std::numeric_limits<int64_t>::
max();
2583bool BestValueSolutionCollector::AtSolution() {
2584 if (prototype_ !=
nullptr) {
2585 const IntVar* objective = prototype_->Objective();
2586 if (objective !=
nullptr) {
2587 if (
maximize_ && (solution_count() == 0 || objective->Max() >
best_)) {
2590 best_ = objective->Max();
2592 (solution_count() == 0 || objective->Min() <
best_)) {
2595 best_ = objective->Min();
2602std::string BestValueSolutionCollector::DebugString()
const {
2603 if (prototype_ ==
nullptr) {
2604 return "BestValueSolutionCollector()";
2606 return "BestValueSolutionCollector(" + prototype_->DebugString() +
")";
2612 const Assignment*
const assignment,
bool maximize) {
2613 return RevAlloc(
new BestValueSolutionCollector(
this, assignment, maximize));
2617 return RevAlloc(
new BestValueSolutionCollector(
this, maximize));
2625 NBestValueSolutionCollector(
Solver*
const solver,
2627 int solution_count,
bool maximize);
2628 NBestValueSolutionCollector(
Solver*
const solver,
int solution_count,
2630 ~NBestValueSolutionCollector()
override { Clear(); }
2644NBestValueSolutionCollector::NBestValueSolutionCollector(
2645 Solver*
const solver,
const Assignment*
const assignment,
2646 int solution_count,
bool maximize)
2647 : SolutionCollector(solver, assignment),
2651NBestValueSolutionCollector::NBestValueSolutionCollector(Solver*
const solver,
2654 : SolutionCollector(solver),
2658void NBestValueSolutionCollector::EnterSearch() {
2659 SolutionCollector::EnterSearch();
2663 solver()->SetUseFastLocalSearch(
false);
2668void NBestValueSolutionCollector::ExitSearch() {
2675bool NBestValueSolutionCollector::AtSolution() {
2676 if (prototype_ !=
nullptr) {
2677 const IntVar* objective = prototype_->Objective();
2678 if (objective !=
nullptr) {
2698std::string NBestValueSolutionCollector::DebugString()
const {
2699 if (prototype_ ==
nullptr) {
2700 return "NBestValueSolutionCollector()";
2702 return "NBestValueSolutionCollector(" + prototype_->DebugString() +
")";
2706void NBestValueSolutionCollector::Clear() {
2716 const Assignment*
const assignment,
int solution_count,
bool maximize) {
2717 if (solution_count == 1) {
2718 return MakeBestValueSolutionCollector(assignment, maximize);
2720 return RevAlloc(
new NBestValueSolutionCollector(
this, assignment,
2721 solution_count, maximize));
2726 if (solution_count == 1) {
2727 return MakeBestValueSolutionCollector(maximize);
2730 new NBestValueSolutionCollector(
this, solution_count, maximize));
2740 explicit AllSolutionCollector(
Solver*
const s);
2741 ~AllSolutionCollector()
override;
2746AllSolutionCollector::AllSolutionCollector(Solver*
const s,
2747 const Assignment*
const a)
2748 : SolutionCollector(s,
a) {}
2750AllSolutionCollector::AllSolutionCollector(Solver*
const s)
2751 : SolutionCollector(s) {}
2753AllSolutionCollector::~AllSolutionCollector() {}
2755bool AllSolutionCollector::AtSolution() {
2760std::string AllSolutionCollector::DebugString()
const {
2761 if (prototype_ ==
nullptr) {
2762 return "AllSolutionCollector()";
2764 return "AllSolutionCollector(" + prototype_->DebugString() +
")";
2771 return RevAlloc(
new AllSolutionCollector(
this, assignment));
2775 return RevAlloc(
new AllSolutionCollector(
this));
2787 found_initial_solution_(false) {
2811 if (
solver()->SearchDepth() == 0) {
2854 if (
delta !=
nullptr) {
2855 const bool delta_has_objective =
delta->HasObjective();
2856 if (!delta_has_objective) {
2863 const int64_t delta_min_objective =
2864 delta_has_objective ?
delta->ObjectiveMin()
2866 const int64_t min_objective =
2870 delta->SetObjectiveMin(
2874 const int64_t delta_max_objective =
2875 delta_has_objective ?
delta->ObjectiveMax()
2877 const int64_t max_objective =
2881 delta->SetObjectiveMax(
2890 return absl::StrFormat(
"objective value = %d, ",
var_->
Value());
2896 out =
"MaximizeVar(";
2898 out =
"MinimizeVar(";
2900 absl::StrAppendFormat(&out,
"%s, step = %d, best = %d)",
var_->
DebugString(),
2930 WeightedOptimizeVar(
Solver* solver,
bool maximize,
2931 const std::vector<IntVar*>& sub_objectives,
2932 const std::vector<int64_t>& weights, int64_t step)
2934 solver->MakeScalProd(sub_objectives, weights)->Var(), step),
2935 sub_objectives_(sub_objectives),
2937 CHECK_EQ(sub_objectives.size(), weights.size());
2940 ~WeightedOptimizeVar()
override {}
2941 std::string Print()
const override;
2944 const std::vector<IntVar*> sub_objectives_;
2945 const std::vector<int64_t> weights_;
2950std::string WeightedOptimizeVar::Print()
const {
2952 result.append(
"\nWeighted Objective:\n");
2953 for (
int i = 0; i < sub_objectives_.size(); ++i) {
2954 absl::StrAppendFormat(&result,
"Variable %s,\tvalue %d,\tweight %d\n",
2955 sub_objectives_[i]->
name(),
2956 sub_objectives_[i]->
Value(), weights_[i]);
2963 bool maximize,
const std::vector<IntVar*>& sub_objectives,
2964 const std::vector<int64_t>& weights, int64_t step) {
2966 new WeightedOptimizeVar(
this, maximize, sub_objectives, weights, step));
2970 const std::vector<IntVar*>& sub_objectives,
2971 const std::vector<int64_t>& weights, int64_t step) {
2973 new WeightedOptimizeVar(
this,
false, sub_objectives, weights, step));
2977 const std::vector<IntVar*>& sub_objectives,
2978 const std::vector<int64_t>& weights, int64_t step) {
2980 new WeightedOptimizeVar(
this,
true, sub_objectives, weights, step));
2984 bool maximize,
const std::vector<IntVar*>& sub_objectives,
2985 const std::vector<int>& weights, int64_t step) {
2991 const std::vector<IntVar*>& sub_objectives,
const std::vector<int>& weights,
2997 const std::vector<IntVar*>& sub_objectives,
const std::vector<int>& weights,
3007 Metaheuristic(
Solver*
const solver,
bool maximize,
IntVar* objective,
3009 ~Metaheuristic()
override {}
3011 bool AtSolution()
override;
3012 void EnterSearch()
override;
3013 void RefuteDecision(Decision*
const d)
override;
3024Metaheuristic::Metaheuristic(Solver*
const solver,
bool maximize,
3025 IntVar* objective, int64_t step)
3026 : SearchMonitor(solver),
3033bool Metaheuristic::AtSolution() {
3043void Metaheuristic::EnterSearch() {
3046 solver()->SetUseFastLocalSearch(
false);
3056void Metaheuristic::RefuteDecision(Decision* d) {
3067 if (
delta !=
nullptr) {
3068 if (!
delta->HasObjective()) {
3073 delta->SetObjectiveMin(
3076 delta->SetObjectiveMax(
3086class TabuSearch :
public Metaheuristic {
3088 TabuSearch(Solver*
const s,
bool maximize, IntVar* objective, int64_t step,
3089 const std::vector<IntVar*>& vars, int64_t keep_tenure,
3090 int64_t forbid_tenure,
double tabu_factor);
3091 ~TabuSearch()
override {}
3092 void EnterSearch()
override;
3093 void ApplyDecision(Decision* d)
override;
3094 bool AtSolution()
override;
3095 bool LocalOptimum()
override;
3097 std::string DebugString()
const override {
return "Tabu Search"; }
3101 VarValue(IntVar*
const var, int64_t
value, int64_t stamp)
3104 const int64_t value_;
3107 typedef std::list<VarValue> TabuList;
3109 virtual std::vector<IntVar*> CreateTabuVars();
3110 const TabuList& forbid_tabu_list() {
return forbid_tabu_list_; }
3113 void AgeList(int64_t tenure, TabuList* list);
3116 const std::vector<IntVar*>
vars_;
3117 Assignment assignment_;
3119 TabuList keep_tabu_list_;
3120 int64_t keep_tenure_;
3121 TabuList forbid_tabu_list_;
3122 int64_t forbid_tenure_;
3123 double tabu_factor_;
3125 bool found_initial_solution_;
3130TabuSearch::TabuSearch(Solver*
const s,
bool maximize, IntVar* objective,
3131 int64_t step,
const std::vector<IntVar*>& vars,
3132 int64_t keep_tenure, int64_t forbid_tenure,
3134 : Metaheuristic(s, maximize, objective, step),
3137 last_(
std::numeric_limits<int64_t>::
max()),
3138 keep_tenure_(keep_tenure),
3139 forbid_tenure_(forbid_tenure),
3140 tabu_factor_(tabu_factor),
3142 found_initial_solution_(false) {
3143 assignment_.Add(
vars_);
3146void TabuSearch::EnterSearch() {
3147 Metaheuristic::EnterSearch();
3148 found_initial_solution_ =
false;
3151void TabuSearch::ApplyDecision(Decision*
const d) {
3152 Solver*
const s = solver();
3153 if (d == s->balancing_decision()) {
3158 IntVar* aspiration = s->MakeBoolVar();
3160 s->AddConstraint(s->MakeIsGreaterOrEqualCstCt(
3167 IntVar* tabu_var =
nullptr;
3171 const std::vector<IntVar*> tabu_vars = CreateTabuVars();
3172 if (!tabu_vars.empty()) {
3173 tabu_var = s->MakeIsGreaterOrEqualCstVar(s->MakeSum(tabu_vars)->Var(),
3174 tabu_vars.size() * tabu_factor_);
3178 if (tabu_var !=
nullptr) {
3180 s->MakeGreaterOrEqual(s->MakeSum(aspiration, tabu_var), int64_t{1}));
3197 if (found_initial_solution_) {
3198 s->AddConstraint(s->MakeNonEquality(
objective_, last_));
3202std::vector<IntVar*> TabuSearch::CreateTabuVars() {
3203 Solver*
const s = solver();
3211 std::vector<IntVar*> tabu_vars;
3212 for (
const VarValue& vv : keep_tabu_list_) {
3213 tabu_vars.push_back(s->MakeIsEqualCstVar(vv.var_, vv.value_));
3215 for (
const VarValue& vv : forbid_tabu_list_) {
3216 tabu_vars.push_back(s->MakeIsDifferentCstVar(vv.var_, vv.value_));
3221bool TabuSearch::AtSolution() {
3222 if (!Metaheuristic::AtSolution()) {
3225 found_initial_solution_ =
true;
3231 for (
int i = 0; i <
vars_.size(); ++i) {
3233 const int64_t old_value = assignment_.Value(
var);
3234 const int64_t new_value =
var->Value();
3235 if (old_value != new_value) {
3236 if (keep_tenure_ > 0) {
3237 VarValue keep_value(
var, new_value,
stamp_);
3238 keep_tabu_list_.push_front(keep_value);
3240 if (forbid_tenure_ > 0) {
3241 VarValue forbid_value(
var, old_value,
stamp_);
3242 forbid_tabu_list_.push_front(forbid_value);
3247 assignment_.Store();
3252bool TabuSearch::LocalOptimum() {
3259 return found_initial_solution_;
3268void TabuSearch::AgeList(int64_t tenure, TabuList* list) {
3269 while (!list->empty() && list->back().stamp_ <
stamp_ - tenure) {
3274void TabuSearch::AgeLists() {
3275 AgeList(keep_tenure_, &keep_tabu_list_);
3276 AgeList(forbid_tenure_, &forbid_tabu_list_);
3280class GenericTabuSearch :
public TabuSearch {
3282 GenericTabuSearch(Solver*
const s,
bool maximize, IntVar* objective,
3283 int64_t step,
const std::vector<IntVar*>& vars,
3284 int64_t forbid_tenure)
3285 : TabuSearch(s, maximize, objective, step, vars, 0, forbid_tenure, 1) {}
3286 std::string DebugString()
const override {
return "Generic Tabu Search"; }
3289 std::vector<IntVar*> CreateTabuVars()
override;
3292std::vector<IntVar*> GenericTabuSearch::CreateTabuVars() {
3293 Solver*
const s = solver();
3297 std::vector<IntVar*> forbid_values;
3298 for (
const VarValue& vv : forbid_tabu_list()) {
3299 forbid_values.push_back(s->MakeIsDifferentCstVar(vv.var_, vv.value_));
3301 std::vector<IntVar*> tabu_vars;
3302 if (!forbid_values.empty()) {
3303 tabu_vars.push_back(s->MakeIsGreaterCstVar(s->MakeSum(forbid_values), 0));
3312 const std::vector<IntVar*>& vars,
3313 int64_t keep_tenure,
3314 int64_t forbid_tenure,
3315 double tabu_factor) {
3316 return RevAlloc(
new TabuSearch(
this, maximize, v, step, vars, keep_tenure,
3317 forbid_tenure, tabu_factor));
3321 bool maximize,
IntVar*
const v, int64_t step,
3322 const std::vector<IntVar*>& tabu_vars, int64_t forbid_tenure) {
3324 new GenericTabuSearch(
this, maximize, v, step, tabu_vars, forbid_tenure));
3330class SimulatedAnnealing :
public Metaheuristic {
3332 SimulatedAnnealing(
Solver*
const s,
bool maximize,
IntVar* objective,
3333 int64_t step, int64_t initial_temperature);
3334 ~SimulatedAnnealing()
override {}
3335 void EnterSearch()
override;
3336 void ApplyDecision(Decision* d)
override;
3337 bool AtSolution()
override;
3338 bool LocalOptimum()
override;
3340 std::string DebugString()
const override {
return "Simulated Annealing"; }
3343 double Temperature()
const;
3345 const int64_t temperature0_;
3348 bool found_initial_solution_;
3353SimulatedAnnealing::SimulatedAnnealing(Solver*
const s,
bool maximize,
3354 IntVar* objective, int64_t step,
3355 int64_t initial_temperature)
3356 : Metaheuristic(s, maximize, objective, step),
3357 temperature0_(initial_temperature),
3360 found_initial_solution_(false) {}
3362void SimulatedAnnealing::EnterSearch() {
3363 Metaheuristic::EnterSearch();
3364 found_initial_solution_ =
false;
3367void SimulatedAnnealing::ApplyDecision(Decision*
const d) {
3368 Solver*
const s = solver();
3369 if (d == s->balancing_decision()) {
3372 const double rand_double = absl::Uniform<double>(rand_, 0.0, 1.0);
3373#if defined(_MSC_VER) || defined(__ANDROID__)
3374 const double rand_log2_double = log(rand_double) / log(2.0L);
3376 const double rand_log2_double = log2(rand_double);
3378 const int64_t energy_bound = Temperature() * rand_log2_double;
3392bool SimulatedAnnealing::AtSolution() {
3393 if (!Metaheuristic::AtSolution()) {
3396 found_initial_solution_ =
true;
3400bool SimulatedAnnealing::LocalOptimum() {
3407 return found_initial_solution_ && Temperature() > 0;
3411 if (iteration_ > 0) {
3416double SimulatedAnnealing::Temperature()
const {
3417 if (iteration_ > 0) {
3418 return (1.0 * temperature0_) / iteration_;
3427 int64_t initial_temperature) {
3429 new SimulatedAnnealing(
this, maximize, v, step, initial_temperature));
3434typedef std::pair<int64_t, int64_t>
Arc;
3439class GuidedLocalSearchPenalties {
3441 virtual ~GuidedLocalSearchPenalties() {}
3442 virtual bool HasValues()
const = 0;
3443 virtual void Increment(
const Arc&
arc) = 0;
3445 virtual void Reset() = 0;
3449class GuidedLocalSearchPenaltiesTable :
public GuidedLocalSearchPenalties {
3451 explicit GuidedLocalSearchPenaltiesTable(
int size);
3452 ~GuidedLocalSearchPenaltiesTable()
override {}
3453 bool HasValues()
const override {
return has_values_; }
3454 void Increment(
const Arc&
arc)
override;
3456 void Reset()
override;
3459 std::vector<std::vector<int64_t>> penalties_;
3463GuidedLocalSearchPenaltiesTable::GuidedLocalSearchPenaltiesTable(
int size)
3464 : penalties_(size), has_values_(
false) {}
3466void GuidedLocalSearchPenaltiesTable::Increment(
const Arc&
arc) {
3467 std::vector<int64_t>& first_penalties = penalties_[
arc.first];
3468 const int64_t second =
arc.second;
3469 if (second >= first_penalties.size()) {
3470 first_penalties.resize(second + 1, 0);
3472 ++first_penalties[second];
3476void GuidedLocalSearchPenaltiesTable::Reset() {
3477 has_values_ =
false;
3478 for (
int i = 0; i < penalties_.size(); ++i) {
3479 penalties_[i].clear();
3484 const std::vector<int64_t>& first_penalties = penalties_[
arc.first];
3485 const int64_t second =
arc.second;
3486 if (second >= first_penalties.size()) {
3489 return first_penalties[second];
3494class GuidedLocalSearchPenaltiesMap :
public GuidedLocalSearchPenalties {
3496 explicit GuidedLocalSearchPenaltiesMap(
int size);
3497 ~GuidedLocalSearchPenaltiesMap()
override {}
3498 bool HasValues()
const override {
return (!penalties_.empty()); }
3499 void Increment(
const Arc&
arc)
override;
3501 void Reset()
override;
3505 absl::flat_hash_map<Arc, int64_t> penalties_;
3508GuidedLocalSearchPenaltiesMap::GuidedLocalSearchPenaltiesMap(
int size)
3509 : penalized_(size,
false) {}
3511void GuidedLocalSearchPenaltiesMap::Increment(
const Arc&
arc) {
3513 penalized_.
Set(
arc.first,
true);
3516void GuidedLocalSearchPenaltiesMap::Reset() {
3522 if (penalized_.
Get(
arc.first)) {
3528class GuidedLocalSearch :
public Metaheuristic {
3530 GuidedLocalSearch(
Solver*
const s,
IntVar* objective,
bool maximize,
3531 int64_t step,
const std::vector<IntVar*>& vars,
3532 double penalty_factor);
3533 ~GuidedLocalSearch()
override {}
3535 void ApplyDecision(
Decision* d)
override;
3536 bool AtSolution()
override;
3537 void EnterSearch()
override;
3538 bool LocalOptimum()
override;
3539 virtual int64_t AssignmentElementPenalty(
const Assignment& assignment,
3541 virtual int64_t AssignmentPenalty(
const Assignment& assignment,
int index,
3544 int64_t
index,
int* container_index,
3545 int64_t* penalty) = 0;
3547 std::string DebugString()
const override {
return "Guided Local Search"; }
3551 bool operator()(
const std::pair<Arc, double>& i,
3552 const std::pair<Arc, double>& j) {
3553 return i.second > j.second;
3558 const int64_t*
const out_values,
bool cache_delta_values);
3561 Assignment assignment_;
3564 const std::vector<IntVar*>
vars_;
3567 std::unique_ptr<GuidedLocalSearchPenalties> penalties_;
3573GuidedLocalSearch::GuidedLocalSearch(Solver*
const s, IntVar* objective,
3574 bool maximize, int64_t step,
3575 const std::vector<IntVar*>& vars,
3576 double penalty_factor)
3577 : Metaheuristic(s, maximize, objective, step),
3585 if (!vars.empty()) {
3587 assignment_.Add(
vars_);
3593 for (
int i = 0; i <
vars_.size(); ++i) {
3596 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
3597 penalties_ = absl::make_unique<GuidedLocalSearchPenaltiesMap>(
vars_.size());
3600 absl::make_unique<GuidedLocalSearchPenaltiesTable>(
vars_.size());
3611void GuidedLocalSearch::ApplyDecision(Decision*
const d) {
3612 if (d == solver()->balancing_decision()) {
3616 if (penalties_->HasValues()) {
3620 std::vector<IntVar*> elements;
3621 for (
int i = 0; i <
vars_.size(); ++i) {
3622 elements.push_back(MakeElementPenalty(i)->Var());
3623 const int64_t penalty = AssignmentElementPenalty(assignment_, i);
3634 IntExpr* min_pen_exp =
3636 IntVar* min_exp = solver()->MakeMin(min_pen_exp,
best_ +
step_)->Var();
3637 solver()->AddConstraint(
3638 solver()->MakeGreaterOrEqual(
objective_, min_exp));
3640 IntExpr* max_pen_exp =
3642 IntVar* max_exp = solver()->MakeMax(max_pen_exp,
best_ -
step_)->Var();
3643 solver()->AddConstraint(solver()->MakeLessOrEqual(
objective_, max_exp));
3661bool GuidedLocalSearch::AtSolution() {
3662 if (!Metaheuristic::AtSolution()) {
3668 assignment_.Store();
3672void GuidedLocalSearch::EnterSearch() {
3673 Metaheuristic::EnterSearch();
3679 penalties_->Reset();
3685 if (
delta !=
nullptr || deltadelta !=
nullptr) {
3686 if (!penalties_->HasValues()) {
3689 int64_t penalty = 0;
3690 if (!deltadelta->Empty()) {
3701 for (
int i = 0; i <
vars_.size(); ++i) {
3711 if (!
delta->HasObjective()) {
3716 delta->SetObjectiveMin(
3719 delta->ObjectiveMin()));
3721 delta->SetObjectiveMax(
3724 delta->ObjectiveMax()));
3731int64_t GuidedLocalSearch::Evaluate(
const Assignment*
delta,
3732 int64_t current_penalty,
3733 const int64_t*
const out_values,
3734 bool cache_delta_values) {
3735 int64_t penalty = current_penalty;
3736 const Assignment::IntContainer& container =
delta->IntVarContainer();
3737 const int size = container.Size();
3738 for (
int i = 0; i < size; ++i) {
3739 const IntVarElement& new_element = container.Element(i);
3740 IntVar*
var = new_element.Var();
3744 int64_t new_penalty = 0;
3745 if (EvaluateElementValue(container,
index, &i, &new_penalty)) {
3746 penalty =
CapAdd(penalty, new_penalty);
3747 if (cache_delta_values) {
3758bool GuidedLocalSearch::LocalOptimum() {
3759 std::vector<std::pair<Arc, double>> utility(
vars_.size());
3760 for (
int i = 0; i <
vars_.size(); ++i) {
3761 if (!assignment_.Bound(
vars_[i])) {
3765 const int64_t var_value = assignment_.Value(
vars_[i]);
3766 const int64_t
value =
3767 (var_value != i) ? AssignmentPenalty(assignment_, i, var_value) : 0;
3768 const Arc arc(i, var_value);
3769 const int64_t penalty = penalties_->Value(
arc);
3770 utility[i] = std::pair<Arc, double>(
arc,
value / (penalty + 1.0));
3772 Comparator comparator;
3773 std::sort(utility.begin(), utility.end(), comparator);
3774 int64_t utility_value = utility[0].second;
3775 penalties_->Increment(utility[0].first);
3776 for (
int i = 1; i < utility.size() && utility_value == utility[i].second;
3778 penalties_->Increment(utility[i].first);
3788class BinaryGuidedLocalSearch :
public GuidedLocalSearch {
3790 BinaryGuidedLocalSearch(
3791 Solver*
const solver, IntVar*
const objective,
3792 std::function<int64_t(int64_t, int64_t)> objective_function,
3793 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
3794 double penalty_factor);
3795 ~BinaryGuidedLocalSearch()
override {}
3796 IntExpr* MakeElementPenalty(
int index)
override;
3797 int64_t AssignmentElementPenalty(
const Assignment& assignment,
3798 int index)
override;
3799 int64_t AssignmentPenalty(
const Assignment& assignment,
int index,
3800 int64_t
next)
override;
3801 bool EvaluateElementValue(
const Assignment::IntContainer& container,
3802 int64_t
index,
int* container_index,
3803 int64_t* penalty)
override;
3806 int64_t PenalizedValue(int64_t i, int64_t j);
3807 std::function<int64_t(int64_t, int64_t)> objective_function_;
3810BinaryGuidedLocalSearch::BinaryGuidedLocalSearch(
3811 Solver*
const solver, IntVar*
const objective,
3812 std::function<int64_t(int64_t, int64_t)> objective_function,
bool maximize,
3813 int64_t step,
const std::vector<IntVar*>& vars,
double penalty_factor)
3814 : GuidedLocalSearch(solver, objective, maximize, step, vars,
3816 objective_function_(
std::move(objective_function)) {}
3818IntExpr* BinaryGuidedLocalSearch::MakeElementPenalty(
int index) {
3819 return solver()->MakeElement(
3820 [
this,
index](int64_t i) {
return PenalizedValue(
index, i); },
3824int64_t BinaryGuidedLocalSearch::AssignmentElementPenalty(
3825 const Assignment& assignment,
int index) {
3829int64_t BinaryGuidedLocalSearch::AssignmentPenalty(
const Assignment& assignment,
3831 return objective_function_(
index,
next);
3834bool BinaryGuidedLocalSearch::EvaluateElementValue(
3835 const Assignment::IntContainer& container, int64_t
index,
3836 int* container_index, int64_t* penalty) {
3837 const IntVarElement& element = container.Element(*container_index);
3838 if (element.Activated()) {
3839 *penalty = PenalizedValue(
index, element.Value());
3846int64_t BinaryGuidedLocalSearch::PenalizedValue(int64_t i, int64_t j) {
3848 const int64_t penalty = penalties_->Value(
arc);
3850 const double penalized_value_fp =
3852 const int64_t penalized_value =
3854 ?
static_cast<int64_t
>(penalized_value_fp)
3857 return -penalized_value;
3859 return penalized_value;
3866class TernaryGuidedLocalSearch :
public GuidedLocalSearch {
3868 TernaryGuidedLocalSearch(
3869 Solver*
const solver, IntVar*
const objective,
3870 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
3871 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
3872 const std::vector<IntVar*>& secondary_vars,
double penalty_factor);
3873 ~TernaryGuidedLocalSearch()
override {}
3874 IntExpr* MakeElementPenalty(
int index)
override;
3875 int64_t AssignmentElementPenalty(
const Assignment& assignment,
3876 int index)
override;
3877 int64_t AssignmentPenalty(
const Assignment& assignment,
int index,
3878 int64_t
next)
override;
3879 bool EvaluateElementValue(
const Assignment::IntContainer& container,
3880 int64_t
index,
int* container_index,
3881 int64_t* penalty)
override;
3884 int64_t PenalizedValue(int64_t i, int64_t j, int64_t k);
3885 int64_t GetAssignmentSecondaryValue(
const Assignment::IntContainer& container,
3886 int index,
int* container_index)
const;
3888 const std::vector<IntVar*> secondary_vars_;
3889 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function_;
3892TernaryGuidedLocalSearch::TernaryGuidedLocalSearch(
3893 Solver*
const solver, IntVar*
const objective,
3894 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
3895 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
3896 const std::vector<IntVar*>& secondary_vars,
double penalty_factor)
3897 : GuidedLocalSearch(solver, objective, maximize, step, vars,
3899 secondary_vars_(secondary_vars),
3900 objective_function_(
std::move(objective_function)) {
3901 if (!secondary_vars.empty()) {
3902 assignment_.Add(secondary_vars);
3906IntExpr* TernaryGuidedLocalSearch::MakeElementPenalty(
int index) {
3907 return solver()->MakeElement(
3908 [
this,
index](int64_t i, int64_t j) {
3909 return PenalizedValue(
index, i, j);
3914int64_t TernaryGuidedLocalSearch::AssignmentElementPenalty(
3915 const Assignment& assignment,
int index) {
3917 assignment.Value(secondary_vars_[
index]));
3920int64_t TernaryGuidedLocalSearch::AssignmentPenalty(
3921 const Assignment& assignment,
int index, int64_t
next) {
3923 assignment.Value(secondary_vars_[
index]));
3926bool TernaryGuidedLocalSearch::EvaluateElementValue(
3927 const Assignment::IntContainer& container, int64_t
index,
3928 int* container_index, int64_t* penalty) {
3929 const IntVarElement& element = container.Element(*container_index);
3930 if (element.Activated()) {
3931 *penalty = PenalizedValue(
3932 index, element.Value(),
3933 GetAssignmentSecondaryValue(container,
index, container_index));
3940int64_t TernaryGuidedLocalSearch::PenalizedValue(int64_t i, int64_t j,
3943 const int64_t penalty = penalties_->Value(
arc);
3945 const double penalized_value_fp =
3947 const int64_t penalized_value =
3949 ?
static_cast<int64_t
>(penalized_value_fp)
3952 return -penalized_value;
3954 return penalized_value;
3961int64_t TernaryGuidedLocalSearch::GetAssignmentSecondaryValue(
3962 const Assignment::IntContainer& container,
int index,
3963 int* container_index)
const {
3964 const IntVar* secondary_var = secondary_vars_[
index];
3965 int hint_index = *container_index + 1;
3966 if (hint_index > 0 && hint_index < container.Size() &&
3967 secondary_var == container.Element(hint_index).Var()) {
3968 *container_index = hint_index;
3969 return container.Element(hint_index).Value();
3971 return container.Element(secondary_var).Value();
3977 bool maximize,
IntVar*
const objective,
3979 const std::vector<IntVar*>& vars,
double penalty_factor) {
3980 return RevAlloc(
new BinaryGuidedLocalSearch(
3981 this, objective, std::move(objective_function), maximize, step, vars,
3986 bool maximize,
IntVar*
const objective,
3988 const std::vector<IntVar*>& vars,
3989 const std::vector<IntVar*>& secondary_vars,
double penalty_factor) {
3990 return RevAlloc(
new TernaryGuidedLocalSearch(
3991 this, objective, std::move(objective_function), maximize, step, vars,
3992 secondary_vars, penalty_factor));
3999SearchLimit::~SearchLimit() {}
4001void SearchLimit::EnterSearch() {
4016void SearchLimit::PeriodicCheck() {
4017 if (crossed_ || Check()) {
4023void SearchLimit::TopPeriodicCheck() {
4024 if (solver()->TopLevelSearch() != solver()->ActiveSearch()) {
4025 solver()->TopPeriodicCheck();
4032 int64_t branches, int64_t failures,
4033 int64_t solutions,
bool smart_time_check,
4036 duration_limit_(
time),
4037 solver_time_at_limit_start_(s->Now()),
4038 last_time_elapsed_(
absl::ZeroDuration()),
4041 smart_time_check_(smart_time_check),
4042 branches_(branches),
4043 branches_offset_(0),
4044 failures_(failures),
4045 failures_offset_(0),
4046 solutions_(solutions),
4047 solutions_offset_(0),
4048 cumulative_(cumulative) {}
4055 duration_limit_ = regular->duration_limit_;
4056 branches_ = regular->branches_;
4057 failures_ = regular->failures_;
4058 solutions_ = regular->solutions_;
4059 smart_time_check_ = regular->smart_time_check_;
4060 cumulative_ = regular->cumulative_;
4074 return s->
branches() - branches_offset_ >= branches_ ||
4075 s->
failures() - failures_offset_ >= failures_ || CheckTime() ||
4076 s->
solutions() - solutions_offset_ >= solutions_;
4081 int64_t progress = GetPercent(s->
branches(), branches_offset_, branches_);
4083 GetPercent(s->
failures(), failures_offset_, failures_));
4085 progress, GetPercent(s->
solutions(), solutions_offset_, solutions_));
4096 solver_time_at_limit_start_ = s->
Now();
4097 last_time_elapsed_ = absl::ZeroDuration();
4107 branches_ -= s->
branches() - branches_offset_;
4108 failures_ -= s->
failures() - failures_offset_;
4109 duration_limit_ -= s->
Now() - solver_time_at_limit_start_;
4110 solutions_ -= s->
solutions() - solutions_offset_;
4115 int64_t failures, int64_t solutions) {
4116 duration_limit_ =
time;
4129 return absl::StrFormat(
4130 "RegularLimit(crossed = %i, duration_limit = %s, "
4131 "branches = %d, failures = %d, solutions = %d cumulative = %s",
4133 solutions_, (cumulative_ ?
"true" :
"false"));
4151bool RegularLimit::CheckTime() {
return TimeElapsed() >=
duration_limit(); }
4153absl::Duration RegularLimit::TimeElapsed() {
4154 const int64_t kMaxSkip = 100;
4155 const int64_t kCheckWarmupIterations = 100;
4158 next_check_ <= check_count_) {
4159 Solver*
const s =
solver();
4160 absl::Duration elapsed = s->Now() - solver_time_at_limit_start_;
4161 if (smart_time_check_ && check_count_ > kCheckWarmupIterations &&
4162 elapsed > absl::ZeroDuration()) {
4164 check_count_ * absl::FDivDuration(duration_limit_, elapsed));
4166 std::min(check_count_ + kMaxSkip, estimated_check_count_at_limit);
4168 last_time_elapsed_ = elapsed;
4170 return last_time_elapsed_;
4188 return MakeLimit(absl::InfiniteDuration(),
4195 return MakeLimit(absl::InfiniteDuration(),
4202 int64_t failures, int64_t solutions,
4203 bool smart_time_check,
bool cumulative) {
4205 smart_time_check, cumulative);
4209 int64_t failures, int64_t solutions,
4210 bool smart_time_check,
bool cumulative) {
4212 smart_time_check, cumulative));
4217 ? absl::InfiniteDuration()
4218 : absl::Milliseconds(
proto.time()),
4220 proto.smart_time_check(),
proto.cumulative());
4224 RegularLimitParameters
proto;
4229 proto.set_smart_time_check(
false);
4230 proto.set_cumulative(
false);
4238 double objective_scaling_factor,
double objective_offset,
4239 double improvement_rate_coefficient,
4240 int improvement_rate_solutions_distance)
4242 objective_var_(objective_var),
4244 objective_scaling_factor_(objective_scaling_factor),
4245 objective_offset_(objective_offset),
4246 improvement_rate_coefficient_(improvement_rate_coefficient),
4247 improvement_rate_solutions_distance_(
4248 improvement_rate_solutions_distance) {
4255 best_objective_ = maximize_ ? -std::numeric_limits<double>::infinity()
4256 : std::numeric_limits<double>::infinity();
4257 threshold_ = std::numeric_limits<double>::infinity();
4258 objective_updated_ =
false;
4259 gradient_stage_ =
true;
4265 objective_var_ = improv->objective_var_;
4266 maximize_ = improv->maximize_;
4267 objective_scaling_factor_ = improv->objective_scaling_factor_;
4268 objective_offset_ = improv->objective_offset_;
4269 improvement_rate_coefficient_ = improv->improvement_rate_coefficient_;
4270 improvement_rate_solutions_distance_ =
4271 improv->improvement_rate_solutions_distance_;
4272 improvements_ = improv->improvements_;
4273 threshold_ = improv->threshold_;
4274 best_objective_ = improv->best_objective_;
4275 objective_updated_ = improv->objective_updated_;
4276 gradient_stage_ = improv->gradient_stage_;
4282 objective_var_, maximize_, objective_scaling_factor_, objective_offset_,
4283 improvement_rate_coefficient_, improvement_rate_solutions_distance_);
4287 if (!objective_updated_) {
4290 objective_updated_ =
false;
4292 if (improvements_.size() <= improvement_rate_solutions_distance_) {
4296 const std::pair<double, int64_t> cur = improvements_.back();
4297 const std::pair<double, int64_t> prev = improvements_.front();
4299 double improvement_rate =
4300 std::abs(prev.first - cur.first) / (cur.second - prev.second);
4301 if (gradient_stage_) {
4302 threshold_ = fmin(threshold_, improvement_rate);
4303 }
else if (improvement_rate_coefficient_ * improvement_rate < threshold_) {
4311 const int64_t new_objective =
4312 objective_var_ !=
nullptr && objective_var_->
Bound()
4313 ? objective_var_->
Value()
4318 const double scaled_new_objective =
4319 objective_scaling_factor_ * (new_objective + objective_offset_);
4321 const bool is_improvement = maximize_
4322 ? scaled_new_objective > best_objective_
4323 : scaled_new_objective < best_objective_;
4325 if (gradient_stage_ && !is_improvement) {
4326 gradient_stage_ =
false;
4329 if (threshold_ == std::numeric_limits<double>::infinity()) {
4334 if (is_improvement) {
4335 best_objective_ = scaled_new_objective;
4336 objective_updated_ =
true;
4337 improvements_.push_back(
4342 if (improvements_.size() - 1 > improvement_rate_solutions_distance_) {
4343 improvements_.pop_front();
4345 DCHECK_LE(improvements_.size() - 1, improvement_rate_solutions_distance_);
4352 IntVar* objective_var,
bool maximize,
double objective_scaling_factor,
4353 double objective_offset,
double improvement_rate_coefficient,
4354 int improvement_rate_solutions_distance) {
4356 this, objective_var, maximize, objective_scaling_factor, objective_offset,
4357 improvement_rate_coefficient, improvement_rate_solutions_distance));
4365 :
SearchLimit(limit_1->solver()), limit_1_(limit_1), limit_2_(limit_2) {
4366 CHECK(limit_1 !=
nullptr);
4367 CHECK(limit_2 !=
nullptr);
4369 <<
"Illegal arguments: cannot combines limits that belong to different "
4370 <<
"solvers, because the reversible allocations could delete one and "
4371 <<
"not the other.";
4374 bool Check()
override {
4377 const bool check_1 = limit_1_->Check();
4378 const bool check_2 = limit_2_->Check();
4379 return check_1 || check_2;
4382 void Init()
override {
4387 void Copy(
const SearchLimit*
const limit)
override {
4391 SearchLimit* MakeClone()
const override {
4393 return solver()->MakeLimit(limit_1_->MakeClone(), limit_2_->MakeClone());
4396 void EnterSearch()
override {
4397 limit_1_->EnterSearch();
4398 limit_2_->EnterSearch();
4400 void BeginNextDecision(DecisionBuilder*
const b)
override {
4401 limit_1_->BeginNextDecision(
b);
4402 limit_2_->BeginNextDecision(
b);
4404 void PeriodicCheck()
override {
4405 limit_1_->PeriodicCheck();
4406 limit_2_->PeriodicCheck();
4408 void RefuteDecision(Decision*
const d)
override {
4409 limit_1_->RefuteDecision(d);
4410 limit_2_->RefuteDecision(d);
4412 std::string DebugString()
const override {
4413 return absl::StrCat(
"OR limit (", limit_1_->DebugString(),
" OR ",
4414 limit_2_->DebugString(),
")");
4418 SearchLimit*
const limit_1_;
4419 SearchLimit*
const limit_2_;
4425 return RevAlloc(
new ORLimit(limit_1, limit_2));
4431 CustomLimit(
Solver*
const s, std::function<
bool()> limiter);
4432 bool Check()
override;
4433 void Init()
override;
4434 void Copy(
const SearchLimit*
const limit)
override;
4438 std::function<bool()> limiter_;
4441CustomLimit::CustomLimit(Solver*
const s, std::function<
bool()> limiter)
4442 : SearchLimit(s), limiter_(
std::move(limiter)) {}
4444bool CustomLimit::Check() {
4445 if (limiter_)
return limiter_();
4449void CustomLimit::Init() {}
4451void CustomLimit::Copy(
const SearchLimit*
const limit) {
4452 const CustomLimit*
const custom =
4453 reinterpret_cast<const CustomLimit* const
>(limit);
4454 limiter_ = custom->limiter_;
4457SearchLimit* CustomLimit::MakeClone()
const {
4458 return solver()->RevAlloc(
new CustomLimit(solver(), limiter_));
4463 return RevAlloc(
new CustomLimit(
this, std::move(limiter)));
4472 CHECK(db !=
nullptr);
4475 SolveOnce(DecisionBuilder*
const db,
4476 const std::vector<SearchMonitor*>& monitors)
4477 : db_(db), monitors_(monitors) {
4478 CHECK(db !=
nullptr);
4481 ~SolveOnce()
override {}
4483 Decision* Next(Solver* s)
override {
4484 bool res = s->SolveAndCommit(db_, monitors_);
4491 std::string DebugString()
const override {
4492 return absl::StrFormat(
"SolveOnce(%s)", db_->DebugString());
4495 void Accept(ModelVisitor*
const visitor)
const override {
4496 db_->Accept(visitor);
4500 DecisionBuilder*
const db_;
4501 std::vector<SearchMonitor*> monitors_;
4506 return RevAlloc(
new SolveOnce(db));
4511 std::vector<SearchMonitor*> monitors;
4512 monitors.push_back(monitor1);
4513 return RevAlloc(
new SolveOnce(db, monitors));
4519 std::vector<SearchMonitor*> monitors;
4520 monitors.push_back(monitor1);
4521 monitors.push_back(monitor2);
4522 return RevAlloc(
new SolveOnce(db, monitors));
4529 std::vector<SearchMonitor*> monitors;
4530 monitors.push_back(monitor1);
4531 monitors.push_back(monitor2);
4532 monitors.push_back(monitor3);
4533 return RevAlloc(
new SolveOnce(db, monitors));
4541 std::vector<SearchMonitor*> monitors;
4542 monitors.push_back(monitor1);
4543 monitors.push_back(monitor2);
4544 monitors.push_back(monitor3);
4545 monitors.push_back(monitor4);
4546 return RevAlloc(
new SolveOnce(db, monitors));
4550 DecisionBuilder*
const db,
const std::vector<SearchMonitor*>& monitors) {
4551 return RevAlloc(
new SolveOnce(db, monitors));
4560 bool maximize, int64_t step)
4562 solution_(solution),
4565 collector_(nullptr) {
4566 CHECK(db !=
nullptr);
4567 CHECK(solution !=
nullptr);
4572 NestedOptimize(DecisionBuilder*
const db, Assignment*
const solution,
4573 bool maximize, int64_t step,
4574 const std::vector<SearchMonitor*>& monitors)
4576 solution_(solution),
4579 monitors_(monitors),
4580 collector_(nullptr) {
4581 CHECK(db !=
nullptr);
4582 CHECK(solution !=
nullptr);
4583 CHECK(solution->HasObjective());
4587 void AddMonitors() {
4588 Solver*
const solver = solution_->solver();
4589 collector_ = solver->MakeLastSolutionCollector(solution_);
4590 monitors_.push_back(collector_);
4591 OptimizeVar*
const optimize =
4593 monitors_.push_back(optimize);
4596 Decision* Next(Solver* solver)
override {
4597 solver->Solve(db_, monitors_);
4598 if (collector_->solution_count() == 0) {
4601 collector_->solution(0)->Restore();
4605 std::string DebugString()
const override {
4606 return absl::StrFormat(
"NestedOptimize(db = %s, maximize = %d, step = %d)",
4610 void Accept(ModelVisitor*
const visitor)
const override {
4611 db_->Accept(visitor);
4615 DecisionBuilder*
const db_;
4616 Assignment*
const solution_;
4618 const int64_t
step_;
4619 std::vector<SearchMonitor*> monitors_;
4620 SolutionCollector* collector_;
4626 bool maximize, int64_t step) {
4627 return RevAlloc(
new NestedOptimize(db, solution, maximize, step));
4632 bool maximize, int64_t step,
4634 std::vector<SearchMonitor*> monitors;
4635 monitors.push_back(monitor1);
4636 return RevAlloc(
new NestedOptimize(db, solution, maximize, step, monitors));
4641 bool maximize, int64_t step,
4644 std::vector<SearchMonitor*> monitors;
4645 monitors.push_back(monitor1);
4646 monitors.push_back(monitor2);
4647 return RevAlloc(
new NestedOptimize(db, solution, maximize, step, monitors));
4652 bool maximize, int64_t step,
4656 std::vector<SearchMonitor*> monitors;
4657 monitors.push_back(monitor1);
4658 monitors.push_back(monitor2);
4659 monitors.push_back(monitor3);
4660 return RevAlloc(
new NestedOptimize(db, solution, maximize, step, monitors));
4667 std::vector<SearchMonitor*> monitors;
4668 monitors.push_back(monitor1);
4669 monitors.push_back(monitor2);
4670 monitors.push_back(monitor3);
4671 monitors.push_back(monitor4);
4672 return RevAlloc(
new NestedOptimize(db, solution, maximize, step, monitors));
4677 int64_t step,
const std::vector<SearchMonitor*>& monitors) {
4678 return RevAlloc(
new NestedOptimize(db, solution, maximize, step, monitors));
4685int64_t NextLuby(
int i) {
4693 while (power < (i + 1)) {
4696 if (power == i + 1) {
4699 return NextLuby(i - (power / 2) + 1);
4702class LubyRestart :
public SearchMonitor {
4704 LubyRestart(Solver*
const s,
int scale_factor)
4706 scale_factor_(scale_factor),
4709 next_step_(scale_factor) {
4713 ~LubyRestart()
override {}
4715 void BeginFail()
override {
4716 if (++current_fails_ >= next_step_) {
4718 next_step_ = NextLuby(++iteration_) * scale_factor_;
4719 solver()->RestartCurrentSearch();
4723 std::string DebugString()
const override {
4724 return absl::StrFormat(
"LubyRestart(%i)", scale_factor_);
4728 const int scale_factor_;
4730 int64_t current_fails_;
4736 return RevAlloc(
new LubyRestart(
this, scale_factor));
4744 ConstantRestart(
Solver*
const s,
int frequency)
4745 :
SearchMonitor(s), frequency_(frequency), current_fails_(0) {
4749 ~ConstantRestart()
override {}
4751 void BeginFail()
override {
4752 if (++current_fails_ >= frequency_) {
4754 solver()->RestartCurrentSearch();
4758 std::string DebugString()
const override {
4759 return absl::StrFormat(
"ConstantRestart(%i)", frequency_);
4763 const int frequency_;
4764 int64_t current_fails_;
4769 return RevAlloc(
new ConstantRestart(
this, frequency));
4792 const std::vector<SymmetryBreaker*>& visitors)
4794 visitors_(visitors),
4795 clauses_(visitors.size()),
4796 decisions_(visitors.size()),
4797 directions_(visitors.size()) {
4798 for (
int i = 0; i < visitors_.size(); ++i) {
4799 visitors_[i]->set_symmetry_manager_and_index(
this, i);
4807 for (
int i = 0; i < visitors_.size(); ++i) {
4808 const void*
const last = clauses_[i].Last();
4810 if (last != clauses_[i].Last()) {
4812 decisions_[i].Push(
solver(), d);
4813 directions_[i].Push(
solver(),
false);
4820 for (
int i = 0; i < visitors_.size(); ++i) {
4821 if (decisions_[i].Last() !=
nullptr && decisions_[i].LastValue() == d) {
4834 std::vector<IntVar*> guard;
4839 IntVar*
const term = *tmp;
4841 if (term->
Max() == 0) {
4845 if (term->
Min() == 0) {
4848 guard.push_back(term);
4854 guard.push_back(clauses_[
index].LastValue());
4855 directions_[
index].SetLastValue(
true);
4867 clauses_[visitor->index_in_symmetry_manager()].Push(
solver(), term);
4870 std::string
DebugString()
const override {
return "SymmetryManager"; }
4873 const std::vector<SymmetryBreaker*> visitors_;
4874 std::vector<SimpleRevFIFO<IntVar*>> clauses_;
4875 std::vector<SimpleRevFIFO<Decision*>> decisions_;
4876 std::vector<SimpleRevFIFO<bool>> directions_;
4908 const std::vector<SymmetryBreaker*>& visitors) {
4913 std::vector<SymmetryBreaker*> visitors;
4914 visitors.push_back(v1);
4920 std::vector<SymmetryBreaker*> visitors;
4921 visitors.push_back(v1);
4922 visitors.push_back(v2);
4929 std::vector<SymmetryBreaker*> visitors;
4930 visitors.push_back(v1);
4931 visitors.push_back(v2);
4932 visitors.push_back(v3);
4940 std::vector<SymmetryBreaker*> visitors;
4941 visitors.push_back(v1);
4942 visitors.push_back(v2);
4943 visitors.push_back(v3);
4944 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_
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.
IntVar * Var() const
Returns the variable that is optimized.
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.
ABSL_MUST_USE_RESULT 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.
ABSL_MUST_USE_RESULT 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)
Decision * MakeAssignVariablesValuesOrFail(const std::vector< IntVar * > &vars, const std::vector< int64_t > &values)
ConstraintSolverParameters parameters() const
Stored Parameters.
SearchMonitor * MakeSymmetryManager(const std::vector< SymmetryBreaker * > &visitors)
Symmetry Breaking.
ABSL_MUST_USE_RESULT 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...
ABSL_MUST_USE_RESULT 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.
ABSL_MUST_USE_RESULT RegularLimit * MakeLimit(absl::Duration time, int64_t branches, int64_t failures, int64_t solutions, bool smart_time_check=false, bool cumulative=false)
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.
Decision * MakeAssignVariablesValuesOrDoNothing(const std::vector< IntVar * > &vars, const std::vector< int64_t > &values)
int64_t failures() const
The number of failures encountered since the creation of the solver.
ABSL_MUST_USE_RESULT ImprovementSearchLimit * MakeImprovementLimit(IntVar *objective_var, bool maximize, double objective_scaling_factor, double objective_offset, double improvement_rate_coefficient, int improvement_rate_solutions_distance)
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.
ABSL_MUST_USE_RESULT 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...
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
T * RevAlloc(T *object)
Registers the given object as being reversible.
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.