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