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