26 #include "absl/base/casts.h"
27 #include "absl/container/flat_hash_map.h"
28 #include "absl/memory/memory.h"
29 #include "absl/strings/str_cat.h"
30 #include "absl/strings/str_format.h"
31 #include "absl/strings/str_join.h"
32 #include "absl/time/time.h"
45 #include "ortools/constraint_solver/search_limit.pb.h"
49 "Use sparse implementation to store Guided Local Search penalties");
51 "Whether search related logging should be "
53 ABSL_FLAG(int64_t, cp_large_domain_no_splitting_limit, 0xFFFFF,
54 "Size limit to allow holes in variables from the strategy.");
60 double scaling_factor,
double offset,
61 std::function<std::string()> display_callback,
62 bool display_on_new_solutions_only,
int period)
68 scaling_factor_(scaling_factor),
70 display_callback_(std::move(display_callback)),
71 display_on_new_solutions_only_(display_on_new_solutions_only),
74 objective_min_(std::numeric_limits<int64_t>::
max()),
75 objective_max_(std::numeric_limits<int64_t>::
min()),
76 min_right_depth_(std::numeric_limits<int32_t>::
max()),
78 sliding_min_depth_(0),
79 sliding_max_depth_(0) {
80 CHECK(obj ==
nullptr ||
var ==
nullptr)
81 <<
"Either var or obj need to be nullptr.";
89 const std::string buffer =
90 absl::StrFormat(
"Start search (%s)", MemoryUsage());
98 int64_t ms = timer_->GetInMs();
102 const std::string buffer = absl::StrFormat(
103 "End search (time = %d ms, branches = %d, failures = %d, %s, speed = %d "
105 ms, branches,
solver()->failures(), MemoryUsage(), branches * 1000 / ms);
112 std::string obj_str =
"";
114 bool objective_updated =
false;
115 const auto scaled_str = [
this](int64_t
value) {
116 if (scaling_factor_ != 1.0 || offset_ != 0.0) {
117 return absl::StrFormat(
"%d (%.8lf)",
value,
118 scaling_factor_ * (
value + offset_));
120 return absl::StrCat(
value);
123 if (obj_ !=
nullptr && obj_->
Var()->
Bound()) {
125 obj_str = obj_->
Print();
126 objective_updated =
true;
127 }
else if (var_ !=
nullptr && var_->
Bound()) {
128 current = var_->
Value();
129 absl::StrAppend(&obj_str, scaled_str(current),
", ");
130 objective_updated =
true;
133 absl::StrAppend(&obj_str, scaled_str(current),
", ");
134 objective_updated =
true;
136 if (objective_updated) {
137 if (current > objective_min_) {
138 absl::StrAppend(&obj_str,
139 "objective minimum = ", scaled_str(objective_min_),
", ");
141 objective_min_ = current;
143 if (current < objective_max_) {
144 absl::StrAppend(&obj_str,
145 "objective maximum = ", scaled_str(objective_max_),
", ");
147 objective_max_ = current;
151 absl::StrAppendFormat(&log,
152 "Solution #%d (%stime = %d ms, branches = %d,"
153 " failures = %d, depth = %d",
154 nsol_++, obj_str, timer_->GetInMs(),
156 if (!
solver()->SearchContext().empty()) {
157 absl::StrAppendFormat(&log,
", %s",
solver()->SearchContext());
159 if (
solver()->neighbors() != 0) {
160 absl::StrAppendFormat(&log,
161 ", neighbors = %d, filtered neighbors = %d,"
162 " accepted neighbors = %d",
164 solver()->accepted_neighbors());
166 absl::StrAppendFormat(&log,
", %s", MemoryUsage());
169 absl::StrAppendFormat(&log,
", limit = %d%%", progress);
171 if (display_callback_) {
172 absl::StrAppendFormat(&log,
", %s", display_callback_());
184 std::string buffer = absl::StrFormat(
185 "Finished search tree (time = %d ms, branches = %d,"
187 timer_->GetInMs(),
solver()->branches(),
solver()->failures());
188 if (
solver()->neighbors() != 0) {
189 absl::StrAppendFormat(&buffer,
190 ", neighbors = %d, filtered neighbors = %d,"
191 " accepted neigbors = %d",
193 solver()->accepted_neighbors());
195 absl::StrAppendFormat(&buffer,
", %s", MemoryUsage());
196 if (!display_on_new_solutions_only_ && display_callback_) {
197 absl::StrAppendFormat(&buffer,
", %s", display_callback_());
206 if (
b % period_ == 0 &&
b > 0) {
212 min_right_depth_ =
std::min(min_right_depth_,
solver()->SearchDepth());
218 absl::StrFormat(
"%d branches, %d ms, %d failures",
solver()->branches(),
219 timer_->GetInMs(),
solver()->failures());
223 absl::StrAppendFormat(&buffer,
", tree pos=%d/%d/%d minref=%d max=%d",
224 sliding_min_depth_, depth, sliding_max_depth_,
225 min_right_depth_, max_depth_);
226 sliding_min_depth_ = depth;
227 sliding_max_depth_ = depth;
229 if (obj_ !=
nullptr &&
232 absl::StrAppendFormat(&buffer,
233 ", objective minimum = %d"
234 ", objective maximum = %d",
235 objective_min_, objective_max_);
239 absl::StrAppendFormat(&buffer,
", limit = %d%%", progress);
246 sliding_min_depth_ =
std::min(current_depth, sliding_min_depth_);
247 sliding_max_depth_ =
std::max(current_depth, sliding_max_depth_);
248 max_depth_ =
std::max(current_depth, max_depth_);
254 const int64_t
delta = std::max<int64_t>(timer_->GetInMs() - tick_, 0);
255 const std::string buffer = absl::StrFormat(
256 "Root node processed (time = %d ms, constraints = %d, %s)",
delta,
257 solver()->constraints(), MemoryUsage());
262 if (absl::GetFlag(FLAGS_cp_log_to_vlog)) {
269 std::string SearchLog::MemoryUsage() {
270 static const int64_t kDisplayThreshold = 2;
271 static const int64_t kKiloByte = 1024;
272 static const int64_t kMegaByte = kKiloByte * kKiloByte;
273 static const int64_t kGigaByte = kMegaByte * kKiloByte;
275 if (memory_usage > kDisplayThreshold * kGigaByte) {
276 return absl::StrFormat(
"memory used = %.2lf GB",
277 memory_usage * 1.0 / kGigaByte);
278 }
else if (memory_usage > kDisplayThreshold * kMegaByte) {
279 return absl::StrFormat(
"memory used = %.2lf MB",
280 memory_usage * 1.0 / kMegaByte);
281 }
else if (memory_usage > kDisplayThreshold * kKiloByte) {
282 return absl::StrFormat(
"memory used = %2lf KB",
283 memory_usage * 1.0 / kKiloByte);
285 return absl::StrFormat(
"memory used = %d", memory_usage);
298 int branch_period, std::function<std::string()> display_callback) {
300 std::move(display_callback));
305 std::function<std::string()> display_callback) {
307 std::move(display_callback),
true,
318 std::function<std::string()> display_callback) {
320 std::move(display_callback),
true,
336 SearchTrace(
Solver*
const s,
const std::string& prefix)
338 ~SearchTrace()
override {}
340 void EnterSearch()
override {
341 LOG(INFO) << prefix_ <<
" EnterSearch(" << solver()->SolveDepth() <<
")";
343 void RestartSearch()
override {
344 LOG(INFO) << prefix_ <<
" RestartSearch(" << solver()->SolveDepth() <<
")";
346 void ExitSearch()
override {
347 LOG(INFO) << prefix_ <<
" ExitSearch(" << solver()->SolveDepth() <<
")";
349 void BeginNextDecision(DecisionBuilder*
const b)
override {
350 LOG(INFO) << prefix_ <<
" BeginNextDecision(" <<
b <<
") ";
352 void EndNextDecision(DecisionBuilder*
const b, Decision*
const d)
override {
354 LOG(INFO) << prefix_ <<
" EndNextDecision(" <<
b <<
", " << d <<
") ";
356 LOG(INFO) << prefix_ <<
" EndNextDecision(" <<
b <<
") ";
359 void ApplyDecision(Decision*
const d)
override {
360 LOG(INFO) << prefix_ <<
" ApplyDecision(" << d <<
") ";
362 void RefuteDecision(Decision*
const d)
override {
363 LOG(INFO) << prefix_ <<
" RefuteDecision(" << d <<
") ";
365 void AfterDecision(Decision*
const d,
bool apply)
override {
366 LOG(INFO) << prefix_ <<
" AfterDecision(" << d <<
", " << apply <<
") ";
368 void BeginFail()
override {
369 LOG(INFO) << prefix_ <<
" BeginFail(" << solver()->SearchDepth() <<
")";
371 void EndFail()
override {
372 LOG(INFO) << prefix_ <<
" EndFail(" << solver()->SearchDepth() <<
")";
374 void BeginInitialPropagation()
override {
375 LOG(INFO) << prefix_ <<
" BeginInitialPropagation()";
377 void EndInitialPropagation()
override {
378 LOG(INFO) << prefix_ <<
" EndInitialPropagation()";
380 bool AtSolution()
override {
381 LOG(INFO) << prefix_ <<
" AtSolution()";
384 bool AcceptSolution()
override {
385 LOG(INFO) << prefix_ <<
" AcceptSolution()";
388 void NoMoreSolutions()
override {
389 LOG(INFO) << prefix_ <<
" NoMoreSolutions()";
392 std::string DebugString()
const override {
return "SearchTrace"; }
395 const std::string prefix_;
400 return RevAlloc(
new SearchTrace(
this, prefix));
407 AtSolutionCallback(
Solver*
const solver, std::function<
void()>
callback)
409 ~AtSolutionCallback()
override {}
410 bool AtSolution()
override;
411 void Install()
override;
414 const std::function<void()> callback_;
417 bool AtSolutionCallback::AtSolution() {
422 void AtSolutionCallback::Install() {
435 EnterSearchCallback(
Solver*
const solver, std::function<
void()>
callback)
437 ~EnterSearchCallback()
override {}
438 void EnterSearch()
override;
439 void Install()
override;
442 const std::function<void()> callback_;
445 void EnterSearchCallback::EnterSearch() { callback_(); }
447 void EnterSearchCallback::Install() {
460 ExitSearchCallback(
Solver*
const solver, std::function<
void()>
callback)
462 ~ExitSearchCallback()
override {}
463 void ExitSearch()
override;
464 void Install()
override;
467 const std::function<void()> callback_;
470 void ExitSearchCallback::ExitSearch() { callback_(); }
472 void ExitSearchCallback::Install() {
487 CompositeDecisionBuilder();
488 explicit CompositeDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs);
489 ~CompositeDecisionBuilder()
override;
491 void AppendMonitors(
Solver*
const solver,
492 std::vector<SearchMonitor*>*
const monitors)
override;
493 void Accept(
ModelVisitor*
const visitor)
const override;
499 CompositeDecisionBuilder::CompositeDecisionBuilder() {}
501 CompositeDecisionBuilder::CompositeDecisionBuilder(
502 const std::vector<DecisionBuilder*>& dbs) {
503 for (
int i = 0; i < dbs.size(); ++i) {
508 CompositeDecisionBuilder::~CompositeDecisionBuilder() {}
510 void CompositeDecisionBuilder::Add(DecisionBuilder*
const db) {
516 void CompositeDecisionBuilder::AppendMonitors(
517 Solver*
const solver, std::vector<SearchMonitor*>*
const monitors) {
518 for (DecisionBuilder*
const db :
builders_) {
519 db->AppendMonitors(solver, monitors);
523 void CompositeDecisionBuilder::Accept(ModelVisitor*
const visitor)
const {
524 for (DecisionBuilder*
const db :
builders_) {
533 class ComposeDecisionBuilder :
public CompositeDecisionBuilder {
535 ComposeDecisionBuilder();
536 explicit ComposeDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs);
537 ~ComposeDecisionBuilder()
override;
538 Decision* Next(Solver*
const s)
override;
539 std::string DebugString()
const override;
545 ComposeDecisionBuilder::ComposeDecisionBuilder() : start_index_(0) {}
547 ComposeDecisionBuilder::ComposeDecisionBuilder(
548 const std::vector<DecisionBuilder*>& dbs)
549 : CompositeDecisionBuilder(dbs), start_index_(0) {}
551 ComposeDecisionBuilder::~ComposeDecisionBuilder() {}
553 Decision* ComposeDecisionBuilder::Next(Solver*
const s) {
555 for (
int i = start_index_; i < size; ++i) {
558 s->SaveAndSetValue(&start_index_, i);
562 s->SaveAndSetValue(&start_index_, size);
566 std::string ComposeDecisionBuilder::DebugString()
const {
567 return absl::StrFormat(
"ComposeDecisionBuilder(%s)",
574 ComposeDecisionBuilder* c = RevAlloc(
new ComposeDecisionBuilder());
583 ComposeDecisionBuilder* c = RevAlloc(
new ComposeDecisionBuilder());
594 ComposeDecisionBuilder* c = RevAlloc(
new ComposeDecisionBuilder());
603 if (dbs.size() == 1) {
606 return RevAlloc(
new ComposeDecisionBuilder(dbs));
612 class ClosureDecision :
public Decision {
615 : apply_(std::move(apply)), refute_(std::move(refute)) {}
616 ~ClosureDecision()
override {}
618 void Apply(Solver*
const s)
override { apply_(s); }
620 void Refute(Solver*
const s)
override { refute_(s); }
622 std::string
DebugString()
const override {
return "ClosureDecision"; }
625 Solver::Action apply_;
626 Solver::Action refute_;
631 return RevAlloc(
new ClosureDecision(std::move(apply), std::move(refute)));
638 class TryDecisionBuilder;
640 class TryDecision :
public Decision {
642 explicit TryDecision(TryDecisionBuilder*
const try_builder);
643 ~TryDecision()
override;
646 std::string
DebugString()
const override {
return "TryDecision"; }
649 TryDecisionBuilder*
const try_builder_;
652 class TryDecisionBuilder :
public CompositeDecisionBuilder {
654 TryDecisionBuilder();
655 explicit TryDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs);
656 ~TryDecisionBuilder()
override;
657 Decision* Next(Solver*
const solver)
override;
658 std::string DebugString()
const override;
659 void AdvanceToNextBuilder(Solver*
const solver);
662 TryDecision try_decision_;
663 int current_builder_;
664 bool start_new_builder_;
667 TryDecision::TryDecision(TryDecisionBuilder*
const try_builder)
668 : try_builder_(try_builder) {}
670 TryDecision::~TryDecision() {}
672 void TryDecision::Apply(Solver*
const solver) {}
674 void TryDecision::Refute(Solver*
const solver) {
675 try_builder_->AdvanceToNextBuilder(solver);
678 TryDecisionBuilder::TryDecisionBuilder()
679 : CompositeDecisionBuilder(),
681 current_builder_(-1),
682 start_new_builder_(true) {}
684 TryDecisionBuilder::TryDecisionBuilder(
const std::vector<DecisionBuilder*>& dbs)
685 : CompositeDecisionBuilder(dbs),
687 current_builder_(-1),
688 start_new_builder_(true) {}
690 TryDecisionBuilder::~TryDecisionBuilder() {}
692 Decision* TryDecisionBuilder::Next(Solver*
const solver) {
693 if (current_builder_ < 0) {
694 solver->SaveAndSetValue(¤t_builder_, 0);
695 start_new_builder_ =
true;
697 if (start_new_builder_) {
698 start_new_builder_ =
false;
699 return &try_decision_;
701 return builders_[current_builder_]->Next(solver);
705 std::string TryDecisionBuilder::DebugString()
const {
706 return absl::StrFormat(
"TryDecisionBuilder(%s)",
710 void TryDecisionBuilder::AdvanceToNextBuilder(Solver*
const solver) {
712 start_new_builder_ =
true;
713 if (current_builder_ >=
builders_.size()) {
722 TryDecisionBuilder* try_db =
RevAlloc(
new TryDecisionBuilder());
731 TryDecisionBuilder* try_db =
RevAlloc(
new TryDecisionBuilder());
742 TryDecisionBuilder* try_db =
RevAlloc(
new TryDecisionBuilder());
751 return RevAlloc(
new TryDecisionBuilder(dbs));
759 class BaseVariableAssignmentSelector :
public BaseObject {
761 BaseVariableAssignmentSelector(
Solver* solver,
762 const std::vector<IntVar*>& vars)
768 ~BaseVariableAssignmentSelector()
override {}
770 virtual int64_t SelectValue(
const IntVar* v, int64_t
id) = 0;
773 virtual int64_t ChooseVariable() = 0;
775 int64_t ChooseVariableWrapper() {
778 if (!
vars_[i]->Bound()) {
787 if (!
vars_[i]->Bound()) {
792 return ChooseVariable();
795 void Accept(ModelVisitor*
const visitor)
const {
802 const std::vector<IntVar*>& vars()
const {
return vars_; }
813 int64_t ChooseFirstUnbound(Solver* solver,
const std::vector<IntVar*>& vars,
814 int64_t first_unbound, int64_t last_unbound) {
815 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
816 if (!vars[i]->Bound()) {
825 int64_t ChooseMinSizeLowestMin(Solver* solver,
const std::vector<IntVar*>& vars,
826 int64_t first_unbound, int64_t last_unbound) {
829 int64_t best_index = -1;
830 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
831 IntVar*
const var = vars[i];
833 if (
var->Size() < best_size ||
834 (
var->Size() == best_size &&
var->Min() < best_min)) {
835 best_size =
var->Size();
836 best_min =
var->Min();
846 int64_t ChooseMinSizeHighestMin(Solver* solver,
847 const std::vector<IntVar*>& vars,
848 int64_t first_unbound, int64_t last_unbound) {
851 int64_t best_index = -1;
852 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
853 IntVar*
const var = vars[i];
855 if (
var->Size() < best_size ||
856 (
var->Size() == best_size &&
var->Min() > best_min)) {
857 best_size =
var->Size();
858 best_min =
var->Min();
868 int64_t ChooseMinSizeLowestMax(Solver* solver,
const std::vector<IntVar*>& vars,
869 int64_t first_unbound, int64_t last_unbound) {
872 int64_t best_index = -1;
873 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
874 IntVar*
const var = vars[i];
876 if (
var->Size() < best_size ||
877 (
var->Size() == best_size &&
var->Max() < best_max)) {
878 best_size =
var->Size();
879 best_max =
var->Max();
889 int64_t ChooseMinSizeHighestMax(Solver* solver,
890 const std::vector<IntVar*>& vars,
891 int64_t first_unbound, int64_t last_unbound) {
894 int64_t best_index = -1;
895 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
896 IntVar*
const var = vars[i];
898 if (
var->Size() < best_size ||
899 (
var->Size() == best_size &&
var->Max() > best_max)) {
900 best_size =
var->Size();
901 best_max =
var->Max();
911 int64_t ChooseLowestMin(Solver* solver,
const std::vector<IntVar*>& vars,
912 int64_t first_unbound, int64_t last_unbound) {
914 int64_t best_index = -1;
915 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
916 IntVar*
const var = vars[i];
918 if (
var->Min() < best_min) {
919 best_min =
var->Min();
929 int64_t ChooseHighestMax(Solver* solver,
const std::vector<IntVar*>& vars,
930 int64_t first_unbound, int64_t last_unbound) {
932 int64_t best_index = -1;
933 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
934 IntVar*
const var = vars[i];
936 if (
var->Max() > best_max) {
937 best_max =
var->Max();
947 int64_t ChooseMinSize(Solver* solver,
const std::vector<IntVar*>& vars,
948 int64_t first_unbound, int64_t last_unbound) {
950 int64_t best_index = -1;
951 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
952 IntVar*
const var = vars[i];
954 if (
var->Size() < best_size) {
955 best_size =
var->Size();
965 int64_t ChooseMaxSize(Solver* solver,
const std::vector<IntVar*>& vars,
966 int64_t first_unbound, int64_t last_unbound) {
967 uint64_t best_size = 0;
968 int64_t best_index = -1;
969 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
970 IntVar*
const var = vars[i];
972 if (
var->Size() > best_size) {
973 best_size =
var->Size();
983 class HighestRegretSelectorOnMin :
public BaseObject {
985 explicit HighestRegretSelectorOnMin(
const std::vector<IntVar*>& vars)
987 for (int64_t i = 0; i < vars.size(); ++i) {
988 iterators_[i] = vars[i]->MakeDomainIterator(
true);
991 ~HighestRegretSelectorOnMin()
override {}
992 int64_t Choose(Solver*
const s,
const std::vector<IntVar*>& vars,
993 int64_t first_unbound, int64_t last_unbound);
994 std::string DebugString()
const override {
return "MaxRegretSelector"; }
996 int64_t ComputeRegret(IntVar*
var, int64_t
index)
const {
997 DCHECK(!
var->Bound());
998 const int64_t vmin =
var->Min();
1002 return iterator->Value() - vmin;
1009 int64_t HighestRegretSelectorOnMin::Choose(Solver*
const s,
1010 const std::vector<IntVar*>& vars,
1011 int64_t first_unbound,
1012 int64_t last_unbound) {
1013 int64_t best_regret = 0;
1015 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
1016 IntVar*
const var = vars[i];
1017 if (!
var->Bound()) {
1018 const int64_t regret = ComputeRegret(
var, i);
1019 if (regret > best_regret) {
1020 best_regret = regret;
1030 int64_t ChooseRandom(Solver* solver,
const std::vector<IntVar*>& vars,
1031 int64_t first_unbound, int64_t last_unbound) {
1032 const int64_t span = last_unbound - first_unbound + 1;
1033 const int64_t shift = solver->Rand32(span);
1034 for (int64_t i = 0; i < span; ++i) {
1035 const int64_t
index = (i + shift) % span + first_unbound;
1036 if (!vars[
index]->Bound()) {
1045 class CheapestVarSelector :
public BaseObject {
1047 explicit CheapestVarSelector(std::function<int64_t(int64_t)> var_evaluator)
1048 : var_evaluator_(std::move(var_evaluator)) {}
1049 ~CheapestVarSelector()
override {}
1050 int64_t Choose(Solver*
const s,
const std::vector<IntVar*>& vars,
1051 int64_t first_unbound, int64_t last_unbound);
1052 std::string DebugString()
const override {
return "CheapestVarSelector"; }
1055 std::function<int64_t(int64_t)> var_evaluator_;
1058 int64_t CheapestVarSelector::Choose(Solver*
const s,
1059 const std::vector<IntVar*>& vars,
1060 int64_t first_unbound,
1061 int64_t last_unbound) {
1064 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
1065 if (!vars[i]->Bound()) {
1066 const int64_t eval = var_evaluator_(i);
1067 if (eval < best_eval) {
1079 class PathSelector :
public BaseObject {
1081 PathSelector() : first_(std::numeric_limits<int64_t>::
max()) {}
1082 ~PathSelector()
override {}
1083 int64_t Choose(Solver*
const s,
const std::vector<IntVar*>& vars,
1084 int64_t first_unbound, int64_t last_unbound);
1085 std::string DebugString()
const override {
return "ChooseNextOnPath"; }
1088 bool UpdateIndex(
const std::vector<IntVar*>& vars, int64_t*
index)
const;
1089 bool FindPathStart(
const std::vector<IntVar*>& vars, int64_t*
index)
const;
1091 Rev<int64_t> first_;
1094 int64_t PathSelector::Choose(Solver*
const s,
const std::vector<IntVar*>& vars,
1095 int64_t first_unbound, int64_t last_unbound) {
1096 int64_t
index = first_.Value();
1097 if (!UpdateIndex(vars, &
index)) {
1101 while (vars[
index]->Bound()) {
1103 if (!UpdateIndex(vars, &
index)) {
1107 if (count >= vars.size() &&
1108 !FindPathStart(vars, &
index)) {
1112 first_.SetValue(s,
index);
1116 bool PathSelector::UpdateIndex(
const std::vector<IntVar*>& vars,
1117 int64_t*
index)
const {
1118 if (*
index >= vars.size()) {
1119 if (!FindPathStart(vars,
index)) {
1132 bool PathSelector::FindPathStart(
const std::vector<IntVar*>& vars,
1133 int64_t*
index)
const {
1135 for (int64_t i = vars.size() - 1; i >= 0; --i) {
1136 if (vars[i]->Bound()) {
1137 const int64_t
next = vars[i]->Value();
1138 if (
next < vars.size() && !vars[
next]->Bound()) {
1145 for (int64_t i = vars.size() - 1; i >= 0; --i) {
1146 if (!vars[i]->Bound()) {
1147 bool has_possible_prev =
false;
1148 for (int64_t j = 0; j < vars.size(); ++j) {
1149 if (vars[j]->Contains(i)) {
1150 has_possible_prev =
true;
1154 if (!has_possible_prev) {
1161 for (int64_t i = 0; i < vars.size(); ++i) {
1162 if (!vars[i]->Bound()) {
1172 int64_t SelectMinValue(
const IntVar* v, int64_t
id) {
return v->Min(); }
1176 int64_t SelectMaxValue(
const IntVar* v, int64_t
id) {
return v->Max(); }
1180 int64_t SelectRandomValue(
const IntVar* v, int64_t
id) {
1181 const uint64_t span = v->Max() - v->Min() + 1;
1182 if (span > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {
1186 const uint64_t size = v->Size();
1187 Solver*
const s = v->solver();
1188 if (size > span / 4) {
1191 const int64_t
value = v->Min() + s->Rand64(span);
1192 if (v->Contains(
value)) {
1197 int64_t
index = s->Rand64(size);
1198 if (
index <= size / 2) {
1199 for (int64_t i = v->Min(); i <= v->Max(); ++i) {
1200 if (v->Contains(i)) {
1208 for (int64_t i = v->Max(); i > v->Min(); --i) {
1209 if (v->Contains(i)) {
1223 int64_t SelectCenterValue(
const IntVar* v, int64_t
id) {
1224 const int64_t vmin = v->Min();
1225 const int64_t vmax = v->Max();
1226 if (vmax - vmin > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {
1230 const int64_t mid = (vmin + vmax) / 2;
1231 if (v->Contains(mid)) {
1234 const int64_t diameter = vmax - mid;
1235 for (int64_t i = 1; i <= diameter; ++i) {
1236 if (v->Contains(mid - i)) {
1239 if (v->Contains(mid + i)) {
1248 int64_t SelectSplitValue(
const IntVar* v, int64_t
id) {
1249 const int64_t vmin = v->Min();
1250 const int64_t vmax = v->Max();
1251 const uint64_t
delta = vmax - vmin;
1252 const int64_t mid = vmin +
delta / 2;
1258 class CheapestValueSelector :
public BaseObject {
1260 CheapestValueSelector(std::function<int64_t(int64_t, int64_t)> eval,
1261 std::function<int64_t(int64_t)> tie_breaker)
1262 : eval_(std::move(eval)), tie_breaker_(std::move(tie_breaker)) {}
1263 ~CheapestValueSelector()
override {}
1264 int64_t Select(
const IntVar* v, int64_t
id);
1265 std::string DebugString()
const override {
return "CheapestValue"; }
1268 std::function<int64_t(int64_t, int64_t)> eval_;
1269 std::function<int64_t(int64_t)> tie_breaker_;
1270 std::vector<int64_t> cache_;
1273 int64_t CheapestValueSelector::Select(
const IntVar* v, int64_t
id) {
1276 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(
false));
1277 for (
const int64_t i : InitAndGetValues(it.get())) {
1278 int64_t eval = eval_(
id, i);
1282 cache_.push_back(i);
1283 }
else if (eval == best) {
1284 cache_.push_back(i);
1287 DCHECK_GT(cache_.size(), 0);
1288 if (tie_breaker_ ==
nullptr || cache_.size() == 1) {
1289 return cache_.back();
1291 return cache_[tie_breaker_(cache_.size())];
1303 class BestValueByComparisonSelector :
public BaseObject {
1305 explicit BestValueByComparisonSelector(
1307 : comparator_(std::move(comparator)) {}
1308 ~BestValueByComparisonSelector()
override {}
1309 int64_t Select(
const IntVar* v, int64_t
id);
1310 std::string DebugString()
const override {
1311 return "BestValueByComparisonSelector";
1318 int64_t BestValueByComparisonSelector::Select(
const IntVar* v, int64_t
id) {
1319 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(
false));
1322 int64_t best_value = it->Value();
1323 for (it->Next(); it->Ok(); it->Next()) {
1324 const int64_t candidate_value = it->Value();
1325 if (comparator_(
id, candidate_value, best_value)) {
1326 best_value = candidate_value;
1334 class VariableAssignmentSelector :
public BaseVariableAssignmentSelector {
1336 VariableAssignmentSelector(Solver* solver,
const std::vector<IntVar*>& vars,
1339 const std::string&
name)
1340 : BaseVariableAssignmentSelector(solver, vars),
1341 var_selector_(std::move(var_selector)),
1342 value_selector_(std::move(value_selector)),
1344 ~VariableAssignmentSelector()
override {}
1345 int64_t SelectValue(
const IntVar*
var, int64_t
id)
override {
1346 return value_selector_(
var,
id);
1348 int64_t ChooseVariable()
override {
1352 std::string DebugString()
const override;
1357 const std::string name_;
1360 std::string VariableAssignmentSelector::DebugString()
const {
1366 class BaseEvaluatorSelector :
public BaseVariableAssignmentSelector {
1368 BaseEvaluatorSelector(Solver* solver,
const std::vector<IntVar*>& vars,
1369 std::function<int64_t(int64_t, int64_t)> evaluator);
1370 ~BaseEvaluatorSelector()
override {}
1375 Element(int64_t i, int64_t j) :
var(i),
value(j) {}
1380 std::string DebugStringInternal(
const std::string&
name)
const {
1387 BaseEvaluatorSelector::BaseEvaluatorSelector(
1388 Solver* solver,
const std::vector<IntVar*>& vars,
1389 std::function<int64_t(int64_t, int64_t)> evaluator)
1390 : BaseVariableAssignmentSelector(solver, vars),
1395 class DynamicEvaluatorSelector :
public BaseEvaluatorSelector {
1397 DynamicEvaluatorSelector(Solver* solver,
const std::vector<IntVar*>& vars,
1398 std::function<int64_t(int64_t, int64_t)> evaluator,
1399 std::function<int64_t(int64_t)> tie_breaker);
1400 ~DynamicEvaluatorSelector()
override {}
1401 int64_t SelectValue(
const IntVar*
var, int64_t
id)
override;
1402 int64_t ChooseVariable()
override;
1403 std::string DebugString()
const override;
1407 std::function<int64_t(int64_t)> tie_breaker_;
1408 std::vector<Element> cache_;
1411 DynamicEvaluatorSelector::DynamicEvaluatorSelector(
1412 Solver* solver,
const std::vector<IntVar*>& vars,
1413 std::function<int64_t(int64_t, int64_t)> evaluator,
1414 std::function<int64_t(int64_t)> tie_breaker)
1415 : BaseEvaluatorSelector(solver, vars, std::move(evaluator)),
1417 tie_breaker_(std::move(tie_breaker)) {}
1419 int64_t DynamicEvaluatorSelector::SelectValue(
const IntVar*
var, int64_t
id) {
1420 return cache_[first_].value;
1423 int64_t DynamicEvaluatorSelector::ChooseVariable() {
1426 for (int64_t i = 0; i <
vars_.size(); ++i) {
1427 const IntVar*
const var =
vars_[i];
1428 if (!
var->Bound()) {
1429 std::unique_ptr<IntVarIterator> it(
var->MakeDomainIterator(
false));
1430 for (
const int64_t j : InitAndGetValues(it.get())) {
1432 if (
value < best_evaluation) {
1433 best_evaluation =
value;
1435 cache_.push_back(Element(i, j));
1436 }
else if (
value == best_evaluation && tie_breaker_) {
1437 cache_.push_back(Element(i, j));
1443 if (cache_.empty()) {
1447 if (tie_breaker_ ==
nullptr || cache_.size() == 1) {
1449 return cache_.front().var;
1451 first_ = tie_breaker_(cache_.size());
1452 return cache_[first_].var;
1456 std::string DynamicEvaluatorSelector::DebugString()
const {
1457 return DebugStringInternal(
"AssignVariablesOnDynamicEvaluator");
1462 class StaticEvaluatorSelector :
public BaseEvaluatorSelector {
1464 StaticEvaluatorSelector(
1465 Solver* solver,
const std::vector<IntVar*>& vars,
1466 const std::function<int64_t(int64_t, int64_t)>& evaluator);
1467 ~StaticEvaluatorSelector()
override {}
1468 int64_t SelectValue(
const IntVar*
var, int64_t
id)
override;
1469 int64_t ChooseVariable()
override;
1470 std::string DebugString()
const override;
1475 explicit Compare(std::function<int64_t(int64_t, int64_t)> evaluator)
1477 bool operator()(
const Element& lhs,
const Element& rhs)
const {
1478 const int64_t value_lhs =
Value(lhs);
1479 const int64_t value_rhs =
Value(rhs);
1480 return value_lhs < value_rhs ||
1481 (value_lhs == value_rhs &&
1482 (lhs.var < rhs.var ||
1483 (lhs.var == rhs.var && lhs.value < rhs.value)));
1485 int64_t
Value(
const Element& element)
const {
1486 return evaluator_(element.var, element.value);
1490 std::function<int64_t(int64_t, int64_t)>
evaluator_;
1494 std::vector<Element> elements_;
1498 StaticEvaluatorSelector::StaticEvaluatorSelector(
1499 Solver* solver,
const std::vector<IntVar*>& vars,
1500 const std::function<int64_t(int64_t, int64_t)>& evaluator)
1501 : BaseEvaluatorSelector(solver, vars, evaluator),
1505 int64_t StaticEvaluatorSelector::SelectValue(
const IntVar*
var, int64_t
id) {
1506 return elements_[first_].value;
1509 int64_t StaticEvaluatorSelector::ChooseVariable() {
1512 int64_t element_size = 0;
1513 for (int64_t i = 0; i <
vars_.size(); ++i) {
1514 if (!
vars_[i]->Bound()) {
1515 element_size +=
vars_[i]->Size();
1518 elements_.resize(element_size);
1520 for (
int i = 0; i <
vars_.size(); ++i) {
1521 const IntVar*
const var =
vars_[i];
1522 if (!
var->Bound()) {
1523 std::unique_ptr<IntVarIterator> it(
var->MakeDomainIterator(
false));
1524 for (
const int64_t
value : InitAndGetValues(it.get())) {
1525 elements_[count++] = Element(i,
value);
1530 std::sort(elements_.begin(), elements_.end(), comp_);
1531 solver_->SaveAndSetValue<int64_t>(&first_, 0);
1533 for (int64_t i = first_; i < elements_.size(); ++i) {
1534 const Element& element = elements_[i];
1535 IntVar*
const var =
vars_[element.var];
1536 if (!
var->Bound() &&
var->Contains(element.value)) {
1537 solver_->SaveAndSetValue(&first_, i);
1541 solver_->SaveAndSetValue(&first_,
static_cast<int64_t
>(elements_.size()));
1545 std::string StaticEvaluatorSelector::DebugString()
const {
1546 return DebugStringInternal(
"AssignVariablesOnStaticEvaluator");
1551 class AssignOneVariableValue :
public Decision {
1553 AssignOneVariableValue(IntVar*
const v, int64_t val);
1554 ~AssignOneVariableValue()
override {}
1555 void Apply(Solver*
const s)
override;
1556 void Refute(Solver*
const s)
override;
1557 std::string DebugString()
const override;
1558 void Accept(DecisionVisitor*
const visitor)
const override {
1559 visitor->VisitSetVariableValue(var_, value_);
1567 AssignOneVariableValue::AssignOneVariableValue(IntVar*
const v, int64_t val)
1568 : var_(v), value_(val) {}
1570 std::string AssignOneVariableValue::DebugString()
const {
1571 return absl::StrFormat(
"[%s == %d] or [%s != %d]", var_->DebugString(),
1572 value_, var_->DebugString(), value_);
1575 void AssignOneVariableValue::Apply(Solver*
const s) { var_->SetValue(value_); }
1577 void AssignOneVariableValue::Refute(Solver*
const s) {
1578 var_->RemoveValue(value_);
1583 return RevAlloc(
new AssignOneVariableValue(
var, val));
1589 class AssignOneVariableValueOrFail :
public Decision {
1591 AssignOneVariableValueOrFail(
IntVar*
const v, int64_t
value);
1592 ~AssignOneVariableValueOrFail()
override {}
1593 void Apply(Solver*
const s)
override;
1594 void Refute(Solver*
const s)
override;
1596 void Accept(DecisionVisitor*
const visitor)
const override {
1597 visitor->VisitSetVariableValue(var_, value_);
1602 const int64_t value_;
1605 AssignOneVariableValueOrFail::AssignOneVariableValueOrFail(IntVar*
const v,
1607 : var_(v), value_(
value) {}
1609 std::string AssignOneVariableValueOrFail::DebugString()
const {
1610 return absl::StrFormat(
"[%s == %d] or fail", var_->
DebugString(), value_);
1613 void AssignOneVariableValueOrFail::Apply(Solver*
const s) {
1617 void AssignOneVariableValueOrFail::Refute(Solver*
const s) { s->Fail(); }
1628 class AssignOneVariableValueDoNothing :
public Decision {
1630 AssignOneVariableValueDoNothing(
IntVar*
const v, int64_t
value)
1631 : var_(v), value_(
value) {}
1632 ~AssignOneVariableValueDoNothing()
override {}
1633 void Apply(Solver*
const s)
override { var_->SetValue(value_); }
1634 void Refute(Solver*
const s)
override {}
1635 std::string DebugString()
const override {
1636 return absl::StrFormat(
"[%s == %d] or []", var_->DebugString(), value_);
1638 void Accept(DecisionVisitor*
const visitor)
const override {
1639 visitor->VisitSetVariableValue(var_, value_);
1644 const int64_t value_;
1657 class SplitOneVariable :
public Decision {
1659 SplitOneVariable(
IntVar*
const v, int64_t val,
bool start_with_lower_half);
1660 ~SplitOneVariable()
override {}
1661 void Apply(Solver*
const s)
override;
1662 void Refute(Solver*
const s)
override;
1663 std::string DebugString()
const override;
1664 void Accept(DecisionVisitor*
const visitor)
const override {
1665 visitor->VisitSplitVariableDomain(var_, value_, start_with_lower_half_);
1670 const int64_t value_;
1671 const bool start_with_lower_half_;
1674 SplitOneVariable::SplitOneVariable(IntVar*
const v, int64_t val,
1675 bool start_with_lower_half)
1676 : var_(v), value_(val), start_with_lower_half_(start_with_lower_half) {}
1678 std::string SplitOneVariable::DebugString()
const {
1679 if (start_with_lower_half_) {
1680 return absl::StrFormat(
"[%s <= %d]", var_->
DebugString(), value_);
1682 return absl::StrFormat(
"[%s >= %d]", var_->
DebugString(), value_);
1686 void SplitOneVariable::Apply(Solver*
const s) {
1687 if (start_with_lower_half_) {
1690 var_->
SetMin(value_ + 1);
1694 void SplitOneVariable::Refute(Solver*
const s) {
1695 if (start_with_lower_half_) {
1696 var_->
SetMin(value_ + 1);
1704 bool start_with_lower_half) {
1705 return RevAlloc(
new SplitOneVariable(
var, val, start_with_lower_half));
1721 class AssignVariablesValues :
public Decision {
1727 enum class RefutationBehavior { kForbidAssignment, kDoNothing, kFail };
1728 AssignVariablesValues(
1729 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values,
1730 RefutationBehavior refutation = RefutationBehavior::kForbidAssignment);
1731 ~AssignVariablesValues()
override {}
1732 void Apply(Solver*
const s)
override;
1733 void Refute(Solver*
const s)
override;
1734 std::string DebugString()
const override;
1735 void Accept(DecisionVisitor*
const visitor)
const override {
1736 for (
int i = 0; i <
vars_.size(); ++i) {
1737 visitor->VisitSetVariableValue(
vars_[i], values_[i]);
1741 virtual void Accept(ModelVisitor*
const visitor)
const {
1749 const std::vector<IntVar*>
vars_;
1750 const std::vector<int64_t> values_;
1751 const RefutationBehavior refutation_;
1754 AssignVariablesValues::AssignVariablesValues(
const std::vector<IntVar*>& vars,
1755 const std::vector<int64_t>& values,
1756 RefutationBehavior refutation)
1757 :
vars_(vars), values_(values), refutation_(refutation) {}
1759 std::string AssignVariablesValues::DebugString()
const {
1761 if (
vars_.empty()) out +=
"do nothing";
1762 for (
int i = 0; i <
vars_.size(); ++i) {
1763 absl::StrAppendFormat(&out,
"[%s == %d]",
vars_[i]->DebugString(),
1766 switch (refutation_) {
1767 case RefutationBehavior::kForbidAssignment:
1768 out +=
" or forbid assignment";
1770 case RefutationBehavior::kDoNothing:
1771 out +=
" or do nothing";
1773 case RefutationBehavior::kFail:
1780 void AssignVariablesValues::Apply(Solver*
const s) {
1781 if (
vars_.empty())
return;
1782 vars_[0]->FreezeQueue();
1783 for (
int i = 0; i <
vars_.size(); ++i) {
1784 vars_[i]->SetValue(values_[i]);
1786 vars_[0]->UnfreezeQueue();
1789 void AssignVariablesValues::Refute(Solver*
const s) {
1790 switch (refutation_) {
1791 case RefutationBehavior::kForbidAssignment: {
1792 std::vector<IntVar*> terms;
1793 for (
int i = 0; i <
vars_.size(); ++i) {
1794 IntVar* term = s->MakeBoolVar();
1795 s->AddConstraint(s->MakeIsDifferentCstCt(
vars_[i], values_[i], term));
1796 terms.push_back(term);
1798 s->AddConstraint(s->MakeSumGreaterOrEqual(terms, 1));
1801 case RefutationBehavior::kDoNothing: {
1804 case RefutationBehavior::kFail: {
1813 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1814 CHECK_EQ(vars.size(), values.size());
1815 return RevAlloc(
new AssignVariablesValues(
1817 AssignVariablesValues::RefutationBehavior::kForbidAssignment));
1821 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1822 CHECK_EQ(vars.size(), values.size());
1823 return RevAlloc(
new AssignVariablesValues(
1824 vars, values, AssignVariablesValues::RefutationBehavior::kDoNothing));
1828 const std::vector<IntVar*>& vars,
const std::vector<int64_t>& values) {
1829 CHECK_EQ(vars.size(), values.size());
1830 return RevAlloc(
new AssignVariablesValues(
1831 vars, values, AssignVariablesValues::RefutationBehavior::kFail));
1845 BaseAssignVariables(BaseVariableAssignmentSelector*
const selector, Mode mode)
1848 ~BaseAssignVariables()
override;
1849 Decision* Next(Solver*
const s)
override;
1850 std::string DebugString()
const override;
1851 static BaseAssignVariables* MakePhase(
1852 Solver*
const s,
const std::vector<IntVar*>& vars,
1855 const std::string& value_selector_name, BaseAssignVariables::Mode mode);
1858 Solver*
const s,
const std::vector<IntVar*>& vars,
1864 return ChooseFirstUnbound;
1866 return ChooseRandom;
1868 return ChooseMinSizeLowestMin;
1870 return ChooseMinSizeHighestMin;
1872 return ChooseMinSizeLowestMax;
1874 return ChooseMinSizeHighestMax;
1876 return ChooseLowestMin;
1878 return ChooseHighestMax;
1880 return ChooseMinSize;
1882 return ChooseMaxSize;
1884 HighestRegretSelectorOnMin*
const selector =
1885 s->RevAlloc(
new HighestRegretSelectorOnMin(vars));
1886 return [selector](Solver* solver,
const std::vector<IntVar*>& vars,
1887 int first_unbound,
int last_unbound) {
1888 return selector->Choose(solver, vars, first_unbound, last_unbound);
1892 PathSelector*
const selector = s->RevAlloc(
new PathSelector());
1893 return [selector](Solver* solver,
const std::vector<IntVar*>& vars,
1894 int first_unbound,
int last_unbound) {
1895 return selector->Choose(solver, vars, first_unbound, last_unbound);
1899 LOG(FATAL) <<
"Unknown int var strategy " << str;
1910 return SelectMinValue;
1912 return SelectMaxValue;
1914 return SelectRandomValue;
1916 return SelectCenterValue;
1918 return SelectSplitValue;
1920 return SelectSplitValue;
1922 LOG(FATAL) <<
"Unknown int value strategy " << val_str;
1927 void Accept(ModelVisitor*
const visitor)
const override {
1936 BaseAssignVariables::~BaseAssignVariables() {}
1938 Decision* BaseAssignVariables::Next(Solver*
const s) {
1939 const std::vector<IntVar*>& vars =
selector_->vars();
1940 int id =
selector_->ChooseVariableWrapper();
1941 if (
id >= 0 &&
id < vars.size()) {
1942 IntVar*
const var = vars[id];
1946 return s->RevAlloc(
new AssignOneVariableValue(
var,
value));
1948 return s->RevAlloc(
new SplitOneVariable(
var,
value,
true));
1950 return s->RevAlloc(
new SplitOneVariable(
var,
value,
false));
1956 std::string BaseAssignVariables::DebugString()
const {
1960 BaseAssignVariables* BaseAssignVariables::MakePhase(
1961 Solver*
const s,
const std::vector<IntVar*>& vars,
1964 const std::string& value_selector_name, BaseAssignVariables::Mode mode) {
1965 BaseVariableAssignmentSelector*
const selector =
1966 s->RevAlloc(
new VariableAssignmentSelector(
1967 s, vars, std::move(var_selector), std::move(value_selector),
1968 value_selector_name));
1969 return s->RevAlloc(
new BaseAssignVariables(selector, mode));
1977 return "ChooseFirstUnbound";
1979 return "ChooseRandom";
1981 return "ChooseMinSizeLowestMin";
1983 return "ChooseMinSizeHighestMin";
1985 return "ChooseMinSizeLowestMax";
1987 return "ChooseMinSizeHighestMax";
1989 return "ChooseLowestMin";
1991 return "ChooseHighestMax";
1993 return "ChooseMinSize";
1995 return "ChooseMaxSize;";
1997 return "HighestRegretSelectorOnMin";
1999 return "PathSelector";
2001 LOG(FATAL) <<
"Unknown int var strategy " << var_str;
2011 return "SelectMinValue";
2013 return "SelectMaxValue";
2015 return "SelectRandomValue";
2017 return "SelectCenterValue";
2019 return "SelectSplitValue";
2021 return "SelectSplitValue";
2023 LOG(FATAL) <<
"Unknown int value strategy " << val_str;
2030 return ChooseVariableName(var_str) +
"_" + SelectValueName(val_str);
2037 std::vector<IntVar*> vars(1);
2039 return MakePhase(vars, var_str, val_str);
2045 std::vector<IntVar*> vars(2);
2048 return MakePhase(vars, var_str, val_str);
2055 std::vector<IntVar*> vars(3);
2059 return MakePhase(vars, var_str, val_str);
2066 std::vector<IntVar*> vars(4);
2071 return MakePhase(vars, var_str, val_str);
2075 BaseAssignVariables::Mode mode = BaseAssignVariables::ASSIGN;
2077 mode = BaseAssignVariables::SPLIT_LOWER;
2079 mode = BaseAssignVariables::SPLIT_UPPER;
2088 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2090 BaseAssignVariables::MakeValueSelector(
this, val_str);
2091 const std::string
name = BuildHeuristicsName(var_str, val_str);
2092 return BaseAssignVariables::MakePhase(
2093 this, vars, var_selector, value_selector,
name,
ChooseMode(val_str));
2099 CHECK(var_evaluator !=
nullptr);
2100 CheapestVarSelector*
const var_selector =
2101 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2103 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2104 int first_unbound,
int last_unbound) {
2105 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2108 BaseAssignVariables::MakeValueSelector(
this, val_str);
2109 const std::string
name =
"ChooseCheapestVariable_" + SelectValueName(val_str);
2110 return BaseAssignVariables::MakePhase(
2111 this, vars, choose_variable, select_value,
name,
ChooseMode(val_str));
2118 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2119 CheapestValueSelector*
const value_selector =
2120 RevAlloc(
new CheapestValueSelector(std::move(value_evaluator),
nullptr));
2122 [value_selector](
const IntVar*
var, int64_t id) {
2123 return value_selector->Select(
var,
id);
2125 const std::string
name = ChooseVariableName(var_str) +
"_SelectCheapestValue";
2126 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2128 BaseAssignVariables::ASSIGN);
2135 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2136 BestValueByComparisonSelector*
const value_selector =
RevAlloc(
2137 new BestValueByComparisonSelector(std::move(var_val1_val2_comparator)));
2139 [value_selector](
const IntVar*
var, int64_t id) {
2140 return value_selector->Select(
var,
id);
2142 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2143 select_value,
"CheapestValue",
2144 BaseAssignVariables::ASSIGN);
2150 CheapestVarSelector*
const var_selector =
2151 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2153 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2154 int first_unbound,
int last_unbound) {
2155 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2157 CheapestValueSelector* value_selector =
2158 RevAlloc(
new CheapestValueSelector(std::move(value_evaluator),
nullptr));
2160 [value_selector](
const IntVar*
var, int64_t id) {
2161 return value_selector->Select(
var,
id);
2163 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2164 select_value,
"CheapestValue",
2165 BaseAssignVariables::ASSIGN);
2173 BaseAssignVariables::MakeVariableSelector(
this, vars, var_str);
2174 CheapestValueSelector* value_selector =
RevAlloc(
new CheapestValueSelector(
2175 std::move(value_evaluator), std::move(tie_breaker)));
2177 [value_selector](
const IntVar*
var, int64_t id) {
2178 return value_selector->Select(
var,
id);
2180 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2181 select_value,
"CheapestValue",
2182 BaseAssignVariables::ASSIGN);
2189 CheapestVarSelector*
const var_selector =
2190 RevAlloc(
new CheapestVarSelector(std::move(var_evaluator)));
2192 [var_selector](
Solver* solver,
const std::vector<IntVar*>& vars,
2193 int first_unbound,
int last_unbound) {
2194 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2196 CheapestValueSelector* value_selector =
RevAlloc(
new CheapestValueSelector(
2197 std::move(value_evaluator), std::move(tie_breaker)));
2199 [value_selector](
const IntVar*
var, int64_t id) {
2200 return value_selector->Select(
var,
id);
2202 return BaseAssignVariables::MakePhase(
this, vars, choose_variable,
2203 select_value,
"CheapestValue",
2204 BaseAssignVariables::ASSIGN);
2210 return MakePhase(vars, std::move(eval),
nullptr, str);
2217 BaseVariableAssignmentSelector* selector =
nullptr;
2221 selector =
RevAlloc(
new StaticEvaluatorSelector(
this, vars, eval));
2225 selector =
RevAlloc(
new DynamicEvaluatorSelector(
this, vars, eval,
2226 std::move(tie_breaker)));
2231 new BaseAssignVariables(selector, BaseAssignVariables::ASSIGN));
2239 AssignVariablesFromAssignment(
const Assignment*
const assignment,
2241 const std::vector<IntVar*>& vars)
2242 : assignment_(assignment), db_(db),
vars_(vars), iter_(0) {}
2244 ~AssignVariablesFromAssignment()
override {}
2246 Decision* Next(Solver*
const s)
override {
2247 if (iter_ <
vars_.size()) {
2248 IntVar*
const var =
vars_[iter_++];
2250 new AssignOneVariableValue(
var, assignment_->Value(
var)));
2252 return db_->Next(s);
2256 void Accept(ModelVisitor*
const visitor)
const override {
2264 const Assignment*
const assignment_;
2265 DecisionBuilder*
const db_;
2266 const std::vector<IntVar*>
vars_;
2273 const std::vector<IntVar*>& vars) {
2274 return RevAlloc(
new AssignVariablesFromAssignment(assignment, db, vars));
2284 prototype_(assignment == nullptr ? nullptr : new
Assignment(assignment)) {
2292 delete data.solution;
2338 if (
prototype_ !=
nullptr && objective !=
nullptr) {
2345 delete data.solution;
2396 CHECK_GE(n, 0) <<
"wrong index in solution getter";
2397 CHECK_LT(n,
solution_data_.size()) <<
"wrong index in solution getter";
2469 explicit FirstSolutionCollector(
Solver*
const s);
2470 ~FirstSolutionCollector()
override;
2471 void EnterSearch()
override;
2472 bool AtSolution()
override;
2473 void Install()
override;
2474 std::string DebugString()
const override;
2480 FirstSolutionCollector::FirstSolutionCollector(Solver*
const s,
2481 const Assignment*
const a)
2482 : SolutionCollector(s,
a), done_(false) {}
2484 FirstSolutionCollector::FirstSolutionCollector(Solver*
const s)
2485 : SolutionCollector(s), done_(false) {}
2487 FirstSolutionCollector::~FirstSolutionCollector() {}
2489 void FirstSolutionCollector::EnterSearch() {
2494 bool FirstSolutionCollector::AtSolution() {
2502 void FirstSolutionCollector::Install() {
2507 std::string FirstSolutionCollector::DebugString()
const {
2508 if (prototype_ ==
nullptr) {
2509 return "FirstSolutionCollector()";
2511 return "FirstSolutionCollector(" + prototype_->DebugString() +
")";
2518 return RevAlloc(
new FirstSolutionCollector(
this, assignment));
2522 return RevAlloc(
new FirstSolutionCollector(
this));
2532 explicit LastSolutionCollector(
Solver*
const s);
2533 ~LastSolutionCollector()
override;
2534 bool AtSolution()
override;
2535 void Install()
override;
2536 std::string DebugString()
const override;
2539 LastSolutionCollector::LastSolutionCollector(Solver*
const s,
2540 const Assignment*
const a)
2541 : SolutionCollector(s,
a) {}
2543 LastSolutionCollector::LastSolutionCollector(Solver*
const s)
2544 : SolutionCollector(s) {}
2546 LastSolutionCollector::~LastSolutionCollector() {}
2548 bool LastSolutionCollector::AtSolution() {
2554 void LastSolutionCollector::Install() {
2559 std::string LastSolutionCollector::DebugString()
const {
2560 if (prototype_ ==
nullptr) {
2561 return "LastSolutionCollector()";
2563 return "LastSolutionCollector(" + prototype_->DebugString() +
")";
2570 return RevAlloc(
new LastSolutionCollector(
this, assignment));
2574 return RevAlloc(
new LastSolutionCollector(
this));
2584 BestValueSolutionCollector(
Solver*
const s,
bool maximize);
2585 ~BestValueSolutionCollector()
override {}
2586 void EnterSearch()
override;
2587 bool AtSolution()
override;
2588 void Install()
override;
2589 std::string DebugString()
const override;
2596 BestValueSolutionCollector::BestValueSolutionCollector(
2597 Solver*
const s,
const Assignment*
const a,
bool maximize)
2598 : SolutionCollector(s,
a),
2600 best_(maximize ? std::numeric_limits<int64_t>::
min()
2601 : std::numeric_limits<int64_t>::
max()) {}
2603 BestValueSolutionCollector::BestValueSolutionCollector(Solver*
const s,
2605 : SolutionCollector(s),
2607 best_(maximize ? std::numeric_limits<int64_t>::
min()
2608 : std::numeric_limits<int64_t>::
max()) {}
2610 void BestValueSolutionCollector::EnterSearch() {
2611 SolutionCollector::EnterSearch();
2613 : std::numeric_limits<int64_t>::
max();
2616 bool BestValueSolutionCollector::AtSolution() {
2617 if (prototype_ !=
nullptr) {
2618 const IntVar* objective = prototype_->Objective();
2619 if (objective !=
nullptr) {
2620 if (
maximize_ && (solution_count() == 0 || objective->Max() >
best_)) {
2623 best_ = objective->Max();
2625 (solution_count() == 0 || objective->Min() <
best_)) {
2628 best_ = objective->Min();
2635 void BestValueSolutionCollector::Install() {
2636 SolutionCollector::Install();
2637 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2640 std::string BestValueSolutionCollector::DebugString()
const {
2641 if (prototype_ ==
nullptr) {
2642 return "BestValueSolutionCollector()";
2644 return "BestValueSolutionCollector(" + prototype_->DebugString() +
")";
2650 const Assignment*
const assignment,
bool maximize) {
2651 return RevAlloc(
new BestValueSolutionCollector(
this, assignment, maximize));
2655 return RevAlloc(
new BestValueSolutionCollector(
this, maximize));
2663 NBestValueSolutionCollector(
Solver*
const solver,
2665 int solution_count,
bool maximize);
2666 NBestValueSolutionCollector(
Solver*
const solver,
int solution_count,
2668 ~NBestValueSolutionCollector()
override { Clear(); }
2683 NBestValueSolutionCollector::NBestValueSolutionCollector(
2684 Solver*
const solver,
const Assignment*
const assignment,
2685 int solution_count,
bool maximize)
2686 : SolutionCollector(solver, assignment),
2690 NBestValueSolutionCollector::NBestValueSolutionCollector(Solver*
const solver,
2693 : SolutionCollector(solver),
2697 void NBestValueSolutionCollector::EnterSearch() {
2698 SolutionCollector::EnterSearch();
2702 solver()->SetUseFastLocalSearch(
false);
2707 void NBestValueSolutionCollector::ExitSearch() {
2714 bool NBestValueSolutionCollector::AtSolution() {
2715 if (prototype_ !=
nullptr) {
2716 const IntVar* objective = prototype_->Objective();
2717 if (objective !=
nullptr) {
2737 void NBestValueSolutionCollector::Install() {
2738 SolutionCollector::Install();
2739 ListenToEvent(Solver::MonitorEvent::kExitSearch);
2740 ListenToEvent(Solver::MonitorEvent::kAtSolution);
2743 std::string NBestValueSolutionCollector::DebugString()
const {
2744 if (prototype_ ==
nullptr) {
2745 return "NBestValueSolutionCollector()";
2747 return "NBestValueSolutionCollector(" + prototype_->DebugString() +
")";
2751 void NBestValueSolutionCollector::Clear() {
2761 const Assignment*
const assignment,
int solution_count,
bool maximize) {
2762 if (solution_count == 1) {
2763 return MakeBestValueSolutionCollector(assignment, maximize);
2765 return RevAlloc(
new NBestValueSolutionCollector(
this, assignment,
2766 solution_count, maximize));
2771 if (solution_count == 1) {
2772 return MakeBestValueSolutionCollector(maximize);
2775 new NBestValueSolutionCollector(
this, solution_count, maximize));
2785 explicit AllSolutionCollector(
Solver*
const s);
2786 ~AllSolutionCollector()
override;
2792 AllSolutionCollector::AllSolutionCollector(Solver*
const s,
2793 const Assignment*
const a)
2794 : SolutionCollector(s,
a) {}
2796 AllSolutionCollector::AllSolutionCollector(Solver*
const s)
2797 : SolutionCollector(s) {}
2799 AllSolutionCollector::~AllSolutionCollector() {}
2801 bool AllSolutionCollector::AtSolution() {
2806 void AllSolutionCollector::Install() {
2811 std::string AllSolutionCollector::DebugString()
const {
2812 if (prototype_ ==
nullptr) {
2813 return "AllSolutionCollector()";
2815 return "AllSolutionCollector(" + prototype_->DebugString() +
")";
2822 return RevAlloc(
new AllSolutionCollector(
this, assignment));
2826 return RevAlloc(
new AllSolutionCollector(
this));
2836 best_(std::numeric_limits<int64_t>::
max()),
2838 found_initial_solution_(false) {
2862 if (
solver()->SearchDepth() == 0) {
2905 if (
delta !=
nullptr) {
2906 const bool delta_has_objective =
delta->HasObjective();
2907 if (!delta_has_objective) {
2914 const int64_t delta_min_objective =
2915 delta_has_objective ?
delta->ObjectiveMin()
2917 const int64_t min_objective =
2921 delta->SetObjectiveMin(
2925 const int64_t delta_max_objective =
2926 delta_has_objective ?
delta->ObjectiveMax()
2928 const int64_t max_objective =
2932 delta->SetObjectiveMax(
2941 return absl::StrFormat(
"objective value = %d, ",
var_->
Value());
2947 out =
"MaximizeVar(";
2949 out =
"MinimizeVar(";
2951 absl::StrAppendFormat(&out,
"%s, step = %d, best = %d)",
var_->
DebugString(),
2981 WeightedOptimizeVar(
Solver* solver,
bool maximize,
2982 const std::vector<IntVar*>& sub_objectives,
2983 const std::vector<int64_t>& weights, int64_t step)
2985 solver->MakeScalProd(sub_objectives, weights)->Var(), step),
2986 sub_objectives_(sub_objectives),
2988 CHECK_EQ(sub_objectives.size(), weights.size());
2991 ~WeightedOptimizeVar()
override {}
2992 std::string Print()
const override;
2995 const std::vector<IntVar*> sub_objectives_;
2996 const std::vector<int64_t> weights_;
3001 std::string WeightedOptimizeVar::Print()
const {
3003 result.append(
"\nWeighted Objective:\n");
3004 for (
int i = 0; i < sub_objectives_.size(); ++i) {
3005 absl::StrAppendFormat(&result,
"Variable %s,\tvalue %d,\tweight %d\n",
3006 sub_objectives_[i]->
name(),
3007 sub_objectives_[i]->
Value(), weights_[i]);
3014 bool maximize,
const std::vector<IntVar*>& sub_objectives,
3015 const std::vector<int64_t>& weights, int64_t step) {
3017 new WeightedOptimizeVar(
this, maximize, sub_objectives, weights, step));
3021 const std::vector<IntVar*>& sub_objectives,
3022 const std::vector<int64_t>& weights, int64_t step) {
3024 new WeightedOptimizeVar(
this,
false, sub_objectives, weights, step));
3028 const std::vector<IntVar*>& sub_objectives,
3029 const std::vector<int64_t>& weights, int64_t step) {
3031 new WeightedOptimizeVar(
this,
true, sub_objectives, weights, step));
3035 bool maximize,
const std::vector<IntVar*>& sub_objectives,
3036 const std::vector<int>& weights, int64_t step) {
3042 const std::vector<IntVar*>& sub_objectives,
const std::vector<int>& weights,
3048 const std::vector<IntVar*>& sub_objectives,
const std::vector<int>& weights,
3058 Metaheuristic(
Solver*
const solver,
bool maximize,
IntVar* objective,
3060 ~Metaheuristic()
override {}
3062 bool AtSolution()
override;
3063 void EnterSearch()
override;
3064 void RefuteDecision(Decision*
const d)
override;
3075 Metaheuristic::Metaheuristic(Solver*
const solver,
bool maximize,
3076 IntVar* objective, int64_t step)
3077 : SearchMonitor(solver),
3081 best_(std::numeric_limits<int64_t>::
max()),
3084 bool Metaheuristic::AtSolution() {
3090 <<
". Taking domain min.";
3097 <<
". Taking domain max.";
3105 void Metaheuristic::EnterSearch() {
3108 solver()->SetUseFastLocalSearch(
false);
3118 void Metaheuristic::RefuteDecision(Decision* d) {
3129 if (
delta !=
nullptr) {
3130 if (!
delta->HasObjective()) {
3135 delta->SetObjectiveMin(
3138 delta->SetObjectiveMax(
3148 class TabuSearch :
public Metaheuristic {
3150 TabuSearch(Solver*
const s,
bool maximize, IntVar* objective, int64_t step,
3151 const std::vector<IntVar*>& vars, int64_t keep_tenure,
3152 int64_t forbid_tenure,
double tabu_factor);
3153 ~TabuSearch()
override {}
3154 void EnterSearch()
override;
3155 void ApplyDecision(Decision* d)
override;
3156 bool AtSolution()
override;
3157 bool LocalOptimum()
override;
3159 std::string DebugString()
const override {
return "Tabu Search"; }
3164 const int64_t
value;
3167 typedef std::list<VarValue> TabuList;
3169 virtual std::vector<IntVar*> CreateTabuVars();
3170 const TabuList& forbid_tabu_list() {
return forbid_tabu_list_; }
3173 void AgeList(int64_t tenure, TabuList* list);
3176 const std::vector<IntVar*>
vars_;
3177 Assignment assignment_;
3179 TabuList keep_tabu_list_;
3180 int64_t keep_tenure_;
3181 TabuList forbid_tabu_list_;
3182 int64_t forbid_tenure_;
3183 double tabu_factor_;
3185 bool found_initial_solution_;
3190 TabuSearch::TabuSearch(Solver*
const s,
bool maximize, IntVar* objective,
3191 int64_t step,
const std::vector<IntVar*>& vars,
3192 int64_t keep_tenure, int64_t forbid_tenure,
3194 : Metaheuristic(s, maximize, objective, step),
3197 last_(std::numeric_limits<int64_t>::
max()),
3198 keep_tenure_(keep_tenure),
3199 forbid_tenure_(forbid_tenure),
3200 tabu_factor_(tabu_factor),
3202 found_initial_solution_(false) {
3203 assignment_.Add(
vars_);
3206 void TabuSearch::EnterSearch() {
3207 Metaheuristic::EnterSearch();
3208 found_initial_solution_ =
false;
3212 void TabuSearch::ApplyDecision(Decision*
const d) {
3213 Solver*
const s = solver();
3214 if (d == s->balancing_decision()) {
3219 IntVar* aspiration = s->MakeBoolVar();
3221 s->AddConstraint(s->MakeIsGreaterOrEqualCstCt(
3228 IntVar* tabu_var =
nullptr;
3232 const std::vector<IntVar*> tabu_vars = CreateTabuVars();
3233 if (!tabu_vars.empty()) {
3234 tabu_var = s->MakeIsGreaterOrEqualCstVar(s->MakeSum(tabu_vars)->Var(),
3235 tabu_vars.size() * tabu_factor_);
3239 if (tabu_var !=
nullptr) {
3241 s->MakeGreaterOrEqual(s->MakeSum(aspiration, tabu_var), int64_t{1}));
3258 if (found_initial_solution_) {
3259 s->AddConstraint(s->MakeNonEquality(
objective_, last_));
3263 std::vector<IntVar*> TabuSearch::CreateTabuVars() {
3264 Solver*
const s = solver();
3272 std::vector<IntVar*> tabu_vars;
3273 for (
const auto [
var,
value, unused_stamp] : keep_tabu_list_) {
3274 tabu_vars.push_back(s->MakeIsEqualCstVar(
var,
value));
3276 for (
const auto [
var,
value, unused_stamp] : forbid_tabu_list_) {
3277 tabu_vars.push_back(s->MakeIsDifferentCstVar(
var,
value));
3282 bool TabuSearch::AtSolution() {
3283 if (!Metaheuristic::AtSolution()) {
3286 found_initial_solution_ =
true;
3292 for (
int i = 0; i <
vars_.size(); ++i) {
3294 const int64_t old_value = assignment_.Value(
var);
3295 const int64_t new_value =
var->Value();
3296 if (old_value != new_value) {
3297 if (keep_tenure_ > 0) {
3298 keep_tabu_list_.push_front({
var, new_value, stamp_});
3300 if (forbid_tenure_ > 0) {
3301 forbid_tabu_list_.push_front({
var, old_value, stamp_});
3306 assignment_.Store();
3311 bool TabuSearch::LocalOptimum() {
3318 return found_initial_solution_;
3327 void TabuSearch::AgeList(int64_t tenure, TabuList* list) {
3328 while (!list->empty() && list->back().stamp < stamp_ - tenure) {
3333 void TabuSearch::AgeLists() {
3334 AgeList(keep_tenure_, &keep_tabu_list_);
3335 AgeList(forbid_tenure_, &forbid_tabu_list_);
3339 class GenericTabuSearch :
public TabuSearch {
3341 GenericTabuSearch(Solver*
const s,
bool maximize, IntVar* objective,
3342 int64_t step,
const std::vector<IntVar*>& vars,
3343 int64_t forbid_tenure)
3344 : TabuSearch(s, maximize, objective, step, vars, 0, forbid_tenure, 1) {}
3345 std::string DebugString()
const override {
return "Generic Tabu Search"; }
3348 std::vector<IntVar*> CreateTabuVars()
override;
3351 std::vector<IntVar*> GenericTabuSearch::CreateTabuVars() {
3352 Solver*
const s = solver();
3356 std::vector<IntVar*> forbid_values;
3357 for (
const auto [
var,
value, unused_stamp] : forbid_tabu_list()) {
3358 forbid_values.push_back(s->MakeIsDifferentCstVar(
var,
value));
3360 std::vector<IntVar*> tabu_vars;
3361 if (!forbid_values.empty()) {
3362 tabu_vars.push_back(s->MakeIsGreaterCstVar(s->MakeSum(forbid_values), 0));
3371 const std::vector<IntVar*>& vars,
3372 int64_t keep_tenure,
3373 int64_t forbid_tenure,
3374 double tabu_factor) {
3375 return RevAlloc(
new TabuSearch(
this, maximize, v, step, vars, keep_tenure,
3376 forbid_tenure, tabu_factor));
3380 bool maximize,
IntVar*
const v, int64_t step,
3381 const std::vector<IntVar*>& tabu_vars, int64_t forbid_tenure) {
3383 new GenericTabuSearch(
this, maximize, v, step, tabu_vars, forbid_tenure));
3389 class SimulatedAnnealing :
public Metaheuristic {
3391 SimulatedAnnealing(
Solver*
const s,
bool maximize,
IntVar* objective,
3392 int64_t step, int64_t initial_temperature);
3393 ~SimulatedAnnealing()
override {}
3394 void EnterSearch()
override;
3395 void ApplyDecision(Decision* d)
override;
3396 bool AtSolution()
override;
3397 bool LocalOptimum()
override;
3399 std::string DebugString()
const override {
return "Simulated Annealing"; }
3402 double Temperature()
const;
3404 const int64_t temperature0_;
3407 bool found_initial_solution_;
3412 SimulatedAnnealing::SimulatedAnnealing(Solver*
const s,
bool maximize,
3413 IntVar* objective, int64_t step,
3414 int64_t initial_temperature)
3415 : Metaheuristic(s, maximize, objective, step),
3416 temperature0_(initial_temperature),
3419 found_initial_solution_(false) {}
3421 void SimulatedAnnealing::EnterSearch() {
3422 Metaheuristic::EnterSearch();
3423 found_initial_solution_ =
false;
3426 void SimulatedAnnealing::ApplyDecision(Decision*
const d) {
3427 Solver*
const s = solver();
3428 if (d == s->balancing_decision()) {
3431 const double rand_double = absl::Uniform<double>(rand_, 0.0, 1.0);
3432 #if defined(_MSC_VER) || defined(__ANDROID__)
3433 const double rand_log2_double = log(rand_double) / log(2.0L);
3435 const double rand_log2_double = log2(rand_double);
3437 const int64_t energy_bound = Temperature() * rand_log2_double;
3451 bool SimulatedAnnealing::AtSolution() {
3452 if (!Metaheuristic::AtSolution()) {
3455 found_initial_solution_ =
true;
3459 bool SimulatedAnnealing::LocalOptimum() {
3466 return found_initial_solution_ && Temperature() > 0;
3470 if (iteration_ > 0) {
3475 double SimulatedAnnealing::Temperature()
const {
3476 if (iteration_ > 0) {
3477 return (1.0 * temperature0_) / iteration_;
3486 int64_t initial_temperature) {
3488 new SimulatedAnnealing(
this, maximize, v, step, initial_temperature));
3498 class GuidedLocalSearchPenaltiesTable {
3504 explicit GuidedLocalSearchPenaltiesTable(
int num_vars);
3505 bool HasPenalties()
const {
return has_values_; }
3506 void IncrementPenalty(
const VarValue& var_value);
3507 int64_t GetPenalty(
const VarValue& var_value)
const;
3511 std::vector<std::vector<int64_t>> penalties_;
3515 GuidedLocalSearchPenaltiesTable::GuidedLocalSearchPenaltiesTable(
int num_vars)
3516 : penalties_(num_vars), has_values_(false) {}
3518 void GuidedLocalSearchPenaltiesTable::IncrementPenalty(
3519 const VarValue& var_value) {
3520 std::vector<int64_t>& var_penalties = penalties_[var_value.var];
3521 const int64_t
value = var_value.value;
3522 if (
value >= var_penalties.size()) {
3523 var_penalties.resize(
value + 1, 0);
3525 ++var_penalties[
value];
3529 void GuidedLocalSearchPenaltiesTable::Reset() {
3530 has_values_ =
false;
3531 for (
int i = 0; i < penalties_.size(); ++i) {
3532 penalties_[i].clear();
3536 int64_t GuidedLocalSearchPenaltiesTable::GetPenalty(
3537 const VarValue& var_value)
const {
3538 const std::vector<int64_t>& var_penalties = penalties_[var_value.var];
3539 const int64_t
value = var_value.value;
3540 return (
value >= var_penalties.size()) ? 0 : var_penalties[
value];
3544 class GuidedLocalSearchPenaltiesMap {
3550 friend bool operator==(
const VarValue& lhs,
const VarValue& rhs) {
3551 return lhs.var == rhs.var && lhs.value == rhs.value;
3553 template <
typename H>
3555 return H::combine(std::move(h), var_value.var, var_value.value);
3558 explicit GuidedLocalSearchPenaltiesMap(
int num_vars);
3559 bool HasPenalties()
const {
return (!penalties_.empty()); }
3560 void IncrementPenalty(
const VarValue& var_value);
3561 int64_t GetPenalty(
const VarValue& var_value)
const;
3566 absl::flat_hash_map<VarValue, int64_t> penalties_;
3569 GuidedLocalSearchPenaltiesMap::GuidedLocalSearchPenaltiesMap(
int num_vars)
3570 : penalized_(num_vars, false) {}
3572 void GuidedLocalSearchPenaltiesMap::IncrementPenalty(
3573 const VarValue& var_value) {
3574 ++penalties_[var_value];
3575 penalized_.
Set(var_value.var,
true);
3578 void GuidedLocalSearchPenaltiesMap::Reset() {
3583 int64_t GuidedLocalSearchPenaltiesMap::GetPenalty(
3584 const VarValue& var_value)
const {
3585 return (penalized_.
Get(var_value.var))
3590 template <
typename P>
3591 class GuidedLocalSearch :
public Metaheuristic {
3593 GuidedLocalSearch(Solver*
const s, IntVar* objective,
bool maximize,
3594 int64_t step,
const std::vector<IntVar*>& vars,
3595 double penalty_factor,
3596 bool reset_penalties_on_new_best_solution);
3597 ~GuidedLocalSearch()
override {}
3599 void ApplyDecision(Decision* d)
override;
3600 bool AtSolution()
override;
3601 void EnterSearch()
override;
3602 bool LocalOptimum()
override;
3603 virtual int64_t AssignmentElementPenalty(
int index)
const = 0;
3604 virtual int64_t AssignmentPenalty(int64_t
var, int64_t
value)
const = 0;
3605 virtual int64_t Evaluate(
const Assignment*
delta, int64_t current_penalty,
3606 bool incremental) = 0;
3607 virtual IntExpr* MakeElementPenalty(
int index) = 0;
3608 std::string DebugString()
const override {
return "Guided Local Search"; }
3614 template <
typename T,
typename IndexType =
int64_t>
3617 explicit DirtyArray(IndexType size)
3618 : base_data_(size), modified_data_(size), touched_(size) {}
3621 void Set(IndexType i,
const T&
value) {
3622 modified_data_[i] =
value;
3626 void SetAll(
const T&
value) {
3627 for (IndexType i = 0; i < modified_data_.size(); ++i) {
3632 T Get(IndexType i)
const {
return modified_data_[i]; }
3636 for (
const IndexType
index : touched_.PositionsSetAtLeastOnce()) {
3639 touched_.SparseClearAll();
3643 for (
const IndexType
index : touched_.PositionsSetAtLeastOnce()) {
3646 touched_.SparseClearAll();
3650 int NumSetValues()
const {
3651 return touched_.NumberOfSetCallsWithDifferentArguments();
3655 std::vector<T> base_data_;
3656 std::vector<T> modified_data_;
3657 SparseBitset<IndexType> touched_;
3660 int64_t GetValue(int64_t
index)
const {
3661 return assignment_.Element(
index).Value();
3663 IntVar* GetVar(int64_t
index)
const {
3664 return assignment_.Element(
index).Var();
3666 void AddVars(
const std::vector<IntVar*>& vars);
3667 int NumPrimaryVars()
const {
return num_vars_; }
3668 int GetLocalIndexFromVar(IntVar*
var)
const {
3669 const int var_index =
var->index();
3674 void ResetPenalties();
3689 template <
typename P>
3690 GuidedLocalSearch<P>::GuidedLocalSearch(
3691 Solver*
const s, IntVar* objective,
bool maximize, int64_t step,
3692 const std::vector<IntVar*>& vars,
double penalty_factor,
3693 bool reset_penalties_on_new_best_solution)
3694 : Metaheuristic(s, maximize, objective, step),
3700 penalties_(vars.size()),
3704 reset_penalties_on_new_best_solution) {
3708 template <
typename P>
3709 void GuidedLocalSearch<P>::AddVars(
const std::vector<IntVar*>& vars) {
3710 const int offset = assignment_.Size();
3711 if (vars.empty())
return;
3712 assignment_.Resize(offset + vars.size());
3713 for (
int i = 0; i < vars.size(); ++i) {
3714 assignment_.AddAtPosition(vars[i], offset + i);
3716 const int max_var_index =
3717 (*std::max_element(vars.begin(), vars.end(), [](IntVar*
a, IntVar*
b) {
3718 return a->index() < b->index();
3723 for (
int i = 0; i < vars.size(); ++i) {
3735 template <
typename P>
3736 void GuidedLocalSearch<P>::ApplyDecision(Decision*
const d) {
3737 if (d == solver()->balancing_decision()) {
3741 if (penalties_.HasPenalties()) {
3745 std::vector<IntVar*> elements;
3747 elements.push_back(MakeElementPenalty(i)->Var());
3748 const int64_t penalty = AssignmentElementPenalty(i);
3759 IntExpr* min_pen_exp =
3761 IntVar* min_exp = solver()->MakeMin(min_pen_exp,
best_ +
step_)->Var();
3762 solver()->AddConstraint(
3763 solver()->MakeGreaterOrEqual(
objective_, min_exp));
3765 IntExpr* max_pen_exp =
3767 IntVar* max_exp = solver()->MakeMax(max_pen_exp,
best_ -
step_)->Var();
3768 solver()->AddConstraint(solver()->MakeLessOrEqual(
objective_, max_exp));
3786 template <
typename P>
3787 void GuidedLocalSearch<P>::ResetPenalties() {
3795 template <
typename P>
3796 bool GuidedLocalSearch<P>::AtSolution() {
3797 const int64_t old_best =
best_;
3798 if (!Metaheuristic::AtSolution()) {
3814 assignment_.Store();
3818 template <
typename P>
3819 void GuidedLocalSearch<P>::EnterSearch() {
3820 Metaheuristic::EnterSearch();
3827 template <
typename P>
3829 Assignment* deltadelta) {
3830 if (
delta ==
nullptr && deltadelta ==
nullptr)
return true;
3831 if (!penalties_.HasPenalties()) {
3834 int64_t penalty = 0;
3835 if (!deltadelta->Empty()) {
3852 if (!
delta->HasObjective()) {
3857 delta->SetObjectiveMin(
3860 delta->ObjectiveMin()));
3862 delta->SetObjectiveMax(
3865 delta->ObjectiveMax()));
3873 template <
typename P>
3874 bool GuidedLocalSearch<P>::LocalOptimum() {
3875 std::vector<double> utilities(
num_vars_);
3876 double max_utility = -std::numeric_limits<double>::infinity();
3878 const IntVarElement& element = assignment_.Element(
var);
3879 if (!element.Bound()) {
3883 const int64_t
value = element.Value();
3887 const double utility =
cost / (penalties_.GetPenalty({
var,
value}) + 1.0);
3888 utilities[
var] = utility;
3889 if (utility > max_utility) max_utility = utility;
3892 if (utilities[
var] == max_utility) {
3893 const IntVarElement& element = assignment_.Element(
var);
3894 DCHECK(element.Bound());
3895 penalties_.IncrementPenalty({
var, element.Value()});
3906 template <
typename P>
3907 class BinaryGuidedLocalSearch :
public GuidedLocalSearch<P> {
3909 BinaryGuidedLocalSearch(
3910 Solver*
const solver, IntVar*
const objective,
3911 std::function<int64_t(int64_t, int64_t)> objective_function,
3912 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
3913 double penalty_factor,
bool reset_penalties_on_new_best_solution);
3914 ~BinaryGuidedLocalSearch()
override {}
3915 IntExpr* MakeElementPenalty(
int index)
override;
3916 int64_t AssignmentElementPenalty(
int index)
const override;
3917 int64_t AssignmentPenalty(int64_t
var, int64_t
value)
const override;
3918 int64_t Evaluate(
const Assignment*
delta, int64_t current_penalty,
3919 bool incremental)
override;
3922 int64_t PenalizedValue(int64_t i, int64_t j)
const;
3923 std::function<int64_t(int64_t, int64_t)> objective_function_;
3926 template <
typename P>
3927 BinaryGuidedLocalSearch<P>::BinaryGuidedLocalSearch(
3928 Solver*
const solver, IntVar*
const objective,
3929 std::function<int64_t(int64_t, int64_t)> objective_function,
bool maximize,
3930 int64_t step,
const std::vector<IntVar*>& vars,
double penalty_factor,
3931 bool reset_penalties_on_new_best_solution)
3932 : GuidedLocalSearch<P>(solver, objective, maximize, step, vars,
3934 reset_penalties_on_new_best_solution),
3935 objective_function_(std::move(objective_function)) {}
3937 template <
typename P>
3938 IntExpr* BinaryGuidedLocalSearch<P>::MakeElementPenalty(
int index) {
3939 return this->solver()->MakeElement(
3940 [
this,
index](int64_t i) {
return PenalizedValue(
index, i); },
3941 this->GetVar(
index));
3944 template <
typename P>
3945 int64_t BinaryGuidedLocalSearch<P>::AssignmentElementPenalty(
int index)
const {
3946 return PenalizedValue(
index, this->GetValue(
index));
3949 template <
typename P>
3950 int64_t BinaryGuidedLocalSearch<P>::AssignmentPenalty(int64_t
var,
3951 int64_t
value)
const {
3952 return objective_function_(
var,
value);
3955 template <
typename P>
3956 int64_t BinaryGuidedLocalSearch<P>::Evaluate(
const Assignment*
delta,
3957 int64_t current_penalty,
3959 int64_t penalty = current_penalty;
3960 const Assignment::IntContainer& container =
delta->IntVarContainer();
3961 for (
const IntVarElement& new_element : container.elements()) {
3962 const int index = this->GetLocalIndexFromVar(new_element.Var());
3963 if (
index == -1)
continue;
3965 if (new_element.Activated()) {
3966 const int64_t new_penalty = PenalizedValue(
index, new_element.Value());
3967 penalty =
CapAdd(penalty, new_penalty);
3977 template <
typename P>
3978 int64_t BinaryGuidedLocalSearch<P>::PenalizedValue(int64_t i, int64_t j)
const {
3979 const int64_t penalty = this->penalties_.GetPenalty({i, j});
3981 if (penalty == 0)
return 0;
3982 const double penalized_value_fp =
3984 const int64_t penalized_value =
3986 ?
static_cast<int64_t
>(penalized_value_fp)
3988 return this->
maximize_ ? -penalized_value : penalized_value;
3991 template <
typename P>
3992 class TernaryGuidedLocalSearch :
public GuidedLocalSearch<P> {
3994 TernaryGuidedLocalSearch(
3995 Solver*
const solver, IntVar*
const objective,
3996 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
3997 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
3998 const std::vector<IntVar*>& secondary_vars,
double penalty_factor,
3999 bool reset_penalties_on_new_best_solution);
4000 ~TernaryGuidedLocalSearch()
override {}
4001 IntExpr* MakeElementPenalty(
int index)
override;
4002 int64_t AssignmentElementPenalty(
int index)
const override;
4003 int64_t AssignmentPenalty(int64_t
var, int64_t
value)
const override;
4004 int64_t Evaluate(
const Assignment*
delta, int64_t current_penalty,
4005 bool incremental)
override;
4008 int64_t PenalizedValue(int64_t i, int64_t j, int64_t k)
const;
4010 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function_;
4011 std::vector<int> secondary_values_;
4014 template <
typename P>
4015 TernaryGuidedLocalSearch<P>::TernaryGuidedLocalSearch(
4016 Solver*
const solver, IntVar*
const objective,
4017 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
4018 bool maximize, int64_t step,
const std::vector<IntVar*>& vars,
4019 const std::vector<IntVar*>& secondary_vars,
double penalty_factor,
4020 bool reset_penalties_on_new_best_solution)
4021 : GuidedLocalSearch<P>(solver, objective, maximize, step, vars,
4023 reset_penalties_on_new_best_solution),
4024 objective_function_(std::move(objective_function)),
4025 secondary_values_(this->NumPrimaryVars(), -1) {
4026 this->AddVars(secondary_vars);
4029 template <
typename P>
4030 IntExpr* TernaryGuidedLocalSearch<P>::MakeElementPenalty(
int index) {
4031 Solver*
const solver = this->solver();
4033 solver->AddConstraint(solver->MakeLightElement(
4034 [
this,
index](int64_t j, int64_t k) {
4035 return PenalizedValue(index, j, k);
4037 var, this->GetVar(
index), this->GetVar(this->NumPrimaryVars() +
index)));
4041 template <
typename P>
4042 int64_t TernaryGuidedLocalSearch<P>::AssignmentElementPenalty(
int index)
const {
4043 return PenalizedValue(
index, this->GetValue(
index),
4044 this->GetValue(this->NumPrimaryVars() +
index));
4047 template <
typename P>
4048 int64_t TernaryGuidedLocalSearch<P>::AssignmentPenalty(int64_t
var,
4049 int64_t
value)
const {
4050 return objective_function_(
var,
value,
4051 this->GetValue(this->NumPrimaryVars() +
var));
4054 template <
typename P>
4055 int64_t TernaryGuidedLocalSearch<P>::Evaluate(
const Assignment*
delta,
4056 int64_t current_penalty,
4058 int64_t penalty = current_penalty;
4059 const Assignment::IntContainer& container =
delta->IntVarContainer();
4063 for (
const IntVarElement& new_element : container.elements()) {
4064 const int index = this->GetLocalIndexFromVar(new_element.Var());
4065 if (
index != -1 && index < this->NumPrimaryVars()) {
4066 secondary_values_[
index] = -1;
4069 for (
const IntVarElement& new_element : container.elements()) {
4070 const int index = this->GetLocalIndexFromVar(new_element.Var());
4071 if (!new_element.Activated())
continue;
4072 if (
index != -1 &&
index >= this->NumPrimaryVars()) {
4073 secondary_values_[
index - this->NumPrimaryVars()] = new_element.Value();
4076 for (
const IntVarElement& new_element : container.elements()) {
4077 const int index = this->GetLocalIndexFromVar(new_element.Var());
4079 if (
index == -1 ||
index >= this->NumPrimaryVars()) {
4084 if (new_element.Activated() && secondary_values_[
index] != -1) {
4085 const int64_t new_penalty =
4086 PenalizedValue(
index, new_element.Value(), secondary_values_[
index]);
4087 penalty =
CapAdd(penalty, new_penalty);
4097 template <
typename P>
4098 int64_t TernaryGuidedLocalSearch<P>::PenalizedValue(int64_t i, int64_t j,
4100 const int64_t penalty = this->penalties_.GetPenalty({i, j});
4102 if (penalty == 0)
return 0;
4103 const double penalized_value_fp =
4105 const int64_t penalized_value =
4107 ?
static_cast<int64_t
>(penalized_value_fp)
4109 return this->
maximize_ ? -penalized_value : penalized_value;
4114 bool maximize,
IntVar*
const objective,
4116 const std::vector<IntVar*>& vars,
double penalty_factor,
4117 bool reset_penalties_on_new_best_solution) {
4118 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
4119 return RevAlloc(
new BinaryGuidedLocalSearch<GuidedLocalSearchPenaltiesMap>(
4120 this, objective, std::move(objective_function), maximize, step, vars,
4121 penalty_factor, reset_penalties_on_new_best_solution));
4124 new BinaryGuidedLocalSearch<GuidedLocalSearchPenaltiesTable>(
4125 this, objective, std::move(objective_function), maximize, step,
4126 vars, penalty_factor, reset_penalties_on_new_best_solution));
4131 bool maximize,
IntVar*
const objective,
4133 const std::vector<IntVar*>& vars,
4134 const std::vector<IntVar*>& secondary_vars,
double penalty_factor,
4135 bool reset_penalties_on_new_best_solution) {
4136 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
4137 return RevAlloc(
new TernaryGuidedLocalSearch<GuidedLocalSearchPenaltiesMap>(
4138 this, objective, std::move(objective_function), maximize, step, vars,
4139 secondary_vars, penalty_factor, reset_penalties_on_new_best_solution));
4142 new TernaryGuidedLocalSearch<GuidedLocalSearchPenaltiesTable>(
4143 this, objective, std::move(objective_function), maximize, step,
4144 vars, secondary_vars, penalty_factor,
4145 reset_penalties_on_new_best_solution));
4153 SearchLimit::~SearchLimit() {}
4155 void SearchLimit::Install() {
4156 ListenToEvent(Solver::MonitorEvent::kEnterSearch);
4157 ListenToEvent(Solver::MonitorEvent::kBeginNextDecision);
4158 ListenToEvent(Solver::MonitorEvent::kPeriodicCheck);
4159 ListenToEvent(Solver::MonitorEvent::kRefuteDecision);
4162 void SearchLimit::EnterSearch() {
4177 void SearchLimit::PeriodicCheck() {
4178 if (crossed_ || Check()) {
4184 void SearchLimit::TopPeriodicCheck() {
4185 if (solver()->TopLevelSearch() != solver()->ActiveSearch()) {
4186 solver()->TopPeriodicCheck();
4193 int64_t branches, int64_t failures,
4194 int64_t solutions,
bool smart_time_check,
4197 duration_limit_(
time),
4198 solver_time_at_limit_start_(s->Now()),
4199 last_time_elapsed_(
absl::ZeroDuration()),
4202 smart_time_check_(smart_time_check),
4203 branches_(branches),
4204 branches_offset_(0),
4205 failures_(failures),
4206 failures_offset_(0),
4207 solutions_(solutions),
4208 solutions_offset_(0),
4209 cumulative_(cumulative) {}
4224 duration_limit_ = regular->duration_limit_;
4225 branches_ = regular->branches_;
4226 failures_ = regular->failures_;
4227 solutions_ = regular->solutions_;
4228 smart_time_check_ = regular->smart_time_check_;
4229 cumulative_ = regular->cumulative_;
4243 return s->
branches() - branches_offset_ >= branches_ ||
4244 s->
failures() - failures_offset_ >= failures_ || CheckTime(offset) ||
4245 s->
solutions() - solutions_offset_ >= solutions_;
4250 int64_t progress = GetPercent(s->
branches(), branches_offset_, branches_);
4252 GetPercent(s->
failures(), failures_offset_, failures_));
4254 progress, GetPercent(s->
solutions(), solutions_offset_, solutions_));
4265 solver_time_at_limit_start_ = s->
Now();
4266 last_time_elapsed_ = absl::ZeroDuration();
4276 branches_ -= s->
branches() - branches_offset_;
4277 failures_ -= s->
failures() - failures_offset_;
4278 duration_limit_ -= s->
Now() - solver_time_at_limit_start_;
4279 solutions_ -= s->
solutions() - solutions_offset_;
4284 int64_t failures, int64_t solutions) {
4285 duration_limit_ =
time;
4298 return absl::StrFormat(
4299 "RegularLimit(crossed = %i, duration_limit = %s, "
4300 "branches = %d, failures = %d, solutions = %d cumulative = %s",
4302 solutions_, (cumulative_ ?
"true" :
"false"));
4320 bool RegularLimit::CheckTime(absl::Duration offset) {
4324 absl::Duration RegularLimit::TimeElapsed() {
4325 const int64_t kMaxSkip = 100;
4326 const int64_t kCheckWarmupIterations = 100;
4329 next_check_ <= check_count_) {
4330 Solver*
const s =
solver();
4331 absl::Duration elapsed = s->Now() - solver_time_at_limit_start_;
4332 if (smart_time_check_ && check_count_ > kCheckWarmupIterations &&
4333 elapsed > absl::ZeroDuration()) {
4335 check_count_ * absl::FDivDuration(duration_limit_, elapsed));
4337 std::min(check_count_ + kMaxSkip, estimated_check_count_at_limit);
4339 last_time_elapsed_ = elapsed;
4341 return last_time_elapsed_;
4359 return MakeLimit(absl::InfiniteDuration(),
4366 return MakeLimit(absl::InfiniteDuration(),
4373 int64_t failures, int64_t solutions,
4374 bool smart_time_check,
bool cumulative) {
4376 smart_time_check, cumulative);
4380 int64_t failures, int64_t solutions,
4381 bool smart_time_check,
bool cumulative) {
4383 smart_time_check, cumulative));
4388 ? absl::InfiniteDuration()
4389 : absl::Milliseconds(
proto.time()),
4391 proto.smart_time_check(),
proto.cumulative());
4395 RegularLimitParameters
proto;
4400 proto.set_smart_time_check(
false);
4401 proto.set_cumulative(
false);
4409 double objective_scaling_factor,
double objective_offset,
4410 double improvement_rate_coefficient,
4411 int improvement_rate_solutions_distance)
4413 objective_var_(objective_var),
4415 objective_scaling_factor_(objective_scaling_factor),
4416 objective_offset_(objective_offset),
4417 improvement_rate_coefficient_(improvement_rate_coefficient),
4418 improvement_rate_solutions_distance_(
4419 improvement_rate_solutions_distance) {
4431 best_objective_ = maximize_ ? -std::numeric_limits<double>::infinity()
4432 : std::numeric_limits<double>::infinity();
4433 threshold_ = std::numeric_limits<double>::infinity();
4434 objective_updated_ =
false;
4435 gradient_stage_ =
true;
4441 objective_var_ = improv->objective_var_;
4442 maximize_ = improv->maximize_;
4443 objective_scaling_factor_ = improv->objective_scaling_factor_;
4444 objective_offset_ = improv->objective_offset_;
4445 improvement_rate_coefficient_ = improv->improvement_rate_coefficient_;
4446 improvement_rate_solutions_distance_ =
4447 improv->improvement_rate_solutions_distance_;
4448 improvements_ = improv->improvements_;
4449 threshold_ = improv->threshold_;
4450 best_objective_ = improv->best_objective_;
4451 objective_updated_ = improv->objective_updated_;
4452 gradient_stage_ = improv->gradient_stage_;
4458 objective_var_, maximize_, objective_scaling_factor_, objective_offset_,
4459 improvement_rate_coefficient_, improvement_rate_solutions_distance_);
4463 if (!objective_updated_) {
4466 objective_updated_ =
false;
4468 if (improvements_.size() <= improvement_rate_solutions_distance_) {
4472 const std::pair<double, int64_t> cur = improvements_.back();
4473 const std::pair<double, int64_t> prev = improvements_.front();
4474 DCHECK_GT(cur.second, prev.second);
4475 double improvement_rate =
4476 std::abs(prev.first - cur.first) / (cur.second - prev.second);
4477 if (gradient_stage_) {
4478 threshold_ = fmin(threshold_, improvement_rate);
4479 }
else if (improvement_rate_coefficient_ * improvement_rate < threshold_) {
4487 const int64_t new_objective =
4488 objective_var_ !=
nullptr && objective_var_->
Bound()
4489 ? objective_var_->
Value()
4494 const double scaled_new_objective =
4495 objective_scaling_factor_ * (new_objective + objective_offset_);
4497 const bool is_improvement = maximize_
4498 ? scaled_new_objective > best_objective_
4499 : scaled_new_objective < best_objective_;
4501 if (gradient_stage_ && !is_improvement) {
4502 gradient_stage_ =
false;
4505 if (threshold_ == std::numeric_limits<double>::infinity()) {
4510 if (is_improvement) {
4511 best_objective_ = scaled_new_objective;
4512 objective_updated_ =
true;
4513 improvements_.push_back(
4518 if (improvements_.size() - 1 > improvement_rate_solutions_distance_) {
4519 improvements_.pop_front();
4521 DCHECK_LE(improvements_.size() - 1, improvement_rate_solutions_distance_);
4528 IntVar* objective_var,
bool maximize,
double objective_scaling_factor,
4529 double objective_offset,
double improvement_rate_coefficient,
4530 int improvement_rate_solutions_distance) {
4532 this, objective_var, maximize, objective_scaling_factor, objective_offset,
4533 improvement_rate_coefficient, improvement_rate_solutions_distance));
4541 :
SearchLimit(limit_1->solver()), limit_1_(limit_1), limit_2_(limit_2) {
4542 CHECK(limit_1 !=
nullptr);
4543 CHECK(limit_2 !=
nullptr);
4545 <<
"Illegal arguments: cannot combines limits that belong to different "
4546 <<
"solvers, because the reversible allocations could delete one and "
4547 <<
"not the other.";
4550 bool CheckWithOffset(absl::Duration offset)
override {
4553 const bool check_1 = limit_1_->CheckWithOffset(offset);
4554 const bool check_2 = limit_2_->CheckWithOffset(offset);
4555 return check_1 || check_2;
4558 void Init()
override {
4563 void Copy(
const SearchLimit*
const limit)
override {
4564 LOG(FATAL) <<
"Not implemented.";
4567 SearchLimit* MakeClone()
const override {
4569 return solver()->MakeLimit(limit_1_->MakeClone(), limit_2_->MakeClone());
4572 void EnterSearch()
override {
4573 limit_1_->EnterSearch();
4574 limit_2_->EnterSearch();
4576 void BeginNextDecision(DecisionBuilder*
const b)
override {
4577 limit_1_->BeginNextDecision(
b);
4578 limit_2_->BeginNextDecision(
b);
4580 void PeriodicCheck()
override {
4581 limit_1_->PeriodicCheck();
4582 limit_2_->PeriodicCheck();
4584 void RefuteDecision(Decision*
const d)
override {
4585 limit_1_->RefuteDecision(d);
4586 limit_2_->RefuteDecision(d);
4588 std::string DebugString()
const override {
4589 return absl::StrCat(
"OR limit (", limit_1_->DebugString(),
" OR ",
4590 limit_2_->DebugString(),
")");
4594 SearchLimit*
const limit_1_;
4595 SearchLimit*
const limit_2_;
4601 return RevAlloc(
new ORLimit(limit_1, limit_2));
4607 CustomLimit(
Solver*
const s, std::function<
bool()> limiter);
4608 bool CheckWithOffset(absl::Duration offset)
override;
4609 void Init()
override;
4610 void Copy(
const SearchLimit*
const limit)
override;
4614 std::function<bool()> limiter_;
4617 CustomLimit::CustomLimit(Solver*
const s, std::function<
bool()> limiter)
4618 : SearchLimit(s), limiter_(std::move(limiter)) {}
4620 bool CustomLimit::CheckWithOffset(absl::Duration offset) {
4622 if (limiter_)
return limiter_();
4626 void CustomLimit::Init() {}
4628 void CustomLimit::Copy(
const SearchLimit*
const limit) {
4629 const CustomLimit*
const custom =
4630 reinterpret_cast<const CustomLimit* const
>(limit);
4631 limiter_ = custom->limiter_;
4634 SearchLimit* CustomLimit::MakeClone()
const {
4635 return solver()->RevAlloc(
new CustomLimit(solver(), limiter_));
4640 return RevAlloc(
new CustomLimit(
this, std::move(limiter)));
4649 CHECK(db !=
nullptr);
4652 SolveOnce(DecisionBuilder*
const db,
4653 const std::vector<SearchMonitor*>& monitors)
4654 : db_(db), monitors_(monitors) {
4655 CHECK(db !=
nullptr);
4658 ~SolveOnce()
override {}
4660 Decision* Next(Solver* s)
override {
4661 bool res = s->SolveAndCommit(db_, monitors_);
4668 std::string DebugString()
const override {
4669 return absl::StrFormat(
"SolveOnce(%s)", db_->DebugString());
4672 void Accept(ModelVisitor*
const visitor)
const override {
4673 db_->Accept(visitor);
4677 DecisionBuilder*
const db_;
4678 std::vector<SearchMonitor*> monitors_;
4683 return RevAlloc(
new SolveOnce(db));
4688 std::vector<SearchMonitor*> monitors;
4689 monitors.push_back(monitor1);
4690 return RevAlloc(
new SolveOnce(db, monitors));
4696 std::vector<SearchMonitor*> monitors;
4697 monitors.push_back(monitor1);
4698 monitors.push_back(monitor2);
4699 return RevAlloc(
new SolveOnce(db, monitors));
4706 std::vector<SearchMonitor*> monitors;
4707 monitors.push_back(monitor1);
4708 monitors.push_back(monitor2);
4709 monitors.push_back(monitor3);
4710 return RevAlloc(
new SolveOnce(db, monitors));
4718 std::vector<SearchMonitor*> monitors;
4719 monitors.push_back(monitor1);
4720 monitors.push_back(monitor2);
4721 monitors.push_back(monitor3);
4722 monitors.push_back(monitor4);
4723 return RevAlloc(
new SolveOnce(db, monitors));
4727 DecisionBuilder*
const db,
const std::vector<SearchMonitor*>& monitors) {
4728 return RevAlloc(
new SolveOnce(db, monitors));
4737 bool maximize, int64_t step)
4739 solution_(solution),
4742 collector_(nullptr) {
4743 CHECK(db !=
nullptr);
4744 CHECK(solution !=
nullptr);
4749 NestedOptimize(DecisionBuilder*
const db, Assignment*
const solution,
4750 bool maximize, int64_t step,
4751 const std::vector<SearchMonitor*>& monitors)
4753 solution_(solution),
4756 monitors_(monitors),
4757 collector_(nullptr) {
4758 CHECK(db !=
nullptr);
4759 CHECK(solution !=
nullptr);
4760 CHECK(solution->HasObjective());
4764 void AddMonitors() {
4765 Solver*
const solver = solution_->solver();
4766 collector_ = solver->MakeLastSolutionCollector(solution_);
4767 monitors_.push_back(collector_);
4768 OptimizeVar*
const optimize =
4770 monitors_.push_back(optimize);
4773 Decision* Next(Solver* solver)
override {
4774 solver->Solve(db_, monitors_);
4775 if (collector_->solution_count() == 0) {
4778 collector_->solution(0)->Restore();
4782 std::string DebugString()
const override {
4783 return absl::StrFormat(
"NestedOptimize(db = %s, maximize = %d, step = %d)",
4787 void Accept(ModelVisitor*
const visitor)
const override {
4788 db_->Accept(visitor);
4792 DecisionBuilder*
const db_;
4793 Assignment*
const solution_;
4795 const int64_t
step_;
4796 std::vector<SearchMonitor*> monitors_;
4797 SolutionCollector* collector_;
4803 bool maximize, int64_t step) {
4804 return RevAlloc(
new NestedOptimize(db, solution, maximize, step));
4809 bool maximize, int64_t step,
4811 std::vector<SearchMonitor*> monitors;
4812 monitors.push_back(monitor1);
4813 return RevAlloc(
new NestedOptimize(db, solution, maximize, step, monitors));
4818 bool maximize, int64_t step,
4821 std::vector<SearchMonitor*> monitors;
4822 monitors.push_back(monitor1);
4823 monitors.push_back(monitor2);
4824 return RevAlloc(
new NestedOptimize(db, solution, maximize, step, monitors));
4829 bool maximize, int64_t step,
4833 std::vector<SearchMonitor*> monitors;
4834 monitors.push_back(monitor1);
4835 monitors.push_back(monitor2);
4836 monitors.push_back(monitor3);
4837 return RevAlloc(
new NestedOptimize(db, solution, maximize, step, monitors));
4844 std::vector<SearchMonitor*> monitors;
4845 monitors.push_back(monitor1);
4846 monitors.push_back(monitor2);
4847 monitors.push_back(monitor3);
4848 monitors.push_back(monitor4);
4849 return RevAlloc(
new NestedOptimize(db, solution, maximize, step, monitors));
4854 int64_t step,
const std::vector<SearchMonitor*>& monitors) {
4855 return RevAlloc(
new NestedOptimize(db, solution, maximize, step, monitors));
4862 int64_t NextLuby(
int i) {
4870 while (power < (i + 1)) {
4873 if (power == i + 1) {
4876 return NextLuby(i - (power / 2) + 1);
4879 class LubyRestart :
public SearchMonitor {
4881 LubyRestart(Solver*
const s,
int scale_factor)
4883 scale_factor_(scale_factor),
4886 next_step_(scale_factor) {
4887 CHECK_GE(scale_factor, 1);
4890 ~LubyRestart()
override {}
4892 void BeginFail()
override {
4893 if (++current_fails_ >= next_step_) {
4895 next_step_ = NextLuby(++iteration_) * scale_factor_;
4896 solver()->RestartCurrentSearch();
4902 std::string DebugString()
const override {
4903 return absl::StrFormat(
"LubyRestart(%i)", scale_factor_);
4907 const int scale_factor_;
4909 int64_t current_fails_;
4915 return RevAlloc(
new LubyRestart(
this, scale_factor));
4923 ConstantRestart(
Solver*
const s,
int frequency)
4924 :
SearchMonitor(s), frequency_(frequency), current_fails_(0) {
4925 CHECK_GE(frequency, 1);
4928 ~ConstantRestart()
override {}
4930 void BeginFail()
override {
4931 if (++current_fails_ >= frequency_) {
4933 solver()->RestartCurrentSearch();
4939 std::string DebugString()
const override {
4940 return absl::StrFormat(
"ConstantRestart(%i)", frequency_);
4944 const int frequency_;
4945 int64_t current_fails_;
4950 return RevAlloc(
new ConstantRestart(
this, frequency));
4973 const std::vector<SymmetryBreaker*>& visitors)
4975 visitors_(visitors),
4976 clauses_(visitors.size()),
4977 decisions_(visitors.size()),
4978 directions_(visitors.size()) {
4979 for (
int i = 0; i < visitors_.size(); ++i) {
4980 visitors_[i]->set_symmetry_manager_and_index(
this, i);
4988 for (
int i = 0; i < visitors_.size(); ++i) {
4989 const void*
const last = clauses_[i].Last();
4991 if (last != clauses_[i].Last()) {
4993 decisions_[i].Push(
solver(), d);
4994 directions_[i].Push(
solver(),
false);
5001 for (
int i = 0; i < visitors_.size(); ++i) {
5002 if (decisions_[i].Last() !=
nullptr && decisions_[i].LastValue() == d) {
5015 std::vector<IntVar*> guard;
5020 IntVar*
const term = *tmp;
5022 if (term->
Max() == 0) {
5026 if (term->
Min() == 0) {
5027 DCHECK_EQ(1, term->
Max());
5029 guard.push_back(term);
5035 guard.push_back(clauses_[
index].LastValue());
5036 directions_[
index].SetLastValue(
true);
5043 DCHECK(
ct !=
nullptr);
5048 clauses_[visitor->index_in_symmetry_manager()].Push(
solver(), term);
5051 std::string
DebugString()
const override {
return "SymmetryManager"; }
5054 const std::vector<SymmetryBreaker*> visitors_;
5055 std::vector<SimpleRevFIFO<IntVar*>> clauses_;
5056 std::vector<SimpleRevFIFO<Decision*>> decisions_;
5057 std::vector<SimpleRevFIFO<bool>> directions_;
5064 CHECK(
var !=
nullptr);
5072 CHECK(
var !=
nullptr);
5080 CHECK(
var !=
nullptr);
5089 const std::vector<SymmetryBreaker*>& visitors) {
5094 std::vector<SymmetryBreaker*> visitors;
5095 visitors.push_back(v1);
5101 std::vector<SymmetryBreaker*> visitors;
5102 visitors.push_back(v1);
5103 visitors.push_back(v2);
5110 std::vector<SymmetryBreaker*> visitors;
5111 visitors.push_back(v1);
5112 visitors.push_back(v2);
5113 visitors.push_back(v3);
5121 std::vector<SymmetryBreaker*> visitors;
5122 visitors.push_back(v1);
5123 visitors.push_back(v2);
5124 visitors.push_back(v3);
5125 visitors.push_back(v4);
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
AssignmentContainer< IntVar, IntVarElement > IntContainer
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
void Install() override
Registers itself on the solver such that it gets notified of the search and propagation events.
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.
bool CheckWithOffset(absl::Duration offset) override
Same as Check() but adds the 'offset' value to the current time when time is considered in the limit.
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.
virtual bool Bound() const
Returns true if the min and the max of the expression are equal.
virtual void SetValue(int64_t v)
This method sets the value of the expression.
virtual int64_t Min() const =0
virtual void SetMax(int64_t m)=0
virtual void SetMin(int64_t m)=0
virtual int64_t Max() const =0
The class IntVar is a subset of IntExpr.
virtual int64_t Value() const =0
This method returns the value of the variable.
Interval variables are often used in scheduling.
static int64_t FastInt64Round(double x)
static const char kSolutionLimitArgument[]
static const char kObjectiveExtension[]
static const char kMaximizeArgument[]
virtual void VisitIntegerArgument(const std::string &arg_name, int64_t value)
Visit integer arguments.
static const char kTimeLimitArgument[]
static const char kBranchesLimitArgument[]
static const char kSmartTimeCheckArgument[]
virtual void BeginVisitExtension(const std::string &type)
virtual void EndVisitExtension(const std::string &type)
static const char kCumulativeArgument[]
static const char kStepArgument[]
static const char kVarsArgument[]
static const char kVariableGroupExtension[]
static const char kExpressionArgument[]
static const char kFailuresLimitArgument[]
virtual void VisitIntegerExpressionArgument(const std::string &arg_name, IntExpr *const argument)
Visit integer expression argument.
static const char kSearchLimitExtension[]
This class encapsulates an objective.
void EnterSearch() override
Beginning of the search.
void BeginNextDecision(DecisionBuilder *const db) override
Before calling DecisionBuilder::Next.
OptimizeVar(Solver *const s, bool maximize, IntVar *const a, int64_t step)
bool found_initial_solution_
IntVar * Var() const
Returns the variable that is optimized.
void Accept(ModelVisitor *const visitor) const override
Accepts the given model visitor.
bool AcceptSolution() override
This method is called when a solution is found.
virtual std::string Print() const
bool AtSolution() override
This method is called when a valid solution is found.
void RefuteDecision(Decision *const d) override
Before refuting the decision.
bool AcceptDelta(Assignment *delta, Assignment *deltadelta) override
Internal methods.
std::string DebugString() const override
std::string DebugString() const override
Usual limit based on wall_time, number of explored branches and number of failures in the search tree...
absl::Duration duration_limit() const
void Install() override
Registers itself on the solver such that it gets notified of the search and propagation events.
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.
bool CheckWithOffset(absl::Duration offset) override
Same as Check() but adds the 'offset' value to the current time when time is considered in the 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.
void Install() override
Registers itself on the solver such that it gets notified of the search and propagation events.
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.
void ListenToEvent(Solver::MonitorEvent event)
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.
void Install() override
Registers itself on the solver such that it gets notified of the search and propagation events.
~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.
@ kIsUncheckedSolutionLimitReached
SearchMonitor * MakeSearchTrace(const std::string &prefix)
Creates a search monitor that will trace precisely the behavior of the search.
int TopProgressPercent()
Returns a percentage representing the propress of the search before reaching the limits of the top-le...
T * RevAlloc(T *object)
Registers the given object as being reversible.
IntVarStrategy
This enum describes the strategy used to select the next branching variable at each node during the s...
@ CHOOSE_RANDOM
Randomly select one of the remaining unbound variables.
@ CHOOSE_MIN_SIZE
Among unbound variables, select the variable with the smallest size.
@ CHOOSE_FIRST_UNBOUND
Select the first unbound variable.
@ CHOOSE_PATH
Selects the next unbound variable on a path, the path being defined by the variables: var[i] correspo...
@ CHOOSE_HIGHEST_MAX
Among unbound variables, select the variable with the highest maximal value.
@ CHOOSE_MIN_SIZE_LOWEST_MIN
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ INT_VAR_DEFAULT
The default behavior is CHOOSE_FIRST_UNBOUND.
@ CHOOSE_MIN_SIZE_HIGHEST_MAX
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ CHOOSE_MAX_REGRET_ON_MIN
Among unbound variables, select the variable with the largest gap between the first and the second va...
@ CHOOSE_MIN_SIZE_HIGHEST_MIN
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ CHOOSE_MAX_SIZE
Among unbound variables, select the variable with the highest size.
@ INT_VAR_SIMPLE
The simple selection is CHOOSE_FIRST_UNBOUND.
@ CHOOSE_MIN_SIZE_LOWEST_MAX
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ CHOOSE_LOWEST_MIN
Among unbound variables, select the variable with the smallest minimal value.
DecisionBuilder * MakePhase(const std::vector< IntVar * > &vars, IntVarStrategy var_str, IntValueStrategy val_str)
Phases on IntVar arrays.
std::function< int64_t(const IntVar *v, int64_t id)> VariableValueSelector
SearchMonitor * MakeEnterSearchCallback(std::function< void()> callback)
--— Callback-based search monitors --—
std::function< void(Solver *)> Action
SolutionCollector * MakeFirstSolutionCollector()
Collect the first solution of the search.
OptimizeVar * MakeWeightedOptimize(bool maximize, const std::vector< IntVar * > &sub_objectives, const std::vector< int64_t > &weights, int64_t step)
Creates a weighted objective with a given sense (true = maximization).
std::function< int64_t(int64_t)> IndexEvaluator1
Callback typedefs.
SearchMonitor * MakeExitSearchCallback(std::function< void()> callback)
Decision * MakeSplitVariableDomain(IntVar *const var, int64_t val, bool start_with_lower_half)
DecisionBuilder * MakeDecisionBuilderFromAssignment(Assignment *const assignment, DecisionBuilder *const db, const std::vector< IntVar * > &vars)
Returns a decision builder for which the left-most leaf corresponds to assignment,...
Decision * MakeVariableLessOrEqualValue(IntVar *const var, int64_t value)
IntVar * MakeIsEqualCstVar(IntExpr *const var, int64_t value)
status var of (var == value)
int64_t solutions() const
The number of solutions found since the start of the search.
std::function< bool(int64_t, int64_t, int64_t)> VariableValueComparator
Decision * MakeAssignVariableValueOrFail(IntVar *const var, int64_t value)
Decision * MakeVariableGreaterOrEqualValue(IntVar *const var, int64_t value)
A symmetry breaker is an object that will visit a decision and create the 'symmetrical' decision in r...
void AddIntegerVariableLessOrEqualValueClause(IntVar *const var, int64_t value)
void AddIntegerVariableEqualValueClause(IntVar *const var, int64_t value)
void AddIntegerVariableGreaterOrEqualValueClause(IntVar *const var, int64_t value)
void AddTermToClause(SymmetryBreaker *const visitor, IntVar *const term)
~SymmetryManager() override
void EndNextDecision(DecisionBuilder *const db, Decision *const d) override
After calling DecisionBuilder::Next, along with the returned decision.
void CheckSymmetries(int index)
void RefuteDecision(Decision *d) override
Before refuting the decision.
SymmetryManager(Solver *const s, const std::vector< SymmetryBreaker * > &visitors)
std::string DebugString() const override
std::vector< IntVarIterator * > iterators_
static const int64_t kint64max
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
void STLDeleteElements(T *container)
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.
H AbslHashValue(H h, const StrongIndex< StrongIndexName > &i)
int64_t CapAdd(int64_t x, int64_t y)
int64_t CapSub(int64_t x, int64_t y)
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)
LinearRange operator==(const LinearExpr &lhs, const LinearExpr &rhs)
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::vector< int > var_index_to_local_index_
BaseVariableAssignmentSelector *const selector_
DirtyArray< int64_t > penalized_values_
const bool reset_penalties_on_new_best_solution_
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_
Creates a search monitor from logging parameters.
#define VLOG(verboselevel)