OR-Tools  9.3
search.cc
Go to the documentation of this file.
1// Copyright 2010-2021 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14#include <algorithm>
15#include <cstdint>
16#include <functional>
17#include <limits>
18#include <list>
19#include <memory>
20#include <queue>
21#include <string>
22#include <utility>
23#include <vector>
24
25#include "absl/base/casts.h"
26#include "absl/container/flat_hash_map.h"
27#include "absl/memory/memory.h"
28#include "absl/strings/str_cat.h"
29#include "absl/strings/str_format.h"
30#include "absl/strings/str_join.h"
31#include "absl/time/time.h"
32#include "ortools/base/bitmap.h"
34#include "ortools/base/hash.h"
37#include "ortools/base/macros.h"
41#include "ortools/base/timer.h"
44#include "ortools/constraint_solver/search_limit.pb.h"
46
47ABSL_FLAG(bool, cp_use_sparse_gls_penalties, false,
48 "Use sparse implementation to store Guided Local Search penalties");
49ABSL_FLAG(bool, cp_log_to_vlog, false,
50 "Whether search related logging should be "
51 "vlog or info.");
52ABSL_FLAG(int64_t, cp_large_domain_no_splitting_limit, 0xFFFFF,
53 "Size limit to allow holes in variables from the strategy.");
54namespace operations_research {
55
56// ---------- Search Log ---------
57
58SearchLog::SearchLog(Solver* const s, OptimizeVar* const obj, IntVar* const var,
59 double scaling_factor, double offset,
60 std::function<std::string()> display_callback,
61 bool display_on_new_solutions_only, int period)
62 : SearchMonitor(s),
63 period_(period),
64 timer_(new WallTimer),
65 var_(var),
66 obj_(obj),
67 scaling_factor_(scaling_factor),
68 offset_(offset),
69 display_callback_(std::move(display_callback)),
70 display_on_new_solutions_only_(display_on_new_solutions_only),
71 nsol_(0),
72 tick_(0),
73 objective_min_(std::numeric_limits<int64_t>::max()),
74 objective_max_(std::numeric_limits<int64_t>::min()),
75 min_right_depth_(std::numeric_limits<int32_t>::max()),
76 max_depth_(0),
77 sliding_min_depth_(0),
78 sliding_max_depth_(0) {
79 CHECK(obj == nullptr || var == nullptr)
80 << "Either var or obj need to be nullptr.";
81}
82
84
85std::string SearchLog::DebugString() const { return "SearchLog"; }
86
88 const std::string buffer =
89 absl::StrFormat("Start search (%s)", MemoryUsage());
90 OutputLine(buffer);
91 timer_->Restart();
92 min_right_depth_ = std::numeric_limits<int32_t>::max();
93}
94
96 const int64_t branches = solver()->branches();
97 int64_t ms = timer_->GetInMs();
98 if (ms == 0) {
99 ms = 1;
100 }
101 const std::string buffer = absl::StrFormat(
102 "End search (time = %d ms, branches = %d, failures = %d, %s, speed = %d "
103 "branches/s)",
104 ms, branches, solver()->failures(), MemoryUsage(), branches * 1000 / ms);
105 OutputLine(buffer);
106}
107
109 Maintain();
110 const int depth = solver()->SearchDepth();
111 std::string obj_str = "";
112 int64_t current = 0;
113 bool objective_updated = false;
114 const auto scaled_str = [this](int64_t value) {
115 if (scaling_factor_ != 1.0 || offset_ != 0.0) {
116 return absl::StrFormat("%d (%.8lf)", value,
117 scaling_factor_ * (value + offset_));
118 } else {
119 return absl::StrCat(value);
120 }
121 };
122 if (obj_ != nullptr && obj_->Var()->Bound()) {
123 current = obj_->Var()->Value();
124 obj_str = obj_->Print();
125 objective_updated = true;
126 } else if (var_ != nullptr && var_->Bound()) {
127 current = var_->Value();
128 absl::StrAppend(&obj_str, scaled_str(current), ", ");
129 objective_updated = true;
130 } else {
132 absl::StrAppend(&obj_str, scaled_str(current), ", ");
133 objective_updated = true;
134 }
135 if (objective_updated) {
136 if (current > objective_min_) {
137 absl::StrAppend(&obj_str,
138 "objective minimum = ", scaled_str(objective_min_), ", ");
139 } else {
140 objective_min_ = current;
141 }
142 if (current < objective_max_) {
143 absl::StrAppend(&obj_str,
144 "objective maximum = ", scaled_str(objective_max_), ", ");
145 } else {
146 objective_max_ = current;
147 }
148 }
149 std::string log;
150 absl::StrAppendFormat(&log,
151 "Solution #%d (%stime = %d ms, branches = %d,"
152 " failures = %d, depth = %d",
153 nsol_++, obj_str, timer_->GetInMs(),
154 solver()->branches(), solver()->failures(), depth);
155 if (!solver()->SearchContext().empty()) {
156 absl::StrAppendFormat(&log, ", %s", solver()->SearchContext());
157 }
158 if (solver()->neighbors() != 0) {
159 absl::StrAppendFormat(&log,
160 ", neighbors = %d, filtered neighbors = %d,"
161 " accepted neighbors = %d",
162 solver()->neighbors(), solver()->filtered_neighbors(),
163 solver()->accepted_neighbors());
164 }
165 absl::StrAppendFormat(&log, ", %s", MemoryUsage());
166 const int progress = solver()->TopProgressPercent();
167 if (progress != SearchMonitor::kNoProgress) {
168 absl::StrAppendFormat(&log, ", limit = %d%%", progress);
169 }
170 if (display_callback_) {
171 absl::StrAppendFormat(&log, ", %s", display_callback_());
172 }
173 log.append(")");
174 OutputLine(log);
175 return false;
176}
177
179
181
183 std::string buffer = absl::StrFormat(
184 "Finished search tree (time = %d ms, branches = %d,"
185 " failures = %d",
186 timer_->GetInMs(), solver()->branches(), solver()->failures());
187 if (solver()->neighbors() != 0) {
188 absl::StrAppendFormat(&buffer,
189 ", neighbors = %d, filtered neighbors = %d,"
190 " accepted neigbors = %d",
191 solver()->neighbors(), solver()->filtered_neighbors(),
192 solver()->accepted_neighbors());
193 }
194 absl::StrAppendFormat(&buffer, ", %s", MemoryUsage());
195 if (!display_on_new_solutions_only_ && display_callback_) {
196 absl::StrAppendFormat(&buffer, ", %s", display_callback_());
197 }
198 buffer.append(")");
199 OutputLine(buffer);
200}
201
202void SearchLog::ApplyDecision(Decision* const decision) {
203 Maintain();
204 const int64_t b = solver()->branches();
205 if (b % period_ == 0 && b > 0) {
207 }
208}
209
210void SearchLog::RefuteDecision(Decision* const decision) {
211 min_right_depth_ = std::min(min_right_depth_, solver()->SearchDepth());
212 ApplyDecision(decision);
213}
214
216 std::string buffer =
217 absl::StrFormat("%d branches, %d ms, %d failures", solver()->branches(),
218 timer_->GetInMs(), solver()->failures());
219 if (min_right_depth_ != std::numeric_limits<int32_t>::max() &&
220 max_depth_ != 0) {
221 const int depth = solver()->SearchDepth();
222 absl::StrAppendFormat(&buffer, ", tree pos=%d/%d/%d minref=%d max=%d",
223 sliding_min_depth_, depth, sliding_max_depth_,
224 min_right_depth_, max_depth_);
225 sliding_min_depth_ = depth;
226 sliding_max_depth_ = depth;
227 }
228 if (obj_ != nullptr &&
229 objective_min_ != std::numeric_limits<int64_t>::max() &&
230 objective_max_ != std::numeric_limits<int64_t>::min()) {
231 absl::StrAppendFormat(&buffer,
232 ", objective minimum = %d"
233 ", objective maximum = %d",
234 objective_min_, objective_max_);
235 }
236 const int progress = solver()->TopProgressPercent();
237 if (progress != SearchMonitor::kNoProgress) {
238 absl::StrAppendFormat(&buffer, ", limit = %d%%", progress);
239 }
240 OutputLine(buffer);
241}
242
244 const int current_depth = solver()->SearchDepth();
245 sliding_min_depth_ = std::min(current_depth, sliding_min_depth_);
246 sliding_max_depth_ = std::max(current_depth, sliding_max_depth_);
247 max_depth_ = std::max(current_depth, max_depth_);
248}
249
250void SearchLog::BeginInitialPropagation() { tick_ = timer_->GetInMs(); }
251
253 const int64_t delta = std::max<int64_t>(timer_->GetInMs() - tick_, 0);
254 const std::string buffer = absl::StrFormat(
255 "Root node processed (time = %d ms, constraints = %d, %s)", delta,
256 solver()->constraints(), MemoryUsage());
257 OutputLine(buffer);
258}
259
260void SearchLog::OutputLine(const std::string& line) {
261 if (absl::GetFlag(FLAGS_cp_log_to_vlog)) {
262 VLOG(1) << line;
263 } else {
264 LOG(INFO) << line;
265 }
266}
267
268std::string SearchLog::MemoryUsage() {
269 static const int64_t kDisplayThreshold = 2;
270 static const int64_t kKiloByte = 1024;
271 static const int64_t kMegaByte = kKiloByte * kKiloByte;
272 static const int64_t kGigaByte = kMegaByte * kKiloByte;
273 const int64_t memory_usage = Solver::MemoryUsage();
274 if (memory_usage > kDisplayThreshold * kGigaByte) {
275 return absl::StrFormat("memory used = %.2lf GB",
276 memory_usage * 1.0 / kGigaByte);
277 } else if (memory_usage > kDisplayThreshold * kMegaByte) {
278 return absl::StrFormat("memory used = %.2lf MB",
279 memory_usage * 1.0 / kMegaByte);
280 } else if (memory_usage > kDisplayThreshold * kKiloByte) {
281 return absl::StrFormat("memory used = %2lf KB",
282 memory_usage * 1.0 / kKiloByte);
283 } else {
284 return absl::StrFormat("memory used = %d", memory_usage);
285 }
286}
287
289 return MakeSearchLog(branch_period, static_cast<IntVar*>(nullptr));
290}
291
292SearchMonitor* Solver::MakeSearchLog(int branch_period, IntVar* const var) {
293 return MakeSearchLog(branch_period, var, nullptr);
294}
295
297 int branch_period, std::function<std::string()> display_callback) {
298 return MakeSearchLog(branch_period, static_cast<IntVar*>(nullptr),
299 std::move(display_callback));
300}
301
303 int branch_period, IntVar* const var,
304 std::function<std::string()> display_callback) {
305 return RevAlloc(new SearchLog(this, nullptr, var, 1.0, 0.0,
306 std::move(display_callback), true,
307 branch_period));
308}
309
311 OptimizeVar* const opt_var) {
312 return MakeSearchLog(branch_period, opt_var, nullptr);
313}
314
316 int branch_period, OptimizeVar* const opt_var,
317 std::function<std::string()> display_callback) {
318 return RevAlloc(new SearchLog(this, opt_var, nullptr, 1.0, 0.0,
319 std::move(display_callback), true,
320 branch_period));
321}
322
324 return RevAlloc(new SearchLog(this, parameters.objective, parameters.variable,
325 parameters.scaling_factor, parameters.offset,
326 std::move(parameters.display_callback),
327 parameters.display_on_new_solutions_only,
328 parameters.branch_period));
329}
330
331// ---------- Search Trace ----------
332namespace {
333class SearchTrace : public SearchMonitor {
334 public:
335 SearchTrace(Solver* const s, const std::string& prefix)
336 : SearchMonitor(s), prefix_(prefix) {}
337 ~SearchTrace() override {}
338
339 void EnterSearch() override {
340 LOG(INFO) << prefix_ << " EnterSearch(" << solver()->SolveDepth() << ")";
341 }
342 void RestartSearch() override {
343 LOG(INFO) << prefix_ << " RestartSearch(" << solver()->SolveDepth() << ")";
344 }
345 void ExitSearch() override {
346 LOG(INFO) << prefix_ << " ExitSearch(" << solver()->SolveDepth() << ")";
347 }
348 void BeginNextDecision(DecisionBuilder* const b) override {
349 LOG(INFO) << prefix_ << " BeginNextDecision(" << b << ") ";
350 }
351 void EndNextDecision(DecisionBuilder* const b, Decision* const d) override {
352 if (d) {
353 LOG(INFO) << prefix_ << " EndNextDecision(" << b << ", " << d << ") ";
354 } else {
355 LOG(INFO) << prefix_ << " EndNextDecision(" << b << ") ";
356 }
357 }
358 void ApplyDecision(Decision* const d) override {
359 LOG(INFO) << prefix_ << " ApplyDecision(" << d << ") ";
360 }
361 void RefuteDecision(Decision* const d) override {
362 LOG(INFO) << prefix_ << " RefuteDecision(" << d << ") ";
363 }
364 void AfterDecision(Decision* const d, bool apply) override {
365 LOG(INFO) << prefix_ << " AfterDecision(" << d << ", " << apply << ") ";
366 }
367 void BeginFail() override {
368 LOG(INFO) << prefix_ << " BeginFail(" << solver()->SearchDepth() << ")";
369 }
370 void EndFail() override {
371 LOG(INFO) << prefix_ << " EndFail(" << solver()->SearchDepth() << ")";
372 }
373 void BeginInitialPropagation() override {
374 LOG(INFO) << prefix_ << " BeginInitialPropagation()";
375 }
376 void EndInitialPropagation() override {
377 LOG(INFO) << prefix_ << " EndInitialPropagation()";
378 }
379 bool AtSolution() override {
380 LOG(INFO) << prefix_ << " AtSolution()";
381 return false;
382 }
383 bool AcceptSolution() override {
384 LOG(INFO) << prefix_ << " AcceptSolution()";
385 return true;
386 }
387 void NoMoreSolutions() override {
388 LOG(INFO) << prefix_ << " NoMoreSolutions()";
389 }
390
391 std::string DebugString() const override { return "SearchTrace"; }
392
393 private:
394 const std::string prefix_;
395};
396} // namespace
397
398SearchMonitor* Solver::MakeSearchTrace(const std::string& prefix) {
399 return RevAlloc(new SearchTrace(this, prefix));
400}
401
402// ---------- Callback-based search monitors ----------
403namespace {
404class AtSolutionCallback : public SearchMonitor {
405 public:
406 AtSolutionCallback(Solver* const solver, std::function<void()> callback)
407 : SearchMonitor(solver), callback_(std::move(callback)) {}
408 ~AtSolutionCallback() override {}
409 bool AtSolution() override;
410
411 private:
412 const std::function<void()> callback_;
413};
414
415bool AtSolutionCallback::AtSolution() {
416 callback_();
417 return false;
418}
419
420} // namespace
421
423 return RevAlloc(new AtSolutionCallback(this, std::move(callback)));
424}
425
426namespace {
427class EnterSearchCallback : public SearchMonitor {
428 public:
429 EnterSearchCallback(Solver* const solver, std::function<void()> callback)
430 : SearchMonitor(solver), callback_(std::move(callback)) {}
431 ~EnterSearchCallback() override {}
432 void EnterSearch() override;
433
434 private:
435 const std::function<void()> callback_;
436};
437
438void EnterSearchCallback::EnterSearch() { callback_(); }
439
440} // namespace
441
443 return RevAlloc(new EnterSearchCallback(this, std::move(callback)));
444}
445
446namespace {
447class ExitSearchCallback : public SearchMonitor {
448 public:
449 ExitSearchCallback(Solver* const solver, std::function<void()> callback)
450 : SearchMonitor(solver), callback_(std::move(callback)) {}
451 ~ExitSearchCallback() override {}
452 void ExitSearch() override;
453
454 private:
455 const std::function<void()> callback_;
456};
457
458void ExitSearchCallback::ExitSearch() { callback_(); }
459
460} // namespace
461
463 return RevAlloc(new ExitSearchCallback(this, std::move(callback)));
464}
465
466// ---------- Composite Decision Builder --------
467
468namespace {
469class CompositeDecisionBuilder : public DecisionBuilder {
470 public:
471 CompositeDecisionBuilder();
472 explicit CompositeDecisionBuilder(const std::vector<DecisionBuilder*>& dbs);
473 ~CompositeDecisionBuilder() override;
474 void Add(DecisionBuilder* const db);
475 void AppendMonitors(Solver* const solver,
476 std::vector<SearchMonitor*>* const monitors) override;
477 void Accept(ModelVisitor* const visitor) const override;
478
479 protected:
480 std::vector<DecisionBuilder*> builders_;
481};
482
483CompositeDecisionBuilder::CompositeDecisionBuilder() {}
484
485CompositeDecisionBuilder::CompositeDecisionBuilder(
486 const std::vector<DecisionBuilder*>& dbs) {
487 for (int i = 0; i < dbs.size(); ++i) {
488 Add(dbs[i]);
489 }
490}
491
492CompositeDecisionBuilder::~CompositeDecisionBuilder() {}
493
494void CompositeDecisionBuilder::Add(DecisionBuilder* const db) {
495 if (db != nullptr) {
496 builders_.push_back(db);
497 }
498}
499
500void CompositeDecisionBuilder::AppendMonitors(
501 Solver* const solver, std::vector<SearchMonitor*>* const monitors) {
502 for (DecisionBuilder* const db : builders_) {
503 db->AppendMonitors(solver, monitors);
504 }
505}
506
507void CompositeDecisionBuilder::Accept(ModelVisitor* const visitor) const {
508 for (DecisionBuilder* const db : builders_) {
509 db->Accept(visitor);
510 }
511}
512} // namespace
513
514// ---------- Compose Decision Builder ----------
515
516namespace {
517class ComposeDecisionBuilder : public CompositeDecisionBuilder {
518 public:
519 ComposeDecisionBuilder();
520 explicit ComposeDecisionBuilder(const std::vector<DecisionBuilder*>& dbs);
521 ~ComposeDecisionBuilder() override;
522 Decision* Next(Solver* const s) override;
523 std::string DebugString() const override;
524
525 private:
526 int start_index_;
527};
528
529ComposeDecisionBuilder::ComposeDecisionBuilder() : start_index_(0) {}
530
531ComposeDecisionBuilder::ComposeDecisionBuilder(
532 const std::vector<DecisionBuilder*>& dbs)
533 : CompositeDecisionBuilder(dbs), start_index_(0) {}
534
535ComposeDecisionBuilder::~ComposeDecisionBuilder() {}
536
537Decision* ComposeDecisionBuilder::Next(Solver* const s) {
538 const int size = builders_.size();
539 for (int i = start_index_; i < size; ++i) {
540 Decision* d = builders_[i]->Next(s);
541 if (d != nullptr) {
542 s->SaveAndSetValue(&start_index_, i);
543 return d;
544 }
545 }
546 s->SaveAndSetValue(&start_index_, size);
547 return nullptr;
548}
549
550std::string ComposeDecisionBuilder::DebugString() const {
551 return absl::StrFormat("ComposeDecisionBuilder(%s)",
553}
554} // namespace
555
556DecisionBuilder* Solver::Compose(DecisionBuilder* const db1,
557 DecisionBuilder* const db2) {
558 ComposeDecisionBuilder* c = RevAlloc(new ComposeDecisionBuilder());
559 c->Add(db1);
560 c->Add(db2);
561 return c;
562}
563
564DecisionBuilder* Solver::Compose(DecisionBuilder* const db1,
565 DecisionBuilder* const db2,
566 DecisionBuilder* const db3) {
567 ComposeDecisionBuilder* c = RevAlloc(new ComposeDecisionBuilder());
568 c->Add(db1);
569 c->Add(db2);
570 c->Add(db3);
571 return c;
572}
573
574DecisionBuilder* Solver::Compose(DecisionBuilder* const db1,
575 DecisionBuilder* const db2,
576 DecisionBuilder* const db3,
577 DecisionBuilder* const db4) {
578 ComposeDecisionBuilder* c = RevAlloc(new ComposeDecisionBuilder());
579 c->Add(db1);
580 c->Add(db2);
581 c->Add(db3);
582 c->Add(db4);
583 return c;
584}
585
586DecisionBuilder* Solver::Compose(const std::vector<DecisionBuilder*>& dbs) {
587 if (dbs.size() == 1) {
588 return dbs[0];
589 }
590 return RevAlloc(new ComposeDecisionBuilder(dbs));
591}
592
593// ---------- ClosureDecision ---------
594
595namespace {
596class ClosureDecision : public Decision {
597 public:
598 ClosureDecision(Solver::Action apply, Solver::Action refute)
599 : apply_(std::move(apply)), refute_(std::move(refute)) {}
600 ~ClosureDecision() override {}
601
602 void Apply(Solver* const s) override { apply_(s); }
603
604 void Refute(Solver* const s) override { refute_(s); }
605
606 std::string DebugString() const override { return "ClosureDecision"; }
607
608 private:
609 Solver::Action apply_;
610 Solver::Action refute_;
611};
612} // namespace
613
614Decision* Solver::MakeDecision(Action apply, Action refute) {
615 return RevAlloc(new ClosureDecision(std::move(apply), std::move(refute)));
616}
617
618// ---------- Try Decision Builder ----------
619
620namespace {
621
622class TryDecisionBuilder;
623
624class TryDecision : public Decision {
625 public:
626 explicit TryDecision(TryDecisionBuilder* const try_builder);
627 ~TryDecision() override;
628 void Apply(Solver* const solver) override;
629 void Refute(Solver* const solver) override;
630 std::string DebugString() const override { return "TryDecision"; }
631
632 private:
633 TryDecisionBuilder* const try_builder_;
634};
635
636class TryDecisionBuilder : public CompositeDecisionBuilder {
637 public:
638 TryDecisionBuilder();
639 explicit TryDecisionBuilder(const std::vector<DecisionBuilder*>& dbs);
640 ~TryDecisionBuilder() override;
641 Decision* Next(Solver* const solver) override;
642 std::string DebugString() const override;
643 void AdvanceToNextBuilder(Solver* const solver);
644
645 private:
646 TryDecision try_decision_;
647 int current_builder_;
648 bool start_new_builder_;
649};
650
651TryDecision::TryDecision(TryDecisionBuilder* const try_builder)
652 : try_builder_(try_builder) {}
653
654TryDecision::~TryDecision() {}
655
656void TryDecision::Apply(Solver* const solver) {}
657
658void TryDecision::Refute(Solver* const solver) {
659 try_builder_->AdvanceToNextBuilder(solver);
660}
661
662TryDecisionBuilder::TryDecisionBuilder()
663 : CompositeDecisionBuilder(),
664 try_decision_(this),
665 current_builder_(-1),
666 start_new_builder_(true) {}
667
668TryDecisionBuilder::TryDecisionBuilder(const std::vector<DecisionBuilder*>& dbs)
669 : CompositeDecisionBuilder(dbs),
670 try_decision_(this),
671 current_builder_(-1),
672 start_new_builder_(true) {}
673
674TryDecisionBuilder::~TryDecisionBuilder() {}
675
676Decision* TryDecisionBuilder::Next(Solver* const solver) {
677 if (current_builder_ < 0) {
678 solver->SaveAndSetValue(&current_builder_, 0);
679 start_new_builder_ = true;
680 }
681 if (start_new_builder_) {
682 start_new_builder_ = false;
683 return &try_decision_;
684 } else {
685 return builders_[current_builder_]->Next(solver);
686 }
687}
688
689std::string TryDecisionBuilder::DebugString() const {
690 return absl::StrFormat("TryDecisionBuilder(%s)",
692}
693
694void TryDecisionBuilder::AdvanceToNextBuilder(Solver* const solver) {
695 ++current_builder_;
696 start_new_builder_ = true;
697 if (current_builder_ >= builders_.size()) {
698 solver->Fail();
699 }
700}
701
702} // namespace
703
705 DecisionBuilder* const db2) {
706 TryDecisionBuilder* try_db = RevAlloc(new TryDecisionBuilder());
707 try_db->Add(db1);
708 try_db->Add(db2);
709 return try_db;
710}
711
713 DecisionBuilder* const db2,
714 DecisionBuilder* const db3) {
715 TryDecisionBuilder* try_db = RevAlloc(new TryDecisionBuilder());
716 try_db->Add(db1);
717 try_db->Add(db2);
718 try_db->Add(db3);
719 return try_db;
720}
721
723 DecisionBuilder* const db2,
724 DecisionBuilder* const db3,
725 DecisionBuilder* const db4) {
726 TryDecisionBuilder* try_db = RevAlloc(new TryDecisionBuilder());
727 try_db->Add(db1);
728 try_db->Add(db2);
729 try_db->Add(db3);
730 try_db->Add(db4);
731 return try_db;
732}
733
734DecisionBuilder* Solver::Try(const std::vector<DecisionBuilder*>& dbs) {
735 return RevAlloc(new TryDecisionBuilder(dbs));
736}
737
738// ---------- Variable Assignments ----------
739
740// ----- BaseAssignmentSelector -----
741
742namespace {
743class BaseVariableAssignmentSelector : public BaseObject {
744 public:
745 BaseVariableAssignmentSelector(Solver* solver,
746 const std::vector<IntVar*>& vars)
747 : solver_(solver),
748 vars_(vars),
750 last_unbound_(vars.size() - 1) {}
751
752 ~BaseVariableAssignmentSelector() override {}
753
754 virtual int64_t SelectValue(const IntVar* v, int64_t id) = 0;
755
756 // Returns -1 if no variable are suitable.
757 virtual int64_t ChooseVariable() = 0;
758
759 int64_t ChooseVariableWrapper() {
760 int64_t i;
761 for (i = first_unbound_.Value(); i <= last_unbound_.Value(); ++i) {
762 if (!vars_[i]->Bound()) {
763 break;
764 }
765 }
766 first_unbound_.SetValue(solver_, i);
767 if (i > last_unbound_.Value()) {
768 return -1;
769 }
770 for (i = last_unbound_.Value(); i >= first_unbound_.Value(); --i) {
771 if (!vars_[i]->Bound()) {
772 break;
773 }
774 }
775 last_unbound_.SetValue(solver_, i);
776 return ChooseVariable();
777 }
778
779 void Accept(ModelVisitor* const visitor) const {
780 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
781 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
782 vars_);
783 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
784 }
785
786 const std::vector<IntVar*>& vars() const { return vars_; }
787
788 protected:
789 Solver* const solver_;
790 std::vector<IntVar*> vars_;
791 Rev<int64_t> first_unbound_;
792 Rev<int64_t> last_unbound_;
793};
794
795// ----- Choose first unbound --
796
797int64_t ChooseFirstUnbound(Solver* solver, const std::vector<IntVar*>& vars,
798 int64_t first_unbound, int64_t last_unbound) {
799 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
800 if (!vars[i]->Bound()) {
801 return i;
802 }
803 }
804 return -1;
805}
806
807// ----- Choose Min Size Lowest Min -----
808
809int64_t ChooseMinSizeLowestMin(Solver* solver, const std::vector<IntVar*>& vars,
810 int64_t first_unbound, int64_t last_unbound) {
811 uint64_t best_size = std::numeric_limits<uint64_t>::max();
812 int64_t best_min = std::numeric_limits<int64_t>::max();
813 int64_t best_index = -1;
814 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
815 IntVar* const var = vars[i];
816 if (!var->Bound()) {
817 if (var->Size() < best_size ||
818 (var->Size() == best_size && var->Min() < best_min)) {
819 best_size = var->Size();
820 best_min = var->Min();
821 best_index = i;
822 }
823 }
824 }
825 return best_index;
826}
827
828// ----- Choose Min Size Highest Min -----
829
830int64_t ChooseMinSizeHighestMin(Solver* solver,
831 const std::vector<IntVar*>& vars,
832 int64_t first_unbound, int64_t last_unbound) {
833 uint64_t best_size = std::numeric_limits<uint64_t>::max();
834 int64_t best_min = std::numeric_limits<int64_t>::min();
835 int64_t best_index = -1;
836 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
837 IntVar* const var = vars[i];
838 if (!var->Bound()) {
839 if (var->Size() < best_size ||
840 (var->Size() == best_size && var->Min() > best_min)) {
841 best_size = var->Size();
842 best_min = var->Min();
843 best_index = i;
844 }
845 }
846 }
847 return best_index;
848}
849
850// ----- Choose Min Size Lowest Max -----
851
852int64_t ChooseMinSizeLowestMax(Solver* solver, const std::vector<IntVar*>& vars,
853 int64_t first_unbound, int64_t last_unbound) {
854 uint64_t best_size = std::numeric_limits<uint64_t>::max();
855 int64_t best_max = std::numeric_limits<int64_t>::max();
856 int64_t best_index = -1;
857 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
858 IntVar* const var = vars[i];
859 if (!var->Bound()) {
860 if (var->Size() < best_size ||
861 (var->Size() == best_size && var->Max() < best_max)) {
862 best_size = var->Size();
863 best_max = var->Max();
864 best_index = i;
865 }
866 }
867 }
868 return best_index;
869}
870
871// ----- Choose Min Size Highest Max -----
872
873int64_t ChooseMinSizeHighestMax(Solver* solver,
874 const std::vector<IntVar*>& vars,
875 int64_t first_unbound, int64_t last_unbound) {
876 uint64_t best_size = std::numeric_limits<uint64_t>::max();
877 int64_t best_max = std::numeric_limits<int64_t>::min();
878 int64_t best_index = -1;
879 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
880 IntVar* const var = vars[i];
881 if (!var->Bound()) {
882 if (var->Size() < best_size ||
883 (var->Size() == best_size && var->Max() > best_max)) {
884 best_size = var->Size();
885 best_max = var->Max();
886 best_index = i;
887 }
888 }
889 }
890 return best_index;
891}
892
893// ----- Choose Lowest Min --
894
895int64_t ChooseLowestMin(Solver* solver, const std::vector<IntVar*>& vars,
896 int64_t first_unbound, int64_t last_unbound) {
897 int64_t best_min = std::numeric_limits<int64_t>::max();
898 int64_t best_index = -1;
899 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
900 IntVar* const var = vars[i];
901 if (!var->Bound()) {
902 if (var->Min() < best_min) {
903 best_min = var->Min();
904 best_index = i;
905 }
906 }
907 }
908 return best_index;
909}
910
911// ----- Choose Highest Max -----
912
913int64_t ChooseHighestMax(Solver* solver, const std::vector<IntVar*>& vars,
914 int64_t first_unbound, int64_t last_unbound) {
915 int64_t best_max = std::numeric_limits<int64_t>::min();
916 int64_t best_index = -1;
917 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
918 IntVar* const var = vars[i];
919 if (!var->Bound()) {
920 if (var->Max() > best_max) {
921 best_max = var->Max();
922 best_index = i;
923 }
924 }
925 }
926 return best_index;
927}
928
929// ----- Choose Lowest Size --
930
931int64_t ChooseMinSize(Solver* solver, const std::vector<IntVar*>& vars,
932 int64_t first_unbound, int64_t last_unbound) {
933 uint64_t best_size = std::numeric_limits<uint64_t>::max();
934 int64_t best_index = -1;
935 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
936 IntVar* const var = vars[i];
937 if (!var->Bound()) {
938 if (var->Size() < best_size) {
939 best_size = var->Size();
940 best_index = i;
941 }
942 }
943 }
944 return best_index;
945}
946
947// ----- Choose Highest Size -----
948
949int64_t ChooseMaxSize(Solver* solver, const std::vector<IntVar*>& vars,
950 int64_t first_unbound, int64_t last_unbound) {
951 uint64_t best_size = 0;
952 int64_t best_index = -1;
953 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
954 IntVar* const var = vars[i];
955 if (!var->Bound()) {
956 if (var->Size() > best_size) {
957 best_size = var->Size();
958 best_index = i;
959 }
960 }
961 }
962 return best_index;
963}
964
965// ----- Choose Highest Regret -----
966
967class HighestRegretSelectorOnMin : public BaseObject {
968 public:
969 explicit HighestRegretSelectorOnMin(const std::vector<IntVar*>& vars)
970 : iterators_(vars.size()) {
971 for (int64_t i = 0; i < vars.size(); ++i) {
972 iterators_[i] = vars[i]->MakeDomainIterator(true);
973 }
974 }
975 ~HighestRegretSelectorOnMin() override {}
976 int64_t Choose(Solver* const s, const std::vector<IntVar*>& vars,
977 int64_t first_unbound, int64_t last_unbound);
978 std::string DebugString() const override { return "MaxRegretSelector"; }
979
980 int64_t ComputeRegret(IntVar* var, int64_t index) const {
981 DCHECK(!var->Bound());
982 const int64_t vmin = var->Min();
983 IntVarIterator* const iterator = iterators_[index];
984 iterator->Init();
985 iterator->Next();
986 return iterator->Value() - vmin;
987 }
988
989 private:
990 std::vector<IntVarIterator*> iterators_;
991};
992
993int64_t HighestRegretSelectorOnMin::Choose(Solver* const s,
994 const std::vector<IntVar*>& vars,
995 int64_t first_unbound,
996 int64_t last_unbound) {
997 int64_t best_regret = 0;
998 int64_t index = -1;
999 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
1000 IntVar* const var = vars[i];
1001 if (!var->Bound()) {
1002 const int64_t regret = ComputeRegret(var, i);
1003 if (regret > best_regret) {
1004 best_regret = regret;
1005 index = i;
1006 }
1007 }
1008 }
1009 return index;
1010}
1011
1012// ----- Choose random unbound --
1013
1014int64_t ChooseRandom(Solver* solver, const std::vector<IntVar*>& vars,
1015 int64_t first_unbound, int64_t last_unbound) {
1016 const int64_t span = last_unbound - first_unbound + 1;
1017 const int64_t shift = solver->Rand32(span);
1018 for (int64_t i = 0; i < span; ++i) {
1019 const int64_t index = (i + shift) % span + first_unbound;
1020 if (!vars[index]->Bound()) {
1021 return index;
1022 }
1023 }
1024 return -1;
1025}
1026
1027// ----- Choose min eval -----
1028
1029class CheapestVarSelector : public BaseObject {
1030 public:
1031 explicit CheapestVarSelector(std::function<int64_t(int64_t)> var_evaluator)
1032 : var_evaluator_(std::move(var_evaluator)) {}
1033 ~CheapestVarSelector() override {}
1034 int64_t Choose(Solver* const s, const std::vector<IntVar*>& vars,
1035 int64_t first_unbound, int64_t last_unbound);
1036 std::string DebugString() const override { return "CheapestVarSelector"; }
1037
1038 private:
1039 std::function<int64_t(int64_t)> var_evaluator_;
1040};
1041
1042int64_t CheapestVarSelector::Choose(Solver* const s,
1043 const std::vector<IntVar*>& vars,
1044 int64_t first_unbound,
1045 int64_t last_unbound) {
1046 int64_t best_eval = std::numeric_limits<int64_t>::max();
1047 int64_t index = -1;
1048 for (int64_t i = first_unbound; i <= last_unbound; ++i) {
1049 if (!vars[i]->Bound()) {
1050 const int64_t eval = var_evaluator_(i);
1051 if (eval < best_eval) {
1052 best_eval = eval;
1053 index = i;
1054 }
1055 }
1056 }
1057 return index;
1058}
1059
1060// ----- Path selector -----
1061// Follow path, where var[i] is represents the next of i
1062
1063class PathSelector : public BaseObject {
1064 public:
1065 PathSelector() : first_(std::numeric_limits<int64_t>::max()) {}
1066 ~PathSelector() override {}
1067 int64_t Choose(Solver* const s, const std::vector<IntVar*>& vars,
1068 int64_t first_unbound, int64_t last_unbound);
1069 std::string DebugString() const override { return "ChooseNextOnPath"; }
1070
1071 private:
1072 bool UpdateIndex(const std::vector<IntVar*>& vars, int64_t* index) const;
1073 bool FindPathStart(const std::vector<IntVar*>& vars, int64_t* index) const;
1074
1075 Rev<int64_t> first_;
1076};
1077
1078int64_t PathSelector::Choose(Solver* const s, const std::vector<IntVar*>& vars,
1079 int64_t first_unbound, int64_t last_unbound) {
1080 int64_t index = first_.Value();
1081 if (!UpdateIndex(vars, &index)) {
1082 return -1;
1083 }
1084 int64_t count = 0;
1085 while (vars[index]->Bound()) {
1086 index = vars[index]->Value();
1087 if (!UpdateIndex(vars, &index)) {
1088 return -1;
1089 }
1090 ++count;
1091 if (count >= vars.size() &&
1092 !FindPathStart(vars, &index)) { // Cycle detected
1093 return -1;
1094 }
1095 }
1096 first_.SetValue(s, index);
1097 return index;
1098}
1099
1100bool PathSelector::UpdateIndex(const std::vector<IntVar*>& vars,
1101 int64_t* index) const {
1102 if (*index >= vars.size()) {
1103 if (!FindPathStart(vars, index)) {
1104 return false;
1105 }
1106 }
1107 return true;
1108}
1109
1110// Select variables on a path:
1111// 1. Try to extend an existing route: look for an unbound variable, to which
1112// some other variable points.
1113// 2. If no such road is found, try to find a start node of a route: look for
1114// an unbound variable, to which no other variable can point.
1115// 3. If everything else fails, pick the first unbound variable.
1116bool PathSelector::FindPathStart(const std::vector<IntVar*>& vars,
1117 int64_t* index) const {
1118 // Try to extend an existing path
1119 for (int64_t i = vars.size() - 1; i >= 0; --i) {
1120 if (vars[i]->Bound()) {
1121 const int64_t next = vars[i]->Value();
1122 if (next < vars.size() && !vars[next]->Bound()) {
1123 *index = next;
1124 return true;
1125 }
1126 }
1127 }
1128 // Pick path start
1129 for (int64_t i = vars.size() - 1; i >= 0; --i) {
1130 if (!vars[i]->Bound()) {
1131 bool has_possible_prev = false;
1132 for (int64_t j = 0; j < vars.size(); ++j) {
1133 if (vars[j]->Contains(i)) {
1134 has_possible_prev = true;
1135 break;
1136 }
1137 }
1138 if (!has_possible_prev) {
1139 *index = i;
1140 return true;
1141 }
1142 }
1143 }
1144 // Pick first unbound
1145 for (int64_t i = 0; i < vars.size(); ++i) {
1146 if (!vars[i]->Bound()) {
1147 *index = i;
1148 return true;
1149 }
1150 }
1151 return false;
1152}
1153
1154// ----- Select min -----
1155
1156int64_t SelectMinValue(const IntVar* v, int64_t id) { return v->Min(); }
1157
1158// ----- Select max -----
1159
1160int64_t SelectMaxValue(const IntVar* v, int64_t id) { return v->Max(); }
1161
1162// ----- Select random -----
1163
1164int64_t SelectRandomValue(const IntVar* v, int64_t id) {
1165 const uint64_t span = v->Max() - v->Min() + 1;
1166 if (span > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {
1167 // Do not create holes in large domains.
1168 return v->Min();
1169 }
1170 const uint64_t size = v->Size();
1171 Solver* const s = v->solver();
1172 if (size > span / 4) { // Dense enough, we can try to find the
1173 // value randomly.
1174 for (;;) {
1175 const int64_t value = v->Min() + s->Rand64(span);
1176 if (v->Contains(value)) {
1177 return value;
1178 }
1179 }
1180 } else { // Not dense enough, we will count.
1181 int64_t index = s->Rand64(size);
1182 if (index <= size / 2) {
1183 for (int64_t i = v->Min(); i <= v->Max(); ++i) {
1184 if (v->Contains(i)) {
1185 if (--index == 0) {
1186 return i;
1187 }
1188 }
1189 }
1190 CHECK_LE(index, 0);
1191 } else {
1192 for (int64_t i = v->Max(); i > v->Min(); --i) {
1193 if (v->Contains(i)) {
1194 if (--index == 0) {
1195 return i;
1196 }
1197 }
1198 }
1199 CHECK_LE(index, 0);
1200 }
1201 }
1202 return 0;
1203}
1204
1205// ----- Select center -----
1206
1207int64_t SelectCenterValue(const IntVar* v, int64_t id) {
1208 const int64_t vmin = v->Min();
1209 const int64_t vmax = v->Max();
1210 if (vmax - vmin > absl::GetFlag(FLAGS_cp_large_domain_no_splitting_limit)) {
1211 // Do not create holes in large domains.
1212 return vmin;
1213 }
1214 const int64_t mid = (vmin + vmax) / 2;
1215 if (v->Contains(mid)) {
1216 return mid;
1217 }
1218 const int64_t diameter = vmax - mid; // always greater than mid - vmix.
1219 for (int64_t i = 1; i <= diameter; ++i) {
1220 if (v->Contains(mid - i)) {
1221 return mid - i;
1222 }
1223 if (v->Contains(mid + i)) {
1224 return mid + i;
1225 }
1226 }
1227 return 0;
1228}
1229
1230// ----- Select center -----
1231
1232int64_t SelectSplitValue(const IntVar* v, int64_t id) {
1233 const int64_t vmin = v->Min();
1234 const int64_t vmax = v->Max();
1235 const uint64_t delta = vmax - vmin;
1236 const int64_t mid = vmin + delta / 2;
1237 return mid;
1238}
1239
1240// ----- Select the value yielding the cheapest "eval" for a var -----
1241
1242class CheapestValueSelector : public BaseObject {
1243 public:
1244 CheapestValueSelector(std::function<int64_t(int64_t, int64_t)> eval,
1245 std::function<int64_t(int64_t)> tie_breaker)
1246 : eval_(std::move(eval)), tie_breaker_(std::move(tie_breaker)) {}
1247 ~CheapestValueSelector() override {}
1248 int64_t Select(const IntVar* v, int64_t id);
1249 std::string DebugString() const override { return "CheapestValue"; }
1250
1251 private:
1252 std::function<int64_t(int64_t, int64_t)> eval_;
1253 std::function<int64_t(int64_t)> tie_breaker_;
1254 std::vector<int64_t> cache_;
1255};
1256
1257int64_t CheapestValueSelector::Select(const IntVar* v, int64_t id) {
1258 cache_.clear();
1259 int64_t best = std::numeric_limits<int64_t>::max();
1260 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(false));
1261 for (const int64_t i : InitAndGetValues(it.get())) {
1262 int64_t eval = eval_(id, i);
1263 if (eval < best) {
1264 best = eval;
1265 cache_.clear();
1266 cache_.push_back(i);
1267 } else if (eval == best) {
1268 cache_.push_back(i);
1269 }
1270 }
1271 DCHECK_GT(cache_.size(), 0);
1272 if (tie_breaker_ == nullptr || cache_.size() == 1) {
1273 return cache_.back();
1274 } else {
1275 return cache_[tie_breaker_(cache_.size())];
1276 }
1277}
1278
1279// ----- Select the best value for the var, based on a comparator callback -----
1280
1281// The comparator should be a total order, but does not have to be a strict
1282// ordering. If there is a tie between two values val1 and val2, i.e. if
1283// !comparator(var_id, val1, val2) && !comparator(var_id, val2, val1), then
1284// the lowest value wins.
1285// comparator(var_id, val1, val2) == true means than val1 should be preferred
1286// over val2 for variable var_id.
1287class BestValueByComparisonSelector : public BaseObject {
1288 public:
1289 explicit BestValueByComparisonSelector(
1291 : comparator_(std::move(comparator)) {}
1292 ~BestValueByComparisonSelector() override {}
1293 int64_t Select(const IntVar* v, int64_t id);
1294 std::string DebugString() const override {
1295 return "BestValueByComparisonSelector";
1296 }
1297
1298 private:
1300};
1301
1302int64_t BestValueByComparisonSelector::Select(const IntVar* v, int64_t id) {
1303 std::unique_ptr<IntVarIterator> it(v->MakeDomainIterator(false));
1304 it->Init();
1305 DCHECK(it->Ok()); // At least one value.
1306 int64_t best_value = it->Value();
1307 for (it->Next(); it->Ok(); it->Next()) {
1308 const int64_t candidate_value = it->Value();
1309 if (comparator_(id, candidate_value, best_value)) {
1310 best_value = candidate_value;
1311 }
1312 }
1313 return best_value;
1314}
1315
1316// ----- VariableAssignmentSelector -----
1317
1318class VariableAssignmentSelector : public BaseVariableAssignmentSelector {
1319 public:
1320 VariableAssignmentSelector(Solver* solver, const std::vector<IntVar*>& vars,
1321 Solver::VariableIndexSelector var_selector,
1322 Solver::VariableValueSelector value_selector,
1323 const std::string& name)
1324 : BaseVariableAssignmentSelector(solver, vars),
1325 var_selector_(std::move(var_selector)),
1326 value_selector_(std::move(value_selector)),
1327 name_(name) {}
1328 ~VariableAssignmentSelector() override {}
1329 int64_t SelectValue(const IntVar* var, int64_t id) override {
1330 return value_selector_(var, id);
1331 }
1332 int64_t ChooseVariable() override {
1333 return var_selector_(solver_, vars_, first_unbound_.Value(),
1334 last_unbound_.Value());
1335 }
1336 std::string DebugString() const override;
1337
1338 private:
1339 Solver::VariableIndexSelector var_selector_;
1340 Solver::VariableValueSelector value_selector_;
1341 const std::string name_;
1342};
1343
1344std::string VariableAssignmentSelector::DebugString() const {
1345 return absl::StrFormat("%s(%s)", name_, JoinDebugStringPtr(vars_, ", "));
1346}
1347
1348// ----- Base Global Evaluator-based selector -----
1349
1350class BaseEvaluatorSelector : public BaseVariableAssignmentSelector {
1351 public:
1352 BaseEvaluatorSelector(Solver* solver, const std::vector<IntVar*>& vars,
1353 std::function<int64_t(int64_t, int64_t)> evaluator);
1354 ~BaseEvaluatorSelector() override {}
1355
1356 protected:
1357 struct Element {
1358 Element() : var(0), value(0) {}
1359 Element(int64_t i, int64_t j) : var(i), value(j) {}
1360 int64_t var;
1361 int64_t value;
1362 };
1363
1364 std::string DebugStringInternal(const std::string& name) const {
1365 return absl::StrFormat("%s(%s)", name, JoinDebugStringPtr(vars_, ", "));
1366 }
1367
1368 std::function<int64_t(int64_t, int64_t)> evaluator_;
1369};
1370
1371BaseEvaluatorSelector::BaseEvaluatorSelector(
1372 Solver* solver, const std::vector<IntVar*>& vars,
1373 std::function<int64_t(int64_t, int64_t)> evaluator)
1374 : BaseVariableAssignmentSelector(solver, vars),
1375 evaluator_(std::move(evaluator)) {}
1376
1377// ----- Global Dynamic Evaluator-based selector -----
1378
1379class DynamicEvaluatorSelector : public BaseEvaluatorSelector {
1380 public:
1381 DynamicEvaluatorSelector(Solver* solver, const std::vector<IntVar*>& vars,
1382 std::function<int64_t(int64_t, int64_t)> evaluator,
1383 std::function<int64_t(int64_t)> tie_breaker);
1384 ~DynamicEvaluatorSelector() override {}
1385 int64_t SelectValue(const IntVar* var, int64_t id) override;
1386 int64_t ChooseVariable() override;
1387 std::string DebugString() const override;
1388
1389 private:
1390 int64_t first_;
1391 std::function<int64_t(int64_t)> tie_breaker_;
1392 std::vector<Element> cache_;
1393};
1394
1395DynamicEvaluatorSelector::DynamicEvaluatorSelector(
1396 Solver* solver, const std::vector<IntVar*>& vars,
1397 std::function<int64_t(int64_t, int64_t)> evaluator,
1398 std::function<int64_t(int64_t)> tie_breaker)
1399 : BaseEvaluatorSelector(solver, vars, std::move(evaluator)),
1400 first_(-1),
1401 tie_breaker_(std::move(tie_breaker)) {}
1402
1403int64_t DynamicEvaluatorSelector::SelectValue(const IntVar* var, int64_t id) {
1404 return cache_[first_].value;
1405}
1406
1407int64_t DynamicEvaluatorSelector::ChooseVariable() {
1408 int64_t best_evaluation = std::numeric_limits<int64_t>::max();
1409 cache_.clear();
1410 for (int64_t i = 0; i < vars_.size(); ++i) {
1411 const IntVar* const var = vars_[i];
1412 if (!var->Bound()) {
1413 std::unique_ptr<IntVarIterator> it(var->MakeDomainIterator(false));
1414 for (const int64_t j : InitAndGetValues(it.get())) {
1415 const int64_t value = evaluator_(i, j);
1416 if (value < best_evaluation) {
1417 best_evaluation = value;
1418 cache_.clear();
1419 cache_.push_back(Element(i, j));
1420 } else if (value == best_evaluation && tie_breaker_) {
1421 cache_.push_back(Element(i, j));
1422 }
1423 }
1424 }
1425 }
1426
1427 if (cache_.empty()) {
1428 return -1;
1429 }
1430
1431 if (tie_breaker_ == nullptr || cache_.size() == 1) {
1432 first_ = 0;
1433 return cache_.front().var;
1434 } else {
1435 first_ = tie_breaker_(cache_.size());
1436 return cache_[first_].var;
1437 }
1438}
1439
1440std::string DynamicEvaluatorSelector::DebugString() const {
1441 return DebugStringInternal("AssignVariablesOnDynamicEvaluator");
1442}
1443
1444// ----- Global Dynamic Evaluator-based selector -----
1445
1446class StaticEvaluatorSelector : public BaseEvaluatorSelector {
1447 public:
1448 StaticEvaluatorSelector(
1449 Solver* solver, const std::vector<IntVar*>& vars,
1450 const std::function<int64_t(int64_t, int64_t)>& evaluator);
1451 ~StaticEvaluatorSelector() override {}
1452 int64_t SelectValue(const IntVar* var, int64_t id) override;
1453 int64_t ChooseVariable() override;
1454 std::string DebugString() const override;
1455
1456 private:
1457 class Compare {
1458 public:
1459 explicit Compare(std::function<int64_t(int64_t, int64_t)> evaluator)
1460 : evaluator_(std::move(evaluator)) {}
1461 bool operator()(const Element& lhs, const Element& rhs) const {
1462 const int64_t value_lhs = Value(lhs);
1463 const int64_t value_rhs = Value(rhs);
1464 return value_lhs < value_rhs ||
1465 (value_lhs == value_rhs &&
1466 (lhs.var < rhs.var ||
1467 (lhs.var == rhs.var && lhs.value < rhs.value)));
1468 }
1469 int64_t Value(const Element& element) const {
1470 return evaluator_(element.var, element.value);
1471 }
1472
1473 private:
1474 std::function<int64_t(int64_t, int64_t)> evaluator_;
1475 };
1476
1477 Compare comp_;
1478 std::vector<Element> elements_;
1479 int64_t first_;
1480};
1481
1482StaticEvaluatorSelector::StaticEvaluatorSelector(
1483 Solver* solver, const std::vector<IntVar*>& vars,
1484 const std::function<int64_t(int64_t, int64_t)>& evaluator)
1485 : BaseEvaluatorSelector(solver, vars, evaluator),
1486 comp_(evaluator),
1487 first_(-1) {}
1488
1489int64_t StaticEvaluatorSelector::SelectValue(const IntVar* var, int64_t id) {
1490 return elements_[first_].value;
1491}
1492
1493int64_t StaticEvaluatorSelector::ChooseVariable() {
1494 if (first_ == -1) { // first call to select. update assignment costs
1495 // Two phases: compute size then filland sort
1496 int64_t element_size = 0;
1497 for (int64_t i = 0; i < vars_.size(); ++i) {
1498 if (!vars_[i]->Bound()) {
1499 element_size += vars_[i]->Size();
1500 }
1501 }
1502 elements_.resize(element_size);
1503 int count = 0;
1504 for (int i = 0; i < vars_.size(); ++i) {
1505 const IntVar* const var = vars_[i];
1506 if (!var->Bound()) {
1507 std::unique_ptr<IntVarIterator> it(var->MakeDomainIterator(false));
1508 for (const int64_t value : InitAndGetValues(it.get())) {
1509 elements_[count++] = Element(i, value);
1510 }
1511 }
1512 }
1513 // Sort is stable here given the tie-breaking rules in comp_.
1514 std::sort(elements_.begin(), elements_.end(), comp_);
1515 solver_->SaveAndSetValue<int64_t>(&first_, 0);
1516 }
1517 for (int64_t i = first_; i < elements_.size(); ++i) {
1518 const Element& element = elements_[i];
1519 IntVar* const var = vars_[element.var];
1520 if (!var->Bound() && var->Contains(element.value)) {
1521 solver_->SaveAndSetValue(&first_, i);
1522 return element.var;
1523 }
1524 }
1525 solver_->SaveAndSetValue(&first_, static_cast<int64_t>(elements_.size()));
1526 return -1;
1527}
1528
1529std::string StaticEvaluatorSelector::DebugString() const {
1530 return DebugStringInternal("AssignVariablesOnStaticEvaluator");
1531}
1532
1533// ----- AssignOneVariableValue decision -----
1534
1535class AssignOneVariableValue : public Decision {
1536 public:
1537 AssignOneVariableValue(IntVar* const v, int64_t val);
1538 ~AssignOneVariableValue() override {}
1539 void Apply(Solver* const s) override;
1540 void Refute(Solver* const s) override;
1541 std::string DebugString() const override;
1542 void Accept(DecisionVisitor* const visitor) const override {
1543 visitor->VisitSetVariableValue(var_, value_);
1544 }
1545
1546 private:
1547 IntVar* const var_;
1548 int64_t value_;
1549};
1550
1551AssignOneVariableValue::AssignOneVariableValue(IntVar* const v, int64_t val)
1552 : var_(v), value_(val) {}
1553
1554std::string AssignOneVariableValue::DebugString() const {
1555 return absl::StrFormat("[%s == %d] or [%s != %d]", var_->DebugString(),
1556 value_, var_->DebugString(), value_);
1557}
1558
1559void AssignOneVariableValue::Apply(Solver* const s) { var_->SetValue(value_); }
1560
1561void AssignOneVariableValue::Refute(Solver* const s) {
1562 var_->RemoveValue(value_);
1563}
1564} // namespace
1565
1566Decision* Solver::MakeAssignVariableValue(IntVar* const var, int64_t val) {
1567 return RevAlloc(new AssignOneVariableValue(var, val));
1568}
1569
1570// ----- AssignOneVariableValueOrFail decision -----
1571
1572namespace {
1573class AssignOneVariableValueOrFail : public Decision {
1574 public:
1575 AssignOneVariableValueOrFail(IntVar* const v, int64_t value);
1576 ~AssignOneVariableValueOrFail() override {}
1577 void Apply(Solver* const s) override;
1578 void Refute(Solver* const s) override;
1579 std::string DebugString() const override;
1580 void Accept(DecisionVisitor* const visitor) const override {
1581 visitor->VisitSetVariableValue(var_, value_);
1582 }
1583
1584 private:
1585 IntVar* const var_;
1586 const int64_t value_;
1587};
1588
1589AssignOneVariableValueOrFail::AssignOneVariableValueOrFail(IntVar* const v,
1590 int64_t value)
1591 : var_(v), value_(value) {}
1592
1593std::string AssignOneVariableValueOrFail::DebugString() const {
1594 return absl::StrFormat("[%s == %d] or fail", var_->DebugString(), value_);
1595}
1596
1597void AssignOneVariableValueOrFail::Apply(Solver* const s) {
1598 var_->SetValue(value_);
1599}
1600
1601void AssignOneVariableValueOrFail::Refute(Solver* const s) { s->Fail(); }
1602} // namespace
1603
1605 int64_t value) {
1606 return RevAlloc(new AssignOneVariableValueOrFail(var, value));
1607}
1608
1609// ----- AssignOneVariableValueOrDoNothing decision -----
1610
1611namespace {
1612class AssignOneVariableValueDoNothing : public Decision {
1613 public:
1614 AssignOneVariableValueDoNothing(IntVar* const v, int64_t value)
1615 : var_(v), value_(value) {}
1616 ~AssignOneVariableValueDoNothing() override {}
1617 void Apply(Solver* const s) override { var_->SetValue(value_); }
1618 void Refute(Solver* const s) override {}
1619 std::string DebugString() const override {
1620 return absl::StrFormat("[%s == %d] or []", var_->DebugString(), value_);
1621 }
1622 void Accept(DecisionVisitor* const visitor) const override {
1623 visitor->VisitSetVariableValue(var_, value_);
1624 }
1625
1626 private:
1627 IntVar* const var_;
1628 const int64_t value_;
1629};
1630
1631} // namespace
1632
1634 int64_t value) {
1635 return RevAlloc(new AssignOneVariableValueDoNothing(var, value));
1636}
1637
1638// ----- AssignOneVariableValue decision -----
1639
1640namespace {
1641class SplitOneVariable : public Decision {
1642 public:
1643 SplitOneVariable(IntVar* const v, int64_t val, bool start_with_lower_half);
1644 ~SplitOneVariable() override {}
1645 void Apply(Solver* const s) override;
1646 void Refute(Solver* const s) override;
1647 std::string DebugString() const override;
1648 void Accept(DecisionVisitor* const visitor) const override {
1649 visitor->VisitSplitVariableDomain(var_, value_, start_with_lower_half_);
1650 }
1651
1652 private:
1653 IntVar* const var_;
1654 const int64_t value_;
1655 const bool start_with_lower_half_;
1656};
1657
1658SplitOneVariable::SplitOneVariable(IntVar* const v, int64_t val,
1659 bool start_with_lower_half)
1660 : var_(v), value_(val), start_with_lower_half_(start_with_lower_half) {}
1661
1662std::string SplitOneVariable::DebugString() const {
1663 if (start_with_lower_half_) {
1664 return absl::StrFormat("[%s <= %d]", var_->DebugString(), value_);
1665 } else {
1666 return absl::StrFormat("[%s >= %d]", var_->DebugString(), value_);
1667 }
1668}
1669
1670void SplitOneVariable::Apply(Solver* const s) {
1671 if (start_with_lower_half_) {
1672 var_->SetMax(value_);
1673 } else {
1674 var_->SetMin(value_ + 1);
1675 }
1676}
1677
1678void SplitOneVariable::Refute(Solver* const s) {
1679 if (start_with_lower_half_) {
1680 var_->SetMin(value_ + 1);
1681 } else {
1682 var_->SetMax(value_);
1683 }
1684}
1685} // namespace
1686
1688 bool start_with_lower_half) {
1689 return RevAlloc(new SplitOneVariable(var, val, start_with_lower_half));
1690}
1691
1693 int64_t value) {
1694 return MakeSplitVariableDomain(var, value, true);
1695}
1696
1698 int64_t value) {
1699 return MakeSplitVariableDomain(var, value, false);
1700}
1701
1702// ----- AssignVariablesValues decision -----
1703
1704namespace {
1705class AssignVariablesValues : public Decision {
1706 public:
1707 // Selects what this Decision does on the Refute() branch:
1708 // - kForbidAssignment: adds a constraint that forbids the assignment.
1709 // - kDoNothing: does nothing.
1710 // - kFail: fails.
1711 enum class RefutationBehavior { kForbidAssignment, kDoNothing, kFail };
1712 AssignVariablesValues(
1713 const std::vector<IntVar*>& vars, const std::vector<int64_t>& values,
1714 RefutationBehavior refutation = RefutationBehavior::kForbidAssignment);
1715 ~AssignVariablesValues() override {}
1716 void Apply(Solver* const s) override;
1717 void Refute(Solver* const s) override;
1718 std::string DebugString() const override;
1719 void Accept(DecisionVisitor* const visitor) const override {
1720 for (int i = 0; i < vars_.size(); ++i) {
1721 visitor->VisitSetVariableValue(vars_[i], values_[i]);
1722 }
1723 }
1724
1725 virtual void Accept(ModelVisitor* const visitor) const {
1726 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
1727 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1728 vars_);
1729 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
1730 }
1731
1732 private:
1733 const std::vector<IntVar*> vars_;
1734 const std::vector<int64_t> values_;
1735 const RefutationBehavior refutation_;
1736};
1737
1738AssignVariablesValues::AssignVariablesValues(const std::vector<IntVar*>& vars,
1739 const std::vector<int64_t>& values,
1740 RefutationBehavior refutation)
1741 : vars_(vars), values_(values), refutation_(refutation) {}
1742
1743std::string AssignVariablesValues::DebugString() const {
1744 std::string out;
1745 if (vars_.empty()) out += "do nothing";
1746 for (int i = 0; i < vars_.size(); ++i) {
1747 absl::StrAppendFormat(&out, "[%s == %d]", vars_[i]->DebugString(),
1748 values_[i]);
1749 }
1750 switch (refutation_) {
1751 case RefutationBehavior::kForbidAssignment:
1752 out += " or forbid assignment";
1753 break;
1754 case RefutationBehavior::kDoNothing:
1755 out += " or do nothing";
1756 break;
1757 case RefutationBehavior::kFail:
1758 out += " or fail";
1759 break;
1760 }
1761 return out;
1762}
1763
1764void AssignVariablesValues::Apply(Solver* const s) {
1765 if (vars_.empty()) return;
1766 vars_[0]->FreezeQueue();
1767 for (int i = 0; i < vars_.size(); ++i) {
1768 vars_[i]->SetValue(values_[i]);
1769 }
1770 vars_[0]->UnfreezeQueue();
1771}
1772
1773void AssignVariablesValues::Refute(Solver* const s) {
1774 switch (refutation_) {
1775 case RefutationBehavior::kForbidAssignment: {
1776 std::vector<IntVar*> terms;
1777 for (int i = 0; i < vars_.size(); ++i) {
1778 IntVar* term = s->MakeBoolVar();
1779 s->AddConstraint(s->MakeIsDifferentCstCt(vars_[i], values_[i], term));
1780 terms.push_back(term);
1781 }
1782 s->AddConstraint(s->MakeSumGreaterOrEqual(terms, 1));
1783 break;
1784 }
1785 case RefutationBehavior::kDoNothing: {
1786 break;
1787 }
1788 case RefutationBehavior::kFail: {
1789 s->Fail();
1790 break;
1791 }
1792 }
1793}
1794} // namespace
1795
1797 const std::vector<IntVar*>& vars, const std::vector<int64_t>& values) {
1798 CHECK_EQ(vars.size(), values.size());
1799 return RevAlloc(new AssignVariablesValues(
1800 vars, values,
1801 AssignVariablesValues::RefutationBehavior::kForbidAssignment));
1802}
1803
1805 const std::vector<IntVar*>& vars, const std::vector<int64_t>& values) {
1806 CHECK_EQ(vars.size(), values.size());
1807 return RevAlloc(new AssignVariablesValues(
1808 vars, values, AssignVariablesValues::RefutationBehavior::kDoNothing));
1809}
1810
1812 const std::vector<IntVar*>& vars, const std::vector<int64_t>& values) {
1813 CHECK_EQ(vars.size(), values.size());
1814 return RevAlloc(new AssignVariablesValues(
1815 vars, values, AssignVariablesValues::RefutationBehavior::kFail));
1816}
1817
1818// ----- AssignAllVariables -----
1819
1820namespace {
1821class BaseAssignVariables : public DecisionBuilder {
1822 public:
1823 enum Mode {
1824 ASSIGN,
1825 SPLIT_LOWER,
1826 SPLIT_UPPER,
1827 };
1828
1829 BaseAssignVariables(BaseVariableAssignmentSelector* const selector, Mode mode)
1830 : selector_(selector), mode_(mode) {}
1831
1832 ~BaseAssignVariables() override;
1833 Decision* Next(Solver* const s) override;
1834 std::string DebugString() const override;
1835 static BaseAssignVariables* MakePhase(
1836 Solver* const s, const std::vector<IntVar*>& vars,
1837 Solver::VariableIndexSelector var_selector,
1838 Solver::VariableValueSelector value_selector,
1839 const std::string& value_selector_name, BaseAssignVariables::Mode mode);
1840
1841 static Solver::VariableIndexSelector MakeVariableSelector(
1842 Solver* const s, const std::vector<IntVar*>& vars,
1844 switch (str) {
1848 return ChooseFirstUnbound;
1850 return ChooseRandom;
1852 return ChooseMinSizeLowestMin;
1854 return ChooseMinSizeHighestMin;
1856 return ChooseMinSizeLowestMax;
1858 return ChooseMinSizeHighestMax;
1860 return ChooseLowestMin;
1862 return ChooseHighestMax;
1864 return ChooseMinSize;
1866 return ChooseMaxSize;
1868 HighestRegretSelectorOnMin* const selector =
1869 s->RevAlloc(new HighestRegretSelectorOnMin(vars));
1870 return [selector](Solver* solver, const std::vector<IntVar*>& vars,
1871 int first_unbound, int last_unbound) {
1872 return selector->Choose(solver, vars, first_unbound, last_unbound);
1873 };
1874 }
1875 case Solver::CHOOSE_PATH: {
1876 PathSelector* const selector = s->RevAlloc(new PathSelector());
1877 return [selector](Solver* solver, const std::vector<IntVar*>& vars,
1878 int first_unbound, int last_unbound) {
1879 return selector->Choose(solver, vars, first_unbound, last_unbound);
1880 };
1881 }
1882 default:
1883 LOG(FATAL) << "Unknown int var strategy " << str;
1884 return nullptr;
1885 }
1886 }
1887
1888 static Solver::VariableValueSelector MakeValueSelector(
1889 Solver* const s, Solver::IntValueStrategy val_str) {
1890 switch (val_str) {
1894 return SelectMinValue;
1896 return SelectMaxValue;
1898 return SelectRandomValue;
1900 return SelectCenterValue;
1902 return SelectSplitValue;
1904 return SelectSplitValue;
1905 default:
1906 LOG(FATAL) << "Unknown int value strategy " << val_str;
1907 return nullptr;
1908 }
1909 }
1910
1911 void Accept(ModelVisitor* const visitor) const override {
1912 selector_->Accept(visitor);
1913 }
1914
1915 protected:
1916 BaseVariableAssignmentSelector* const selector_;
1917 const Mode mode_;
1918};
1919
1920BaseAssignVariables::~BaseAssignVariables() {}
1921
1922Decision* BaseAssignVariables::Next(Solver* const s) {
1923 const std::vector<IntVar*>& vars = selector_->vars();
1924 int id = selector_->ChooseVariableWrapper();
1925 if (id >= 0 && id < vars.size()) {
1926 IntVar* const var = vars[id];
1927 const int64_t value = selector_->SelectValue(var, id);
1928 switch (mode_) {
1929 case ASSIGN:
1930 return s->RevAlloc(new AssignOneVariableValue(var, value));
1931 case SPLIT_LOWER:
1932 return s->RevAlloc(new SplitOneVariable(var, value, true));
1933 case SPLIT_UPPER:
1934 return s->RevAlloc(new SplitOneVariable(var, value, false));
1935 }
1936 }
1937 return nullptr;
1938}
1939
1940std::string BaseAssignVariables::DebugString() const {
1941 return selector_->DebugString();
1942}
1943
1944BaseAssignVariables* BaseAssignVariables::MakePhase(
1945 Solver* const s, const std::vector<IntVar*>& vars,
1946 Solver::VariableIndexSelector var_selector,
1947 Solver::VariableValueSelector value_selector,
1948 const std::string& value_selector_name, BaseAssignVariables::Mode mode) {
1949 BaseVariableAssignmentSelector* const selector =
1950 s->RevAlloc(new VariableAssignmentSelector(
1951 s, vars, std::move(var_selector), std::move(value_selector),
1952 value_selector_name));
1953 return s->RevAlloc(new BaseAssignVariables(selector, mode));
1954}
1955
1956std::string ChooseVariableName(Solver::IntVarStrategy var_str) {
1957 switch (var_str) {
1961 return "ChooseFirstUnbound";
1963 return "ChooseRandom";
1965 return "ChooseMinSizeLowestMin";
1967 return "ChooseMinSizeHighestMin";
1969 return "ChooseMinSizeLowestMax";
1971 return "ChooseMinSizeHighestMax";
1973 return "ChooseLowestMin";
1975 return "ChooseHighestMax";
1977 return "ChooseMinSize";
1979 return "ChooseMaxSize;";
1981 return "HighestRegretSelectorOnMin";
1983 return "PathSelector";
1984 default:
1985 LOG(FATAL) << "Unknown int var strategy " << var_str;
1986 return "";
1987 }
1988}
1989
1990std::string SelectValueName(Solver::IntValueStrategy val_str) {
1991 switch (val_str) {
1995 return "SelectMinValue";
1997 return "SelectMaxValue";
1999 return "SelectRandomValue";
2001 return "SelectCenterValue";
2003 return "SelectSplitValue";
2005 return "SelectSplitValue";
2006 default:
2007 LOG(FATAL) << "Unknown int value strategy " << val_str;
2008 return "";
2009 }
2010}
2011
2012std::string BuildHeuristicsName(Solver::IntVarStrategy var_str,
2013 Solver::IntValueStrategy val_str) {
2014 return ChooseVariableName(var_str) + "_" + SelectValueName(val_str);
2015}
2016} // namespace
2017
2019 Solver::IntVarStrategy var_str,
2020 Solver::IntValueStrategy val_str) {
2021 std::vector<IntVar*> vars(1);
2022 vars[0] = v0;
2023 return MakePhase(vars, var_str, val_str);
2024}
2025
2027 Solver::IntVarStrategy var_str,
2028 Solver::IntValueStrategy val_str) {
2029 std::vector<IntVar*> vars(2);
2030 vars[0] = v0;
2031 vars[1] = v1;
2032 return MakePhase(vars, var_str, val_str);
2033}
2034
2036 IntVar* const v2,
2037 Solver::IntVarStrategy var_str,
2038 Solver::IntValueStrategy val_str) {
2039 std::vector<IntVar*> vars(3);
2040 vars[0] = v0;
2041 vars[1] = v1;
2042 vars[2] = v2;
2043 return MakePhase(vars, var_str, val_str);
2044}
2045
2047 IntVar* const v2, IntVar* const v3,
2048 Solver::IntVarStrategy var_str,
2049 Solver::IntValueStrategy val_str) {
2050 std::vector<IntVar*> vars(4);
2051 vars[0] = v0;
2052 vars[1] = v1;
2053 vars[2] = v2;
2054 vars[3] = v3;
2055 return MakePhase(vars, var_str, val_str);
2056}
2057
2058BaseAssignVariables::Mode ChooseMode(Solver::IntValueStrategy val_str) {
2059 BaseAssignVariables::Mode mode = BaseAssignVariables::ASSIGN;
2060 if (val_str == Solver::SPLIT_LOWER_HALF) {
2061 mode = BaseAssignVariables::SPLIT_LOWER;
2062 } else if (val_str == Solver::SPLIT_UPPER_HALF) {
2063 mode = BaseAssignVariables::SPLIT_UPPER;
2064 }
2065 return mode;
2066}
2067
2068DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2069 Solver::IntVarStrategy var_str,
2070 Solver::IntValueStrategy val_str) {
2071 Solver::VariableIndexSelector var_selector =
2072 BaseAssignVariables::MakeVariableSelector(this, vars, var_str);
2073 Solver::VariableValueSelector value_selector =
2074 BaseAssignVariables::MakeValueSelector(this, val_str);
2075 const std::string name = BuildHeuristicsName(var_str, val_str);
2076 return BaseAssignVariables::MakePhase(
2077 this, vars, var_selector, value_selector, name, ChooseMode(val_str));
2078}
2079
2080DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2081 Solver::IndexEvaluator1 var_evaluator,
2082 Solver::IntValueStrategy val_str) {
2083 CHECK(var_evaluator != nullptr);
2084 CheapestVarSelector* const var_selector =
2085 RevAlloc(new CheapestVarSelector(std::move(var_evaluator)));
2086 Solver::VariableIndexSelector choose_variable =
2087 [var_selector](Solver* solver, const std::vector<IntVar*>& vars,
2088 int first_unbound, int last_unbound) {
2089 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2090 };
2091 Solver::VariableValueSelector select_value =
2092 BaseAssignVariables::MakeValueSelector(this, val_str);
2093 const std::string name = "ChooseCheapestVariable_" + SelectValueName(val_str);
2094 return BaseAssignVariables::MakePhase(
2095 this, vars, choose_variable, select_value, name, ChooseMode(val_str));
2096}
2097
2098DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2099 Solver::IntVarStrategy var_str,
2100 Solver::IndexEvaluator2 value_evaluator) {
2101 Solver::VariableIndexSelector choose_variable =
2102 BaseAssignVariables::MakeVariableSelector(this, vars, var_str);
2103 CheapestValueSelector* const value_selector =
2104 RevAlloc(new CheapestValueSelector(std::move(value_evaluator), nullptr));
2105 Solver::VariableValueSelector select_value =
2106 [value_selector](const IntVar* var, int64_t id) {
2107 return value_selector->Select(var, id);
2108 };
2109 const std::string name = ChooseVariableName(var_str) + "_SelectCheapestValue";
2110 return BaseAssignVariables::MakePhase(this, vars, choose_variable,
2111 select_value, name,
2112 BaseAssignVariables::ASSIGN);
2113}
2114
2116 const std::vector<IntVar*>& vars, IntVarStrategy var_str,
2117 VariableValueComparator var_val1_val2_comparator) {
2118 Solver::VariableIndexSelector choose_variable =
2119 BaseAssignVariables::MakeVariableSelector(this, vars, var_str);
2120 BestValueByComparisonSelector* const value_selector = RevAlloc(
2121 new BestValueByComparisonSelector(std::move(var_val1_val2_comparator)));
2122 Solver::VariableValueSelector select_value =
2123 [value_selector](const IntVar* var, int64_t id) {
2124 return value_selector->Select(var, id);
2125 };
2126 return BaseAssignVariables::MakePhase(this, vars, choose_variable,
2127 select_value, "CheapestValue",
2128 BaseAssignVariables::ASSIGN);
2129}
2130
2131DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2132 Solver::IndexEvaluator1 var_evaluator,
2133 Solver::IndexEvaluator2 value_evaluator) {
2134 CheapestVarSelector* const var_selector =
2135 RevAlloc(new CheapestVarSelector(std::move(var_evaluator)));
2136 Solver::VariableIndexSelector choose_variable =
2137 [var_selector](Solver* solver, const std::vector<IntVar*>& vars,
2138 int first_unbound, int last_unbound) {
2139 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2140 };
2141 CheapestValueSelector* value_selector =
2142 RevAlloc(new CheapestValueSelector(std::move(value_evaluator), nullptr));
2143 Solver::VariableValueSelector select_value =
2144 [value_selector](const IntVar* var, int64_t id) {
2145 return value_selector->Select(var, id);
2146 };
2147 return BaseAssignVariables::MakePhase(this, vars, choose_variable,
2148 select_value, "CheapestValue",
2149 BaseAssignVariables::ASSIGN);
2150}
2151
2152DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2153 Solver::IntVarStrategy var_str,
2154 Solver::IndexEvaluator2 value_evaluator,
2155 Solver::IndexEvaluator1 tie_breaker) {
2156 Solver::VariableIndexSelector choose_variable =
2157 BaseAssignVariables::MakeVariableSelector(this, vars, var_str);
2158 CheapestValueSelector* value_selector = RevAlloc(new CheapestValueSelector(
2159 std::move(value_evaluator), std::move(tie_breaker)));
2160 Solver::VariableValueSelector select_value =
2161 [value_selector](const IntVar* var, int64_t id) {
2162 return value_selector->Select(var, id);
2163 };
2164 return BaseAssignVariables::MakePhase(this, vars, choose_variable,
2165 select_value, "CheapestValue",
2166 BaseAssignVariables::ASSIGN);
2167}
2168
2169DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2170 Solver::IndexEvaluator1 var_evaluator,
2171 Solver::IndexEvaluator2 value_evaluator,
2172 Solver::IndexEvaluator1 tie_breaker) {
2173 CheapestVarSelector* const var_selector =
2174 RevAlloc(new CheapestVarSelector(std::move(var_evaluator)));
2175 Solver::VariableIndexSelector choose_variable =
2176 [var_selector](Solver* solver, const std::vector<IntVar*>& vars,
2177 int first_unbound, int last_unbound) {
2178 return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2179 };
2180 CheapestValueSelector* value_selector = RevAlloc(new CheapestValueSelector(
2181 std::move(value_evaluator), std::move(tie_breaker)));
2182 Solver::VariableValueSelector select_value =
2183 [value_selector](const IntVar* var, int64_t id) {
2184 return value_selector->Select(var, id);
2185 };
2186 return BaseAssignVariables::MakePhase(this, vars, choose_variable,
2187 select_value, "CheapestValue",
2188 BaseAssignVariables::ASSIGN);
2189}
2190
2191DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2194 return MakePhase(vars, std::move(eval), nullptr, str);
2195}
2196
2197DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2199 Solver::IndexEvaluator1 tie_breaker,
2201 BaseVariableAssignmentSelector* selector = nullptr;
2202 switch (str) {
2204 // TODO(user): support tie breaker
2205 selector = RevAlloc(new StaticEvaluatorSelector(this, vars, eval));
2206 break;
2207 }
2209 selector = RevAlloc(new DynamicEvaluatorSelector(this, vars, eval,
2210 std::move(tie_breaker)));
2211 break;
2212 }
2213 }
2214 return RevAlloc(
2215 new BaseAssignVariables(selector, BaseAssignVariables::ASSIGN));
2216}
2217
2218// ----- AssignAllVariablesFromAssignment decision builder -----
2219
2220namespace {
2221class AssignVariablesFromAssignment : public DecisionBuilder {
2222 public:
2223 AssignVariablesFromAssignment(const Assignment* const assignment,
2224 DecisionBuilder* const db,
2225 const std::vector<IntVar*>& vars)
2226 : assignment_(assignment), db_(db), vars_(vars), iter_(0) {}
2227
2228 ~AssignVariablesFromAssignment() override {}
2229
2230 Decision* Next(Solver* const s) override {
2231 if (iter_ < vars_.size()) {
2232 IntVar* const var = vars_[iter_++];
2233 return s->RevAlloc(
2234 new AssignOneVariableValue(var, assignment_->Value(var)));
2235 } else {
2236 return db_->Next(s);
2237 }
2238 }
2239
2240 void Accept(ModelVisitor* const visitor) const override {
2241 visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
2242 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2243 vars_);
2244 visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
2245 }
2246
2247 private:
2248 const Assignment* const assignment_;
2249 DecisionBuilder* const db_;
2250 const std::vector<IntVar*> vars_;
2251 int iter_;
2252};
2253} // namespace
2254
2256 Assignment* const assignment, DecisionBuilder* const db,
2257 const std::vector<IntVar*>& vars) {
2258 return RevAlloc(new AssignVariablesFromAssignment(assignment, db, vars));
2259}
2260
2261// ---------- Solution Collectors -----------
2262
2263// ----- Base Class -----
2264
2266 const Assignment* const assignment)
2267 : SearchMonitor(solver),
2268 prototype_(assignment == nullptr ? nullptr : new Assignment(assignment)) {
2269}
2270
2272 : SearchMonitor(solver), prototype_(new Assignment(solver)) {}
2273
2275 for (auto& data : solution_data_) {
2276 delete data.solution;
2277 }
2279}
2280
2282 if (prototype_ != nullptr) {
2283 prototype_->Add(var);
2284 }
2285}
2286
2287void SolutionCollector::Add(const std::vector<IntVar*>& vars) {
2288 if (prototype_ != nullptr) {
2289 prototype_->Add(vars);
2290 }
2291}
2292
2294 if (prototype_ != nullptr) {
2295 prototype_->Add(var);
2296 }
2297}
2298
2299void SolutionCollector::Add(const std::vector<IntervalVar*>& vars) {
2300 if (prototype_ != nullptr) {
2301 prototype_->Add(vars);
2302 }
2303}
2304
2306 if (prototype_ != nullptr) {
2307 prototype_->Add(var);
2308 }
2309}
2310
2311void SolutionCollector::Add(const std::vector<SequenceVar*>& vars) {
2312 if (prototype_ != nullptr) {
2313 prototype_->Add(vars);
2314 }
2315}
2316
2318 if (prototype_ != nullptr && objective != nullptr) {
2319 prototype_->AddObjective(objective);
2320 }
2321}
2322
2324 for (auto& data : solution_data_) {
2325 delete data.solution;
2326 }
2328 solution_data_.clear();
2329 recycle_solutions_.clear();
2330}
2331
2334}
2335
2337 if (!solution_data_.empty()) {
2338 FreeSolution(solution_data_.back().solution);
2339 solution_data_.pop_back();
2340 }
2341}
2342
2345 Assignment* solution = nullptr;
2346 if (prototype_ != nullptr) {
2347 if (!recycle_solutions_.empty()) {
2349 DCHECK(solution != nullptr);
2350 recycle_solutions_.pop_back();
2351 } else {
2352 solution = new Assignment(prototype_.get());
2353 }
2354 solution->Store();
2355 }
2356 SolutionData data;
2357 data.solution = solution;
2358 data.time = solver()->wall_time();
2359 data.branches = solver()->branches();
2360 data.failures = solver()->failures();
2361 if (solution != nullptr) {
2363 } else {
2364 data.objective_value = 0;
2365 }
2366 return data;
2367}
2368
2370 if (solution != nullptr) {
2371 recycle_solutions_.push_back(solution);
2372 }
2373}
2374
2376 CHECK_GE(n, 0) << "wrong index in solution getter";
2377 CHECK_LT(n, solution_data_.size()) << "wrong index in solution getter";
2378}
2379
2381 check_index(n);
2382 return solution_data_[n].solution;
2383}
2384
2386
2387int64_t SolutionCollector::wall_time(int n) const {
2388 check_index(n);
2389 return solution_data_[n].time;
2390}
2391
2392int64_t SolutionCollector::branches(int n) const {
2393 check_index(n);
2394 return solution_data_[n].branches;
2395}
2396
2397int64_t SolutionCollector::failures(int n) const {
2398 check_index(n);
2399 return solution_data_[n].failures;
2400}
2401
2403 check_index(n);
2404 return solution_data_[n].objective_value;
2405}
2406
2407int64_t SolutionCollector::Value(int n, IntVar* const var) const {
2408 return solution(n)->Value(var);
2409}
2410
2411int64_t SolutionCollector::StartValue(int n, IntervalVar* const var) const {
2412 return solution(n)->StartValue(var);
2413}
2414
2416 return solution(n)->DurationValue(var);
2417}
2418
2419int64_t SolutionCollector::EndValue(int n, IntervalVar* const var) const {
2420 return solution(n)->EndValue(var);
2421}
2422
2424 return solution(n)->PerformedValue(var);
2425}
2426
2428 int n, SequenceVar* const var) const {
2429 return solution(n)->ForwardSequence(var);
2430}
2431
2433 int n, SequenceVar* const var) const {
2434 return solution(n)->BackwardSequence(var);
2435}
2436
2437const std::vector<int>& SolutionCollector::Unperformed(
2438 int n, SequenceVar* const var) const {
2439 return solution(n)->Unperformed(var);
2440}
2441
2442namespace {
2443// ----- First Solution Collector -----
2444
2445// Collect first solution, useful when looking satisfaction problems
2446class FirstSolutionCollector : public SolutionCollector {
2447 public:
2448 FirstSolutionCollector(Solver* const s, const Assignment* const a);
2449 explicit FirstSolutionCollector(Solver* const s);
2450 ~FirstSolutionCollector() override;
2451 void EnterSearch() override;
2452 bool AtSolution() override;
2453 std::string DebugString() const override;
2454
2455 private:
2456 bool done_;
2457};
2458
2459FirstSolutionCollector::FirstSolutionCollector(Solver* const s,
2460 const Assignment* const a)
2461 : SolutionCollector(s, a), done_(false) {}
2462
2463FirstSolutionCollector::FirstSolutionCollector(Solver* const s)
2464 : SolutionCollector(s), done_(false) {}
2465
2466FirstSolutionCollector::~FirstSolutionCollector() {}
2467
2468void FirstSolutionCollector::EnterSearch() {
2470 done_ = false;
2471}
2472
2473bool FirstSolutionCollector::AtSolution() {
2474 if (!done_) {
2475 PushSolution();
2476 done_ = true;
2477 }
2478 return false;
2479}
2480
2481std::string FirstSolutionCollector::DebugString() const {
2482 if (prototype_ == nullptr) {
2483 return "FirstSolutionCollector()";
2484 } else {
2485 return "FirstSolutionCollector(" + prototype_->DebugString() + ")";
2486 }
2487}
2488} // namespace
2489
2491 const Assignment* const assignment) {
2492 return RevAlloc(new FirstSolutionCollector(this, assignment));
2493}
2494
2496 return RevAlloc(new FirstSolutionCollector(this));
2497}
2498
2499// ----- Last Solution Collector -----
2500
2501// Collect last solution, useful when optimizing
2502namespace {
2503class LastSolutionCollector : public SolutionCollector {
2504 public:
2505 LastSolutionCollector(Solver* const s, const Assignment* const a);
2506 explicit LastSolutionCollector(Solver* const s);
2507 ~LastSolutionCollector() override;
2508 bool AtSolution() override;
2509 std::string DebugString() const override;
2510};
2511
2512LastSolutionCollector::LastSolutionCollector(Solver* const s,
2513 const Assignment* const a)
2514 : SolutionCollector(s, a) {}
2515
2516LastSolutionCollector::LastSolutionCollector(Solver* const s)
2517 : SolutionCollector(s) {}
2518
2519LastSolutionCollector::~LastSolutionCollector() {}
2520
2521bool LastSolutionCollector::AtSolution() {
2522 PopSolution();
2523 PushSolution();
2524 return true;
2525}
2526
2527std::string LastSolutionCollector::DebugString() const {
2528 if (prototype_ == nullptr) {
2529 return "LastSolutionCollector()";
2530 } else {
2531 return "LastSolutionCollector(" + prototype_->DebugString() + ")";
2532 }
2533}
2534} // namespace
2535
2537 const Assignment* const assignment) {
2538 return RevAlloc(new LastSolutionCollector(this, assignment));
2539}
2540
2542 return RevAlloc(new LastSolutionCollector(this));
2543}
2544
2545// ----- Best Solution Collector -----
2546
2547namespace {
2548class BestValueSolutionCollector : public SolutionCollector {
2549 public:
2550 BestValueSolutionCollector(Solver* const s, const Assignment* const a,
2551 bool maximize);
2552 BestValueSolutionCollector(Solver* const s, bool maximize);
2553 ~BestValueSolutionCollector() override {}
2554 void EnterSearch() override;
2555 bool AtSolution() override;
2556 std::string DebugString() const override;
2557
2558 public:
2559 const bool maximize_;
2560 int64_t best_;
2561};
2562
2563BestValueSolutionCollector::BestValueSolutionCollector(
2564 Solver* const s, const Assignment* const a, bool maximize)
2565 : SolutionCollector(s, a),
2566 maximize_(maximize),
2567 best_(maximize ? std::numeric_limits<int64_t>::min()
2568 : std::numeric_limits<int64_t>::max()) {}
2569
2570BestValueSolutionCollector::BestValueSolutionCollector(Solver* const s,
2571 bool maximize)
2572 : SolutionCollector(s),
2573 maximize_(maximize),
2574 best_(maximize ? std::numeric_limits<int64_t>::min()
2575 : std::numeric_limits<int64_t>::max()) {}
2576
2577void BestValueSolutionCollector::EnterSearch() {
2578 SolutionCollector::EnterSearch();
2580 : std::numeric_limits<int64_t>::max();
2581}
2582
2583bool BestValueSolutionCollector::AtSolution() {
2584 if (prototype_ != nullptr) {
2585 const IntVar* objective = prototype_->Objective();
2586 if (objective != nullptr) {
2587 if (maximize_ && (solution_count() == 0 || objective->Max() > best_)) {
2588 PopSolution();
2589 PushSolution();
2590 best_ = objective->Max();
2591 } else if (!maximize_ &&
2592 (solution_count() == 0 || objective->Min() < best_)) {
2593 PopSolution();
2594 PushSolution();
2595 best_ = objective->Min();
2596 }
2597 }
2598 }
2599 return true;
2600}
2601
2602std::string BestValueSolutionCollector::DebugString() const {
2603 if (prototype_ == nullptr) {
2604 return "BestValueSolutionCollector()";
2605 } else {
2606 return "BestValueSolutionCollector(" + prototype_->DebugString() + ")";
2607 }
2608}
2609} // namespace
2610
2611SolutionCollector* Solver::MakeBestValueSolutionCollector(
2612 const Assignment* const assignment, bool maximize) {
2613 return RevAlloc(new BestValueSolutionCollector(this, assignment, maximize));
2614}
2615
2616SolutionCollector* Solver::MakeBestValueSolutionCollector(bool maximize) {
2617 return RevAlloc(new BestValueSolutionCollector(this, maximize));
2618}
2619
2620// ----- N Best Solution Collector -----
2621
2622namespace {
2623class NBestValueSolutionCollector : public SolutionCollector {
2624 public:
2625 NBestValueSolutionCollector(Solver* const solver,
2626 const Assignment* const assignment,
2627 int solution_count, bool maximize);
2628 NBestValueSolutionCollector(Solver* const solver, int solution_count,
2629 bool maximize);
2630 ~NBestValueSolutionCollector() override { Clear(); }
2631 void EnterSearch() override;
2632 void ExitSearch() override;
2633 bool AtSolution() override;
2634 std::string DebugString() const override;
2635
2636 public:
2637 void Clear();
2638
2639 const bool maximize_;
2640 std::priority_queue<std::pair<int64_t, SolutionData>> solutions_pq_;
2642};
2643
2644NBestValueSolutionCollector::NBestValueSolutionCollector(
2645 Solver* const solver, const Assignment* const assignment,
2646 int solution_count, bool maximize)
2647 : SolutionCollector(solver, assignment),
2648 maximize_(maximize),
2649 solution_count_(solution_count) {}
2650
2651NBestValueSolutionCollector::NBestValueSolutionCollector(Solver* const solver,
2652 int solution_count,
2653 bool maximize)
2654 : SolutionCollector(solver),
2655 maximize_(maximize),
2656 solution_count_(solution_count) {}
2657
2658void NBestValueSolutionCollector::EnterSearch() {
2659 SolutionCollector::EnterSearch();
2660 // TODO(user): Remove this when fast local search works with
2661 // multiple solutions collected.
2662 if (solution_count_ > 1) {
2663 solver()->SetUseFastLocalSearch(false);
2664 }
2665 Clear();
2666}
2667
2668void NBestValueSolutionCollector::ExitSearch() {
2669 while (!solutions_pq_.empty()) {
2670 Push(solutions_pq_.top().second);
2671 solutions_pq_.pop();
2672 }
2673}
2674
2675bool NBestValueSolutionCollector::AtSolution() {
2676 if (prototype_ != nullptr) {
2677 const IntVar* objective = prototype_->Objective();
2678 if (objective != nullptr) {
2679 const int64_t objective_value =
2680 maximize_ ? CapSub(0, objective->Max()) : objective->Min();
2681 if (solutions_pq_.size() < solution_count_) {
2682 solutions_pq_.push(
2683 {objective_value, BuildSolutionDataForCurrentState()});
2684 } else if (!solutions_pq_.empty()) {
2685 const auto& top = solutions_pq_.top();
2686 if (top.first > objective_value) {
2687 FreeSolution(solutions_pq_.top().second.solution);
2688 solutions_pq_.pop();
2689 solutions_pq_.push(
2690 {objective_value, BuildSolutionDataForCurrentState()});
2691 }
2692 }
2693 }
2694 }
2695 return true;
2696}
2697
2698std::string NBestValueSolutionCollector::DebugString() const {
2699 if (prototype_ == nullptr) {
2700 return "NBestValueSolutionCollector()";
2701 } else {
2702 return "NBestValueSolutionCollector(" + prototype_->DebugString() + ")";
2703 }
2704}
2705
2706void NBestValueSolutionCollector::Clear() {
2707 while (!solutions_pq_.empty()) {
2708 delete solutions_pq_.top().second.solution;
2709 solutions_pq_.pop();
2710 }
2711}
2712
2713} // namespace
2714
2715SolutionCollector* Solver::MakeNBestValueSolutionCollector(
2716 const Assignment* const assignment, int solution_count, bool maximize) {
2717 if (solution_count == 1) {
2718 return MakeBestValueSolutionCollector(assignment, maximize);
2719 }
2720 return RevAlloc(new NBestValueSolutionCollector(this, assignment,
2721 solution_count, maximize));
2722}
2723
2724SolutionCollector* Solver::MakeNBestValueSolutionCollector(int solution_count,
2725 bool maximize) {
2726 if (solution_count == 1) {
2727 return MakeBestValueSolutionCollector(maximize);
2728 }
2729 return RevAlloc(
2730 new NBestValueSolutionCollector(this, solution_count, maximize));
2731}
2732
2733// ----- All Solution Collector -----
2734
2735// collect all solutions
2736namespace {
2737class AllSolutionCollector : public SolutionCollector {
2738 public:
2739 AllSolutionCollector(Solver* const s, const Assignment* const a);
2740 explicit AllSolutionCollector(Solver* const s);
2741 ~AllSolutionCollector() override;
2742 bool AtSolution() override;
2743 std::string DebugString() const override;
2744};
2745
2746AllSolutionCollector::AllSolutionCollector(Solver* const s,
2747 const Assignment* const a)
2748 : SolutionCollector(s, a) {}
2749
2750AllSolutionCollector::AllSolutionCollector(Solver* const s)
2751 : SolutionCollector(s) {}
2752
2753AllSolutionCollector::~AllSolutionCollector() {}
2754
2755bool AllSolutionCollector::AtSolution() {
2756 PushSolution();
2757 return true;
2758}
2759
2760std::string AllSolutionCollector::DebugString() const {
2761 if (prototype_ == nullptr) {
2762 return "AllSolutionCollector()";
2763 } else {
2764 return "AllSolutionCollector(" + prototype_->DebugString() + ")";
2765 }
2766}
2767} // namespace
2768
2770 const Assignment* const assignment) {
2771 return RevAlloc(new AllSolutionCollector(this, assignment));
2772}
2773
2775 return RevAlloc(new AllSolutionCollector(this));
2776}
2777
2778// ---------- Objective Management ----------
2779
2780OptimizeVar::OptimizeVar(Solver* const s, bool maximize, IntVar* const a,
2781 int64_t step)
2782 : SearchMonitor(s),
2783 var_(a),
2784 step_(step),
2785 best_(std::numeric_limits<int64_t>::max()),
2786 maximize_(maximize),
2787 found_initial_solution_(false) {
2788 CHECK_GT(step_, 0);
2789 // TODO(user): Store optimization direction in Solver. Besides making the
2790 // code simpler it would also having two monitors optimizing in opposite
2791 // directions.
2792 if (maximize) {
2794 } else {
2796 }
2797}
2798
2800
2803 if (maximize_) {
2805 } else {
2807 }
2808}
2809
2811 if (solver()->SearchDepth() == 0) { // after a restart.
2812 ApplyBound();
2813 }
2814}
2815
2818 if (maximize_) {
2819 var_->SetMin(best_ + step_);
2820 } else {
2821 var_->SetMax(best_ - step_);
2822 }
2823 }
2824}
2825
2827
2829 const int64_t val = var_->Value();
2831 return true;
2832 } else {
2833 // This code should never return false in sequential mode because
2834 // ApplyBound should have been called before. In parallel, this is
2835 // no longer true. That is why we keep it there, just in case.
2836 return (maximize_ && val > best_) || (!maximize_ && val < best_);
2837 }
2838}
2839
2841 int64_t val = var_->Value();
2842 if (maximize_) {
2844 best_ = val;
2845 } else {
2847 best_ = val;
2848 }
2850 return true;
2851}
2852
2854 if (delta != nullptr) {
2855 const bool delta_has_objective = delta->HasObjective();
2856 if (!delta_has_objective) {
2857 delta->AddObjective(var_);
2858 }
2859 if (delta->Objective() == var_) {
2860 const Assignment* const local_search_state =
2862 if (maximize_) {
2863 const int64_t delta_min_objective =
2864 delta_has_objective ? delta->ObjectiveMin()
2866 const int64_t min_objective =
2867 local_search_state->HasObjective()
2868 ? CapAdd(local_search_state->ObjectiveMin(), step_)
2870 delta->SetObjectiveMin(
2871 std::max({var_->Min(), min_objective, delta_min_objective}));
2872
2873 } else {
2874 const int64_t delta_max_objective =
2875 delta_has_objective ? delta->ObjectiveMax()
2877 const int64_t max_objective =
2878 local_search_state->HasObjective()
2879 ? CapSub(local_search_state->ObjectiveMax(), step_)
2881 delta->SetObjectiveMax(
2882 std::min({var_->Max(), max_objective, delta_max_objective}));
2883 }
2884 }
2885 }
2886 return true;
2887}
2888
2889std::string OptimizeVar::Print() const {
2890 return absl::StrFormat("objective value = %d, ", var_->Value());
2891}
2892
2893std::string OptimizeVar::DebugString() const {
2894 std::string out;
2895 if (maximize_) {
2896 out = "MaximizeVar(";
2897 } else {
2898 out = "MinimizeVar(";
2899 }
2900 absl::StrAppendFormat(&out, "%s, step = %d, best = %d)", var_->DebugString(),
2901 step_, best_);
2902 return out;
2903}
2904
2905void OptimizeVar::Accept(ModelVisitor* const visitor) const {
2910 var_);
2912}
2913
2914OptimizeVar* Solver::MakeMinimize(IntVar* const v, int64_t step) {
2915 return RevAlloc(new OptimizeVar(this, false, v, step));
2916}
2917
2918OptimizeVar* Solver::MakeMaximize(IntVar* const v, int64_t step) {
2919 return RevAlloc(new OptimizeVar(this, true, v, step));
2920}
2921
2922OptimizeVar* Solver::MakeOptimize(bool maximize, IntVar* const v,
2923 int64_t step) {
2924 return RevAlloc(new OptimizeVar(this, maximize, v, step));
2925}
2926
2927namespace {
2928class WeightedOptimizeVar : public OptimizeVar {
2929 public:
2930 WeightedOptimizeVar(Solver* solver, bool maximize,
2931 const std::vector<IntVar*>& sub_objectives,
2932 const std::vector<int64_t>& weights, int64_t step)
2933 : OptimizeVar(solver, maximize,
2934 solver->MakeScalProd(sub_objectives, weights)->Var(), step),
2935 sub_objectives_(sub_objectives),
2936 weights_(weights) {
2937 CHECK_EQ(sub_objectives.size(), weights.size());
2938 }
2939
2940 ~WeightedOptimizeVar() override {}
2941 std::string Print() const override;
2942
2943 private:
2944 const std::vector<IntVar*> sub_objectives_;
2945 const std::vector<int64_t> weights_;
2946
2947 DISALLOW_COPY_AND_ASSIGN(WeightedOptimizeVar);
2948};
2949
2950std::string WeightedOptimizeVar::Print() const {
2951 std::string result(OptimizeVar::Print());
2952 result.append("\nWeighted Objective:\n");
2953 for (int i = 0; i < sub_objectives_.size(); ++i) {
2954 absl::StrAppendFormat(&result, "Variable %s,\tvalue %d,\tweight %d\n",
2955 sub_objectives_[i]->name(),
2956 sub_objectives_[i]->Value(), weights_[i]);
2957 }
2958 return result;
2959}
2960} // namespace
2961
2963 bool maximize, const std::vector<IntVar*>& sub_objectives,
2964 const std::vector<int64_t>& weights, int64_t step) {
2965 return RevAlloc(
2966 new WeightedOptimizeVar(this, maximize, sub_objectives, weights, step));
2967}
2968
2970 const std::vector<IntVar*>& sub_objectives,
2971 const std::vector<int64_t>& weights, int64_t step) {
2972 return RevAlloc(
2973 new WeightedOptimizeVar(this, false, sub_objectives, weights, step));
2974}
2975
2977 const std::vector<IntVar*>& sub_objectives,
2978 const std::vector<int64_t>& weights, int64_t step) {
2979 return RevAlloc(
2980 new WeightedOptimizeVar(this, true, sub_objectives, weights, step));
2981}
2982
2984 bool maximize, const std::vector<IntVar*>& sub_objectives,
2985 const std::vector<int>& weights, int64_t step) {
2986 return MakeWeightedOptimize(maximize, sub_objectives, ToInt64Vector(weights),
2987 step);
2988}
2989
2991 const std::vector<IntVar*>& sub_objectives, const std::vector<int>& weights,
2992 int64_t step) {
2993 return MakeWeightedMinimize(sub_objectives, ToInt64Vector(weights), step);
2994}
2995
2997 const std::vector<IntVar*>& sub_objectives, const std::vector<int>& weights,
2998 int64_t step) {
2999 return MakeWeightedMaximize(sub_objectives, ToInt64Vector(weights), step);
3000}
3001
3002// ---------- Metaheuristics ---------
3003
3004namespace {
3005class Metaheuristic : public SearchMonitor {
3006 public:
3007 Metaheuristic(Solver* const solver, bool maximize, IntVar* objective,
3008 int64_t step);
3009 ~Metaheuristic() override {}
3010
3011 bool AtSolution() override;
3012 void EnterSearch() override;
3013 void RefuteDecision(Decision* const d) override;
3014 bool AcceptDelta(Assignment* delta, Assignment* deltadelta) override;
3015
3016 protected:
3017 IntVar* const objective_;
3018 int64_t step_;
3019 int64_t current_;
3020 int64_t best_;
3021 bool maximize_;
3022};
3023
3024Metaheuristic::Metaheuristic(Solver* const solver, bool maximize,
3025 IntVar* objective, int64_t step)
3026 : SearchMonitor(solver),
3027 objective_(objective),
3028 step_(step),
3029 current_(std::numeric_limits<int64_t>::max()),
3030 best_(std::numeric_limits<int64_t>::max()),
3031 maximize_(maximize) {}
3032
3033bool Metaheuristic::AtSolution() {
3034 current_ = objective_->Value();
3035 if (maximize_) {
3037 } else {
3039 }
3040 return true;
3041}
3042
3043void Metaheuristic::EnterSearch() {
3044 // TODO(user): Remove this when fast local search works with
3045 // metaheuristics.
3046 solver()->SetUseFastLocalSearch(false);
3047 if (maximize_) {
3048 best_ = objective_->Min();
3050 } else {
3051 best_ = objective_->Max();
3053 }
3054}
3055
3056void Metaheuristic::RefuteDecision(Decision* d) {
3057 if (maximize_) {
3058 if (objective_->Max() < best_ + step_) {
3059 solver()->Fail();
3060 }
3061 } else if (objective_->Min() > best_ - step_) {
3062 solver()->Fail();
3063 }
3064}
3065
3066bool Metaheuristic::AcceptDelta(Assignment* delta, Assignment* deltadelta) {
3067 if (delta != nullptr) {
3068 if (!delta->HasObjective()) {
3069 delta->AddObjective(objective_);
3070 }
3071 if (delta->Objective() == objective_) {
3072 if (maximize_) {
3073 delta->SetObjectiveMin(
3074 std::max(objective_->Min(), delta->ObjectiveMin()));
3075 } else {
3076 delta->SetObjectiveMax(
3077 std::min(objective_->Max(), delta->ObjectiveMax()));
3078 }
3079 }
3080 }
3081 return true;
3082}
3083
3084// ---------- Tabu Search ----------
3085
3086class TabuSearch : public Metaheuristic {
3087 public:
3088 TabuSearch(Solver* const s, bool maximize, IntVar* objective, int64_t step,
3089 const std::vector<IntVar*>& vars, int64_t keep_tenure,
3090 int64_t forbid_tenure, double tabu_factor);
3091 ~TabuSearch() override {}
3092 void EnterSearch() override;
3093 void ApplyDecision(Decision* d) override;
3094 bool AtSolution() override;
3095 bool LocalOptimum() override;
3096 void AcceptNeighbor() override;
3097 std::string DebugString() const override { return "Tabu Search"; }
3098
3099 protected:
3100 struct VarValue {
3101 VarValue(IntVar* const var, int64_t value, int64_t stamp)
3102 : var_(var), value_(value), stamp_(stamp) {}
3103 IntVar* const var_;
3104 const int64_t value_;
3105 const int64_t stamp_;
3106 };
3107 typedef std::list<VarValue> TabuList;
3108
3109 virtual std::vector<IntVar*> CreateTabuVars();
3110 const TabuList& forbid_tabu_list() { return forbid_tabu_list_; }
3111
3112 private:
3113 void AgeList(int64_t tenure, TabuList* list);
3114 void AgeLists();
3115
3116 const std::vector<IntVar*> vars_;
3117 Assignment assignment_;
3118 int64_t last_;
3119 TabuList keep_tabu_list_;
3120 int64_t keep_tenure_;
3121 TabuList forbid_tabu_list_;
3122 int64_t forbid_tenure_;
3123 double tabu_factor_;
3124 int64_t stamp_;
3125 bool found_initial_solution_;
3126
3127 DISALLOW_COPY_AND_ASSIGN(TabuSearch);
3128};
3129
3130TabuSearch::TabuSearch(Solver* const s, bool maximize, IntVar* objective,
3131 int64_t step, const std::vector<IntVar*>& vars,
3132 int64_t keep_tenure, int64_t forbid_tenure,
3133 double tabu_factor)
3134 : Metaheuristic(s, maximize, objective, step),
3135 vars_(vars),
3136 assignment_(s),
3137 last_(std::numeric_limits<int64_t>::max()),
3138 keep_tenure_(keep_tenure),
3139 forbid_tenure_(forbid_tenure),
3140 tabu_factor_(tabu_factor),
3141 stamp_(0),
3142 found_initial_solution_(false) {
3143 assignment_.Add(vars_);
3144}
3145
3146void TabuSearch::EnterSearch() {
3147 Metaheuristic::EnterSearch();
3148 found_initial_solution_ = false;
3149}
3150
3151void TabuSearch::ApplyDecision(Decision* const d) {
3152 Solver* const s = solver();
3153 if (d == s->balancing_decision()) {
3154 return;
3155 }
3156 // Aspiration criterion
3157 // Accept a neighbor if it improves the best solution found so far
3158 IntVar* aspiration = s->MakeBoolVar();
3159 if (maximize_) {
3160 s->AddConstraint(s->MakeIsGreaterOrEqualCstCt(
3161 objective_, CapAdd(best_, step_), aspiration));
3162 } else {
3163 s->AddConstraint(s->MakeIsLessOrEqualCstCt(objective_, CapSub(best_, step_),
3164 aspiration));
3165 }
3166
3167 IntVar* tabu_var = nullptr;
3168 {
3169 // Creating the vector in a scope to make sure it gets deleted before
3170 // adding further constraints which could fail and lead to a leak.
3171 const std::vector<IntVar*> tabu_vars = CreateTabuVars();
3172 if (!tabu_vars.empty()) {
3173 tabu_var = s->MakeIsGreaterOrEqualCstVar(s->MakeSum(tabu_vars)->Var(),
3174 tabu_vars.size() * tabu_factor_);
3175 }
3176 }
3177
3178 if (tabu_var != nullptr) {
3179 s->AddConstraint(
3180 s->MakeGreaterOrEqual(s->MakeSum(aspiration, tabu_var), int64_t{1}));
3181 }
3182
3183 // Go downhill to the next local optimum
3184 if (maximize_) {
3186 ? current_ + step_
3187 : current_;
3188 s->AddConstraint(s->MakeGreaterOrEqual(objective_, bound));
3189 } else {
3191 ? current_ - step_
3192 : current_;
3193 s->AddConstraint(s->MakeLessOrEqual(objective_, bound));
3194 }
3195
3196 // Avoid cost plateau's which lead to tabu cycles
3197 if (found_initial_solution_) {
3198 s->AddConstraint(s->MakeNonEquality(objective_, last_));
3199 }
3200}
3201
3202std::vector<IntVar*> TabuSearch::CreateTabuVars() {
3203 Solver* const s = solver();
3204
3205 // Tabu criterion
3206 // A variable in the "keep" list must keep its value, a variable in the
3207 // "forbid" list must not take its value in the list. The tabu criterion is
3208 // softened by the tabu factor which gives the number of violations to
3209 // the tabu criterion which is tolerated; a factor of 1 means no violations
3210 // allowed, a factor of 0 means all violations allowed.
3211 std::vector<IntVar*> tabu_vars;
3212 for (const VarValue& vv : keep_tabu_list_) {
3213 tabu_vars.push_back(s->MakeIsEqualCstVar(vv.var_, vv.value_));
3214 }
3215 for (const VarValue& vv : forbid_tabu_list_) {
3216 tabu_vars.push_back(s->MakeIsDifferentCstVar(vv.var_, vv.value_));
3217 }
3218 return tabu_vars;
3219}
3220
3221bool TabuSearch::AtSolution() {
3222 if (!Metaheuristic::AtSolution()) {
3223 return false;
3224 }
3225 found_initial_solution_ = true;
3226 last_ = current_;
3227
3228 // New solution found: add new assignments to tabu lists; this is only
3229 // done after the first local optimum (stamp_ != 0)
3230 if (0 != stamp_) {
3231 for (int i = 0; i < vars_.size(); ++i) {
3232 IntVar* const var = vars_[i];
3233 const int64_t old_value = assignment_.Value(var);
3234 const int64_t new_value = var->Value();
3235 if (old_value != new_value) {
3236 if (keep_tenure_ > 0) {
3237 VarValue keep_value(var, new_value, stamp_);
3238 keep_tabu_list_.push_front(keep_value);
3239 }
3240 if (forbid_tenure_ > 0) {
3241 VarValue forbid_value(var, old_value, stamp_);
3242 forbid_tabu_list_.push_front(forbid_value);
3243 }
3244 }
3245 }
3246 }
3247 assignment_.Store();
3248
3249 return true;
3250}
3251
3252bool TabuSearch::LocalOptimum() {
3253 AgeLists();
3254 if (maximize_) {
3256 } else {
3258 }
3259 return found_initial_solution_;
3260}
3261
3263 if (0 != stamp_) {
3264 AgeLists();
3265 }
3266}
3267
3268void TabuSearch::AgeList(int64_t tenure, TabuList* list) {
3269 while (!list->empty() && list->back().stamp_ < stamp_ - tenure) {
3270 list->pop_back();
3271 }
3272}
3273
3274void TabuSearch::AgeLists() {
3275 AgeList(keep_tenure_, &keep_tabu_list_);
3276 AgeList(forbid_tenure_, &forbid_tabu_list_);
3277 ++stamp_;
3278}
3279
3280class GenericTabuSearch : public TabuSearch {
3281 public:
3282 GenericTabuSearch(Solver* const s, bool maximize, IntVar* objective,
3283 int64_t step, const std::vector<IntVar*>& vars,
3284 int64_t forbid_tenure)
3285 : TabuSearch(s, maximize, objective, step, vars, 0, forbid_tenure, 1) {}
3286 std::string DebugString() const override { return "Generic Tabu Search"; }
3287
3288 protected:
3289 std::vector<IntVar*> CreateTabuVars() override;
3290};
3291
3292std::vector<IntVar*> GenericTabuSearch::CreateTabuVars() {
3293 Solver* const s = solver();
3294
3295 // Tabu criterion
3296 // At least one element of the forbid_tabu_list must change value.
3297 std::vector<IntVar*> forbid_values;
3298 for (const VarValue& vv : forbid_tabu_list()) {
3299 forbid_values.push_back(s->MakeIsDifferentCstVar(vv.var_, vv.value_));
3300 }
3301 std::vector<IntVar*> tabu_vars;
3302 if (!forbid_values.empty()) {
3303 tabu_vars.push_back(s->MakeIsGreaterCstVar(s->MakeSum(forbid_values), 0));
3304 }
3305 return tabu_vars;
3306}
3307
3308} // namespace
3309
3310SearchMonitor* Solver::MakeTabuSearch(bool maximize, IntVar* const v,
3311 int64_t step,
3312 const std::vector<IntVar*>& vars,
3313 int64_t keep_tenure,
3314 int64_t forbid_tenure,
3315 double tabu_factor) {
3316 return RevAlloc(new TabuSearch(this, maximize, v, step, vars, keep_tenure,
3317 forbid_tenure, tabu_factor));
3318}
3319
3320SearchMonitor* Solver::MakeGenericTabuSearch(
3321 bool maximize, IntVar* const v, int64_t step,
3322 const std::vector<IntVar*>& tabu_vars, int64_t forbid_tenure) {
3323 return RevAlloc(
3324 new GenericTabuSearch(this, maximize, v, step, tabu_vars, forbid_tenure));
3325}
3326
3327// ---------- Simulated Annealing ----------
3328
3329namespace {
3330class SimulatedAnnealing : public Metaheuristic {
3331 public:
3332 SimulatedAnnealing(Solver* const s, bool maximize, IntVar* objective,
3333 int64_t step, int64_t initial_temperature);
3334 ~SimulatedAnnealing() override {}
3335 void EnterSearch() override;
3336 void ApplyDecision(Decision* d) override;
3337 bool AtSolution() override;
3338 bool LocalOptimum() override;
3339 void AcceptNeighbor() override;
3340 std::string DebugString() const override { return "Simulated Annealing"; }
3341
3342 private:
3343 double Temperature() const;
3344
3345 const int64_t temperature0_;
3346 int64_t iteration_;
3347 std::mt19937 rand_;
3348 bool found_initial_solution_;
3349
3350 DISALLOW_COPY_AND_ASSIGN(SimulatedAnnealing);
3351};
3352
3353SimulatedAnnealing::SimulatedAnnealing(Solver* const s, bool maximize,
3354 IntVar* objective, int64_t step,
3355 int64_t initial_temperature)
3356 : Metaheuristic(s, maximize, objective, step),
3357 temperature0_(initial_temperature),
3358 iteration_(0),
3359 rand_(CpRandomSeed()),
3360 found_initial_solution_(false) {}
3361
3362void SimulatedAnnealing::EnterSearch() {
3363 Metaheuristic::EnterSearch();
3364 found_initial_solution_ = false;
3365}
3366
3367void SimulatedAnnealing::ApplyDecision(Decision* const d) {
3368 Solver* const s = solver();
3369 if (d == s->balancing_decision()) {
3370 return;
3371 }
3372 const double rand_double = absl::Uniform<double>(rand_, 0.0, 1.0);
3373#if defined(_MSC_VER) || defined(__ANDROID__)
3374 const double rand_log2_double = log(rand_double) / log(2.0L);
3375#else
3376 const double rand_log2_double = log2(rand_double);
3377#endif
3378 const int64_t energy_bound = Temperature() * rand_log2_double;
3379 if (maximize_) {
3381 ? current_ + step_ + energy_bound
3382 : current_;
3383 s->AddConstraint(s->MakeGreaterOrEqual(objective_, bound));
3384 } else {
3386 ? current_ - step_ - energy_bound
3387 : current_;
3388 s->AddConstraint(s->MakeLessOrEqual(objective_, bound));
3389 }
3390}
3391
3392bool SimulatedAnnealing::AtSolution() {
3393 if (!Metaheuristic::AtSolution()) {
3394 return false;
3395 }
3396 found_initial_solution_ = true;
3397 return true;
3398}
3399
3400bool SimulatedAnnealing::LocalOptimum() {
3401 if (maximize_) {
3403 } else {
3405 }
3406 ++iteration_;
3407 return found_initial_solution_ && Temperature() > 0;
3408}
3409
3411 if (iteration_ > 0) {
3412 ++iteration_;
3413 }
3414}
3415
3416double SimulatedAnnealing::Temperature() const {
3417 if (iteration_ > 0) {
3418 return (1.0 * temperature0_) / iteration_; // Cauchy annealing
3419 } else {
3420 return 0.;
3421 }
3422}
3423} // namespace
3424
3426 int64_t step,
3427 int64_t initial_temperature) {
3428 return RevAlloc(
3429 new SimulatedAnnealing(this, maximize, v, step, initial_temperature));
3430}
3431
3432// ---------- Guided Local Search ----------
3433
3434typedef std::pair<int64_t, int64_t> Arc;
3435
3436namespace {
3437// Base GLS penalties abstract class. Maintains the penalty frequency for each
3438// (variable, value) arc.
3439class GuidedLocalSearchPenalties {
3440 public:
3441 virtual ~GuidedLocalSearchPenalties() {}
3442 virtual bool HasValues() const = 0;
3443 virtual void Increment(const Arc& arc) = 0;
3444 virtual int64_t Value(const Arc& arc) const = 0;
3445 virtual void Reset() = 0;
3446};
3447
3448// Dense GLS penalties implementation using a matrix to store penalties.
3449class GuidedLocalSearchPenaltiesTable : public GuidedLocalSearchPenalties {
3450 public:
3451 explicit GuidedLocalSearchPenaltiesTable(int size);
3452 ~GuidedLocalSearchPenaltiesTable() override {}
3453 bool HasValues() const override { return has_values_; }
3454 void Increment(const Arc& arc) override;
3455 int64_t Value(const Arc& arc) const override;
3456 void Reset() override;
3457
3458 private:
3459 std::vector<std::vector<int64_t>> penalties_;
3460 bool has_values_;
3461};
3462
3463GuidedLocalSearchPenaltiesTable::GuidedLocalSearchPenaltiesTable(int size)
3464 : penalties_(size), has_values_(false) {}
3465
3466void GuidedLocalSearchPenaltiesTable::Increment(const Arc& arc) {
3467 std::vector<int64_t>& first_penalties = penalties_[arc.first];
3468 const int64_t second = arc.second;
3469 if (second >= first_penalties.size()) {
3470 first_penalties.resize(second + 1, 0);
3471 }
3472 ++first_penalties[second];
3473 has_values_ = true;
3474}
3475
3476void GuidedLocalSearchPenaltiesTable::Reset() {
3477 has_values_ = false;
3478 for (int i = 0; i < penalties_.size(); ++i) {
3479 penalties_[i].clear();
3480 }
3481}
3482
3483int64_t GuidedLocalSearchPenaltiesTable::Value(const Arc& arc) const {
3484 const std::vector<int64_t>& first_penalties = penalties_[arc.first];
3485 const int64_t second = arc.second;
3486 if (second >= first_penalties.size()) {
3487 return 0;
3488 } else {
3489 return first_penalties[second];
3490 }
3491}
3492
3493// Sparse GLS penalties implementation using hash_map to store penalties.
3494class GuidedLocalSearchPenaltiesMap : public GuidedLocalSearchPenalties {
3495 public:
3496 explicit GuidedLocalSearchPenaltiesMap(int size);
3497 ~GuidedLocalSearchPenaltiesMap() override {}
3498 bool HasValues() const override { return (!penalties_.empty()); }
3499 void Increment(const Arc& arc) override;
3500 int64_t Value(const Arc& arc) const override;
3501 void Reset() override;
3502
3503 private:
3504 Bitmap penalized_;
3505 absl::flat_hash_map<Arc, int64_t> penalties_;
3506};
3507
3508GuidedLocalSearchPenaltiesMap::GuidedLocalSearchPenaltiesMap(int size)
3509 : penalized_(size, false) {}
3510
3511void GuidedLocalSearchPenaltiesMap::Increment(const Arc& arc) {
3512 ++penalties_[arc];
3513 penalized_.Set(arc.first, true);
3514}
3515
3516void GuidedLocalSearchPenaltiesMap::Reset() {
3517 penalties_.clear();
3518 penalized_.Clear();
3519}
3520
3521int64_t GuidedLocalSearchPenaltiesMap::Value(const Arc& arc) const {
3522 if (penalized_.Get(arc.first)) {
3523 return gtl::FindWithDefault(penalties_, arc, 0);
3524 }
3525 return 0;
3526}
3527
3528class GuidedLocalSearch : public Metaheuristic {
3529 public:
3530 GuidedLocalSearch(Solver* const s, IntVar* objective, bool maximize,
3531 int64_t step, const std::vector<IntVar*>& vars,
3532 double penalty_factor);
3533 ~GuidedLocalSearch() override {}
3534 bool AcceptDelta(Assignment* delta, Assignment* deltadelta) override;
3535 void ApplyDecision(Decision* d) override;
3536 bool AtSolution() override;
3537 void EnterSearch() override;
3538 bool LocalOptimum() override;
3539 virtual int64_t AssignmentElementPenalty(const Assignment& assignment,
3540 int index) = 0;
3541 virtual int64_t AssignmentPenalty(const Assignment& assignment, int index,
3542 int64_t next) = 0;
3543 virtual bool EvaluateElementValue(const Assignment::IntContainer& container,
3544 int64_t index, int* container_index,
3545 int64_t* penalty) = 0;
3546 virtual IntExpr* MakeElementPenalty(int index) = 0;
3547 std::string DebugString() const override { return "Guided Local Search"; }
3548
3549 protected:
3550 struct Comparator {
3551 bool operator()(const std::pair<Arc, double>& i,
3552 const std::pair<Arc, double>& j) {
3553 return i.second > j.second;
3554 }
3555 };
3556
3557 int64_t Evaluate(const Assignment* delta, int64_t current_penalty,
3558 const int64_t* const out_values, bool cache_delta_values);
3559
3561 Assignment assignment_;
3564 const std::vector<IntVar*> vars_;
3565 absl::flat_hash_map<const IntVar*, int64_t> indices_;
3566 const double penalty_factor_;
3567 std::unique_ptr<GuidedLocalSearchPenalties> penalties_;
3568 std::unique_ptr<int64_t[]> current_penalized_values_;
3569 std::unique_ptr<int64_t[]> delta_cache_;
3571};
3572
3573GuidedLocalSearch::GuidedLocalSearch(Solver* const s, IntVar* objective,
3574 bool maximize, int64_t step,
3575 const std::vector<IntVar*>& vars,
3576 double penalty_factor)
3577 : Metaheuristic(s, maximize, objective, step),
3578 penalized_objective_(nullptr),
3579 assignment_(s),
3582 vars_(vars),
3583 penalty_factor_(penalty_factor),
3584 incremental_(false) {
3585 if (!vars.empty()) {
3586 // TODO(user): Remove scoped_array.
3587 assignment_.Add(vars_);
3588 current_penalized_values_ = absl::make_unique<int64_t[]>(vars_.size());
3589 delta_cache_ = absl::make_unique<int64_t[]>(vars_.size());
3590 memset(current_penalized_values_.get(), 0,
3591 vars_.size() * sizeof(*current_penalized_values_.get()));
3592 }
3593 for (int i = 0; i < vars_.size(); ++i) {
3594 indices_[vars_[i]] = i;
3595 }
3596 if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
3597 penalties_ = absl::make_unique<GuidedLocalSearchPenaltiesMap>(vars_.size());
3598 } else {
3599 penalties_ =
3600 absl::make_unique<GuidedLocalSearchPenaltiesTable>(vars_.size());
3601 }
3602}
3603
3604// Add the following constraint (includes aspiration criterion):
3605// if minimizing,
3606// objective =< Max(current penalized cost - penalized_objective - step,
3607// best solution cost - step)
3608// if maximizing,
3609// objective >= Min(current penalized cost - penalized_objective + step,
3610// best solution cost + step)
3611void GuidedLocalSearch::ApplyDecision(Decision* const d) {
3612 if (d == solver()->balancing_decision()) {
3613 return;
3614 }
3616 if (penalties_->HasValues()) {
3617 // Computing sum of penalties expression.
3618 // Scope needed to avoid potential leak of elements.
3619 {
3620 std::vector<IntVar*> elements;
3621 for (int i = 0; i < vars_.size(); ++i) {
3622 elements.push_back(MakeElementPenalty(i)->Var());
3623 const int64_t penalty = AssignmentElementPenalty(assignment_, i);
3624 current_penalized_values_[i] = penalty;
3625 delta_cache_[i] = penalty;
3628 }
3629 penalized_objective_ = solver()->MakeSum(elements)->Var();
3630 }
3632 incremental_ = false;
3633 if (maximize_) {
3634 IntExpr* min_pen_exp =
3635 solver()->MakeDifference(current_ + step_, penalized_objective_);
3636 IntVar* min_exp = solver()->MakeMin(min_pen_exp, best_ + step_)->Var();
3637 solver()->AddConstraint(
3638 solver()->MakeGreaterOrEqual(objective_, min_exp));
3639 } else {
3640 IntExpr* max_pen_exp =
3641 solver()->MakeDifference(current_ - step_, penalized_objective_);
3642 IntVar* max_exp = solver()->MakeMax(max_pen_exp, best_ - step_)->Var();
3643 solver()->AddConstraint(solver()->MakeLessOrEqual(objective_, max_exp));
3644 }
3645 } else {
3646 penalized_objective_ = nullptr;
3647 if (maximize_) {
3649 ? current_ + step_
3650 : current_;
3651 objective_->SetMin(bound);
3652 } else {
3654 ? current_ - step_
3655 : current_;
3656 objective_->SetMax(bound);
3657 }
3658 }
3659}
3660
3661bool GuidedLocalSearch::AtSolution() {
3662 if (!Metaheuristic::AtSolution()) {
3663 return false;
3664 }
3665 if (penalized_objective_ != nullptr) { // In case no move has been found
3666 current_ += penalized_objective_->Value();
3667 }
3668 assignment_.Store();
3669 return true;
3670}
3671
3672void GuidedLocalSearch::EnterSearch() {
3673 Metaheuristic::EnterSearch();
3674 penalized_objective_ = nullptr;
3677 memset(current_penalized_values_.get(), 0,
3678 vars_.size() * sizeof(*current_penalized_values_.get()));
3679 penalties_->Reset();
3680}
3681
3682// GLS filtering; compute the penalized value corresponding to the delta and
3683// modify objective bound accordingly.
3684bool GuidedLocalSearch::AcceptDelta(Assignment* delta, Assignment* deltadelta) {
3685 if (delta != nullptr || deltadelta != nullptr) {
3686 if (!penalties_->HasValues()) {
3687 return Metaheuristic::AcceptDelta(delta, deltadelta);
3688 }
3689 int64_t penalty = 0;
3690 if (!deltadelta->Empty()) {
3691 if (!incremental_) {
3692 penalty = Evaluate(delta, assignment_penalized_value_,
3693 current_penalized_values_.get(), true);
3694 } else {
3695 penalty = Evaluate(deltadelta, old_penalized_value_, delta_cache_.get(),
3696 true);
3697 }
3698 incremental_ = true;
3699 } else {
3700 if (incremental_) {
3701 for (int i = 0; i < vars_.size(); ++i) {
3703 }
3705 }
3706 incremental_ = false;
3707 penalty = Evaluate(delta, assignment_penalized_value_,
3708 current_penalized_values_.get(), false);
3709 }
3710 old_penalized_value_ = penalty;
3711 if (!delta->HasObjective()) {
3712 delta->AddObjective(objective_);
3713 }
3714 if (delta->Objective() == objective_) {
3715 if (maximize_) {
3716 delta->SetObjectiveMin(
3718 CapAdd(best_, step_)),
3719 delta->ObjectiveMin()));
3720 } else {
3721 delta->SetObjectiveMax(
3723 CapSub(best_, step_)),
3724 delta->ObjectiveMax()));
3725 }
3726 }
3727 }
3728 return true;
3729}
3730
3731int64_t GuidedLocalSearch::Evaluate(const Assignment* delta,
3732 int64_t current_penalty,
3733 const int64_t* const out_values,
3734 bool cache_delta_values) {
3735 int64_t penalty = current_penalty;
3736 const Assignment::IntContainer& container = delta->IntVarContainer();
3737 const int size = container.Size();
3738 for (int i = 0; i < size; ++i) {
3739 const IntVarElement& new_element = container.Element(i);
3740 IntVar* var = new_element.Var();
3741 int64_t index = -1;
3742 if (gtl::FindCopy(indices_, var, &index)) {
3743 penalty = CapSub(penalty, out_values[index]);
3744 int64_t new_penalty = 0;
3745 if (EvaluateElementValue(container, index, &i, &new_penalty)) {
3746 penalty = CapAdd(penalty, new_penalty);
3747 if (cache_delta_values) {
3748 delta_cache_[index] = new_penalty;
3749 }
3750 }
3751 }
3752 }
3753 return penalty;
3754}
3755
3756// Penalize all the most expensive arcs (var, value) according to their utility:
3757// utility(i, j) = cost(i, j) / (1 + penalty(i, j))
3758bool GuidedLocalSearch::LocalOptimum() {
3759 std::vector<std::pair<Arc, double>> utility(vars_.size());
3760 for (int i = 0; i < vars_.size(); ++i) {
3761 if (!assignment_.Bound(vars_[i])) {
3762 // Never synced with a solution, problem infeasible.
3763 return false;
3764 }
3765 const int64_t var_value = assignment_.Value(vars_[i]);
3766 const int64_t value =
3767 (var_value != i) ? AssignmentPenalty(assignment_, i, var_value) : 0;
3768 const Arc arc(i, var_value);
3769 const int64_t penalty = penalties_->Value(arc);
3770 utility[i] = std::pair<Arc, double>(arc, value / (penalty + 1.0));
3771 }
3772 Comparator comparator;
3773 std::sort(utility.begin(), utility.end(), comparator);
3774 int64_t utility_value = utility[0].second;
3775 penalties_->Increment(utility[0].first);
3776 for (int i = 1; i < utility.size() && utility_value == utility[i].second;
3777 ++i) {
3778 penalties_->Increment(utility[i].first);
3779 }
3780 if (maximize_) {
3782 } else {
3784 }
3785 return true;
3786}
3787
3788class BinaryGuidedLocalSearch : public GuidedLocalSearch {
3789 public:
3790 BinaryGuidedLocalSearch(
3791 Solver* const solver, IntVar* const objective,
3792 std::function<int64_t(int64_t, int64_t)> objective_function,
3793 bool maximize, int64_t step, const std::vector<IntVar*>& vars,
3794 double penalty_factor);
3795 ~BinaryGuidedLocalSearch() override {}
3796 IntExpr* MakeElementPenalty(int index) override;
3797 int64_t AssignmentElementPenalty(const Assignment& assignment,
3798 int index) override;
3799 int64_t AssignmentPenalty(const Assignment& assignment, int index,
3800 int64_t next) override;
3801 bool EvaluateElementValue(const Assignment::IntContainer& container,
3802 int64_t index, int* container_index,
3803 int64_t* penalty) override;
3804
3805 private:
3806 int64_t PenalizedValue(int64_t i, int64_t j);
3807 std::function<int64_t(int64_t, int64_t)> objective_function_;
3808};
3809
3810BinaryGuidedLocalSearch::BinaryGuidedLocalSearch(
3811 Solver* const solver, IntVar* const objective,
3812 std::function<int64_t(int64_t, int64_t)> objective_function, bool maximize,
3813 int64_t step, const std::vector<IntVar*>& vars, double penalty_factor)
3814 : GuidedLocalSearch(solver, objective, maximize, step, vars,
3815 penalty_factor),
3816 objective_function_(std::move(objective_function)) {}
3817
3818IntExpr* BinaryGuidedLocalSearch::MakeElementPenalty(int index) {
3819 return solver()->MakeElement(
3820 [this, index](int64_t i) { return PenalizedValue(index, i); },
3821 vars_[index]);
3822}
3823
3824int64_t BinaryGuidedLocalSearch::AssignmentElementPenalty(
3825 const Assignment& assignment, int index) {
3826 return PenalizedValue(index, assignment.Value(vars_[index]));
3827}
3828
3829int64_t BinaryGuidedLocalSearch::AssignmentPenalty(const Assignment& assignment,
3830 int index, int64_t next) {
3831 return objective_function_(index, next);
3832}
3833
3834bool BinaryGuidedLocalSearch::EvaluateElementValue(
3835 const Assignment::IntContainer& container, int64_t index,
3836 int* container_index, int64_t* penalty) {
3837 const IntVarElement& element = container.Element(*container_index);
3838 if (element.Activated()) {
3839 *penalty = PenalizedValue(index, element.Value());
3840 return true;
3841 }
3842 return false;
3843}
3844
3845// Penalized value for (i, j) = penalty_factor_ * penalty(i, j) * cost (i, j)
3846int64_t BinaryGuidedLocalSearch::PenalizedValue(int64_t i, int64_t j) {
3847 const Arc arc(i, j);
3848 const int64_t penalty = penalties_->Value(arc);
3849 if (penalty != 0) { // objective_function_->Run(i, j) can be costly
3850 const double penalized_value_fp =
3851 penalty_factor_ * penalty * objective_function_(i, j);
3852 const int64_t penalized_value =
3854 ? static_cast<int64_t>(penalized_value_fp)
3856 if (maximize_) {
3857 return -penalized_value;
3858 } else {
3859 return penalized_value;
3860 }
3861 } else {
3862 return 0;
3863 }
3864}
3865
3866class TernaryGuidedLocalSearch : public GuidedLocalSearch {
3867 public:
3868 TernaryGuidedLocalSearch(
3869 Solver* const solver, IntVar* const objective,
3870 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
3871 bool maximize, int64_t step, const std::vector<IntVar*>& vars,
3872 const std::vector<IntVar*>& secondary_vars, double penalty_factor);
3873 ~TernaryGuidedLocalSearch() override {}
3874 IntExpr* MakeElementPenalty(int index) override;
3875 int64_t AssignmentElementPenalty(const Assignment& assignment,
3876 int index) override;
3877 int64_t AssignmentPenalty(const Assignment& assignment, int index,
3878 int64_t next) override;
3879 bool EvaluateElementValue(const Assignment::IntContainer& container,
3880 int64_t index, int* container_index,
3881 int64_t* penalty) override;
3882
3883 private:
3884 int64_t PenalizedValue(int64_t i, int64_t j, int64_t k);
3885 int64_t GetAssignmentSecondaryValue(const Assignment::IntContainer& container,
3886 int index, int* container_index) const;
3887
3888 const std::vector<IntVar*> secondary_vars_;
3889 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function_;
3890};
3891
3892TernaryGuidedLocalSearch::TernaryGuidedLocalSearch(
3893 Solver* const solver, IntVar* const objective,
3894 std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
3895 bool maximize, int64_t step, const std::vector<IntVar*>& vars,
3896 const std::vector<IntVar*>& secondary_vars, double penalty_factor)
3897 : GuidedLocalSearch(solver, objective, maximize, step, vars,
3898 penalty_factor),
3899 secondary_vars_(secondary_vars),
3900 objective_function_(std::move(objective_function)) {
3901 if (!secondary_vars.empty()) {
3902 assignment_.Add(secondary_vars);
3903 }
3904}
3905
3906IntExpr* TernaryGuidedLocalSearch::MakeElementPenalty(int index) {
3907 return solver()->MakeElement(
3908 [this, index](int64_t i, int64_t j) {
3909 return PenalizedValue(index, i, j);
3910 },
3911 vars_[index], secondary_vars_[index]);
3912}
3913
3914int64_t TernaryGuidedLocalSearch::AssignmentElementPenalty(
3915 const Assignment& assignment, int index) {
3916 return PenalizedValue(index, assignment.Value(vars_[index]),
3917 assignment.Value(secondary_vars_[index]));
3918}
3919
3920int64_t TernaryGuidedLocalSearch::AssignmentPenalty(
3921 const Assignment& assignment, int index, int64_t next) {
3922 return objective_function_(index, next,
3923 assignment.Value(secondary_vars_[index]));
3924}
3925
3926bool TernaryGuidedLocalSearch::EvaluateElementValue(
3927 const Assignment::IntContainer& container, int64_t index,
3928 int* container_index, int64_t* penalty) {
3929 const IntVarElement& element = container.Element(*container_index);
3930 if (element.Activated()) {
3931 *penalty = PenalizedValue(
3932 index, element.Value(),
3933 GetAssignmentSecondaryValue(container, index, container_index));
3934 return true;
3935 }
3936 return false;
3937}
3938
3939// Penalized value for (i, j) = penalty_factor_ * penalty(i, j) * cost (i, j)
3940int64_t TernaryGuidedLocalSearch::PenalizedValue(int64_t i, int64_t j,
3941 int64_t k) {
3942 const Arc arc(i, j);
3943 const int64_t penalty = penalties_->Value(arc);
3944 if (penalty != 0) { // objective_function_(i, j, k) can be costly
3945 const double penalized_value_fp =
3946 penalty_factor_ * penalty * objective_function_(i, j, k);
3947 const int64_t penalized_value =
3949 ? static_cast<int64_t>(penalized_value_fp)
3951 if (maximize_) {
3952 return -penalized_value;
3953 } else {
3954 return penalized_value;
3955 }
3956 } else {
3957 return 0;
3958 }
3959}
3960
3961int64_t TernaryGuidedLocalSearch::GetAssignmentSecondaryValue(
3962 const Assignment::IntContainer& container, int index,
3963 int* container_index) const {
3964 const IntVar* secondary_var = secondary_vars_[index];
3965 int hint_index = *container_index + 1;
3966 if (hint_index > 0 && hint_index < container.Size() &&
3967 secondary_var == container.Element(hint_index).Var()) {
3968 *container_index = hint_index;
3969 return container.Element(hint_index).Value();
3970 } else {
3971 return container.Element(secondary_var).Value();
3972 }
3973}
3974} // namespace
3975
3976SearchMonitor* Solver::MakeGuidedLocalSearch(
3977 bool maximize, IntVar* const objective,
3978 Solver::IndexEvaluator2 objective_function, int64_t step,
3979 const std::vector<IntVar*>& vars, double penalty_factor) {
3980 return RevAlloc(new BinaryGuidedLocalSearch(
3981 this, objective, std::move(objective_function), maximize, step, vars,
3982 penalty_factor));
3983}
3984
3985SearchMonitor* Solver::MakeGuidedLocalSearch(
3986 bool maximize, IntVar* const objective,
3987 Solver::IndexEvaluator3 objective_function, int64_t step,
3988 const std::vector<IntVar*>& vars,
3989 const std::vector<IntVar*>& secondary_vars, double penalty_factor) {
3990 return RevAlloc(new TernaryGuidedLocalSearch(
3991 this, objective, std::move(objective_function), maximize, step, vars,
3992 secondary_vars, penalty_factor));
3993}
3994
3995// ---------- Search Limits ----------
3996
3997// ----- Base Class -----
3998
3999SearchLimit::~SearchLimit() {}
4000
4001void SearchLimit::EnterSearch() {
4002 crossed_ = false;
4003 Init();
4004}
4005
4006void SearchLimit::BeginNextDecision(DecisionBuilder* const b) {
4007 PeriodicCheck();
4008 TopPeriodicCheck();
4009}
4010
4011void SearchLimit::RefuteDecision(Decision* const d) {
4012 PeriodicCheck();
4013 TopPeriodicCheck();
4014}
4015
4016void SearchLimit::PeriodicCheck() {
4017 if (crossed_ || Check()) {
4018 crossed_ = true;
4019 solver()->Fail();
4020 }
4021}
4022
4023void SearchLimit::TopPeriodicCheck() {
4024 if (solver()->TopLevelSearch() != solver()->ActiveSearch()) {
4025 solver()->TopPeriodicCheck();
4026 }
4027}
4028
4029// ----- Regular Limit -----
4030
4031RegularLimit::RegularLimit(Solver* const s, absl::Duration time,
4032 int64_t branches, int64_t failures,
4033 int64_t solutions, bool smart_time_check,
4034 bool cumulative)
4035 : SearchLimit(s),
4036 duration_limit_(time),
4037 solver_time_at_limit_start_(s->Now()),
4038 last_time_elapsed_(absl::ZeroDuration()),
4039 check_count_(0),
4040 next_check_(0),
4041 smart_time_check_(smart_time_check),
4042 branches_(branches),
4043 branches_offset_(0),
4044 failures_(failures),
4045 failures_offset_(0),
4046 solutions_(solutions),
4047 solutions_offset_(0),
4048 cumulative_(cumulative) {}
4049
4051
4052void RegularLimit::Copy(const SearchLimit* const limit) {
4053 const RegularLimit* const regular =
4054 reinterpret_cast<const RegularLimit* const>(limit);
4055 duration_limit_ = regular->duration_limit_;
4056 branches_ = regular->branches_;
4057 failures_ = regular->failures_;
4058 solutions_ = regular->solutions_;
4059 smart_time_check_ = regular->smart_time_check_;
4060 cumulative_ = regular->cumulative_;
4061}
4062
4064
4066 Solver* const s = solver();
4067 return s->MakeLimit(wall_time(), branches_, failures_, solutions_,
4068 smart_time_check_);
4069}
4070
4072 Solver* const s = solver();
4073 // Warning limits might be kint64max, do not move the offset to the rhs
4074 return s->branches() - branches_offset_ >= branches_ ||
4075 s->failures() - failures_offset_ >= failures_ || CheckTime() ||
4076 s->solutions() - solutions_offset_ >= solutions_;
4077}
4078
4080 Solver* const s = solver();
4081 int64_t progress = GetPercent(s->branches(), branches_offset_, branches_);
4082 progress = std::max(progress,
4083 GetPercent(s->failures(), failures_offset_, failures_));
4084 progress = std::max(
4085 progress, GetPercent(s->solutions(), solutions_offset_, solutions_));
4086 if (duration_limit() != absl::InfiniteDuration()) {
4087 progress = std::max(progress, (100 * TimeElapsed()) / duration_limit());
4088 }
4089 return progress;
4090}
4091
4093 Solver* const s = solver();
4094 branches_offset_ = s->branches();
4095 failures_offset_ = s->failures();
4096 solver_time_at_limit_start_ = s->Now();
4097 last_time_elapsed_ = absl::ZeroDuration();
4098 solutions_offset_ = s->solutions();
4099 check_count_ = 0;
4100 next_check_ = 0;
4101}
4102
4104 if (cumulative_) {
4105 // Reduce the limits by the amount consumed during this search
4106 Solver* const s = solver();
4107 branches_ -= s->branches() - branches_offset_;
4108 failures_ -= s->failures() - failures_offset_;
4109 duration_limit_ -= s->Now() - solver_time_at_limit_start_;
4110 solutions_ -= s->solutions() - solutions_offset_;
4111 }
4112}
4113
4114void RegularLimit::UpdateLimits(absl::Duration time, int64_t branches,
4115 int64_t failures, int64_t solutions) {
4116 duration_limit_ = time;
4117 branches_ = branches;
4118 failures_ = failures;
4119 solutions_ = solutions;
4120}
4121
4123 Solver* const s = solver();
4124 return s->solutions() + s->unchecked_solutions() - solutions_offset_ >=
4125 solutions_;
4126}
4127
4128std::string RegularLimit::DebugString() const {
4129 return absl::StrFormat(
4130 "RegularLimit(crossed = %i, duration_limit = %s, "
4131 "branches = %d, failures = %d, solutions = %d cumulative = %s",
4132 crossed(), absl::FormatDuration(duration_limit()), branches_, failures_,
4133 solutions_, (cumulative_ ? "true" : "false"));
4134}
4135
4136void RegularLimit::Accept(ModelVisitor* const visitor) const {
4140 branches_);
4142 failures_);
4144 solutions_);
4146 smart_time_check_);
4149}
4150
4151bool RegularLimit::CheckTime() { return TimeElapsed() >= duration_limit(); }
4152
4153absl::Duration RegularLimit::TimeElapsed() {
4154 const int64_t kMaxSkip = 100;
4155 const int64_t kCheckWarmupIterations = 100;
4156 ++check_count_;
4157 if (duration_limit() != absl::InfiniteDuration() &&
4158 next_check_ <= check_count_) {
4159 Solver* const s = solver();
4160 absl::Duration elapsed = s->Now() - solver_time_at_limit_start_;
4161 if (smart_time_check_ && check_count_ > kCheckWarmupIterations &&
4162 elapsed > absl::ZeroDuration()) {
4163 const int64_t estimated_check_count_at_limit = MathUtil::FastInt64Round(
4164 check_count_ * absl::FDivDuration(duration_limit_, elapsed));
4165 next_check_ =
4166 std::min(check_count_ + kMaxSkip, estimated_check_count_at_limit);
4167 }
4168 last_time_elapsed_ = elapsed;
4169 }
4170 return last_time_elapsed_;
4171}
4172
4177 /*smart_time_check=*/false, /*cumulative=*/false);
4178}
4179
4181 return MakeLimit(absl::InfiniteDuration(), branches,
4184 /*smart_time_check=*/false, /*cumulative=*/false);
4185}
4186
4188 return MakeLimit(absl::InfiniteDuration(),
4191 /*smart_time_check=*/false, /*cumulative=*/false);
4192}
4193
4195 return MakeLimit(absl::InfiniteDuration(),
4198 /*smart_time_check=*/false, /*cumulative=*/false);
4199}
4200
4201RegularLimit* Solver::MakeLimit(int64_t time, int64_t branches,
4202 int64_t failures, int64_t solutions,
4203 bool smart_time_check, bool cumulative) {
4204 return MakeLimit(absl::Milliseconds(time), branches, failures, solutions,
4205 smart_time_check, cumulative);
4206}
4207
4208RegularLimit* Solver::MakeLimit(absl::Duration time, int64_t branches,
4209 int64_t failures, int64_t solutions,
4210 bool smart_time_check, bool cumulative) {
4212 smart_time_check, cumulative));
4213}
4214
4215RegularLimit* Solver::MakeLimit(const RegularLimitParameters& proto) {
4217 ? absl::InfiniteDuration()
4218 : absl::Milliseconds(proto.time()),
4219 proto.branches(), proto.failures(), proto.solutions(),
4220 proto.smart_time_check(), proto.cumulative());
4221}
4222
4223RegularLimitParameters Solver::MakeDefaultRegularLimitParameters() const {
4224 RegularLimitParameters proto;
4229 proto.set_smart_time_check(false);
4230 proto.set_cumulative(false);
4231 return proto;
4232}
4233
4234// ----- Improvement Search Limit -----
4235
4237 Solver* const s, IntVar* objective_var, bool maximize,
4238 double objective_scaling_factor, double objective_offset,
4239 double improvement_rate_coefficient,
4240 int improvement_rate_solutions_distance)
4241 : SearchLimit(s),
4242 objective_var_(objective_var),
4243 maximize_(maximize),
4244 objective_scaling_factor_(objective_scaling_factor),
4245 objective_offset_(objective_offset),
4246 improvement_rate_coefficient_(improvement_rate_coefficient),
4247 improvement_rate_solutions_distance_(
4248 improvement_rate_solutions_distance) {
4249 Init();
4250}
4251
4253
4255 best_objective_ = maximize_ ? -std::numeric_limits<double>::infinity()
4256 : std::numeric_limits<double>::infinity();
4257 threshold_ = std::numeric_limits<double>::infinity();
4258 objective_updated_ = false;
4259 gradient_stage_ = true;
4260}
4261
4263 const ImprovementSearchLimit* const improv =
4264 reinterpret_cast<const ImprovementSearchLimit* const>(limit);
4265 objective_var_ = improv->objective_var_;
4266 maximize_ = improv->maximize_;
4267 objective_scaling_factor_ = improv->objective_scaling_factor_;
4268 objective_offset_ = improv->objective_offset_;
4269 improvement_rate_coefficient_ = improv->improvement_rate_coefficient_;
4270 improvement_rate_solutions_distance_ =
4271 improv->improvement_rate_solutions_distance_;
4272 improvements_ = improv->improvements_;
4273 threshold_ = improv->threshold_;
4274 best_objective_ = improv->best_objective_;
4275 objective_updated_ = improv->objective_updated_;
4276 gradient_stage_ = improv->gradient_stage_;
4277}
4278
4280 Solver* const s = solver();
4281 return s->MakeImprovementLimit(
4282 objective_var_, maximize_, objective_scaling_factor_, objective_offset_,
4283 improvement_rate_coefficient_, improvement_rate_solutions_distance_);
4284}
4285
4287 if (!objective_updated_) {
4288 return false;
4289 }
4290 objective_updated_ = false;
4291
4292 if (improvements_.size() <= improvement_rate_solutions_distance_) {
4293 return false;
4294 }
4295
4296 const std::pair<double, int64_t> cur = improvements_.back();
4297 const std::pair<double, int64_t> prev = improvements_.front();
4298 DCHECK_GT(cur.second, prev.second);
4299 double improvement_rate =
4300 std::abs(prev.first - cur.first) / (cur.second - prev.second);
4301 if (gradient_stage_) {
4302 threshold_ = fmin(threshold_, improvement_rate);
4303 } else if (improvement_rate_coefficient_ * improvement_rate < threshold_) {
4304 return true;
4305 }
4306
4307 return false;
4308}
4309
4311 const int64_t new_objective =
4312 objective_var_ != nullptr && objective_var_->Bound()
4313 ? objective_var_->Value()
4314 : (maximize_
4317
4318 const double scaled_new_objective =
4319 objective_scaling_factor_ * (new_objective + objective_offset_);
4320
4321 const bool is_improvement = maximize_
4322 ? scaled_new_objective > best_objective_
4323 : scaled_new_objective < best_objective_;
4324
4325 if (gradient_stage_ && !is_improvement) {
4326 gradient_stage_ = false;
4327 // In case we haven't got enough solutions during the first stage, the limit
4328 // never stops the search.
4329 if (threshold_ == std::numeric_limits<double>::infinity()) {
4330 threshold_ = -1;
4331 }
4332 }
4333
4334 if (is_improvement) {
4335 best_objective_ = scaled_new_objective;
4336 objective_updated_ = true;
4337 improvements_.push_back(
4338 std::make_pair(scaled_new_objective, solver()->neighbors()));
4339 // We need to have 'improvement_rate_solutions_distance_' + 1 element in the
4340 // 'improvements_', so the distance between improvements is
4341 // 'improvement_rate_solutions_distance_'.
4342 if (improvements_.size() - 1 > improvement_rate_solutions_distance_) {
4343 improvements_.pop_front();
4344 }
4345 DCHECK_LE(improvements_.size() - 1, improvement_rate_solutions_distance_);
4346 }
4347
4348 return true;
4349}
4350
4352 IntVar* objective_var, bool maximize, double objective_scaling_factor,
4353 double objective_offset, double improvement_rate_coefficient,
4354 int improvement_rate_solutions_distance) {
4356 this, objective_var, maximize, objective_scaling_factor, objective_offset,
4357 improvement_rate_coefficient, improvement_rate_solutions_distance));
4358}
4359
4360// A limit whose Check function is the OR of two underlying limits.
4361namespace {
4362class ORLimit : public SearchLimit {
4363 public:
4364 ORLimit(SearchLimit* limit_1, SearchLimit* limit_2)
4365 : SearchLimit(limit_1->solver()), limit_1_(limit_1), limit_2_(limit_2) {
4366 CHECK(limit_1 != nullptr);
4367 CHECK(limit_2 != nullptr);
4368 CHECK_EQ(limit_1->solver(), limit_2->solver())
4369 << "Illegal arguments: cannot combines limits that belong to different "
4370 << "solvers, because the reversible allocations could delete one and "
4371 << "not the other.";
4372 }
4373
4374 bool Check() override {
4375 // Check being non-const, there may be side effects. So we always call both
4376 // checks.
4377 const bool check_1 = limit_1_->Check();
4378 const bool check_2 = limit_2_->Check();
4379 return check_1 || check_2;
4380 }
4381
4382 void Init() override {
4383 limit_1_->Init();
4384 limit_2_->Init();
4385 }
4386
4387 void Copy(const SearchLimit* const limit) override {
4388 LOG(FATAL) << "Not implemented.";
4389 }
4390
4391 SearchLimit* MakeClone() const override {
4392 // Deep cloning: the underlying limits are cloned, too.
4393 return solver()->MakeLimit(limit_1_->MakeClone(), limit_2_->MakeClone());
4394 }
4395
4396 void EnterSearch() override {
4397 limit_1_->EnterSearch();
4398 limit_2_->EnterSearch();
4399 }
4400 void BeginNextDecision(DecisionBuilder* const b) override {
4401 limit_1_->BeginNextDecision(b);
4402 limit_2_->BeginNextDecision(b);
4403 }
4404 void PeriodicCheck() override {
4405 limit_1_->PeriodicCheck();
4406 limit_2_->PeriodicCheck();
4407 }
4408 void RefuteDecision(Decision* const d) override {
4409 limit_1_->RefuteDecision(d);
4410 limit_2_->RefuteDecision(d);
4411 }
4412 std::string DebugString() const override {
4413 return absl::StrCat("OR limit (", limit_1_->DebugString(), " OR ",
4414 limit_2_->DebugString(), ")");
4415 }
4416
4417 private:
4418 SearchLimit* const limit_1_;
4419 SearchLimit* const limit_2_;
4420};
4421} // namespace
4422
4424 SearchLimit* const limit_2) {
4425 return RevAlloc(new ORLimit(limit_1, limit_2));
4426}
4427
4428namespace {
4429class CustomLimit : public SearchLimit {
4430 public:
4431 CustomLimit(Solver* const s, std::function<bool()> limiter);
4432 bool Check() override;
4433 void Init() override;
4434 void Copy(const SearchLimit* const limit) override;
4435 SearchLimit* MakeClone() const override;
4436
4437 private:
4438 std::function<bool()> limiter_;
4439};
4440
4441CustomLimit::CustomLimit(Solver* const s, std::function<bool()> limiter)
4442 : SearchLimit(s), limiter_(std::move(limiter)) {}
4443
4444bool CustomLimit::Check() {
4445 if (limiter_) return limiter_();
4446 return false;
4447}
4448
4449void CustomLimit::Init() {}
4450
4451void CustomLimit::Copy(const SearchLimit* const limit) {
4452 const CustomLimit* const custom =
4453 reinterpret_cast<const CustomLimit* const>(limit);
4454 limiter_ = custom->limiter_;
4455}
4456
4457SearchLimit* CustomLimit::MakeClone() const {
4458 return solver()->RevAlloc(new CustomLimit(solver(), limiter_));
4459}
4460} // namespace
4461
4462SearchLimit* Solver::MakeCustomLimit(std::function<bool()> limiter) {
4463 return RevAlloc(new CustomLimit(this, std::move(limiter)));
4464}
4465
4466// ---------- SolveOnce ----------
4467
4468namespace {
4469class SolveOnce : public DecisionBuilder {
4470 public:
4471 explicit SolveOnce(DecisionBuilder* const db) : db_(db) {
4472 CHECK(db != nullptr);
4473 }
4474
4475 SolveOnce(DecisionBuilder* const db,
4476 const std::vector<SearchMonitor*>& monitors)
4477 : db_(db), monitors_(monitors) {
4478 CHECK(db != nullptr);
4479 }
4480
4481 ~SolveOnce() override {}
4482
4483 Decision* Next(Solver* s) override {
4484 bool res = s->SolveAndCommit(db_, monitors_);
4485 if (!res) {
4486 s->Fail();
4487 }
4488 return nullptr;
4489 }
4490
4491 std::string DebugString() const override {
4492 return absl::StrFormat("SolveOnce(%s)", db_->DebugString());
4493 }
4494
4495 void Accept(ModelVisitor* const visitor) const override {
4496 db_->Accept(visitor);
4497 }
4498
4499 private:
4500 DecisionBuilder* const db_;
4501 std::vector<SearchMonitor*> monitors_;
4502};
4503} // namespace
4504
4506 return RevAlloc(new SolveOnce(db));
4507}
4508
4510 SearchMonitor* const monitor1) {
4511 std::vector<SearchMonitor*> monitors;
4512 monitors.push_back(monitor1);
4513 return RevAlloc(new SolveOnce(db, monitors));
4514}
4515
4517 SearchMonitor* const monitor1,
4518 SearchMonitor* const monitor2) {
4519 std::vector<SearchMonitor*> monitors;
4520 monitors.push_back(monitor1);
4521 monitors.push_back(monitor2);
4522 return RevAlloc(new SolveOnce(db, monitors));
4523}
4524
4526 SearchMonitor* const monitor1,
4527 SearchMonitor* const monitor2,
4528 SearchMonitor* const monitor3) {
4529 std::vector<SearchMonitor*> monitors;
4530 monitors.push_back(monitor1);
4531 monitors.push_back(monitor2);
4532 monitors.push_back(monitor3);
4533 return RevAlloc(new SolveOnce(db, monitors));
4534}
4535
4537 SearchMonitor* const monitor1,
4538 SearchMonitor* const monitor2,
4539 SearchMonitor* const monitor3,
4540 SearchMonitor* const monitor4) {
4541 std::vector<SearchMonitor*> monitors;
4542 monitors.push_back(monitor1);
4543 monitors.push_back(monitor2);
4544 monitors.push_back(monitor3);
4545 monitors.push_back(monitor4);
4546 return RevAlloc(new SolveOnce(db, monitors));
4547}
4548
4550 DecisionBuilder* const db, const std::vector<SearchMonitor*>& monitors) {
4551 return RevAlloc(new SolveOnce(db, monitors));
4552}
4553
4554// ---------- NestedOptimize ----------
4555
4556namespace {
4557class NestedOptimize : public DecisionBuilder {
4558 public:
4559 NestedOptimize(DecisionBuilder* const db, Assignment* const solution,
4560 bool maximize, int64_t step)
4561 : db_(db),
4562 solution_(solution),
4563 maximize_(maximize),
4564 step_(step),
4565 collector_(nullptr) {
4566 CHECK(db != nullptr);
4567 CHECK(solution != nullptr);
4568 CHECK(solution->HasObjective());
4569 AddMonitors();
4570 }
4571
4572 NestedOptimize(DecisionBuilder* const db, Assignment* const solution,
4573 bool maximize, int64_t step,
4574 const std::vector<SearchMonitor*>& monitors)
4575 : db_(db),
4576 solution_(solution),
4577 maximize_(maximize),
4578 step_(step),
4579 monitors_(monitors),
4580 collector_(nullptr) {
4581 CHECK(db != nullptr);
4582 CHECK(solution != nullptr);
4583 CHECK(solution->HasObjective());
4584 AddMonitors();
4585 }
4586
4587 void AddMonitors() {
4588 Solver* const solver = solution_->solver();
4589 collector_ = solver->MakeLastSolutionCollector(solution_);
4590 monitors_.push_back(collector_);
4591 OptimizeVar* const optimize =
4592 solver->MakeOptimize(maximize_, solution_->Objective(), step_);
4593 monitors_.push_back(optimize);
4594 }
4595
4596 Decision* Next(Solver* solver) override {
4597 solver->Solve(db_, monitors_);
4598 if (collector_->solution_count() == 0) {
4599 solver->Fail();
4600 }
4601 collector_->solution(0)->Restore();
4602 return nullptr;
4603 }
4604
4605 std::string DebugString() const override {
4606 return absl::StrFormat("NestedOptimize(db = %s, maximize = %d, step = %d)",
4607 db_->DebugString(), maximize_, step_);
4608 }
4609
4610 void Accept(ModelVisitor* const visitor) const override {
4611 db_->Accept(visitor);
4612 }
4613
4614 private:
4615 DecisionBuilder* const db_;
4616 Assignment* const solution_;
4617 const bool maximize_;
4618 const int64_t step_;
4619 std::vector<SearchMonitor*> monitors_;
4620 SolutionCollector* collector_;
4621};
4622} // namespace
4623
4625 Assignment* const solution,
4626 bool maximize, int64_t step) {
4627 return RevAlloc(new NestedOptimize(db, solution, maximize, step));
4628}
4629
4631 Assignment* const solution,
4632 bool maximize, int64_t step,
4633 SearchMonitor* const monitor1) {
4634 std::vector<SearchMonitor*> monitors;
4635 monitors.push_back(monitor1);
4636 return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));
4637}
4638
4640 Assignment* const solution,
4641 bool maximize, int64_t step,
4642 SearchMonitor* const monitor1,
4643 SearchMonitor* const monitor2) {
4644 std::vector<SearchMonitor*> monitors;
4645 monitors.push_back(monitor1);
4646 monitors.push_back(monitor2);
4647 return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));
4648}
4649
4651 Assignment* const solution,
4652 bool maximize, int64_t step,
4653 SearchMonitor* const monitor1,
4654 SearchMonitor* const monitor2,
4655 SearchMonitor* const monitor3) {
4656 std::vector<SearchMonitor*> monitors;
4657 monitors.push_back(monitor1);
4658 monitors.push_back(monitor2);
4659 monitors.push_back(monitor3);
4660 return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));
4661}
4662
4664 DecisionBuilder* const db, Assignment* const solution, bool maximize,
4665 int64_t step, SearchMonitor* const monitor1, SearchMonitor* const monitor2,
4666 SearchMonitor* const monitor3, SearchMonitor* const monitor4) {
4667 std::vector<SearchMonitor*> monitors;
4668 monitors.push_back(monitor1);
4669 monitors.push_back(monitor2);
4670 monitors.push_back(monitor3);
4671 monitors.push_back(monitor4);
4672 return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));
4673}
4674
4676 DecisionBuilder* const db, Assignment* const solution, bool maximize,
4677 int64_t step, const std::vector<SearchMonitor*>& monitors) {
4678 return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));
4679}
4680
4681// ---------- Restart ----------
4682
4683namespace {
4684// Luby Strategy
4685int64_t NextLuby(int i) {
4686 DCHECK_GT(i, 0);
4688 int64_t power;
4689
4690 // let's find the least power of 2 >= (i+1).
4691 power = 2;
4692 // Cannot overflow, because bounded by kint32max + 1.
4693 while (power < (i + 1)) {
4694 power <<= 1;
4695 }
4696 if (power == i + 1) {
4697 return (power / 2);
4698 }
4699 return NextLuby(i - (power / 2) + 1);
4700}
4701
4702class LubyRestart : public SearchMonitor {
4703 public:
4704 LubyRestart(Solver* const s, int scale_factor)
4705 : SearchMonitor(s),
4706 scale_factor_(scale_factor),
4707 iteration_(1),
4708 current_fails_(0),
4709 next_step_(scale_factor) {
4710 CHECK_GE(scale_factor, 1);
4711 }
4712
4713 ~LubyRestart() override {}
4714
4715 void BeginFail() override {
4716 if (++current_fails_ >= next_step_) {
4717 current_fails_ = 0;
4718 next_step_ = NextLuby(++iteration_) * scale_factor_;
4719 solver()->RestartCurrentSearch();
4720 }
4721 }
4722
4723 std::string DebugString() const override {
4724 return absl::StrFormat("LubyRestart(%i)", scale_factor_);
4725 }
4726
4727 private:
4728 const int scale_factor_;
4729 int iteration_;
4730 int64_t current_fails_;
4731 int64_t next_step_;
4732};
4733} // namespace
4734
4736 return RevAlloc(new LubyRestart(this, scale_factor));
4737}
4738
4739// ----- Constant Restart -----
4740
4741namespace {
4742class ConstantRestart : public SearchMonitor {
4743 public:
4744 ConstantRestart(Solver* const s, int frequency)
4745 : SearchMonitor(s), frequency_(frequency), current_fails_(0) {
4746 CHECK_GE(frequency, 1);
4747 }
4748
4749 ~ConstantRestart() override {}
4750
4751 void BeginFail() override {
4752 if (++current_fails_ >= frequency_) {
4753 current_fails_ = 0;
4754 solver()->RestartCurrentSearch();
4755 }
4756 }
4757
4758 std::string DebugString() const override {
4759 return absl::StrFormat("ConstantRestart(%i)", frequency_);
4760 }
4761
4762 private:
4763 const int frequency_;
4764 int64_t current_fails_;
4765};
4766} // namespace
4767
4769 return RevAlloc(new ConstantRestart(this, frequency));
4770}
4771
4772// ---------- Symmetry Breaking ----------
4773
4774// The symmetry manager maintains a list of problem symmetries. Each
4775// symmetry is called on each decision and should return a term
4776// representing the boolean status of the symmetrical decision.
4777// e.g. : the decision is x == 3, the symmetrical decision is y == 5
4778// then the symmetry breaker should use
4779// AddIntegerVariableEqualValueClause(y, 5). Once this is done, upon
4780// refutation, for each symmetry breaker, the system adds a constraint
4781// that will forbid the symmetrical variation of the current explored
4782// search tree. This constraint can be expressed very simply just by
4783// keeping the list of current symmetrical decisions.
4784//
4785// This is called Symmetry Breaking During Search (Ian Gent, Barbara
4786// Smith, ECAI 2000).
4787// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.42.3788&rep=rep1&type=pdf
4788//
4790 public:
4792 const std::vector<SymmetryBreaker*>& visitors)
4793 : SearchMonitor(s),
4794 visitors_(visitors),
4795 clauses_(visitors.size()),
4796 decisions_(visitors.size()),
4797 directions_(visitors.size()) { // false = left.
4798 for (int i = 0; i < visitors_.size(); ++i) {
4799 visitors_[i]->set_symmetry_manager_and_index(this, i);
4800 }
4801 }
4802
4803 ~SymmetryManager() override {}
4804
4805 void EndNextDecision(DecisionBuilder* const db, Decision* const d) override {
4806 if (d) {
4807 for (int i = 0; i < visitors_.size(); ++i) {
4808 const void* const last = clauses_[i].Last();
4809 d->Accept(visitors_[i]);
4810 if (last != clauses_[i].Last()) {
4811 // Synchroneous push of decision as marker.
4812 decisions_[i].Push(solver(), d);
4813 directions_[i].Push(solver(), false);
4814 }
4815 }
4816 }
4817 }
4818
4819 void RefuteDecision(Decision* d) override {
4820 for (int i = 0; i < visitors_.size(); ++i) {
4821 if (decisions_[i].Last() != nullptr && decisions_[i].LastValue() == d) {
4822 CheckSymmetries(i);
4823 }
4824 }
4825 }
4826
4827 // TODO(user) : Improve speed, cache previous min and build them
4828 // incrementally.
4831 SimpleRevFIFO<bool>::Iterator tmp_dir(&directions_[index]);
4832 Constraint* ct = nullptr;
4833 {
4834 std::vector<IntVar*> guard;
4835 // keep the last entry for later, if loop doesn't exit.
4836 ++tmp;
4837 ++tmp_dir;
4838 while (tmp.ok()) {
4839 IntVar* const term = *tmp;
4840 if (!*tmp_dir) {
4841 if (term->Max() == 0) {
4842 // Premise is wrong. The clause will never apply.
4843 return;
4844 }
4845 if (term->Min() == 0) {
4846 DCHECK_EQ(1, term->Max());
4847 // Premise may be true. Adding to guard vector.
4848 guard.push_back(term);
4849 }
4850 }
4851 ++tmp;
4852 ++tmp_dir;
4853 }
4854 guard.push_back(clauses_[index].LastValue());
4855 directions_[index].SetLastValue(true);
4856 // Given premises: xi = ai
4857 // and a term y != b
4858 // The following is equivalent to
4859 // And(xi == a1) => y != b.
4860 ct = solver()->MakeEquality(solver()->MakeMin(guard), Zero());
4861 }
4862 DCHECK(ct != nullptr);
4864 }
4865
4866 void AddTermToClause(SymmetryBreaker* const visitor, IntVar* const term) {
4867 clauses_[visitor->index_in_symmetry_manager()].Push(solver(), term);
4868 }
4869
4870 std::string DebugString() const override { return "SymmetryManager"; }
4871
4872 private:
4873 const std::vector<SymmetryBreaker*> visitors_;
4874 std::vector<SimpleRevFIFO<IntVar*>> clauses_;
4875 std::vector<SimpleRevFIFO<Decision*>> decisions_;
4876 std::vector<SimpleRevFIFO<bool>> directions_;
4877};
4878
4879// ----- Symmetry Breaker -----
4880
4882 int64_t value) {
4883 CHECK(var != nullptr);
4884 Solver* const solver = var->solver();
4885 IntVar* const term = solver->MakeIsEqualCstVar(var, value);
4886 symmetry_manager()->AddTermToClause(this, term);
4887}
4888
4890 IntVar* const var, int64_t value) {
4891 CHECK(var != nullptr);
4892 Solver* const solver = var->solver();
4893 IntVar* const term = solver->MakeIsGreaterOrEqualCstVar(var, value);
4894 symmetry_manager()->AddTermToClause(this, term);
4895}
4896
4898 IntVar* const var, int64_t value) {
4899 CHECK(var != nullptr);
4900 Solver* const solver = var->solver();
4901 IntVar* const term = solver->MakeIsLessOrEqualCstVar(var, value);
4902 symmetry_manager()->AddTermToClause(this, term);
4903}
4904
4905// ----- API -----
4906
4908 const std::vector<SymmetryBreaker*>& visitors) {
4909 return RevAlloc(new SymmetryManager(this, visitors));
4910}
4911
4913 std::vector<SymmetryBreaker*> visitors;
4914 visitors.push_back(v1);
4915 return MakeSymmetryManager(visitors);
4916}
4917
4919 SymmetryBreaker* const v2) {
4920 std::vector<SymmetryBreaker*> visitors;
4921 visitors.push_back(v1);
4922 visitors.push_back(v2);
4923 return MakeSymmetryManager(visitors);
4924}
4925
4927 SymmetryBreaker* const v2,
4928 SymmetryBreaker* const v3) {
4929 std::vector<SymmetryBreaker*> visitors;
4930 visitors.push_back(v1);
4931 visitors.push_back(v2);
4932 visitors.push_back(v3);
4933 return MakeSymmetryManager(visitors);
4934}
4935
4937 SymmetryBreaker* const v2,
4938 SymmetryBreaker* const v3,
4939 SymmetryBreaker* const v4) {
4940 std::vector<SymmetryBreaker*> visitors;
4941 visitors.push_back(v1);
4942 visitors.push_back(v2);
4943 visitors.push_back(v3);
4944 visitors.push_back(v4);
4945 return MakeSymmetryManager(visitors);
4946}
4947} // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
#define CHECK(condition)
Definition: base/logging.h:495
#define DCHECK_LE(val1, val2)
Definition: base/logging.h:893
#define CHECK_LT(val1, val2)
Definition: base/logging.h:706
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:703
#define CHECK_GE(val1, val2)
Definition: base/logging.h:707
#define CHECK_GT(val1, val2)
Definition: base/logging.h:708
#define DCHECK_GT(val1, val2)
Definition: base/logging.h:896
#define DCHECK_LT(val1, val2)
Definition: base/logging.h:894
#define LOG(severity)
Definition: base/logging.h:420
#define DCHECK(condition)
Definition: base/logging.h:890
#define CHECK_LE(val1, val2)
Definition: base/logging.h:705
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:891
#define VLOG(verboselevel)
Definition: base/logging.h:984
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 StartValue(const IntervalVar *const var) const
int64_t PerformedValue(const IntervalVar *const var) const
int64_t DurationValue(const IntervalVar *const var) const
const std::vector< int > & ForwardSequence(const SequenceVar *const var) const
int64_t Value(const IntVar *const var) const
A BaseObject is the root of all reversibly allocated objects.
void Set(uint32_t index, bool value)
Definition: bitmap.h:62
bool Get(uint32_t index) const
Definition: bitmap.h:58
A constraint is the main modeling object.
A DecisionBuilder is responsible for creating the search tree.
A Decision represents a choice point in the search tree.
virtual void Accept(DecisionVisitor *const visitor) const
Accepts the given visitor.
virtual void Apply(Solver *const s)=0
Apply will be called first when the decision is executed.
virtual void Refute(Solver *const s)=0
Refute will be called after a backtrack.
std::string DebugString() const override
bool Check() override
This method is called to check the status of the limit.
Definition: search.cc:4286
void Init() override
This method is called when the search limit is initialized.
Definition: search.cc:4254
void Copy(const SearchLimit *const limit) override
Copy a limit.
Definition: search.cc:4262
bool AtSolution() override
This method is called when a valid solution is found.
Definition: search.cc:4310
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)
Definition: search.cc:4236
SearchLimit * MakeClone() const override
Allocates a clone of the limit.
Definition: search.cc:4279
The class IntExpr is the base of all integer expressions in constraint programming.
virtual bool Bound() const
Returns true if the min and the max of the expression are equal.
virtual void SetValue(int64_t v)
This method sets the value of the expression.
virtual int64_t Min() const =0
virtual void SetMax(int64_t m)=0
virtual void SetMin(int64_t m)=0
virtual int64_t Max() const =0
The class IntVar is a subset of IntExpr.
virtual int64_t Value() const =0
This method returns the value of the variable.
Interval variables are often used in scheduling.
static int64_t FastInt64Round(double x)
Definition: mathutil.h:138
static const char kSolutionLimitArgument[]
virtual void VisitIntegerArgument(const std::string &arg_name, int64_t value)
Visit integer arguments.
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 kVariableGroupExtension[]
static const char kFailuresLimitArgument[]
virtual void VisitIntegerExpressionArgument(const std::string &arg_name, IntExpr *const argument)
Visit integer expression argument.
This class encapsulates an objective.
void EnterSearch() override
Beginning of the search.
Definition: search.cc:2801
void BeginNextDecision(DecisionBuilder *const db) override
Before calling DecisionBuilder::Next.
Definition: search.cc:2810
OptimizeVar(Solver *const s, bool maximize, IntVar *const a, int64_t step)
Definition: search.cc:2780
void Accept(ModelVisitor *const visitor) const override
Accepts the given model visitor.
Definition: search.cc:2905
bool AcceptSolution() override
This method is called when a solution is found.
Definition: search.cc:2828
virtual std::string Print() const
Definition: search.cc:2889
bool AtSolution() override
This method is called when a valid solution is found.
Definition: search.cc:2840
void RefuteDecision(Decision *const d) override
Before refuting the decision.
Definition: search.cc:2826
IntVar * Var() const
Returns the variable that is optimized.
bool AcceptDelta(Assignment *delta, Assignment *deltadelta) override
Internal methods.
Definition: search.cc:2853
std::string DebugString() const override
Definition: search.cc:2893
Usual limit based on wall_time, number of explored branches and number of failures in the search tree...
bool Check() override
This method is called to check the status of the limit.
Definition: search.cc:4071
absl::Duration duration_limit() const
bool IsUncheckedSolutionLimitReached() override
Returns true if the limit of solutions has been reached including unchecked solutions.
Definition: search.cc:4122
void UpdateLimits(absl::Duration time, int64_t branches, int64_t failures, int64_t solutions)
Definition: search.cc:4114
void Init() override
This method is called when the search limit is initialized.
Definition: search.cc:4092
void ExitSearch() override
End of the search.
Definition: search.cc:4103
int ProgressPercent() override
Returns a percentage representing the propress of the search before reaching limits.
Definition: search.cc:4079
void Accept(ModelVisitor *const visitor) const override
Accepts the given model visitor.
Definition: search.cc:4136
void Copy(const SearchLimit *const limit) override
Copy a limit.
Definition: search.cc:4052
RegularLimit * MakeIdenticalClone() const
Definition: search.cc:4065
std::string DebugString() const override
Definition: search.cc:4128
SearchLimit * MakeClone() const override
Allocates a clone of the limit.
Definition: search.cc:4063
Base class of all search limits.
bool crossed() const
Returns true if the limit has been crossed.
The base class of all search logs that periodically outputs information when the search is running.
void BeginFail() override
Just when the failure occurs.
Definition: search.cc:180
virtual void OutputLine(const std::string &line)
Definition: search.cc:260
void EnterSearch() override
Beginning of the search.
Definition: search.cc:87
void RefuteDecision(Decision *const decision) override
Before refuting the decision.
Definition: search.cc:210
void ExitSearch() override
End of the search.
Definition: search.cc:95
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)
Definition: search.cc:58
void BeginInitialPropagation() override
Before the initial propagation.
Definition: search.cc:250
void NoMoreSolutions() override
When the search tree is finished.
Definition: search.cc:182
void ApplyDecision(Decision *const decision) override
Before applying the decision.
Definition: search.cc:202
bool AtSolution() override
This method is called when a valid solution is found.
Definition: search.cc:108
std::string DebugString() const override
Definition: search.cc:85
void AcceptUncheckedNeighbor() override
After accepting an unchecked neighbor during local search.
Definition: search.cc:178
void EndInitialPropagation() override
After the initial propagation.
Definition: search.cc:252
A search monitor is a simple set of callbacks to monitor all search events.
virtual void ExitSearch()
End of the search.
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 EnterSearch() override
Beginning of the search.
Definition: search.cc:2323
void Push(const SolutionData &data)
void PushSolution()
Push the current state as a new solution.
Definition: search.cc:2332
void AddObjective(IntVar *const objective)
Definition: search.cc:2317
std::vector< Assignment * > recycle_solutions_
std::vector< SolutionData > solution_data_
void Add(IntVar *const var)
Add API.
Definition: search.cc:2281
int solution_count() const
Returns how many solutions were stored during the search.
Definition: search.cc:2385
int64_t Value(int n, IntVar *const var) const
This is a shortcut to get the Value of 'var' in the nth solution.
Definition: search.cc:2407
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.
Definition: search.cc:2437
SolutionData BuildSolutionDataForCurrentState()
Definition: search.cc:2344
int64_t DurationValue(int n, IntervalVar *const var) const
This is a shortcut to get the DurationValue of 'var' in the nth solution.
Definition: search.cc:2415
int64_t StartValue(int n, IntervalVar *const var) const
This is a shortcut to get the StartValue of 'var' in the nth solution.
Definition: search.cc:2411
Assignment * solution(int n) const
Returns the nth solution.
Definition: search.cc:2380
int64_t EndValue(int n, IntervalVar *const var) const
This is a shortcut to get the EndValue of 'var' in the nth solution.
Definition: search.cc:2419
int64_t objective_value(int n) const
Returns the objective value of the nth solution.
Definition: search.cc:2402
int64_t wall_time(int n) const
Returns the wall time in ms for the nth solution.
Definition: search.cc:2387
int64_t branches(int n) const
Returns the number of branches when the nth solution was found.
Definition: search.cc:2392
int64_t PerformedValue(int n, IntervalVar *const var) const
This is a shortcut to get the PerformedValue of 'var' in the nth solution.
Definition: search.cc:2423
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.
Definition: search.cc:2427
void FreeSolution(Assignment *solution)
Definition: search.cc:2369
int64_t failures(int n) const
Returns the number of failures encountered at the time of the nth solution.
Definition: search.cc:2397
std::unique_ptr< Assignment > prototype_
SolutionCollector(Solver *const solver, const Assignment *assignment)
Definition: search.cc:2265
void PopSolution()
Remove and delete the last popped solution.
Definition: search.cc:2336
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.
Definition: search.cc:2432
int64_t neighbors() const
The number of neighbors created.
SearchMonitor * MakeLubyRestart(int scale_factor)
This search monitor will restart the search periodically.
Definition: search.cc:4735
SolutionCollector * MakeAllSolutionCollector()
Collect all solutions of the search.
Definition: search.cc:2774
ABSL_MUST_USE_RESULT RegularLimit * MakeSolutionsLimit(int64_t solutions)
Creates a search limit that constrains the number of solutions found during the search.
Definition: search.cc:4194
OptimizeVar * MakeWeightedMinimize(const std::vector< IntVar * > &sub_objectives, const std::vector< int64_t > &weights, int64_t step)
Creates a minimization weighted objective.
Definition: search.cc:2969
SolutionCollector * MakeLastSolutionCollector()
Collect the last solution of the search.
Definition: search.cc:2541
Decision * MakeAssignVariableValueOrDoNothing(IntVar *const var, int64_t value)
Definition: search.cc:1633
SearchMonitor * MakeAtSolutionCallback(std::function< void()> callback)
Definition: search.cc:422
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.
Definition: search.cc:4462
Constraint * MakeEquality(IntExpr *const left, IntExpr *const right)
left == right
Definition: range_cst.cc:512
OptimizeVar * MakeOptimize(bool maximize, IntVar *const v, int64_t step)
Creates a objective with a given sense (true = maximization).
Definition: search.cc:2922
IntVar * MakeIsGreaterOrEqualCstVar(IntExpr *const var, int64_t value)
status var of (var >= value)
Definition: expr_cst.cc:679
Decision * MakeAssignVariablesValuesOrFail(const std::vector< IntVar * > &vars, const std::vector< int64_t > &values)
Definition: search.cc:1811
ConstraintSolverParameters parameters() const
Stored Parameters.
SearchMonitor * MakeSymmetryManager(const std::vector< SymmetryBreaker * > &visitors)
Symmetry Breaking.
Definition: search.cc:4907
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...
Definition: search.cc:4187
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...
Definition: search.cc:4624
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...
Definition: search.cc:704
ABSL_MUST_USE_RESULT RegularLimit * MakeBranchesLimit(int64_t branches)
Creates a search limit that constrains the number of branches explored in the search tree.
Definition: search.cc:4180
OptimizeVar * MakeMaximize(IntVar *const v, int64_t step)
Creates a maximization objective.
Definition: search.cc:2918
SearchMonitor * MakeSearchLog(int branch_period)
The SearchMonitors below will display a periodic search log on LOG(INFO) every branch_period branches...
Definition: search.cc:288
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.
Definition: search.cc:4208
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.
Definition: search.cc:2914
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)
Definition: search.cc:1796
DecisionBuilder * MakeSolveOnce(DecisionBuilder *const db)
SolveOnce will collapse a search tree described by a decision builder 'db' and a set of monitors and ...
Definition: search.cc:4505
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.
Definition: search.cc:2976
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)
Definition: search.cc:1804
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'.
Definition: search.cc:4351
SearchMonitor * MakeConstantRestart(int frequency)
This search monitor will restart the search periodically after 'frequency' failures.
Definition: search.cc:4768
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)
Definition: expr_cst.cc:779
SearchMonitor * MakeSimulatedAnnealing(bool maximize, IntVar *const v, int64_t step, int64_t initial_temperature)
Creates a Simulated Annealing monitor.
Definition: search.cc:3425
RegularLimitParameters MakeDefaultRegularLimitParameters() const
Creates a regular limit proto containing default values.
Definition: search.cc:4223
ABSL_MUST_USE_RESULT RegularLimit * MakeTimeLimit(absl::Duration time)
Creates a search limit that constrains the running time.
Definition: search.cc:4173
SearchMonitor * MakeSearchTrace(const std::string &prefix)
Creates a search monitor that will trace precisely the behavior of the search.
Definition: search.cc:398
int TopProgressPercent()
Returns a percentage representing the propress of the search before reaching the limits of the top-le...
IntVarStrategy
This enum describes the strategy used to select the next branching variable at each node during the s...
@ CHOOSE_RANDOM
Randomly select one of the remaining unbound variables.
@ CHOOSE_MIN_SIZE
Among unbound variables, select the variable with the smallest size.
@ CHOOSE_FIRST_UNBOUND
Select the first unbound variable.
@ CHOOSE_PATH
Selects the next unbound variable on a path, the path being defined by the variables: var[i] correspo...
@ CHOOSE_HIGHEST_MAX
Among unbound variables, select the variable with the highest maximal value.
@ CHOOSE_MIN_SIZE_LOWEST_MIN
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ INT_VAR_DEFAULT
The default behavior is CHOOSE_FIRST_UNBOUND.
@ CHOOSE_MIN_SIZE_HIGHEST_MAX
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ CHOOSE_MAX_REGRET_ON_MIN
Among unbound variables, select the variable with the largest gap between the first and the second va...
@ CHOOSE_MIN_SIZE_HIGHEST_MIN
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ CHOOSE_MAX_SIZE
Among unbound variables, select the variable with the highest size.
@ INT_VAR_SIMPLE
The simple selection is CHOOSE_FIRST_UNBOUND.
@ CHOOSE_MIN_SIZE_LOWEST_MAX
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ CHOOSE_LOWEST_MIN
Among unbound variables, select the variable with the smallest minimal value.
DecisionBuilder * MakePhase(const std::vector< IntVar * > &vars, IntVarStrategy var_str, IntValueStrategy val_str)
Phases on IntVar arrays.
Definition: search.cc:2068
std::function< int64_t(const IntVar *v, int64_t id)> VariableValueSelector
SearchMonitor * MakeEnterSearchCallback(std::function< void()> callback)
--— Callback-based search monitors --—
Definition: search.cc:442
std::function< void(Solver *)> Action
SolutionCollector * MakeFirstSolutionCollector()
Collect the first solution of the search.
Definition: search.cc:2495
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).
Definition: search.cc:2962
std::function< int64_t(int64_t)> IndexEvaluator1
Callback typedefs.
SearchMonitor * MakeExitSearchCallback(std::function< void()> callback)
Definition: search.cc:462
Decision * MakeSplitVariableDomain(IntVar *const var, int64_t val, bool start_with_lower_half)
Definition: search.cc:1687
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,...
Definition: search.cc:2255
Decision * MakeVariableLessOrEqualValue(IntVar *const var, int64_t value)
Definition: search.cc:1692
IntVar * MakeIsEqualCstVar(IntExpr *const var, int64_t value)
status var of (var == value)
Definition: expr_cst.cc:462
int64_t solutions() const
The number of solutions found since the start of the search.
std::function< bool(int64_t, int64_t, int64_t)> VariableValueComparator
T * RevAlloc(T *object)
Registers the given object as being reversible.
Decision * MakeAssignVariableValueOrFail(IntVar *const var, int64_t value)
Definition: search.cc:1604
Decision * MakeVariableGreaterOrEqualValue(IntVar *const var, int64_t value)
Definition: search.cc:1697
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)
Definition: search.cc:4897
void AddIntegerVariableEqualValueClause(IntVar *const var, int64_t value)
Definition: search.cc:4881
void AddIntegerVariableGreaterOrEqualValueClause(IntVar *const var, int64_t value)
Definition: search.cc:4889
void AddTermToClause(SymmetryBreaker *const visitor, IntVar *const term)
Definition: search.cc:4866
void EndNextDecision(DecisionBuilder *const db, Decision *const d) override
After calling DecisionBuilder::Next, along with the returned decision.
Definition: search.cc:4805
void RefuteDecision(Decision *d) override
Before refuting the decision.
Definition: search.cc:4819
SymmetryManager(Solver *const s, const std::vector< SymmetryBreaker * > &visitors)
Definition: search.cc:4791
std::string DebugString() const override
Definition: search.cc:4870
int64_t b
int64_t a
std::vector< IntVarIterator * > iterators_
Block * next
SatParameters parameters
CpModelProto proto
const std::string name
const Constraint * ct
MPCallback * callback
const int64_t offset_
Definition: interval.cc:2108
int arc
int index
const int INFO
Definition: log_severity.h:31
const int FATAL
Definition: log_severity.h:32
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: macros.h:29
Definition: cleanup.h:22
void STLDeleteElements(T *container)
Definition: stl_util.h:372
bool FindCopy(const Collection &collection, const Key &key, Value *const value)
Definition: map_util.h:185
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)
Definition: map_util.h:29
std::function< int64_t(const Model &)> Value(IntegerVariable v)
Definition: integer.h:1683
Collection of objects used to extend the Constraint Solver library.
int64_t CapAdd(int64_t x, int64_t y)
int64_t CapSub(int64_t x, int64_t y)
int64_t Zero()
NOLINT.
std::pair< int64_t, int64_t > Arc
Definition: search.cc:3434
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)
Definition: string_array.h:45
bool AcceptDelta(Search *const search, Assignment *delta, Assignment *deltadelta)
std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)
Definition: utilities.cc:828
void AcceptNeighbor(Search *const search)
BaseAssignVariables::Mode ChooseMode(Solver::IntValueStrategy val_str)
Definition: search.cc:2058
STL namespace.
int64_t time
Definition: resource.cc:1693
int64_t delta
Definition: resource.cc:1694
int64_t bound
std::priority_queue< std::pair< int64_t, SolutionData > > solutions_pq_
Definition: search.cc:2640
int64_t assignment_penalized_value_
Definition: search.cc:3562
const double penalty_factor_
Definition: search.cc:3566
int64_t step_
Definition: search.cc:3018
std::vector< DecisionBuilder * > builders_
Definition: search.cc:480
std::unique_ptr< int64_t[]> delta_cache_
Definition: search.cc:3569
BaseVariableAssignmentSelector *const selector_
Definition: search.cc:1916
int64_t best_
Definition: search.cc:2560
std::unique_ptr< int64_t[]> current_penalized_values_
Definition: search.cc:3568
const int solution_count_
Definition: search.cc:2641
int64_t var
Definition: search.cc:1360
int64_t current_
Definition: search.cc:3019
ABSL_FLAG(bool, cp_use_sparse_gls_penalties, false, "Use sparse implementation to store Guided Local Search penalties")
IntVar * penalized_objective_
Definition: search.cc:3560
const bool maximize_
Definition: search.cc:2559
std::vector< IntVar * > vars_
Definition: search.cc:790
IntVar *const objective_
Definition: search.cc:3017
Rev< int64_t > first_unbound_
Definition: search.cc:791
Rev< int64_t > last_unbound_
Definition: search.cc:792
std::function< int64_t(int64_t, int64_t)> evaluator_
Definition: search.cc:1368
Solver *const solver_
Definition: search.cc:789
int64_t value
Definition: search.cc:1361
int64_t old_penalized_value_
Definition: search.cc:3563
bool incremental_
Definition: search.cc:3570
absl::flat_hash_map< const IntVar *, int64_t > indices_
Definition: search.cc:3565
const int64_t stamp_
Definition: search.cc:3105
const Mode mode_
Definition: search.cc:1917
Creates a search monitor from logging parameters.
double objective_value