OR-Tools  9.0
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  AssignVariablesValues(const std::vector<IntVar*>& vars,
1708  const std::vector<int64_t>& values);
1709  ~AssignVariablesValues() override {}
1710  void Apply(Solver* const s) override;
1711  void Refute(Solver* const s) override;
1712  std::string DebugString() const override;
1713  void Accept(DecisionVisitor* const visitor) const override {
1714  for (int i = 0; i < vars_.size(); ++i) {
1715  visitor->VisitSetVariableValue(vars_[i], values_[i]);
1716  }
1717  }
1718 
1719  virtual void Accept(ModelVisitor* const visitor) const {
1720  visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
1721  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
1722  vars_);
1723  visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
1724  }
1725 
1726  private:
1727  const std::vector<IntVar*> vars_;
1728  const std::vector<int64_t> values_;
1729 };
1730 
1731 AssignVariablesValues::AssignVariablesValues(const std::vector<IntVar*>& vars,
1732  const std::vector<int64_t>& values)
1733  : vars_(vars), values_(values) {}
1734 
1735 std::string AssignVariablesValues::DebugString() const {
1736  std::string out;
1737  for (int i = 0; i < vars_.size(); ++i) {
1738  absl::StrAppendFormat(&out, "[%s == %d]", vars_[i]->DebugString(),
1739  values_[i]);
1740  }
1741  return out;
1742 }
1743 
1744 void AssignVariablesValues::Apply(Solver* const s) {
1745  for (int i = 0; i < vars_.size(); ++i) {
1746  vars_[i]->SetValue(values_[i]);
1747  }
1748 }
1749 
1750 void AssignVariablesValues::Refute(Solver* const s) {
1751  std::vector<IntVar*> terms;
1752  for (int i = 0; i < vars_.size(); ++i) {
1753  IntVar* term = s->MakeBoolVar();
1754  s->MakeIsDifferentCstCt(vars_[i], values_[i], term);
1755  terms.push_back(term);
1756  }
1757  s->AddConstraint(s->MakeSumGreaterOrEqual(terms, 1));
1758 }
1759 } // namespace
1760 
1762  const std::vector<IntVar*>& vars, const std::vector<int64_t>& values) {
1763  CHECK_EQ(vars.size(), values.size());
1764  return RevAlloc(new AssignVariablesValues(vars, values));
1765 }
1766 
1767 // ----- AssignAllVariables -----
1768 
1769 namespace {
1770 class BaseAssignVariables : public DecisionBuilder {
1771  public:
1772  enum Mode {
1773  ASSIGN,
1774  SPLIT_LOWER,
1775  SPLIT_UPPER,
1776  };
1777 
1778  BaseAssignVariables(BaseVariableAssignmentSelector* const selector, Mode mode)
1779  : selector_(selector), mode_(mode) {}
1780 
1781  ~BaseAssignVariables() override;
1782  Decision* Next(Solver* const s) override;
1783  std::string DebugString() const override;
1784  static BaseAssignVariables* MakePhase(
1785  Solver* const s, const std::vector<IntVar*>& vars,
1786  Solver::VariableIndexSelector var_selector,
1787  Solver::VariableValueSelector value_selector,
1788  const std::string& value_selector_name, BaseAssignVariables::Mode mode);
1789 
1790  static Solver::VariableIndexSelector MakeVariableSelector(
1791  Solver* const s, const std::vector<IntVar*>& vars,
1792  Solver::IntVarStrategy str) {
1793  switch (str) {
1797  return ChooseFirstUnbound;
1798  case Solver::CHOOSE_RANDOM:
1799  return ChooseRandom;
1801  return ChooseMinSizeLowestMin;
1803  return ChooseMinSizeHighestMin;
1805  return ChooseMinSizeLowestMax;
1807  return ChooseMinSizeHighestMax;
1809  return ChooseLowestMin;
1811  return ChooseHighestMax;
1813  return ChooseMinSize;
1815  return ChooseMaxSize;
1817  HighestRegretSelectorOnMin* const selector =
1818  s->RevAlloc(new HighestRegretSelectorOnMin(vars));
1819  return [selector](Solver* solver, const std::vector<IntVar*>& vars,
1820  int first_unbound, int last_unbound) {
1821  return selector->Choose(solver, vars, first_unbound, last_unbound);
1822  };
1823  }
1824  case Solver::CHOOSE_PATH: {
1825  PathSelector* const selector = s->RevAlloc(new PathSelector());
1826  return [selector](Solver* solver, const std::vector<IntVar*>& vars,
1827  int first_unbound, int last_unbound) {
1828  return selector->Choose(solver, vars, first_unbound, last_unbound);
1829  };
1830  }
1831  default:
1832  LOG(FATAL) << "Unknown int var strategy " << str;
1833  return nullptr;
1834  }
1835  }
1836 
1837  static Solver::VariableValueSelector MakeValueSelector(
1838  Solver* const s, Solver::IntValueStrategy val_str) {
1839  switch (val_str) {
1843  return SelectMinValue;
1845  return SelectMaxValue;
1847  return SelectRandomValue;
1849  return SelectCenterValue;
1851  return SelectSplitValue;
1853  return SelectSplitValue;
1854  default:
1855  LOG(FATAL) << "Unknown int value strategy " << val_str;
1856  return nullptr;
1857  }
1858  }
1859 
1860  void Accept(ModelVisitor* const visitor) const override {
1861  selector_->Accept(visitor);
1862  }
1863 
1864  protected:
1865  BaseVariableAssignmentSelector* const selector_;
1866  const Mode mode_;
1867 };
1868 
1869 BaseAssignVariables::~BaseAssignVariables() {}
1870 
1871 Decision* BaseAssignVariables::Next(Solver* const s) {
1872  const std::vector<IntVar*>& vars = selector_->vars();
1873  int id = selector_->ChooseVariableWrapper();
1874  if (id >= 0 && id < vars.size()) {
1875  IntVar* const var = vars[id];
1876  const int64_t value = selector_->SelectValue(var, id);
1877  switch (mode_) {
1878  case ASSIGN:
1879  return s->RevAlloc(new AssignOneVariableValue(var, value));
1880  case SPLIT_LOWER:
1881  return s->RevAlloc(new SplitOneVariable(var, value, true));
1882  case SPLIT_UPPER:
1883  return s->RevAlloc(new SplitOneVariable(var, value, false));
1884  }
1885  }
1886  return nullptr;
1887 }
1888 
1889 std::string BaseAssignVariables::DebugString() const {
1890  return selector_->DebugString();
1891 }
1892 
1893 BaseAssignVariables* BaseAssignVariables::MakePhase(
1894  Solver* const s, const std::vector<IntVar*>& vars,
1895  Solver::VariableIndexSelector var_selector,
1896  Solver::VariableValueSelector value_selector,
1897  const std::string& value_selector_name, BaseAssignVariables::Mode mode) {
1898  BaseVariableAssignmentSelector* const selector =
1899  s->RevAlloc(new VariableAssignmentSelector(
1900  s, vars, std::move(var_selector), std::move(value_selector),
1901  value_selector_name));
1902  return s->RevAlloc(new BaseAssignVariables(selector, mode));
1903 }
1904 
1905 std::string ChooseVariableName(Solver::IntVarStrategy var_str) {
1906  switch (var_str) {
1910  return "ChooseFirstUnbound";
1911  case Solver::CHOOSE_RANDOM:
1912  return "ChooseRandom";
1914  return "ChooseMinSizeLowestMin";
1916  return "ChooseMinSizeHighestMin";
1918  return "ChooseMinSizeLowestMax";
1920  return "ChooseMinSizeHighestMax";
1922  return "ChooseLowestMin";
1924  return "ChooseHighestMax";
1926  return "ChooseMinSize";
1928  return "ChooseMaxSize;";
1930  return "HighestRegretSelectorOnMin";
1931  case Solver::CHOOSE_PATH:
1932  return "PathSelector";
1933  default:
1934  LOG(FATAL) << "Unknown int var strategy " << var_str;
1935  return "";
1936  }
1937 }
1938 
1939 std::string SelectValueName(Solver::IntValueStrategy val_str) {
1940  switch (val_str) {
1944  return "SelectMinValue";
1946  return "SelectMaxValue";
1948  return "SelectRandomValue";
1950  return "SelectCenterValue";
1952  return "SelectSplitValue";
1954  return "SelectSplitValue";
1955  default:
1956  LOG(FATAL) << "Unknown int value strategy " << val_str;
1957  return "";
1958  }
1959 }
1960 
1961 std::string BuildHeuristicsName(Solver::IntVarStrategy var_str,
1962  Solver::IntValueStrategy val_str) {
1963  return ChooseVariableName(var_str) + "_" + SelectValueName(val_str);
1964 }
1965 } // namespace
1966 
1968  Solver::IntVarStrategy var_str,
1969  Solver::IntValueStrategy val_str) {
1970  std::vector<IntVar*> vars(1);
1971  vars[0] = v0;
1972  return MakePhase(vars, var_str, val_str);
1973 }
1974 
1976  Solver::IntVarStrategy var_str,
1977  Solver::IntValueStrategy val_str) {
1978  std::vector<IntVar*> vars(2);
1979  vars[0] = v0;
1980  vars[1] = v1;
1981  return MakePhase(vars, var_str, val_str);
1982 }
1983 
1985  IntVar* const v2,
1986  Solver::IntVarStrategy var_str,
1987  Solver::IntValueStrategy val_str) {
1988  std::vector<IntVar*> vars(3);
1989  vars[0] = v0;
1990  vars[1] = v1;
1991  vars[2] = v2;
1992  return MakePhase(vars, var_str, val_str);
1993 }
1994 
1996  IntVar* const v2, IntVar* const v3,
1997  Solver::IntVarStrategy var_str,
1998  Solver::IntValueStrategy val_str) {
1999  std::vector<IntVar*> vars(4);
2000  vars[0] = v0;
2001  vars[1] = v1;
2002  vars[2] = v2;
2003  vars[3] = v3;
2004  return MakePhase(vars, var_str, val_str);
2005 }
2006 
2007 BaseAssignVariables::Mode ChooseMode(Solver::IntValueStrategy val_str) {
2008  BaseAssignVariables::Mode mode = BaseAssignVariables::ASSIGN;
2009  if (val_str == Solver::SPLIT_LOWER_HALF) {
2010  mode = BaseAssignVariables::SPLIT_LOWER;
2011  } else if (val_str == Solver::SPLIT_UPPER_HALF) {
2012  mode = BaseAssignVariables::SPLIT_UPPER;
2013  }
2014  return mode;
2015 }
2016 
2017 DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2018  Solver::IntVarStrategy var_str,
2019  Solver::IntValueStrategy val_str) {
2020  Solver::VariableIndexSelector var_selector =
2021  BaseAssignVariables::MakeVariableSelector(this, vars, var_str);
2022  Solver::VariableValueSelector value_selector =
2023  BaseAssignVariables::MakeValueSelector(this, val_str);
2024  const std::string name = BuildHeuristicsName(var_str, val_str);
2025  return BaseAssignVariables::MakePhase(
2026  this, vars, var_selector, value_selector, name, ChooseMode(val_str));
2027 }
2028 
2029 DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2030  Solver::IndexEvaluator1 var_evaluator,
2031  Solver::IntValueStrategy val_str) {
2032  CHECK(var_evaluator != nullptr);
2033  CheapestVarSelector* const var_selector =
2034  RevAlloc(new CheapestVarSelector(std::move(var_evaluator)));
2035  Solver::VariableIndexSelector choose_variable =
2036  [var_selector](Solver* solver, const std::vector<IntVar*>& vars,
2037  int first_unbound, int last_unbound) {
2038  return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2039  };
2040  Solver::VariableValueSelector select_value =
2041  BaseAssignVariables::MakeValueSelector(this, val_str);
2042  const std::string name = "ChooseCheapestVariable_" + SelectValueName(val_str);
2043  return BaseAssignVariables::MakePhase(
2044  this, vars, choose_variable, select_value, name, ChooseMode(val_str));
2045 }
2046 
2047 DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2048  Solver::IntVarStrategy var_str,
2049  Solver::IndexEvaluator2 value_evaluator) {
2050  Solver::VariableIndexSelector choose_variable =
2051  BaseAssignVariables::MakeVariableSelector(this, vars, var_str);
2052  CheapestValueSelector* const value_selector =
2053  RevAlloc(new CheapestValueSelector(std::move(value_evaluator), nullptr));
2054  Solver::VariableValueSelector select_value =
2055  [value_selector](const IntVar* var, int64_t id) {
2056  return value_selector->Select(var, id);
2057  };
2058  const std::string name = ChooseVariableName(var_str) + "_SelectCheapestValue";
2059  return BaseAssignVariables::MakePhase(this, vars, choose_variable,
2060  select_value, name,
2061  BaseAssignVariables::ASSIGN);
2062 }
2063 
2065  const std::vector<IntVar*>& vars, IntVarStrategy var_str,
2066  VariableValueComparator var_val1_val2_comparator) {
2067  Solver::VariableIndexSelector choose_variable =
2068  BaseAssignVariables::MakeVariableSelector(this, vars, var_str);
2069  BestValueByComparisonSelector* const value_selector = RevAlloc(
2070  new BestValueByComparisonSelector(std::move(var_val1_val2_comparator)));
2071  Solver::VariableValueSelector select_value =
2072  [value_selector](const IntVar* var, int64_t id) {
2073  return value_selector->Select(var, id);
2074  };
2075  return BaseAssignVariables::MakePhase(this, vars, choose_variable,
2076  select_value, "CheapestValue",
2077  BaseAssignVariables::ASSIGN);
2078 }
2079 
2080 DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2081  Solver::IndexEvaluator1 var_evaluator,
2082  Solver::IndexEvaluator2 value_evaluator) {
2083  CheapestVarSelector* const var_selector =
2084  RevAlloc(new CheapestVarSelector(std::move(var_evaluator)));
2085  Solver::VariableIndexSelector choose_variable =
2086  [var_selector](Solver* solver, const std::vector<IntVar*>& vars,
2087  int first_unbound, int last_unbound) {
2088  return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2089  };
2090  CheapestValueSelector* value_selector =
2091  RevAlloc(new CheapestValueSelector(std::move(value_evaluator), nullptr));
2092  Solver::VariableValueSelector select_value =
2093  [value_selector](const IntVar* var, int64_t id) {
2094  return value_selector->Select(var, id);
2095  };
2096  return BaseAssignVariables::MakePhase(this, vars, choose_variable,
2097  select_value, "CheapestValue",
2098  BaseAssignVariables::ASSIGN);
2099 }
2100 
2101 DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2102  Solver::IntVarStrategy var_str,
2103  Solver::IndexEvaluator2 value_evaluator,
2104  Solver::IndexEvaluator1 tie_breaker) {
2105  Solver::VariableIndexSelector choose_variable =
2106  BaseAssignVariables::MakeVariableSelector(this, vars, var_str);
2107  CheapestValueSelector* value_selector = RevAlloc(new CheapestValueSelector(
2108  std::move(value_evaluator), std::move(tie_breaker)));
2109  Solver::VariableValueSelector select_value =
2110  [value_selector](const IntVar* var, int64_t id) {
2111  return value_selector->Select(var, id);
2112  };
2113  return BaseAssignVariables::MakePhase(this, vars, choose_variable,
2114  select_value, "CheapestValue",
2115  BaseAssignVariables::ASSIGN);
2116 }
2117 
2118 DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2119  Solver::IndexEvaluator1 var_evaluator,
2120  Solver::IndexEvaluator2 value_evaluator,
2121  Solver::IndexEvaluator1 tie_breaker) {
2122  CheapestVarSelector* const var_selector =
2123  RevAlloc(new CheapestVarSelector(std::move(var_evaluator)));
2124  Solver::VariableIndexSelector choose_variable =
2125  [var_selector](Solver* solver, const std::vector<IntVar*>& vars,
2126  int first_unbound, int last_unbound) {
2127  return var_selector->Choose(solver, vars, first_unbound, last_unbound);
2128  };
2129  CheapestValueSelector* value_selector = RevAlloc(new CheapestValueSelector(
2130  std::move(value_evaluator), std::move(tie_breaker)));
2131  Solver::VariableValueSelector select_value =
2132  [value_selector](const IntVar* var, int64_t id) {
2133  return value_selector->Select(var, id);
2134  };
2135  return BaseAssignVariables::MakePhase(this, vars, choose_variable,
2136  select_value, "CheapestValue",
2137  BaseAssignVariables::ASSIGN);
2138 }
2139 
2140 DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2143  return MakePhase(vars, std::move(eval), nullptr, str);
2144 }
2145 
2146 DecisionBuilder* Solver::MakePhase(const std::vector<IntVar*>& vars,
2148  Solver::IndexEvaluator1 tie_breaker,
2150  BaseVariableAssignmentSelector* selector = nullptr;
2151  switch (str) {
2153  // TODO(user): support tie breaker
2154  selector = RevAlloc(new StaticEvaluatorSelector(this, vars, eval));
2155  break;
2156  }
2158  selector = RevAlloc(new DynamicEvaluatorSelector(this, vars, eval,
2159  std::move(tie_breaker)));
2160  break;
2161  }
2162  }
2163  return RevAlloc(
2164  new BaseAssignVariables(selector, BaseAssignVariables::ASSIGN));
2165 }
2166 
2167 // ----- AssignAllVariablesFromAssignment decision builder -----
2168 
2169 namespace {
2170 class AssignVariablesFromAssignment : public DecisionBuilder {
2171  public:
2172  AssignVariablesFromAssignment(const Assignment* const assignment,
2173  DecisionBuilder* const db,
2174  const std::vector<IntVar*>& vars)
2175  : assignment_(assignment), db_(db), vars_(vars), iter_(0) {}
2176 
2177  ~AssignVariablesFromAssignment() override {}
2178 
2179  Decision* Next(Solver* const s) override {
2180  if (iter_ < vars_.size()) {
2181  IntVar* const var = vars_[iter_++];
2182  return s->RevAlloc(
2183  new AssignOneVariableValue(var, assignment_->Value(var)));
2184  } else {
2185  return db_->Next(s);
2186  }
2187  }
2188 
2189  void Accept(ModelVisitor* const visitor) const override {
2190  visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
2191  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
2192  vars_);
2193  visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
2194  }
2195 
2196  private:
2197  const Assignment* const assignment_;
2198  DecisionBuilder* const db_;
2199  const std::vector<IntVar*> vars_;
2200  int iter_;
2201 };
2202 } // namespace
2203 
2205  Assignment* const assignment, DecisionBuilder* const db,
2206  const std::vector<IntVar*>& vars) {
2207  return RevAlloc(new AssignVariablesFromAssignment(assignment, db, vars));
2208 }
2209 
2210 // ---------- Solution Collectors -----------
2211 
2212 // ----- Base Class -----
2213 
2215  const Assignment* const assignment)
2216  : SearchMonitor(solver),
2217  prototype_(assignment == nullptr ? nullptr : new Assignment(assignment)) {
2218 }
2219 
2221  : SearchMonitor(solver), prototype_(new Assignment(solver)) {}
2222 
2224  for (auto& data : solution_data_) {
2225  delete data.solution;
2226  }
2228 }
2229 
2231  if (prototype_ != nullptr) {
2232  prototype_->Add(var);
2233  }
2234 }
2235 
2236 void SolutionCollector::Add(const std::vector<IntVar*>& vars) {
2237  if (prototype_ != nullptr) {
2238  prototype_->Add(vars);
2239  }
2240 }
2241 
2243  if (prototype_ != nullptr) {
2244  prototype_->Add(var);
2245  }
2246 }
2247 
2248 void SolutionCollector::Add(const std::vector<IntervalVar*>& vars) {
2249  if (prototype_ != nullptr) {
2250  prototype_->Add(vars);
2251  }
2252 }
2253 
2255  if (prototype_ != nullptr) {
2256  prototype_->Add(var);
2257  }
2258 }
2259 
2260 void SolutionCollector::Add(const std::vector<SequenceVar*>& vars) {
2261  if (prototype_ != nullptr) {
2262  prototype_->Add(vars);
2263  }
2264 }
2265 
2266 void SolutionCollector::AddObjective(IntVar* const objective) {
2267  if (prototype_ != nullptr && objective != nullptr) {
2268  prototype_->AddObjective(objective);
2269  }
2270 }
2271 
2273  for (auto& data : solution_data_) {
2274  delete data.solution;
2275  }
2277  solution_data_.clear();
2278  recycle_solutions_.clear();
2279 }
2280 
2283 }
2284 
2286  if (!solution_data_.empty()) {
2287  FreeSolution(solution_data_.back().solution);
2288  solution_data_.pop_back();
2289  }
2290 }
2291 
2294  Assignment* solution = nullptr;
2295  if (prototype_ != nullptr) {
2296  if (!recycle_solutions_.empty()) {
2297  solution = recycle_solutions_.back();
2298  DCHECK(solution != nullptr);
2299  recycle_solutions_.pop_back();
2300  } else {
2301  solution = new Assignment(prototype_.get());
2302  }
2303  solution->Store();
2304  }
2305  SolutionData data;
2306  data.solution = solution;
2307  data.time = solver()->wall_time();
2308  data.branches = solver()->branches();
2309  data.failures = solver()->failures();
2310  if (solution != nullptr) {
2312  } else {
2313  data.objective_value = 0;
2314  }
2315  return data;
2316 }
2317 
2319  if (solution != nullptr) {
2320  recycle_solutions_.push_back(solution);
2321  }
2322 }
2323 
2325  CHECK_GE(n, 0) << "wrong index in solution getter";
2326  CHECK_LT(n, solution_data_.size()) << "wrong index in solution getter";
2327 }
2328 
2330  check_index(n);
2331  return solution_data_[n].solution;
2332 }
2333 
2335 
2336 int64_t SolutionCollector::wall_time(int n) const {
2337  check_index(n);
2338  return solution_data_[n].time;
2339 }
2340 
2341 int64_t SolutionCollector::branches(int n) const {
2342  check_index(n);
2343  return solution_data_[n].branches;
2344 }
2345 
2346 int64_t SolutionCollector::failures(int n) const {
2347  check_index(n);
2348  return solution_data_[n].failures;
2349 }
2350 
2352  check_index(n);
2353  return solution_data_[n].objective_value;
2354 }
2355 
2356 int64_t SolutionCollector::Value(int n, IntVar* const var) const {
2357  return solution(n)->Value(var);
2358 }
2359 
2360 int64_t SolutionCollector::StartValue(int n, IntervalVar* const var) const {
2361  return solution(n)->StartValue(var);
2362 }
2363 
2364 int64_t SolutionCollector::DurationValue(int n, IntervalVar* const var) const {
2365  return solution(n)->DurationValue(var);
2366 }
2367 
2368 int64_t SolutionCollector::EndValue(int n, IntervalVar* const var) const {
2369  return solution(n)->EndValue(var);
2370 }
2371 
2372 int64_t SolutionCollector::PerformedValue(int n, IntervalVar* const var) const {
2373  return solution(n)->PerformedValue(var);
2374 }
2375 
2376 const std::vector<int>& SolutionCollector::ForwardSequence(
2377  int n, SequenceVar* const var) const {
2378  return solution(n)->ForwardSequence(var);
2379 }
2380 
2381 const std::vector<int>& SolutionCollector::BackwardSequence(
2382  int n, SequenceVar* const var) const {
2383  return solution(n)->BackwardSequence(var);
2384 }
2385 
2386 const std::vector<int>& SolutionCollector::Unperformed(
2387  int n, SequenceVar* const var) const {
2388  return solution(n)->Unperformed(var);
2389 }
2390 
2391 namespace {
2392 // ----- First Solution Collector -----
2393 
2394 // Collect first solution, useful when looking satisfaction problems
2395 class FirstSolutionCollector : public SolutionCollector {
2396  public:
2397  FirstSolutionCollector(Solver* const s, const Assignment* const a);
2398  explicit FirstSolutionCollector(Solver* const s);
2399  ~FirstSolutionCollector() override;
2400  void EnterSearch() override;
2401  bool AtSolution() override;
2402  std::string DebugString() const override;
2403 
2404  private:
2405  bool done_;
2406 };
2407 
2408 FirstSolutionCollector::FirstSolutionCollector(Solver* const s,
2409  const Assignment* const a)
2410  : SolutionCollector(s, a), done_(false) {}
2411 
2412 FirstSolutionCollector::FirstSolutionCollector(Solver* const s)
2413  : SolutionCollector(s), done_(false) {}
2414 
2415 FirstSolutionCollector::~FirstSolutionCollector() {}
2416 
2417 void FirstSolutionCollector::EnterSearch() {
2419  done_ = false;
2420 }
2421 
2422 bool FirstSolutionCollector::AtSolution() {
2423  if (!done_) {
2424  PushSolution();
2425  done_ = true;
2426  }
2427  return false;
2428 }
2429 
2430 std::string FirstSolutionCollector::DebugString() const {
2431  if (prototype_ == nullptr) {
2432  return "FirstSolutionCollector()";
2433  } else {
2434  return "FirstSolutionCollector(" + prototype_->DebugString() + ")";
2435  }
2436 }
2437 } // namespace
2438 
2440  const Assignment* const assignment) {
2441  return RevAlloc(new FirstSolutionCollector(this, assignment));
2442 }
2443 
2445  return RevAlloc(new FirstSolutionCollector(this));
2446 }
2447 
2448 // ----- Last Solution Collector -----
2449 
2450 // Collect last solution, useful when optimizing
2451 namespace {
2452 class LastSolutionCollector : public SolutionCollector {
2453  public:
2454  LastSolutionCollector(Solver* const s, const Assignment* const a);
2455  explicit LastSolutionCollector(Solver* const s);
2456  ~LastSolutionCollector() override;
2457  bool AtSolution() override;
2458  std::string DebugString() const override;
2459 };
2460 
2461 LastSolutionCollector::LastSolutionCollector(Solver* const s,
2462  const Assignment* const a)
2463  : SolutionCollector(s, a) {}
2464 
2465 LastSolutionCollector::LastSolutionCollector(Solver* const s)
2466  : SolutionCollector(s) {}
2467 
2468 LastSolutionCollector::~LastSolutionCollector() {}
2469 
2470 bool LastSolutionCollector::AtSolution() {
2471  PopSolution();
2472  PushSolution();
2473  return true;
2474 }
2475 
2476 std::string LastSolutionCollector::DebugString() const {
2477  if (prototype_ == nullptr) {
2478  return "LastSolutionCollector()";
2479  } else {
2480  return "LastSolutionCollector(" + prototype_->DebugString() + ")";
2481  }
2482 }
2483 } // namespace
2484 
2486  const Assignment* const assignment) {
2487  return RevAlloc(new LastSolutionCollector(this, assignment));
2488 }
2489 
2491  return RevAlloc(new LastSolutionCollector(this));
2492 }
2493 
2494 // ----- Best Solution Collector -----
2495 
2496 namespace {
2497 class BestValueSolutionCollector : public SolutionCollector {
2498  public:
2499  BestValueSolutionCollector(Solver* const s, const Assignment* const a,
2500  bool maximize);
2501  BestValueSolutionCollector(Solver* const s, bool maximize);
2502  ~BestValueSolutionCollector() override {}
2503  void EnterSearch() override;
2504  bool AtSolution() override;
2505  std::string DebugString() const override;
2506 
2507  public:
2508  const bool maximize_;
2509  int64_t best_;
2510 };
2511 
2512 BestValueSolutionCollector::BestValueSolutionCollector(
2513  Solver* const s, const Assignment* const a, bool maximize)
2514  : SolutionCollector(s, a),
2515  maximize_(maximize),
2516  best_(maximize ? std::numeric_limits<int64_t>::min()
2517  : std::numeric_limits<int64_t>::max()) {}
2518 
2519 BestValueSolutionCollector::BestValueSolutionCollector(Solver* const s,
2520  bool maximize)
2521  : SolutionCollector(s),
2522  maximize_(maximize),
2523  best_(maximize ? std::numeric_limits<int64_t>::min()
2524  : std::numeric_limits<int64_t>::max()) {}
2525 
2526 void BestValueSolutionCollector::EnterSearch() {
2527  SolutionCollector::EnterSearch();
2529  : std::numeric_limits<int64_t>::max();
2530 }
2531 
2532 bool BestValueSolutionCollector::AtSolution() {
2533  if (prototype_ != nullptr) {
2534  const IntVar* objective = prototype_->Objective();
2535  if (objective != nullptr) {
2536  if (maximize_ && (solution_count() == 0 || objective->Max() > best_)) {
2537  PopSolution();
2538  PushSolution();
2539  best_ = objective->Max();
2540  } else if (!maximize_ &&
2541  (solution_count() == 0 || objective->Min() < best_)) {
2542  PopSolution();
2543  PushSolution();
2544  best_ = objective->Min();
2545  }
2546  }
2547  }
2548  return true;
2549 }
2550 
2551 std::string BestValueSolutionCollector::DebugString() const {
2552  if (prototype_ == nullptr) {
2553  return "BestValueSolutionCollector()";
2554  } else {
2555  return "BestValueSolutionCollector(" + prototype_->DebugString() + ")";
2556  }
2557 }
2558 } // namespace
2559 
2560 SolutionCollector* Solver::MakeBestValueSolutionCollector(
2561  const Assignment* const assignment, bool maximize) {
2562  return RevAlloc(new BestValueSolutionCollector(this, assignment, maximize));
2563 }
2564 
2565 SolutionCollector* Solver::MakeBestValueSolutionCollector(bool maximize) {
2566  return RevAlloc(new BestValueSolutionCollector(this, maximize));
2567 }
2568 
2569 // ----- N Best Solution Collector -----
2570 
2571 namespace {
2572 class NBestValueSolutionCollector : public SolutionCollector {
2573  public:
2574  NBestValueSolutionCollector(Solver* const solver,
2575  const Assignment* const assignment,
2576  int solution_count, bool maximize);
2577  NBestValueSolutionCollector(Solver* const solver, int solution_count,
2578  bool maximize);
2579  ~NBestValueSolutionCollector() override { Clear(); }
2580  void EnterSearch() override;
2581  void ExitSearch() override;
2582  bool AtSolution() override;
2583  std::string DebugString() const override;
2584 
2585  public:
2586  void Clear();
2587 
2588  const bool maximize_;
2589  std::priority_queue<std::pair<int64_t, SolutionData>> solutions_pq_;
2590  const int solution_count_;
2591 };
2592 
2593 NBestValueSolutionCollector::NBestValueSolutionCollector(
2594  Solver* const solver, const Assignment* const assignment,
2595  int solution_count, bool maximize)
2596  : SolutionCollector(solver, assignment),
2597  maximize_(maximize),
2598  solution_count_(solution_count) {}
2599 
2600 NBestValueSolutionCollector::NBestValueSolutionCollector(Solver* const solver,
2601  int solution_count,
2602  bool maximize)
2603  : SolutionCollector(solver),
2604  maximize_(maximize),
2605  solution_count_(solution_count) {}
2606 
2607 void NBestValueSolutionCollector::EnterSearch() {
2608  SolutionCollector::EnterSearch();
2609  // TODO(user): Remove this when fast local search works with
2610  // multiple solutions collected.
2611  if (solution_count_ > 1) {
2612  solver()->SetUseFastLocalSearch(false);
2613  }
2614  Clear();
2615 }
2616 
2617 void NBestValueSolutionCollector::ExitSearch() {
2618  while (!solutions_pq_.empty()) {
2619  Push(solutions_pq_.top().second);
2620  solutions_pq_.pop();
2621  }
2622 }
2623 
2624 bool NBestValueSolutionCollector::AtSolution() {
2625  if (prototype_ != nullptr) {
2626  const IntVar* objective = prototype_->Objective();
2627  if (objective != nullptr) {
2628  const int64_t objective_value =
2629  maximize_ ? CapSub(0, objective->Max()) : objective->Min();
2630  if (solutions_pq_.size() < solution_count_) {
2631  solutions_pq_.push(
2632  {objective_value, BuildSolutionDataForCurrentState()});
2633  } else if (!solutions_pq_.empty()) {
2634  const auto& top = solutions_pq_.top();
2635  if (top.first > objective_value) {
2636  FreeSolution(solutions_pq_.top().second.solution);
2637  solutions_pq_.pop();
2638  solutions_pq_.push(
2639  {objective_value, BuildSolutionDataForCurrentState()});
2640  }
2641  }
2642  }
2643  }
2644  return true;
2645 }
2646 
2647 std::string NBestValueSolutionCollector::DebugString() const {
2648  if (prototype_ == nullptr) {
2649  return "NBestValueSolutionCollector()";
2650  } else {
2651  return "NBestValueSolutionCollector(" + prototype_->DebugString() + ")";
2652  }
2653 }
2654 
2655 void NBestValueSolutionCollector::Clear() {
2656  while (!solutions_pq_.empty()) {
2657  delete solutions_pq_.top().second.solution;
2658  solutions_pq_.pop();
2659  }
2660 }
2661 
2662 } // namespace
2663 
2664 SolutionCollector* Solver::MakeNBestValueSolutionCollector(
2665  const Assignment* const assignment, int solution_count, bool maximize) {
2666  if (solution_count == 1) {
2667  return MakeBestValueSolutionCollector(assignment, maximize);
2668  }
2669  return RevAlloc(new NBestValueSolutionCollector(this, assignment,
2670  solution_count, maximize));
2671 }
2672 
2673 SolutionCollector* Solver::MakeNBestValueSolutionCollector(int solution_count,
2674  bool maximize) {
2675  if (solution_count == 1) {
2676  return MakeBestValueSolutionCollector(maximize);
2677  }
2678  return RevAlloc(
2679  new NBestValueSolutionCollector(this, solution_count, maximize));
2680 }
2681 
2682 // ----- All Solution Collector -----
2683 
2684 // collect all solutions
2685 namespace {
2686 class AllSolutionCollector : public SolutionCollector {
2687  public:
2688  AllSolutionCollector(Solver* const s, const Assignment* const a);
2689  explicit AllSolutionCollector(Solver* const s);
2690  ~AllSolutionCollector() override;
2691  bool AtSolution() override;
2692  std::string DebugString() const override;
2693 };
2694 
2695 AllSolutionCollector::AllSolutionCollector(Solver* const s,
2696  const Assignment* const a)
2697  : SolutionCollector(s, a) {}
2698 
2699 AllSolutionCollector::AllSolutionCollector(Solver* const s)
2700  : SolutionCollector(s) {}
2701 
2702 AllSolutionCollector::~AllSolutionCollector() {}
2703 
2704 bool AllSolutionCollector::AtSolution() {
2705  PushSolution();
2706  return true;
2707 }
2708 
2709 std::string AllSolutionCollector::DebugString() const {
2710  if (prototype_ == nullptr) {
2711  return "AllSolutionCollector()";
2712  } else {
2713  return "AllSolutionCollector(" + prototype_->DebugString() + ")";
2714  }
2715 }
2716 } // namespace
2717 
2719  const Assignment* const assignment) {
2720  return RevAlloc(new AllSolutionCollector(this, assignment));
2721 }
2722 
2724  return RevAlloc(new AllSolutionCollector(this));
2725 }
2726 
2727 // ---------- Objective Management ----------
2728 
2729 OptimizeVar::OptimizeVar(Solver* const s, bool maximize, IntVar* const a,
2730  int64_t step)
2731  : SearchMonitor(s),
2732  var_(a),
2733  step_(step),
2734  best_(std::numeric_limits<int64_t>::max()),
2735  maximize_(maximize),
2736  found_initial_solution_(false) {
2737  CHECK_GT(step_, 0);
2738  // TODO(user): Store optimization direction in Solver. Besides making the
2739  // code simpler it would also having two monitors optimizing in opposite
2740  // directions.
2741  if (maximize) {
2743  } else {
2745  }
2746 }
2747 
2749 
2751  found_initial_solution_ = false;
2752  if (maximize_) {
2754  } else {
2756  }
2757 }
2758 
2760  if (solver()->SearchDepth() == 0) { // after a restart.
2761  ApplyBound();
2762  }
2763 }
2764 
2767  if (maximize_) {
2768  var_->SetMin(best_ + step_);
2769  } else {
2770  var_->SetMax(best_ - step_);
2771  }
2772  }
2773 }
2774 
2776 
2778  const int64_t val = var_->Value();
2779  if (!found_initial_solution_) {
2780  return true;
2781  } else {
2782  // This code should never return false in sequential mode because
2783  // ApplyBound should have been called before. In parallel, this is
2784  // no longer true. That is why we keep it there, just in case.
2785  return (maximize_ && val > best_) || (!maximize_ && val < best_);
2786  }
2787 }
2788 
2790  int64_t val = var_->Value();
2791  if (maximize_) {
2792  CHECK(!found_initial_solution_ || val > best_);
2793  best_ = val;
2794  } else {
2795  CHECK(!found_initial_solution_ || val < best_);
2796  best_ = val;
2797  }
2798  found_initial_solution_ = true;
2799  return true;
2800 }
2801 
2803  if (delta != nullptr) {
2804  const bool delta_has_objective = delta->HasObjective();
2805  if (!delta_has_objective) {
2806  delta->AddObjective(var_);
2807  }
2808  if (delta->Objective() == var_) {
2809  const Assignment* const local_search_state =
2811  if (maximize_) {
2812  const int64_t delta_min_objective =
2813  delta_has_objective ? delta->ObjectiveMin()
2815  const int64_t min_objective =
2816  local_search_state->HasObjective()
2817  ? CapAdd(local_search_state->ObjectiveMin(), step_)
2819  delta->SetObjectiveMin(
2820  std::max({var_->Min(), min_objective, delta_min_objective}));
2821 
2822  } else {
2823  const int64_t delta_max_objective =
2824  delta_has_objective ? delta->ObjectiveMax()
2826  const int64_t max_objective =
2827  local_search_state->HasObjective()
2828  ? CapSub(local_search_state->ObjectiveMax(), step_)
2830  delta->SetObjectiveMax(
2831  std::min({var_->Max(), max_objective, delta_max_objective}));
2832  }
2833  }
2834  }
2835  return true;
2836 }
2837 
2838 std::string OptimizeVar::Print() const {
2839  return absl::StrFormat("objective value = %d, ", var_->Value());
2840 }
2841 
2842 std::string OptimizeVar::DebugString() const {
2843  std::string out;
2844  if (maximize_) {
2845  out = "MaximizeVar(";
2846  } else {
2847  out = "MinimizeVar(";
2848  }
2849  absl::StrAppendFormat(&out, "%s, step = %d, best = %d)", var_->DebugString(),
2850  step_, best_);
2851  return out;
2852 }
2853 
2854 void OptimizeVar::Accept(ModelVisitor* const visitor) const {
2859  var_);
2861 }
2862 
2863 OptimizeVar* Solver::MakeMinimize(IntVar* const v, int64_t step) {
2864  return RevAlloc(new OptimizeVar(this, false, v, step));
2865 }
2866 
2867 OptimizeVar* Solver::MakeMaximize(IntVar* const v, int64_t step) {
2868  return RevAlloc(new OptimizeVar(this, true, v, step));
2869 }
2870 
2871 OptimizeVar* Solver::MakeOptimize(bool maximize, IntVar* const v,
2872  int64_t step) {
2873  return RevAlloc(new OptimizeVar(this, maximize, v, step));
2874 }
2875 
2876 namespace {
2877 class WeightedOptimizeVar : public OptimizeVar {
2878  public:
2879  WeightedOptimizeVar(Solver* solver, bool maximize,
2880  const std::vector<IntVar*>& sub_objectives,
2881  const std::vector<int64_t>& weights, int64_t step)
2882  : OptimizeVar(solver, maximize,
2883  solver->MakeScalProd(sub_objectives, weights)->Var(), step),
2884  sub_objectives_(sub_objectives),
2885  weights_(weights) {
2886  CHECK_EQ(sub_objectives.size(), weights.size());
2887  }
2888 
2889  ~WeightedOptimizeVar() override {}
2890  std::string Print() const override;
2891 
2892  private:
2893  const std::vector<IntVar*> sub_objectives_;
2894  const std::vector<int64_t> weights_;
2895 
2896  DISALLOW_COPY_AND_ASSIGN(WeightedOptimizeVar);
2897 };
2898 
2899 std::string WeightedOptimizeVar::Print() const {
2900  std::string result(OptimizeVar::Print());
2901  result.append("\nWeighted Objective:\n");
2902  for (int i = 0; i < sub_objectives_.size(); ++i) {
2903  absl::StrAppendFormat(&result, "Variable %s,\tvalue %d,\tweight %d\n",
2904  sub_objectives_[i]->name(),
2905  sub_objectives_[i]->Value(), weights_[i]);
2906  }
2907  return result;
2908 }
2909 } // namespace
2910 
2912  bool maximize, const std::vector<IntVar*>& sub_objectives,
2913  const std::vector<int64_t>& weights, int64_t step) {
2914  return RevAlloc(
2915  new WeightedOptimizeVar(this, maximize, sub_objectives, weights, step));
2916 }
2917 
2919  const std::vector<IntVar*>& sub_objectives,
2920  const std::vector<int64_t>& weights, int64_t step) {
2921  return RevAlloc(
2922  new WeightedOptimizeVar(this, false, sub_objectives, weights, step));
2923 }
2924 
2926  const std::vector<IntVar*>& sub_objectives,
2927  const std::vector<int64_t>& weights, int64_t step) {
2928  return RevAlloc(
2929  new WeightedOptimizeVar(this, true, sub_objectives, weights, step));
2930 }
2931 
2933  bool maximize, const std::vector<IntVar*>& sub_objectives,
2934  const std::vector<int>& weights, int64_t step) {
2935  return MakeWeightedOptimize(maximize, sub_objectives, ToInt64Vector(weights),
2936  step);
2937 }
2938 
2940  const std::vector<IntVar*>& sub_objectives, const std::vector<int>& weights,
2941  int64_t step) {
2942  return MakeWeightedMinimize(sub_objectives, ToInt64Vector(weights), step);
2943 }
2944 
2946  const std::vector<IntVar*>& sub_objectives, const std::vector<int>& weights,
2947  int64_t step) {
2948  return MakeWeightedMaximize(sub_objectives, ToInt64Vector(weights), step);
2949 }
2950 
2951 // ---------- Metaheuristics ---------
2952 
2953 namespace {
2954 class Metaheuristic : public SearchMonitor {
2955  public:
2956  Metaheuristic(Solver* const solver, bool maximize, IntVar* objective,
2957  int64_t step);
2958  ~Metaheuristic() override {}
2959 
2960  bool AtSolution() override;
2961  void EnterSearch() override;
2962  void RefuteDecision(Decision* const d) override;
2963  bool AcceptDelta(Assignment* delta, Assignment* deltadelta) override;
2964 
2965  protected:
2966  IntVar* const objective_;
2967  int64_t step_;
2968  int64_t current_;
2969  int64_t best_;
2970  bool maximize_;
2971 };
2972 
2973 Metaheuristic::Metaheuristic(Solver* const solver, bool maximize,
2974  IntVar* objective, int64_t step)
2975  : SearchMonitor(solver),
2976  objective_(objective),
2977  step_(step),
2978  current_(std::numeric_limits<int64_t>::max()),
2979  best_(std::numeric_limits<int64_t>::max()),
2980  maximize_(maximize) {}
2981 
2982 bool Metaheuristic::AtSolution() {
2983  current_ = objective_->Value();
2984  if (maximize_) {
2986  } else {
2988  }
2989  return true;
2990 }
2991 
2992 void Metaheuristic::EnterSearch() {
2993  // TODO(user): Remove this when fast local search works with
2994  // metaheuristics.
2995  solver()->SetUseFastLocalSearch(false);
2996  if (maximize_) {
2997  best_ = objective_->Min();
2999  } else {
3000  best_ = objective_->Max();
3002  }
3003 }
3004 
3005 void Metaheuristic::RefuteDecision(Decision* d) {
3006  if (maximize_) {
3007  if (objective_->Max() < best_ + step_) {
3008  solver()->Fail();
3009  }
3010  } else if (objective_->Min() > best_ - step_) {
3011  solver()->Fail();
3012  }
3013 }
3014 
3015 bool Metaheuristic::AcceptDelta(Assignment* delta, Assignment* deltadelta) {
3016  if (delta != nullptr) {
3017  if (!delta->HasObjective()) {
3018  delta->AddObjective(objective_);
3019  }
3020  if (delta->Objective() == objective_) {
3021  if (maximize_) {
3022  delta->SetObjectiveMin(
3023  std::max(objective_->Min(), delta->ObjectiveMin()));
3024  } else {
3025  delta->SetObjectiveMax(
3026  std::min(objective_->Max(), delta->ObjectiveMax()));
3027  }
3028  }
3029  }
3030  return true;
3031 }
3032 
3033 // ---------- Tabu Search ----------
3034 
3035 class TabuSearch : public Metaheuristic {
3036  public:
3037  TabuSearch(Solver* const s, bool maximize, IntVar* objective, int64_t step,
3038  const std::vector<IntVar*>& vars, int64_t keep_tenure,
3039  int64_t forbid_tenure, double tabu_factor);
3040  ~TabuSearch() override {}
3041  void EnterSearch() override;
3042  void ApplyDecision(Decision* d) override;
3043  bool AtSolution() override;
3044  bool LocalOptimum() override;
3045  void AcceptNeighbor() override;
3046  std::string DebugString() const override { return "Tabu Search"; }
3047 
3048  protected:
3049  struct VarValue {
3050  VarValue(IntVar* const var, int64_t value, int64_t stamp)
3051  : var_(var), value_(value), stamp_(stamp) {}
3052  IntVar* const var_;
3053  const int64_t value_;
3054  const int64_t stamp_;
3055  };
3056  typedef std::list<VarValue> TabuList;
3057 
3058  virtual std::vector<IntVar*> CreateTabuVars();
3059  const TabuList& forbid_tabu_list() { return forbid_tabu_list_; }
3060 
3061  private:
3062  void AgeList(int64_t tenure, TabuList* list);
3063  void AgeLists();
3064 
3065  const std::vector<IntVar*> vars_;
3066  Assignment assignment_;
3067  int64_t last_;
3068  TabuList keep_tabu_list_;
3069  int64_t keep_tenure_;
3070  TabuList forbid_tabu_list_;
3071  int64_t forbid_tenure_;
3072  double tabu_factor_;
3073  int64_t stamp_;
3074  bool found_initial_solution_;
3075 
3076  DISALLOW_COPY_AND_ASSIGN(TabuSearch);
3077 };
3078 
3079 TabuSearch::TabuSearch(Solver* const s, bool maximize, IntVar* objective,
3080  int64_t step, const std::vector<IntVar*>& vars,
3081  int64_t keep_tenure, int64_t forbid_tenure,
3082  double tabu_factor)
3083  : Metaheuristic(s, maximize, objective, step),
3084  vars_(vars),
3085  assignment_(s),
3086  last_(std::numeric_limits<int64_t>::max()),
3087  keep_tenure_(keep_tenure),
3088  forbid_tenure_(forbid_tenure),
3089  tabu_factor_(tabu_factor),
3090  stamp_(0),
3091  found_initial_solution_(false) {
3092  assignment_.Add(vars_);
3093 }
3094 
3095 void TabuSearch::EnterSearch() {
3096  Metaheuristic::EnterSearch();
3097  found_initial_solution_ = false;
3098 }
3099 
3100 void TabuSearch::ApplyDecision(Decision* const d) {
3101  Solver* const s = solver();
3102  if (d == s->balancing_decision()) {
3103  return;
3104  }
3105  // Aspiration criterion
3106  // Accept a neighbor if it improves the best solution found so far
3107  IntVar* aspiration = s->MakeBoolVar();
3108  if (maximize_) {
3109  s->AddConstraint(s->MakeIsGreaterOrEqualCstCt(
3110  objective_, CapAdd(best_, step_), aspiration));
3111  } else {
3112  s->AddConstraint(s->MakeIsLessOrEqualCstCt(objective_, CapSub(best_, step_),
3113  aspiration));
3114  }
3115 
3116  IntVar* tabu_var = nullptr;
3117  {
3118  // Creating the vector in a scope to make sure it gets deleted before
3119  // adding further constraints which could fail and lead to a leak.
3120  const std::vector<IntVar*> tabu_vars = CreateTabuVars();
3121  if (!tabu_vars.empty()) {
3122  tabu_var = s->MakeIsGreaterOrEqualCstVar(s->MakeSum(tabu_vars)->Var(),
3123  tabu_vars.size() * tabu_factor_);
3124  }
3125  }
3126 
3127  if (tabu_var != nullptr) {
3128  s->AddConstraint(
3129  s->MakeGreaterOrEqual(s->MakeSum(aspiration, tabu_var), int64_t{1}));
3130  }
3131 
3132  // Go downhill to the next local optimum
3133  if (maximize_) {
3134  const int64_t bound = (current_ > std::numeric_limits<int64_t>::min())
3135  ? current_ + step_
3136  : current_;
3137  s->AddConstraint(s->MakeGreaterOrEqual(objective_, bound));
3138  } else {
3140  ? current_ - step_
3141  : current_;
3142  s->AddConstraint(s->MakeLessOrEqual(objective_, bound));
3143  }
3144 
3145  // Avoid cost plateau's which lead to tabu cycles
3146  if (found_initial_solution_) {
3147  s->AddConstraint(s->MakeNonEquality(objective_, last_));
3148  }
3149 }
3150 
3151 std::vector<IntVar*> TabuSearch::CreateTabuVars() {
3152  Solver* const s = solver();
3153 
3154  // Tabu criterion
3155  // A variable in the "keep" list must keep its value, a variable in the
3156  // "forbid" list must not take its value in the list. The tabu criterion is
3157  // softened by the tabu factor which gives the number of violations to
3158  // the tabu criterion which is tolerated; a factor of 1 means no violations
3159  // allowed, a factor of 0 means all violations allowed.
3160  std::vector<IntVar*> tabu_vars;
3161  for (const VarValue& vv : keep_tabu_list_) {
3162  tabu_vars.push_back(s->MakeIsEqualCstVar(vv.var_, vv.value_));
3163  }
3164  for (const VarValue& vv : forbid_tabu_list_) {
3165  tabu_vars.push_back(s->MakeIsDifferentCstVar(vv.var_, vv.value_));
3166  }
3167  return tabu_vars;
3168 }
3169 
3170 bool TabuSearch::AtSolution() {
3171  if (!Metaheuristic::AtSolution()) {
3172  return false;
3173  }
3174  found_initial_solution_ = true;
3175  last_ = current_;
3176 
3177  // New solution found: add new assignments to tabu lists; this is only
3178  // done after the first local optimum (stamp_ != 0)
3179  if (0 != stamp_) {
3180  for (int i = 0; i < vars_.size(); ++i) {
3181  IntVar* const var = vars_[i];
3182  const int64_t old_value = assignment_.Value(var);
3183  const int64_t new_value = var->Value();
3184  if (old_value != new_value) {
3185  if (keep_tenure_ > 0) {
3186  VarValue keep_value(var, new_value, stamp_);
3187  keep_tabu_list_.push_front(keep_value);
3188  }
3189  if (forbid_tenure_ > 0) {
3190  VarValue forbid_value(var, old_value, stamp_);
3191  forbid_tabu_list_.push_front(forbid_value);
3192  }
3193  }
3194  }
3195  }
3196  assignment_.Store();
3197 
3198  return true;
3199 }
3200 
3201 bool TabuSearch::LocalOptimum() {
3202  AgeLists();
3203  if (maximize_) {
3205  } else {
3207  }
3208  return found_initial_solution_;
3209 }
3210 
3212  if (0 != stamp_) {
3213  AgeLists();
3214  }
3215 }
3216 
3217 void TabuSearch::AgeList(int64_t tenure, TabuList* list) {
3218  while (!list->empty() && list->back().stamp_ < stamp_ - tenure) {
3219  list->pop_back();
3220  }
3221 }
3222 
3223 void TabuSearch::AgeLists() {
3224  AgeList(keep_tenure_, &keep_tabu_list_);
3225  AgeList(forbid_tenure_, &forbid_tabu_list_);
3226  ++stamp_;
3227 }
3228 
3229 class GenericTabuSearch : public TabuSearch {
3230  public:
3231  GenericTabuSearch(Solver* const s, bool maximize, IntVar* objective,
3232  int64_t step, const std::vector<IntVar*>& vars,
3233  int64_t forbid_tenure)
3234  : TabuSearch(s, maximize, objective, step, vars, 0, forbid_tenure, 1) {}
3235  std::string DebugString() const override { return "Generic Tabu Search"; }
3236 
3237  protected:
3238  std::vector<IntVar*> CreateTabuVars() override;
3239 };
3240 
3241 std::vector<IntVar*> GenericTabuSearch::CreateTabuVars() {
3242  Solver* const s = solver();
3243 
3244  // Tabu criterion
3245  // At least one element of the forbid_tabu_list must change value.
3246  std::vector<IntVar*> forbid_values;
3247  for (const VarValue& vv : forbid_tabu_list()) {
3248  forbid_values.push_back(s->MakeIsDifferentCstVar(vv.var_, vv.value_));
3249  }
3250  std::vector<IntVar*> tabu_vars;
3251  if (!forbid_values.empty()) {
3252  tabu_vars.push_back(s->MakeIsGreaterCstVar(s->MakeSum(forbid_values), 0));
3253  }
3254  return tabu_vars;
3255 }
3256 
3257 } // namespace
3258 
3259 SearchMonitor* Solver::MakeTabuSearch(bool maximize, IntVar* const v,
3260  int64_t step,
3261  const std::vector<IntVar*>& vars,
3262  int64_t keep_tenure,
3263  int64_t forbid_tenure,
3264  double tabu_factor) {
3265  return RevAlloc(new TabuSearch(this, maximize, v, step, vars, keep_tenure,
3266  forbid_tenure, tabu_factor));
3267 }
3268 
3269 SearchMonitor* Solver::MakeGenericTabuSearch(
3270  bool maximize, IntVar* const v, int64_t step,
3271  const std::vector<IntVar*>& tabu_vars, int64_t forbid_tenure) {
3272  return RevAlloc(
3273  new GenericTabuSearch(this, maximize, v, step, tabu_vars, forbid_tenure));
3274 }
3275 
3276 // ---------- Simulated Annealing ----------
3277 
3278 namespace {
3279 class SimulatedAnnealing : public Metaheuristic {
3280  public:
3281  SimulatedAnnealing(Solver* const s, bool maximize, IntVar* objective,
3282  int64_t step, int64_t initial_temperature);
3283  ~SimulatedAnnealing() override {}
3284  void EnterSearch() override;
3285  void ApplyDecision(Decision* d) override;
3286  bool AtSolution() override;
3287  bool LocalOptimum() override;
3288  void AcceptNeighbor() override;
3289  std::string DebugString() const override { return "Simulated Annealing"; }
3290 
3291  private:
3292  double Temperature() const;
3293 
3294  const int64_t temperature0_;
3295  int64_t iteration_;
3296  std::mt19937 rand_;
3297  bool found_initial_solution_;
3298 
3299  DISALLOW_COPY_AND_ASSIGN(SimulatedAnnealing);
3300 };
3301 
3302 SimulatedAnnealing::SimulatedAnnealing(Solver* const s, bool maximize,
3303  IntVar* objective, int64_t step,
3304  int64_t initial_temperature)
3305  : Metaheuristic(s, maximize, objective, step),
3306  temperature0_(initial_temperature),
3307  iteration_(0),
3308  rand_(CpRandomSeed()),
3309  found_initial_solution_(false) {}
3310 
3311 void SimulatedAnnealing::EnterSearch() {
3312  Metaheuristic::EnterSearch();
3313  found_initial_solution_ = false;
3314 }
3315 
3316 void SimulatedAnnealing::ApplyDecision(Decision* const d) {
3317  Solver* const s = solver();
3318  if (d == s->balancing_decision()) {
3319  return;
3320  }
3321  const double rand_double = absl::Uniform<double>(rand_, 0.0, 1.0);
3322 #if defined(_MSC_VER) || defined(__ANDROID__)
3323  const double rand_log2_double = log(rand_double) / log(2.0L);
3324 #else
3325  const double rand_log2_double = log2(rand_double);
3326 #endif
3327  const int64_t energy_bound = Temperature() * rand_log2_double;
3328  if (maximize_) {
3329  const int64_t bound = (current_ > std::numeric_limits<int64_t>::min())
3330  ? current_ + step_ + energy_bound
3331  : current_;
3332  s->AddConstraint(s->MakeGreaterOrEqual(objective_, bound));
3333  } else {
3335  ? current_ - step_ - energy_bound
3336  : current_;
3337  s->AddConstraint(s->MakeLessOrEqual(objective_, bound));
3338  }
3339 }
3340 
3341 bool SimulatedAnnealing::AtSolution() {
3342  if (!Metaheuristic::AtSolution()) {
3343  return false;
3344  }
3345  found_initial_solution_ = true;
3346  return true;
3347 }
3348 
3349 bool SimulatedAnnealing::LocalOptimum() {
3350  if (maximize_) {
3352  } else {
3354  }
3355  ++iteration_;
3356  return found_initial_solution_ && Temperature() > 0;
3357 }
3358 
3360  if (iteration_ > 0) {
3361  ++iteration_;
3362  }
3363 }
3364 
3365 double SimulatedAnnealing::Temperature() const {
3366  if (iteration_ > 0) {
3367  return (1.0 * temperature0_) / iteration_; // Cauchy annealing
3368  } else {
3369  return 0.;
3370  }
3371 }
3372 } // namespace
3373 
3375  int64_t step,
3376  int64_t initial_temperature) {
3377  return RevAlloc(
3378  new SimulatedAnnealing(this, maximize, v, step, initial_temperature));
3379 }
3380 
3381 // ---------- Guided Local Search ----------
3382 
3383 typedef std::pair<int64_t, int64_t> Arc;
3384 
3385 namespace {
3386 // Base GLS penalties abstract class. Maintains the penalty frequency for each
3387 // (variable, value) arc.
3388 class GuidedLocalSearchPenalties {
3389  public:
3390  virtual ~GuidedLocalSearchPenalties() {}
3391  virtual bool HasValues() const = 0;
3392  virtual void Increment(const Arc& arc) = 0;
3393  virtual int64_t Value(const Arc& arc) const = 0;
3394  virtual void Reset() = 0;
3395 };
3396 
3397 // Dense GLS penalties implementation using a matrix to store penalties.
3398 class GuidedLocalSearchPenaltiesTable : public GuidedLocalSearchPenalties {
3399  public:
3400  explicit GuidedLocalSearchPenaltiesTable(int size);
3401  ~GuidedLocalSearchPenaltiesTable() override {}
3402  bool HasValues() const override { return has_values_; }
3403  void Increment(const Arc& arc) override;
3404  int64_t Value(const Arc& arc) const override;
3405  void Reset() override;
3406 
3407  private:
3408  std::vector<std::vector<int64_t>> penalties_;
3409  bool has_values_;
3410 };
3411 
3412 GuidedLocalSearchPenaltiesTable::GuidedLocalSearchPenaltiesTable(int size)
3413  : penalties_(size), has_values_(false) {}
3414 
3415 void GuidedLocalSearchPenaltiesTable::Increment(const Arc& arc) {
3416  std::vector<int64_t>& first_penalties = penalties_[arc.first];
3417  const int64_t second = arc.second;
3418  if (second >= first_penalties.size()) {
3419  first_penalties.resize(second + 1, 0);
3420  }
3421  ++first_penalties[second];
3422  has_values_ = true;
3423 }
3424 
3425 void GuidedLocalSearchPenaltiesTable::Reset() {
3426  has_values_ = false;
3427  for (int i = 0; i < penalties_.size(); ++i) {
3428  penalties_[i].clear();
3429  }
3430 }
3431 
3432 int64_t GuidedLocalSearchPenaltiesTable::Value(const Arc& arc) const {
3433  const std::vector<int64_t>& first_penalties = penalties_[arc.first];
3434  const int64_t second = arc.second;
3435  if (second >= first_penalties.size()) {
3436  return 0;
3437  } else {
3438  return first_penalties[second];
3439  }
3440 }
3441 
3442 // Sparse GLS penalties implementation using hash_map to store penalties.
3443 class GuidedLocalSearchPenaltiesMap : public GuidedLocalSearchPenalties {
3444  public:
3445  explicit GuidedLocalSearchPenaltiesMap(int size);
3446  ~GuidedLocalSearchPenaltiesMap() override {}
3447  bool HasValues() const override { return (!penalties_.empty()); }
3448  void Increment(const Arc& arc) override;
3449  int64_t Value(const Arc& arc) const override;
3450  void Reset() override;
3451 
3452  private:
3453  Bitmap penalized_;
3454  absl::flat_hash_map<Arc, int64_t> penalties_;
3455 };
3456 
3457 GuidedLocalSearchPenaltiesMap::GuidedLocalSearchPenaltiesMap(int size)
3458  : penalized_(size, false) {}
3459 
3460 void GuidedLocalSearchPenaltiesMap::Increment(const Arc& arc) {
3461  ++penalties_[arc];
3462  penalized_.Set(arc.first, true);
3463 }
3464 
3465 void GuidedLocalSearchPenaltiesMap::Reset() {
3466  penalties_.clear();
3467  penalized_.Clear();
3468 }
3469 
3470 int64_t GuidedLocalSearchPenaltiesMap::Value(const Arc& arc) const {
3471  if (penalized_.Get(arc.first)) {
3472  return gtl::FindWithDefault(penalties_, arc, 0);
3473  }
3474  return 0;
3475 }
3476 
3477 class GuidedLocalSearch : public Metaheuristic {
3478  public:
3479  GuidedLocalSearch(Solver* const s, IntVar* objective, bool maximize,
3480  int64_t step, const std::vector<IntVar*>& vars,
3481  double penalty_factor);
3482  ~GuidedLocalSearch() override {}
3483  bool AcceptDelta(Assignment* delta, Assignment* deltadelta) override;
3484  void ApplyDecision(Decision* d) override;
3485  bool AtSolution() override;
3486  void EnterSearch() override;
3487  bool LocalOptimum() override;
3488  virtual int64_t AssignmentElementPenalty(const Assignment& assignment,
3489  int index) = 0;
3490  virtual int64_t AssignmentPenalty(const Assignment& assignment, int index,
3491  int64_t next) = 0;
3492  virtual bool EvaluateElementValue(const Assignment::IntContainer& container,
3493  int64_t index, int* container_index,
3494  int64_t* penalty) = 0;
3495  virtual IntExpr* MakeElementPenalty(int index) = 0;
3496  std::string DebugString() const override { return "Guided Local Search"; }
3497 
3498  protected:
3499  struct Comparator {
3500  bool operator()(const std::pair<Arc, double>& i,
3501  const std::pair<Arc, double>& j) {
3502  return i.second > j.second;
3503  }
3504  };
3505 
3506  int64_t Evaluate(const Assignment* delta, int64_t current_penalty,
3507  const int64_t* const out_values, bool cache_delta_values);
3508 
3510  Assignment assignment_;
3513  const std::vector<IntVar*> vars_;
3514  absl::flat_hash_map<const IntVar*, int64_t> indices_;
3515  const double penalty_factor_;
3516  std::unique_ptr<GuidedLocalSearchPenalties> penalties_;
3517  std::unique_ptr<int64_t[]> current_penalized_values_;
3518  std::unique_ptr<int64_t[]> delta_cache_;
3520 };
3521 
3522 GuidedLocalSearch::GuidedLocalSearch(Solver* const s, IntVar* objective,
3523  bool maximize, int64_t step,
3524  const std::vector<IntVar*>& vars,
3525  double penalty_factor)
3526  : Metaheuristic(s, maximize, objective, step),
3527  penalized_objective_(nullptr),
3528  assignment_(s),
3531  vars_(vars),
3532  penalty_factor_(penalty_factor),
3533  incremental_(false) {
3534  if (!vars.empty()) {
3535  // TODO(user): Remove scoped_array.
3536  assignment_.Add(vars_);
3537  current_penalized_values_ = absl::make_unique<int64_t[]>(vars_.size());
3538  delta_cache_ = absl::make_unique<int64_t[]>(vars_.size());
3539  memset(current_penalized_values_.get(), 0,
3540  vars_.size() * sizeof(*current_penalized_values_.get()));
3541  }
3542  for (int i = 0; i < vars_.size(); ++i) {
3543  indices_[vars_[i]] = i;
3544  }
3545  if (absl::GetFlag(FLAGS_cp_use_sparse_gls_penalties)) {
3546  penalties_ = absl::make_unique<GuidedLocalSearchPenaltiesMap>(vars_.size());
3547  } else {
3548  penalties_ =
3549  absl::make_unique<GuidedLocalSearchPenaltiesTable>(vars_.size());
3550  }
3551 }
3552 
3553 // Add the following constraint (includes aspiration criterion):
3554 // if minimizing,
3555 // objective =< Max(current penalized cost - penalized_objective - step,
3556 // best solution cost - step)
3557 // if maximizing,
3558 // objective >= Min(current penalized cost - penalized_objective + step,
3559 // best solution cost + step)
3560 void GuidedLocalSearch::ApplyDecision(Decision* const d) {
3561  if (d == solver()->balancing_decision()) {
3562  return;
3563  }
3565  if (penalties_->HasValues()) {
3566  // Computing sum of penalties expression.
3567  // Scope needed to avoid potential leak of elements.
3568  {
3569  std::vector<IntVar*> elements;
3570  for (int i = 0; i < vars_.size(); ++i) {
3571  elements.push_back(MakeElementPenalty(i)->Var());
3572  const int64_t penalty = AssignmentElementPenalty(assignment_, i);
3573  current_penalized_values_[i] = penalty;
3574  delta_cache_[i] = penalty;
3577  }
3578  penalized_objective_ = solver()->MakeSum(elements)->Var();
3579  }
3581  incremental_ = false;
3582  if (maximize_) {
3583  IntExpr* min_pen_exp =
3584  solver()->MakeDifference(current_ + step_, penalized_objective_);
3585  IntVar* min_exp = solver()->MakeMin(min_pen_exp, best_ + step_)->Var();
3586  solver()->AddConstraint(
3587  solver()->MakeGreaterOrEqual(objective_, min_exp));
3588  } else {
3589  IntExpr* max_pen_exp =
3590  solver()->MakeDifference(current_ - step_, penalized_objective_);
3591  IntVar* max_exp = solver()->MakeMax(max_pen_exp, best_ - step_)->Var();
3592  solver()->AddConstraint(solver()->MakeLessOrEqual(objective_, max_exp));
3593  }
3594  } else {
3595  penalized_objective_ = nullptr;
3596  if (maximize_) {
3597  const int64_t bound = (current_ > std::numeric_limits<int64_t>::min())
3598  ? current_ + step_
3599  : current_;
3600  objective_->SetMin(bound);
3601  } else {
3603  ? current_ - step_
3604  : current_;
3605  objective_->SetMax(bound);
3606  }
3607  }
3608 }
3609 
3610 bool GuidedLocalSearch::AtSolution() {
3611  if (!Metaheuristic::AtSolution()) {
3612  return false;
3613  }
3614  if (penalized_objective_ != nullptr) { // In case no move has been found
3615  current_ += penalized_objective_->Value();
3616  }
3617  assignment_.Store();
3618  return true;
3619 }
3620 
3621 void GuidedLocalSearch::EnterSearch() {
3622  Metaheuristic::EnterSearch();
3623  penalized_objective_ = nullptr;
3626  memset(current_penalized_values_.get(), 0,
3627  vars_.size() * sizeof(*current_penalized_values_.get()));
3628  penalties_->Reset();
3629 }
3630 
3631 // GLS filtering; compute the penalized value corresponding to the delta and
3632 // modify objective bound accordingly.
3633 bool GuidedLocalSearch::AcceptDelta(Assignment* delta, Assignment* deltadelta) {
3634  if (delta != nullptr || deltadelta != nullptr) {
3635  if (!penalties_->HasValues()) {
3636  return Metaheuristic::AcceptDelta(delta, deltadelta);
3637  }
3638  int64_t penalty = 0;
3639  if (!deltadelta->Empty()) {
3640  if (!incremental_) {
3641  penalty = Evaluate(delta, assignment_penalized_value_,
3642  current_penalized_values_.get(), true);
3643  } else {
3644  penalty = Evaluate(deltadelta, old_penalized_value_, delta_cache_.get(),
3645  true);
3646  }
3647  incremental_ = true;
3648  } else {
3649  if (incremental_) {
3650  for (int i = 0; i < vars_.size(); ++i) {
3652  }
3654  }
3655  incremental_ = false;
3656  penalty = Evaluate(delta, assignment_penalized_value_,
3657  current_penalized_values_.get(), false);
3658  }
3659  old_penalized_value_ = penalty;
3660  if (!delta->HasObjective()) {
3661  delta->AddObjective(objective_);
3662  }
3663  if (delta->Objective() == objective_) {
3664  if (maximize_) {
3665  delta->SetObjectiveMin(
3667  CapAdd(best_, step_)),
3668  delta->ObjectiveMin()));
3669  } else {
3670  delta->SetObjectiveMax(
3672  CapSub(best_, step_)),
3673  delta->ObjectiveMax()));
3674  }
3675  }
3676  }
3677  return true;
3678 }
3679 
3680 int64_t GuidedLocalSearch::Evaluate(const Assignment* delta,
3681  int64_t current_penalty,
3682  const int64_t* const out_values,
3683  bool cache_delta_values) {
3684  int64_t penalty = current_penalty;
3685  const Assignment::IntContainer& container = delta->IntVarContainer();
3686  const int size = container.Size();
3687  for (int i = 0; i < size; ++i) {
3688  const IntVarElement& new_element = container.Element(i);
3689  IntVar* var = new_element.Var();
3690  int64_t index = -1;
3691  if (gtl::FindCopy(indices_, var, &index)) {
3692  penalty = CapSub(penalty, out_values[index]);
3693  int64_t new_penalty = 0;
3694  if (EvaluateElementValue(container, index, &i, &new_penalty)) {
3695  penalty = CapAdd(penalty, new_penalty);
3696  if (cache_delta_values) {
3697  delta_cache_[index] = new_penalty;
3698  }
3699  }
3700  }
3701  }
3702  return penalty;
3703 }
3704 
3705 // Penalize all the most expensive arcs (var, value) according to their utility:
3706 // utility(i, j) = cost(i, j) / (1 + penalty(i, j))
3707 bool GuidedLocalSearch::LocalOptimum() {
3708  std::vector<std::pair<Arc, double>> utility(vars_.size());
3709  for (int i = 0; i < vars_.size(); ++i) {
3710  if (!assignment_.Bound(vars_[i])) {
3711  // Never synced with a solution, problem infeasible.
3712  return false;
3713  }
3714  const int64_t var_value = assignment_.Value(vars_[i]);
3715  const int64_t value =
3716  (var_value != i) ? AssignmentPenalty(assignment_, i, var_value) : 0;
3717  const Arc arc(i, var_value);
3718  const int64_t penalty = penalties_->Value(arc);
3719  utility[i] = std::pair<Arc, double>(arc, value / (penalty + 1.0));
3720  }
3721  Comparator comparator;
3722  std::sort(utility.begin(), utility.end(), comparator);
3723  int64_t utility_value = utility[0].second;
3724  penalties_->Increment(utility[0].first);
3725  for (int i = 1; i < utility.size() && utility_value == utility[i].second;
3726  ++i) {
3727  penalties_->Increment(utility[i].first);
3728  }
3729  if (maximize_) {
3731  } else {
3733  }
3734  return true;
3735 }
3736 
3737 class BinaryGuidedLocalSearch : public GuidedLocalSearch {
3738  public:
3739  BinaryGuidedLocalSearch(
3740  Solver* const solver, IntVar* const objective,
3741  std::function<int64_t(int64_t, int64_t)> objective_function,
3742  bool maximize, int64_t step, const std::vector<IntVar*>& vars,
3743  double penalty_factor);
3744  ~BinaryGuidedLocalSearch() override {}
3745  IntExpr* MakeElementPenalty(int index) override;
3746  int64_t AssignmentElementPenalty(const Assignment& assignment,
3747  int index) override;
3748  int64_t AssignmentPenalty(const Assignment& assignment, int index,
3749  int64_t next) override;
3750  bool EvaluateElementValue(const Assignment::IntContainer& container,
3751  int64_t index, int* container_index,
3752  int64_t* penalty) override;
3753 
3754  private:
3755  int64_t PenalizedValue(int64_t i, int64_t j);
3756  std::function<int64_t(int64_t, int64_t)> objective_function_;
3757 };
3758 
3759 BinaryGuidedLocalSearch::BinaryGuidedLocalSearch(
3760  Solver* const solver, IntVar* const objective,
3761  std::function<int64_t(int64_t, int64_t)> objective_function, bool maximize,
3762  int64_t step, const std::vector<IntVar*>& vars, double penalty_factor)
3763  : GuidedLocalSearch(solver, objective, maximize, step, vars,
3764  penalty_factor),
3765  objective_function_(std::move(objective_function)) {}
3766 
3767 IntExpr* BinaryGuidedLocalSearch::MakeElementPenalty(int index) {
3768  return solver()->MakeElement(
3769  [this, index](int64_t i) { return PenalizedValue(index, i); },
3770  vars_[index]);
3771 }
3772 
3773 int64_t BinaryGuidedLocalSearch::AssignmentElementPenalty(
3774  const Assignment& assignment, int index) {
3775  return PenalizedValue(index, assignment.Value(vars_[index]));
3776 }
3777 
3778 int64_t BinaryGuidedLocalSearch::AssignmentPenalty(const Assignment& assignment,
3779  int index, int64_t next) {
3780  return objective_function_(index, next);
3781 }
3782 
3783 bool BinaryGuidedLocalSearch::EvaluateElementValue(
3784  const Assignment::IntContainer& container, int64_t index,
3785  int* container_index, int64_t* penalty) {
3786  const IntVarElement& element = container.Element(*container_index);
3787  if (element.Activated()) {
3788  *penalty = PenalizedValue(index, element.Value());
3789  return true;
3790  }
3791  return false;
3792 }
3793 
3794 // Penalized value for (i, j) = penalty_factor_ * penalty(i, j) * cost (i, j)
3795 int64_t BinaryGuidedLocalSearch::PenalizedValue(int64_t i, int64_t j) {
3796  const Arc arc(i, j);
3797  const int64_t penalty = penalties_->Value(arc);
3798  if (penalty != 0) { // objective_function_->Run(i, j) can be costly
3799  const double penalized_value_fp =
3800  penalty_factor_ * penalty * objective_function_(i, j);
3801  const int64_t penalized_value =
3803  ? static_cast<int64_t>(penalized_value_fp)
3805  if (maximize_) {
3806  return -penalized_value;
3807  } else {
3808  return penalized_value;
3809  }
3810  } else {
3811  return 0;
3812  }
3813 }
3814 
3815 class TernaryGuidedLocalSearch : public GuidedLocalSearch {
3816  public:
3817  TernaryGuidedLocalSearch(
3818  Solver* const solver, IntVar* const objective,
3819  std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
3820  bool maximize, int64_t step, const std::vector<IntVar*>& vars,
3821  const std::vector<IntVar*>& secondary_vars, double penalty_factor);
3822  ~TernaryGuidedLocalSearch() override {}
3823  IntExpr* MakeElementPenalty(int index) override;
3824  int64_t AssignmentElementPenalty(const Assignment& assignment,
3825  int index) override;
3826  int64_t AssignmentPenalty(const Assignment& assignment, int index,
3827  int64_t next) override;
3828  bool EvaluateElementValue(const Assignment::IntContainer& container,
3829  int64_t index, int* container_index,
3830  int64_t* penalty) override;
3831 
3832  private:
3833  int64_t PenalizedValue(int64_t i, int64_t j, int64_t k);
3834  int64_t GetAssignmentSecondaryValue(const Assignment::IntContainer& container,
3835  int index, int* container_index) const;
3836 
3837  const std::vector<IntVar*> secondary_vars_;
3838  std::function<int64_t(int64_t, int64_t, int64_t)> objective_function_;
3839 };
3840 
3841 TernaryGuidedLocalSearch::TernaryGuidedLocalSearch(
3842  Solver* const solver, IntVar* const objective,
3843  std::function<int64_t(int64_t, int64_t, int64_t)> objective_function,
3844  bool maximize, int64_t step, const std::vector<IntVar*>& vars,
3845  const std::vector<IntVar*>& secondary_vars, double penalty_factor)
3846  : GuidedLocalSearch(solver, objective, maximize, step, vars,
3847  penalty_factor),
3848  secondary_vars_(secondary_vars),
3849  objective_function_(std::move(objective_function)) {
3850  if (!secondary_vars.empty()) {
3851  assignment_.Add(secondary_vars);
3852  }
3853 }
3854 
3855 IntExpr* TernaryGuidedLocalSearch::MakeElementPenalty(int index) {
3856  return solver()->MakeElement(
3857  [this, index](int64_t i, int64_t j) {
3858  return PenalizedValue(index, i, j);
3859  },
3860  vars_[index], secondary_vars_[index]);
3861 }
3862 
3863 int64_t TernaryGuidedLocalSearch::AssignmentElementPenalty(
3864  const Assignment& assignment, int index) {
3865  return PenalizedValue(index, assignment.Value(vars_[index]),
3866  assignment.Value(secondary_vars_[index]));
3867 }
3868 
3869 int64_t TernaryGuidedLocalSearch::AssignmentPenalty(
3870  const Assignment& assignment, int index, int64_t next) {
3871  return objective_function_(index, next,
3872  assignment.Value(secondary_vars_[index]));
3873 }
3874 
3875 bool TernaryGuidedLocalSearch::EvaluateElementValue(
3876  const Assignment::IntContainer& container, int64_t index,
3877  int* container_index, int64_t* penalty) {
3878  const IntVarElement& element = container.Element(*container_index);
3879  if (element.Activated()) {
3880  *penalty = PenalizedValue(
3881  index, element.Value(),
3882  GetAssignmentSecondaryValue(container, index, container_index));
3883  return true;
3884  }
3885  return false;
3886 }
3887 
3888 // Penalized value for (i, j) = penalty_factor_ * penalty(i, j) * cost (i, j)
3889 int64_t TernaryGuidedLocalSearch::PenalizedValue(int64_t i, int64_t j,
3890  int64_t k) {
3891  const Arc arc(i, j);
3892  const int64_t penalty = penalties_->Value(arc);
3893  if (penalty != 0) { // objective_function_(i, j, k) can be costly
3894  const double penalized_value_fp =
3895  penalty_factor_ * penalty * objective_function_(i, j, k);
3896  const int64_t penalized_value =
3898  ? static_cast<int64_t>(penalized_value_fp)
3900  if (maximize_) {
3901  return -penalized_value;
3902  } else {
3903  return penalized_value;
3904  }
3905  } else {
3906  return 0;
3907  }
3908 }
3909 
3910 int64_t TernaryGuidedLocalSearch::GetAssignmentSecondaryValue(
3911  const Assignment::IntContainer& container, int index,
3912  int* container_index) const {
3913  const IntVar* secondary_var = secondary_vars_[index];
3914  int hint_index = *container_index + 1;
3915  if (hint_index > 0 && hint_index < container.Size() &&
3916  secondary_var == container.Element(hint_index).Var()) {
3917  *container_index = hint_index;
3918  return container.Element(hint_index).Value();
3919  } else {
3920  return container.Element(secondary_var).Value();
3921  }
3922 }
3923 } // namespace
3924 
3925 SearchMonitor* Solver::MakeGuidedLocalSearch(
3926  bool maximize, IntVar* const objective,
3927  Solver::IndexEvaluator2 objective_function, int64_t step,
3928  const std::vector<IntVar*>& vars, double penalty_factor) {
3929  return RevAlloc(new BinaryGuidedLocalSearch(
3930  this, objective, std::move(objective_function), maximize, step, vars,
3931  penalty_factor));
3932 }
3933 
3934 SearchMonitor* Solver::MakeGuidedLocalSearch(
3935  bool maximize, IntVar* const objective,
3936  Solver::IndexEvaluator3 objective_function, int64_t step,
3937  const std::vector<IntVar*>& vars,
3938  const std::vector<IntVar*>& secondary_vars, double penalty_factor) {
3939  return RevAlloc(new TernaryGuidedLocalSearch(
3940  this, objective, std::move(objective_function), maximize, step, vars,
3941  secondary_vars, penalty_factor));
3942 }
3943 
3944 // ---------- Search Limits ----------
3945 
3946 // ----- Base Class -----
3947 
3948 SearchLimit::~SearchLimit() {}
3949 
3950 void SearchLimit::EnterSearch() {
3951  crossed_ = false;
3952  Init();
3953 }
3954 
3955 void SearchLimit::BeginNextDecision(DecisionBuilder* const b) {
3956  PeriodicCheck();
3957  TopPeriodicCheck();
3958 }
3959 
3960 void SearchLimit::RefuteDecision(Decision* const d) {
3961  PeriodicCheck();
3962  TopPeriodicCheck();
3963 }
3964 
3965 void SearchLimit::PeriodicCheck() {
3966  if (crossed_ || Check()) {
3967  crossed_ = true;
3968  solver()->Fail();
3969  }
3970 }
3971 
3972 void SearchLimit::TopPeriodicCheck() {
3973  if (solver()->TopLevelSearch() != solver()->ActiveSearch()) {
3974  solver()->TopPeriodicCheck();
3975  }
3976 }
3977 
3978 // ----- Regular Limit -----
3979 
3980 RegularLimit::RegularLimit(Solver* const s, absl::Duration time,
3981  int64_t branches, int64_t failures,
3982  int64_t solutions, bool smart_time_check,
3983  bool cumulative)
3984  : SearchLimit(s),
3985  duration_limit_(time),
3986  solver_time_at_limit_start_(s->Now()),
3987  last_time_elapsed_(absl::ZeroDuration()),
3988  check_count_(0),
3989  next_check_(0),
3990  smart_time_check_(smart_time_check),
3991  branches_(branches),
3992  branches_offset_(0),
3993  failures_(failures),
3994  failures_offset_(0),
3995  solutions_(solutions),
3996  solutions_offset_(0),
3997  cumulative_(cumulative) {}
3998 
4000 
4001 void RegularLimit::Copy(const SearchLimit* const limit) {
4002  const RegularLimit* const regular =
4003  reinterpret_cast<const RegularLimit* const>(limit);
4004  duration_limit_ = regular->duration_limit_;
4005  branches_ = regular->branches_;
4006  failures_ = regular->failures_;
4007  solutions_ = regular->solutions_;
4008  smart_time_check_ = regular->smart_time_check_;
4009  cumulative_ = regular->cumulative_;
4010 }
4011 
4013 
4015  Solver* const s = solver();
4016  return s->MakeLimit(wall_time(), branches_, failures_, solutions_,
4017  smart_time_check_);
4018 }
4019 
4021  Solver* const s = solver();
4022  // Warning limits might be kint64max, do not move the offset to the rhs
4023  return s->branches() - branches_offset_ >= branches_ ||
4024  s->failures() - failures_offset_ >= failures_ || CheckTime() ||
4025  s->solutions() - solutions_offset_ >= solutions_;
4026 }
4027 
4029  Solver* const s = solver();
4030  int64_t progress = GetPercent(s->branches(), branches_offset_, branches_);
4031  progress = std::max(progress,
4032  GetPercent(s->failures(), failures_offset_, failures_));
4033  progress = std::max(
4034  progress, GetPercent(s->solutions(), solutions_offset_, solutions_));
4035  if (duration_limit() != absl::InfiniteDuration()) {
4036  progress = std::max(progress, (100 * TimeElapsed()) / duration_limit());
4037  }
4038  return progress;
4039 }
4040 
4042  Solver* const s = solver();
4043  branches_offset_ = s->branches();
4044  failures_offset_ = s->failures();
4045  solver_time_at_limit_start_ = s->Now();
4046  last_time_elapsed_ = absl::ZeroDuration();
4047  solutions_offset_ = s->solutions();
4048  check_count_ = 0;
4049  next_check_ = 0;
4050 }
4051 
4053  if (cumulative_) {
4054  // Reduce the limits by the amount consumed during this search
4055  Solver* const s = solver();
4056  branches_ -= s->branches() - branches_offset_;
4057  failures_ -= s->failures() - failures_offset_;
4058  duration_limit_ -= s->Now() - solver_time_at_limit_start_;
4059  solutions_ -= s->solutions() - solutions_offset_;
4060  }
4061 }
4062 
4063 void RegularLimit::UpdateLimits(absl::Duration time, int64_t branches,
4064  int64_t failures, int64_t solutions) {
4065  duration_limit_ = time;
4066  branches_ = branches;
4067  failures_ = failures;
4068  solutions_ = solutions;
4069 }
4070 
4072  Solver* const s = solver();
4073  return s->solutions() + s->unchecked_solutions() - solutions_offset_ >=
4074  solutions_;
4075 }
4076 
4077 std::string RegularLimit::DebugString() const {
4078  return absl::StrFormat(
4079  "RegularLimit(crossed = %i, duration_limit = %s, "
4080  "branches = %d, failures = %d, solutions = %d cumulative = %s",
4081  crossed(), absl::FormatDuration(duration_limit()), branches_, failures_,
4082  solutions_, (cumulative_ ? "true" : "false"));
4083 }
4084 
4085 void RegularLimit::Accept(ModelVisitor* const visitor) const {
4089  branches_);
4091  failures_);
4093  solutions_);
4095  smart_time_check_);
4098 }
4099 
4100 bool RegularLimit::CheckTime() { return TimeElapsed() >= duration_limit(); }
4101 
4102 absl::Duration RegularLimit::TimeElapsed() {
4103  const int64_t kMaxSkip = 100;
4104  const int64_t kCheckWarmupIterations = 100;
4105  ++check_count_;
4106  if (duration_limit() != absl::InfiniteDuration() &&
4107  next_check_ <= check_count_) {
4108  Solver* const s = solver();
4109  absl::Duration elapsed = s->Now() - solver_time_at_limit_start_;
4110  if (smart_time_check_ && check_count_ > kCheckWarmupIterations &&
4111  elapsed > absl::ZeroDuration()) {
4112  const int64_t estimated_check_count_at_limit = MathUtil::FastInt64Round(
4113  check_count_ * absl::FDivDuration(duration_limit_, elapsed));
4114  next_check_ =
4115  std::min(check_count_ + kMaxSkip, estimated_check_count_at_limit);
4116  }
4117  last_time_elapsed_ = elapsed;
4118  }
4119  return last_time_elapsed_;
4120 }
4121 
4126  /*smart_time_check=*/false, /*cumulative=*/false);
4127 }
4128 
4130  return MakeLimit(absl::InfiniteDuration(), branches,
4133  /*smart_time_check=*/false, /*cumulative=*/false);
4134 }
4135 
4137  return MakeLimit(absl::InfiniteDuration(),
4140  /*smart_time_check=*/false, /*cumulative=*/false);
4141 }
4142 
4144  return MakeLimit(absl::InfiniteDuration(),
4147  /*smart_time_check=*/false, /*cumulative=*/false);
4148 }
4149 
4150 RegularLimit* Solver::MakeLimit(int64_t time, int64_t branches,
4151  int64_t failures, int64_t solutions,
4152  bool smart_time_check, bool cumulative) {
4153  return MakeLimit(absl::Milliseconds(time), branches, failures, solutions,
4154  smart_time_check, cumulative);
4155 }
4156 
4157 RegularLimit* Solver::MakeLimit(absl::Duration time, int64_t branches,
4158  int64_t failures, int64_t solutions,
4159  bool smart_time_check, bool cumulative) {
4160  return RevAlloc(new RegularLimit(this, time, branches, failures, solutions,
4161  smart_time_check, cumulative));
4162 }
4163 
4164 RegularLimit* Solver::MakeLimit(const RegularLimitParameters& proto) {
4166  ? absl::InfiniteDuration()
4167  : absl::Milliseconds(proto.time()),
4168  proto.branches(), proto.failures(), proto.solutions(),
4169  proto.smart_time_check(), proto.cumulative());
4170 }
4171 
4172 RegularLimitParameters Solver::MakeDefaultRegularLimitParameters() const {
4173  RegularLimitParameters proto;
4175  proto.set_branches(std::numeric_limits<int64_t>::max());
4176  proto.set_failures(std::numeric_limits<int64_t>::max());
4177  proto.set_solutions(std::numeric_limits<int64_t>::max());
4178  proto.set_smart_time_check(false);
4179  proto.set_cumulative(false);
4180  return proto;
4181 }
4182 
4183 // ----- Improvement Search Limit -----
4184 
4186  Solver* const s, IntVar* objective_var, bool maximize,
4187  double objective_scaling_factor, double objective_offset,
4188  double improvement_rate_coefficient,
4189  int improvement_rate_solutions_distance)
4190  : SearchLimit(s),
4191  objective_var_(objective_var),
4192  maximize_(maximize),
4193  objective_scaling_factor_(objective_scaling_factor),
4194  objective_offset_(objective_offset),
4195  improvement_rate_coefficient_(improvement_rate_coefficient),
4196  improvement_rate_solutions_distance_(
4197  improvement_rate_solutions_distance) {
4198  Init();
4199 }
4200 
4202 
4204  best_objective_ = maximize_ ? -std::numeric_limits<double>::infinity()
4205  : std::numeric_limits<double>::infinity();
4206  threshold_ = std::numeric_limits<double>::infinity();
4207  objective_updated_ = false;
4208  gradient_stage_ = true;
4209 }
4210 
4211 void ImprovementSearchLimit::Copy(const SearchLimit* const limit) {
4212  const ImprovementSearchLimit* const improv =
4213  reinterpret_cast<const ImprovementSearchLimit* const>(limit);
4214  objective_var_ = improv->objective_var_;
4215  maximize_ = improv->maximize_;
4216  objective_scaling_factor_ = improv->objective_scaling_factor_;
4217  objective_offset_ = improv->objective_offset_;
4218  improvement_rate_coefficient_ = improv->improvement_rate_coefficient_;
4219  improvement_rate_solutions_distance_ =
4220  improv->improvement_rate_solutions_distance_;
4221  improvements_ = improv->improvements_;
4222  threshold_ = improv->threshold_;
4223  best_objective_ = improv->best_objective_;
4224  objective_updated_ = improv->objective_updated_;
4225  gradient_stage_ = improv->gradient_stage_;
4226 }
4227 
4229  Solver* const s = solver();
4230  return s->MakeImprovementLimit(
4231  objective_var_, maximize_, objective_scaling_factor_, objective_offset_,
4232  improvement_rate_coefficient_, improvement_rate_solutions_distance_);
4233 }
4234 
4236  if (!objective_updated_) {
4237  return false;
4238  }
4239  objective_updated_ = false;
4240 
4241  if (improvements_.size() <= improvement_rate_solutions_distance_) {
4242  return false;
4243  }
4244 
4245  const std::pair<double, int64_t> cur = improvements_.back();
4246  const std::pair<double, int64_t> prev = improvements_.front();
4247  DCHECK_GT(cur.second, prev.second);
4248  double improvement_rate =
4249  std::abs(prev.first - cur.first) / (cur.second - prev.second);
4250  if (gradient_stage_) {
4251  threshold_ = fmin(threshold_, improvement_rate);
4252  } else if (improvement_rate_coefficient_ * improvement_rate < threshold_) {
4253  return true;
4254  }
4255 
4256  return false;
4257 }
4258 
4260  const int64_t new_objective =
4261  objective_var_ != nullptr && objective_var_->Bound()
4262  ? objective_var_->Value()
4263  : (maximize_
4266 
4267  const double scaled_new_objective =
4268  objective_scaling_factor_ * (new_objective + objective_offset_);
4269 
4270  const bool is_improvement = maximize_
4271  ? scaled_new_objective > best_objective_
4272  : scaled_new_objective < best_objective_;
4273 
4274  if (gradient_stage_ && !is_improvement) {
4275  gradient_stage_ = false;
4276  // In case we haven't got enough solutions during the first stage, the limit
4277  // never stops the search.
4278  if (threshold_ == std::numeric_limits<double>::infinity()) {
4279  threshold_ = -1;
4280  }
4281  }
4282 
4283  if (is_improvement) {
4284  best_objective_ = scaled_new_objective;
4285  objective_updated_ = true;
4286  improvements_.push_back(
4287  std::make_pair(scaled_new_objective, solver()->neighbors()));
4288  // We need to have 'improvement_rate_solutions_distance_' + 1 element in the
4289  // 'improvements_', so the distance between improvements is
4290  // 'improvement_rate_solutions_distance_'.
4291  if (improvements_.size() - 1 > improvement_rate_solutions_distance_) {
4292  improvements_.pop_front();
4293  }
4294  DCHECK_LE(improvements_.size() - 1, improvement_rate_solutions_distance_);
4295  }
4296 
4297  return true;
4298 }
4299 
4301  IntVar* objective_var, bool maximize, double objective_scaling_factor,
4302  double objective_offset, double improvement_rate_coefficient,
4303  int improvement_rate_solutions_distance) {
4304  return RevAlloc(new ImprovementSearchLimit(
4305  this, objective_var, maximize, objective_scaling_factor, objective_offset,
4306  improvement_rate_coefficient, improvement_rate_solutions_distance));
4307 }
4308 
4309 // A limit whose Check function is the OR of two underlying limits.
4310 namespace {
4311 class ORLimit : public SearchLimit {
4312  public:
4313  ORLimit(SearchLimit* limit_1, SearchLimit* limit_2)
4314  : SearchLimit(limit_1->solver()), limit_1_(limit_1), limit_2_(limit_2) {
4315  CHECK(limit_1 != nullptr);
4316  CHECK(limit_2 != nullptr);
4317  CHECK_EQ(limit_1->solver(), limit_2->solver())
4318  << "Illegal arguments: cannot combines limits that belong to different "
4319  << "solvers, because the reversible allocations could delete one and "
4320  << "not the other.";
4321  }
4322 
4323  bool Check() override {
4324  // Check being non-const, there may be side effects. So we always call both
4325  // checks.
4326  const bool check_1 = limit_1_->Check();
4327  const bool check_2 = limit_2_->Check();
4328  return check_1 || check_2;
4329  }
4330 
4331  void Init() override {
4332  limit_1_->Init();
4333  limit_2_->Init();
4334  }
4335 
4336  void Copy(const SearchLimit* const limit) override {
4337  LOG(FATAL) << "Not implemented.";
4338  }
4339 
4340  SearchLimit* MakeClone() const override {
4341  // Deep cloning: the underlying limits are cloned, too.
4342  return solver()->MakeLimit(limit_1_->MakeClone(), limit_2_->MakeClone());
4343  }
4344 
4345  void EnterSearch() override {
4346  limit_1_->EnterSearch();
4347  limit_2_->EnterSearch();
4348  }
4349  void BeginNextDecision(DecisionBuilder* const b) override {
4350  limit_1_->BeginNextDecision(b);
4351  limit_2_->BeginNextDecision(b);
4352  }
4353  void PeriodicCheck() override {
4354  limit_1_->PeriodicCheck();
4355  limit_2_->PeriodicCheck();
4356  }
4357  void RefuteDecision(Decision* const d) override {
4358  limit_1_->RefuteDecision(d);
4359  limit_2_->RefuteDecision(d);
4360  }
4361  std::string DebugString() const override {
4362  return absl::StrCat("OR limit (", limit_1_->DebugString(), " OR ",
4363  limit_2_->DebugString(), ")");
4364  }
4365 
4366  private:
4367  SearchLimit* const limit_1_;
4368  SearchLimit* const limit_2_;
4369 };
4370 } // namespace
4371 
4373  SearchLimit* const limit_2) {
4374  return RevAlloc(new ORLimit(limit_1, limit_2));
4375 }
4376 
4377 namespace {
4378 class CustomLimit : public SearchLimit {
4379  public:
4380  CustomLimit(Solver* const s, std::function<bool()> limiter);
4381  bool Check() override;
4382  void Init() override;
4383  void Copy(const SearchLimit* const limit) override;
4384  SearchLimit* MakeClone() const override;
4385 
4386  private:
4387  std::function<bool()> limiter_;
4388 };
4389 
4390 CustomLimit::CustomLimit(Solver* const s, std::function<bool()> limiter)
4391  : SearchLimit(s), limiter_(std::move(limiter)) {}
4392 
4393 bool CustomLimit::Check() {
4394  if (limiter_) return limiter_();
4395  return false;
4396 }
4397 
4398 void CustomLimit::Init() {}
4399 
4400 void CustomLimit::Copy(const SearchLimit* const limit) {
4401  const CustomLimit* const custom =
4402  reinterpret_cast<const CustomLimit* const>(limit);
4403  limiter_ = custom->limiter_;
4404 }
4405 
4406 SearchLimit* CustomLimit::MakeClone() const {
4407  return solver()->RevAlloc(new CustomLimit(solver(), limiter_));
4408 }
4409 } // namespace
4410 
4411 SearchLimit* Solver::MakeCustomLimit(std::function<bool()> limiter) {
4412  return RevAlloc(new CustomLimit(this, std::move(limiter)));
4413 }
4414 
4415 // ---------- SolveOnce ----------
4416 
4417 namespace {
4418 class SolveOnce : public DecisionBuilder {
4419  public:
4420  explicit SolveOnce(DecisionBuilder* const db) : db_(db) {
4421  CHECK(db != nullptr);
4422  }
4423 
4424  SolveOnce(DecisionBuilder* const db,
4425  const std::vector<SearchMonitor*>& monitors)
4426  : db_(db), monitors_(monitors) {
4427  CHECK(db != nullptr);
4428  }
4429 
4430  ~SolveOnce() override {}
4431 
4432  Decision* Next(Solver* s) override {
4433  bool res = s->SolveAndCommit(db_, monitors_);
4434  if (!res) {
4435  s->Fail();
4436  }
4437  return nullptr;
4438  }
4439 
4440  std::string DebugString() const override {
4441  return absl::StrFormat("SolveOnce(%s)", db_->DebugString());
4442  }
4443 
4444  void Accept(ModelVisitor* const visitor) const override {
4445  db_->Accept(visitor);
4446  }
4447 
4448  private:
4449  DecisionBuilder* const db_;
4450  std::vector<SearchMonitor*> monitors_;
4451 };
4452 } // namespace
4453 
4455  return RevAlloc(new SolveOnce(db));
4456 }
4457 
4459  SearchMonitor* const monitor1) {
4460  std::vector<SearchMonitor*> monitors;
4461  monitors.push_back(monitor1);
4462  return RevAlloc(new SolveOnce(db, monitors));
4463 }
4464 
4466  SearchMonitor* const monitor1,
4467  SearchMonitor* const monitor2) {
4468  std::vector<SearchMonitor*> monitors;
4469  monitors.push_back(monitor1);
4470  monitors.push_back(monitor2);
4471  return RevAlloc(new SolveOnce(db, monitors));
4472 }
4473 
4475  SearchMonitor* const monitor1,
4476  SearchMonitor* const monitor2,
4477  SearchMonitor* const monitor3) {
4478  std::vector<SearchMonitor*> monitors;
4479  monitors.push_back(monitor1);
4480  monitors.push_back(monitor2);
4481  monitors.push_back(monitor3);
4482  return RevAlloc(new SolveOnce(db, monitors));
4483 }
4484 
4486  SearchMonitor* const monitor1,
4487  SearchMonitor* const monitor2,
4488  SearchMonitor* const monitor3,
4489  SearchMonitor* const monitor4) {
4490  std::vector<SearchMonitor*> monitors;
4491  monitors.push_back(monitor1);
4492  monitors.push_back(monitor2);
4493  monitors.push_back(monitor3);
4494  monitors.push_back(monitor4);
4495  return RevAlloc(new SolveOnce(db, monitors));
4496 }
4497 
4499  DecisionBuilder* const db, const std::vector<SearchMonitor*>& monitors) {
4500  return RevAlloc(new SolveOnce(db, monitors));
4501 }
4502 
4503 // ---------- NestedOptimize ----------
4504 
4505 namespace {
4506 class NestedOptimize : public DecisionBuilder {
4507  public:
4508  NestedOptimize(DecisionBuilder* const db, Assignment* const solution,
4509  bool maximize, int64_t step)
4510  : db_(db),
4511  solution_(solution),
4512  maximize_(maximize),
4513  step_(step),
4514  collector_(nullptr) {
4515  CHECK(db != nullptr);
4516  CHECK(solution != nullptr);
4517  CHECK(solution->HasObjective());
4518  AddMonitors();
4519  }
4520 
4521  NestedOptimize(DecisionBuilder* const db, Assignment* const solution,
4522  bool maximize, int64_t step,
4523  const std::vector<SearchMonitor*>& monitors)
4524  : db_(db),
4525  solution_(solution),
4526  maximize_(maximize),
4527  step_(step),
4528  monitors_(monitors),
4529  collector_(nullptr) {
4530  CHECK(db != nullptr);
4531  CHECK(solution != nullptr);
4532  CHECK(solution->HasObjective());
4533  AddMonitors();
4534  }
4535 
4536  void AddMonitors() {
4537  Solver* const solver = solution_->solver();
4538  collector_ = solver->MakeLastSolutionCollector(solution_);
4539  monitors_.push_back(collector_);
4540  OptimizeVar* const optimize =
4541  solver->MakeOptimize(maximize_, solution_->Objective(), step_);
4542  monitors_.push_back(optimize);
4543  }
4544 
4545  Decision* Next(Solver* solver) override {
4546  solver->Solve(db_, monitors_);
4547  if (collector_->solution_count() == 0) {
4548  solver->Fail();
4549  }
4550  collector_->solution(0)->Restore();
4551  return nullptr;
4552  }
4553 
4554  std::string DebugString() const override {
4555  return absl::StrFormat("NestedOptimize(db = %s, maximize = %d, step = %d)",
4556  db_->DebugString(), maximize_, step_);
4557  }
4558 
4559  void Accept(ModelVisitor* const visitor) const override {
4560  db_->Accept(visitor);
4561  }
4562 
4563  private:
4564  DecisionBuilder* const db_;
4565  Assignment* const solution_;
4566  const bool maximize_;
4567  const int64_t step_;
4568  std::vector<SearchMonitor*> monitors_;
4569  SolutionCollector* collector_;
4570 };
4571 } // namespace
4572 
4574  Assignment* const solution,
4575  bool maximize, int64_t step) {
4576  return RevAlloc(new NestedOptimize(db, solution, maximize, step));
4577 }
4578 
4580  Assignment* const solution,
4581  bool maximize, int64_t step,
4582  SearchMonitor* const monitor1) {
4583  std::vector<SearchMonitor*> monitors;
4584  monitors.push_back(monitor1);
4585  return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));
4586 }
4587 
4589  Assignment* const solution,
4590  bool maximize, int64_t step,
4591  SearchMonitor* const monitor1,
4592  SearchMonitor* const monitor2) {
4593  std::vector<SearchMonitor*> monitors;
4594  monitors.push_back(monitor1);
4595  monitors.push_back(monitor2);
4596  return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));
4597 }
4598 
4600  Assignment* const solution,
4601  bool maximize, int64_t step,
4602  SearchMonitor* const monitor1,
4603  SearchMonitor* const monitor2,
4604  SearchMonitor* const monitor3) {
4605  std::vector<SearchMonitor*> monitors;
4606  monitors.push_back(monitor1);
4607  monitors.push_back(monitor2);
4608  monitors.push_back(monitor3);
4609  return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));
4610 }
4611 
4613  DecisionBuilder* const db, Assignment* const solution, bool maximize,
4614  int64_t step, SearchMonitor* const monitor1, SearchMonitor* const monitor2,
4615  SearchMonitor* const monitor3, SearchMonitor* const monitor4) {
4616  std::vector<SearchMonitor*> monitors;
4617  monitors.push_back(monitor1);
4618  monitors.push_back(monitor2);
4619  monitors.push_back(monitor3);
4620  monitors.push_back(monitor4);
4621  return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));
4622 }
4623 
4625  DecisionBuilder* const db, Assignment* const solution, bool maximize,
4626  int64_t step, const std::vector<SearchMonitor*>& monitors) {
4627  return RevAlloc(new NestedOptimize(db, solution, maximize, step, monitors));
4628 }
4629 
4630 // ---------- Restart ----------
4631 
4632 namespace {
4633 // Luby Strategy
4634 int64_t NextLuby(int i) {
4635  DCHECK_GT(i, 0);
4637  int64_t power;
4638 
4639  // let's find the least power of 2 >= (i+1).
4640  power = 2;
4641  // Cannot overflow, because bounded by kint32max + 1.
4642  while (power < (i + 1)) {
4643  power <<= 1;
4644  }
4645  if (power == i + 1) {
4646  return (power / 2);
4647  }
4648  return NextLuby(i - (power / 2) + 1);
4649 }
4650 
4651 class LubyRestart : public SearchMonitor {
4652  public:
4653  LubyRestart(Solver* const s, int scale_factor)
4654  : SearchMonitor(s),
4655  scale_factor_(scale_factor),
4656  iteration_(1),
4657  current_fails_(0),
4658  next_step_(scale_factor) {
4659  CHECK_GE(scale_factor, 1);
4660  }
4661 
4662  ~LubyRestart() override {}
4663 
4664  void BeginFail() override {
4665  if (++current_fails_ >= next_step_) {
4666  current_fails_ = 0;
4667  next_step_ = NextLuby(++iteration_) * scale_factor_;
4668  solver()->RestartCurrentSearch();
4669  }
4670  }
4671 
4672  std::string DebugString() const override {
4673  return absl::StrFormat("LubyRestart(%i)", scale_factor_);
4674  }
4675 
4676  private:
4677  const int scale_factor_;
4678  int iteration_;
4679  int64_t current_fails_;
4680  int64_t next_step_;
4681 };
4682 } // namespace
4683 
4685  return RevAlloc(new LubyRestart(this, scale_factor));
4686 }
4687 
4688 // ----- Constant Restart -----
4689 
4690 namespace {
4691 class ConstantRestart : public SearchMonitor {
4692  public:
4693  ConstantRestart(Solver* const s, int frequency)
4694  : SearchMonitor(s), frequency_(frequency), current_fails_(0) {
4695  CHECK_GE(frequency, 1);
4696  }
4697 
4698  ~ConstantRestart() override {}
4699 
4700  void BeginFail() override {
4701  if (++current_fails_ >= frequency_) {
4702  current_fails_ = 0;
4703  solver()->RestartCurrentSearch();
4704  }
4705  }
4706 
4707  std::string DebugString() const override {
4708  return absl::StrFormat("ConstantRestart(%i)", frequency_);
4709  }
4710 
4711  private:
4712  const int frequency_;
4713  int64_t current_fails_;
4714 };
4715 } // namespace
4716 
4718  return RevAlloc(new ConstantRestart(this, frequency));
4719 }
4720 
4721 // ---------- Symmetry Breaking ----------
4722 
4723 // The symmetry manager maintains a list of problem symmetries. Each
4724 // symmetry is called on each decision and should return a term
4725 // representing the boolean status of the symmetrical decision.
4726 // e.g. : the decision is x == 3, the symmetrical decision is y == 5
4727 // then the symmetry breaker should use
4728 // AddIntegerVariableEqualValueClause(y, 5). Once this is done, upon
4729 // refutation, for each symmetry breaker, the system adds a constraint
4730 // that will forbid the symmetrical variation of the current explored
4731 // search tree. This constraint can be expressed very simply just by
4732 // keeping the list of current symmetrical decisions.
4733 //
4734 // This is called Symmetry Breaking During Search (Ian Gent, Barbara
4735 // Smith, ECAI 2000).
4736 // http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.42.3788&rep=rep1&type=pdf
4737 //
4739  public:
4741  const std::vector<SymmetryBreaker*>& visitors)
4742  : SearchMonitor(s),
4743  visitors_(visitors),
4744  clauses_(visitors.size()),
4745  decisions_(visitors.size()),
4746  directions_(visitors.size()) { // false = left.
4747  for (int i = 0; i < visitors_.size(); ++i) {
4748  visitors_[i]->set_symmetry_manager_and_index(this, i);
4749  }
4750  }
4751 
4752  ~SymmetryManager() override {}
4753 
4754  void EndNextDecision(DecisionBuilder* const db, Decision* const d) override {
4755  if (d) {
4756  for (int i = 0; i < visitors_.size(); ++i) {
4757  const void* const last = clauses_[i].Last();
4758  d->Accept(visitors_[i]);
4759  if (last != clauses_[i].Last()) {
4760  // Synchroneous push of decision as marker.
4761  decisions_[i].Push(solver(), d);
4762  directions_[i].Push(solver(), false);
4763  }
4764  }
4765  }
4766  }
4767 
4768  void RefuteDecision(Decision* d) override {
4769  for (int i = 0; i < visitors_.size(); ++i) {
4770  if (decisions_[i].Last() != nullptr && decisions_[i].LastValue() == d) {
4771  CheckSymmetries(i);
4772  }
4773  }
4774  }
4775 
4776  // TODO(user) : Improve speed, cache previous min and build them
4777  // incrementally.
4779  SimpleRevFIFO<IntVar*>::Iterator tmp(&clauses_[index]);
4780  SimpleRevFIFO<bool>::Iterator tmp_dir(&directions_[index]);
4781  Constraint* ct = nullptr;
4782  {
4783  std::vector<IntVar*> guard;
4784  // keep the last entry for later, if loop doesn't exit.
4785  ++tmp;
4786  ++tmp_dir;
4787  while (tmp.ok()) {
4788  IntVar* const term = *tmp;
4789  if (!*tmp_dir) {
4790  if (term->Max() == 0) {
4791  // Premise is wrong. The clause will never apply.
4792  return;
4793  }
4794  if (term->Min() == 0) {
4795  DCHECK_EQ(1, term->Max());
4796  // Premise may be true. Adding to guard vector.
4797  guard.push_back(term);
4798  }
4799  }
4800  ++tmp;
4801  ++tmp_dir;
4802  }
4803  guard.push_back(clauses_[index].LastValue());
4804  directions_[index].SetLastValue(true);
4805  // Given premises: xi = ai
4806  // and a term y != b
4807  // The following is equivalent to
4808  // And(xi == a1) => y != b.
4809  ct = solver()->MakeEquality(solver()->MakeMin(guard), Zero());
4810  }
4811  DCHECK(ct != nullptr);
4812  solver()->AddConstraint(ct);
4813  }
4814 
4815  void AddTermToClause(SymmetryBreaker* const visitor, IntVar* const term) {
4816  clauses_[visitor->index_in_symmetry_manager()].Push(solver(), term);
4817  }
4818 
4819  std::string DebugString() const override { return "SymmetryManager"; }
4820 
4821  private:
4822  const std::vector<SymmetryBreaker*> visitors_;
4823  std::vector<SimpleRevFIFO<IntVar*>> clauses_;
4824  std::vector<SimpleRevFIFO<Decision*>> decisions_;
4825  std::vector<SimpleRevFIFO<bool>> directions_;
4826 };
4827 
4828 // ----- Symmetry Breaker -----
4829 
4831  int64_t value) {
4832  CHECK(var != nullptr);
4833  Solver* const solver = var->solver();
4834  IntVar* const term = solver->MakeIsEqualCstVar(var, value);
4835  symmetry_manager()->AddTermToClause(this, term);
4836 }
4837 
4839  IntVar* const var, int64_t value) {
4840  CHECK(var != nullptr);
4841  Solver* const solver = var->solver();
4842  IntVar* const term = solver->MakeIsGreaterOrEqualCstVar(var, value);
4843  symmetry_manager()->AddTermToClause(this, term);
4844 }
4845 
4847  IntVar* const var, int64_t value) {
4848  CHECK(var != nullptr);
4849  Solver* const solver = var->solver();
4850  IntVar* const term = solver->MakeIsLessOrEqualCstVar(var, value);
4851  symmetry_manager()->AddTermToClause(this, term);
4852 }
4853 
4854 // ----- API -----
4855 
4857  const std::vector<SymmetryBreaker*>& visitors) {
4858  return RevAlloc(new SymmetryManager(this, visitors));
4859 }
4860 
4862  std::vector<SymmetryBreaker*> visitors;
4863  visitors.push_back(v1);
4864  return MakeSymmetryManager(visitors);
4865 }
4866 
4868  SymmetryBreaker* const v2) {
4869  std::vector<SymmetryBreaker*> visitors;
4870  visitors.push_back(v1);
4871  visitors.push_back(v2);
4872  return MakeSymmetryManager(visitors);
4873 }
4874 
4876  SymmetryBreaker* const v2,
4877  SymmetryBreaker* const v3) {
4878  std::vector<SymmetryBreaker*> visitors;
4879  visitors.push_back(v1);
4880  visitors.push_back(v2);
4881  visitors.push_back(v3);
4882  return MakeSymmetryManager(visitors);
4883 }
4884 
4886  SymmetryBreaker* const v2,
4887  SymmetryBreaker* const v3,
4888  SymmetryBreaker* const v4) {
4889  std::vector<SymmetryBreaker*> visitors;
4890  visitors.push_back(v1);
4891  visitors.push_back(v2);
4892  visitors.push_back(v3);
4893  visitors.push_back(v4);
4894  return MakeSymmetryManager(visitors);
4895 }
4896 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
#define CHECK(condition)
Definition: base/logging.h:498
#define DCHECK_LE(val1, val2)
Definition: base/logging.h:895
#define CHECK_LT(val1, val2)
Definition: base/logging.h:708
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:705
#define CHECK_GE(val1, val2)
Definition: base/logging.h:709
#define CHECK_GT(val1, val2)
Definition: base/logging.h:710
#define DCHECK_GT(val1, val2)
Definition: base/logging.h:898
#define DCHECK_LT(val1, val2)
Definition: base/logging.h:896
#define LOG(severity)
Definition: base/logging.h:423
#define DCHECK(condition)
Definition: base/logging.h:892
#define CHECK_LE(val1, val2)
Definition: base/logging.h:707
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:893
#define VLOG(verboselevel)
Definition: base/logging.h:986
An Assignment is a variable -> domains mapping, used to report solutions to the user.
const std::vector< int > & Unperformed(const SequenceVar *const var) const
const std::vector< int > & BackwardSequence(const SequenceVar *const var) const
int64_t EndValue(const IntervalVar *const var) const
int64_t StartValue(const IntervalVar *const var) const
int64_t PerformedValue(const IntervalVar *const var) const
int64_t DurationValue(const IntervalVar *const var) const
const std::vector< int > & ForwardSequence(const SequenceVar *const var) const
int64_t Value(const IntVar *const var) const
A BaseObject is the root of all reversibly allocated objects.
void Set(uint32_t index, bool value)
Definition: bitmap.h:62
bool Get(uint32_t index) const
Definition: bitmap.h:58
A constraint is the main modeling object.
A DecisionBuilder is responsible for creating the search tree.
A Decision represents a choice point in the search tree.
virtual void Accept(DecisionVisitor *const visitor) const
Accepts the given visitor.
virtual void Apply(Solver *const s)=0
Apply will be called first when the decision is executed.
virtual void Refute(Solver *const s)=0
Refute will be called after a backtrack.
std::string DebugString() const override
bool Check() override
This method is called to check the status of the limit.
Definition: search.cc:4235
void Init() override
This method is called when the search limit is initialized.
Definition: search.cc:4203
void Copy(const SearchLimit *const limit) override
Copy a limit.
Definition: search.cc:4211
bool AtSolution() override
This method is called when a valid solution is found.
Definition: search.cc:4259
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:4185
SearchLimit * MakeClone() const override
Allocates a clone of the limit.
Definition: search.cc:4228
The class IntExpr is the base of all integer expressions in constraint programming.
virtual bool Bound() const
Returns true if the min and the max of the expression are equal.
virtual void SetValue(int64_t v)
This method sets the value of the expression.
virtual int64_t Min() const =0
virtual void SetMax(int64_t m)=0
virtual void SetMin(int64_t m)=0
virtual int64_t Max() const =0
The class IntVar is a subset of IntExpr.
virtual int64_t Value() const =0
This method returns the value of the variable.
Interval variables are often used in scheduling.
static int64_t FastInt64Round(double x)
Definition: mathutil.h:138
static const char kSolutionLimitArgument[]
virtual void VisitIntegerArgument(const std::string &arg_name, int64_t value)
Visit integer arguments.
static const char kBranchesLimitArgument[]
static const char kSmartTimeCheckArgument[]
virtual void BeginVisitExtension(const std::string &type)
virtual void EndVisitExtension(const std::string &type)
static const char kVariableGroupExtension[]
static const char kFailuresLimitArgument[]
virtual void VisitIntegerExpressionArgument(const std::string &arg_name, IntExpr *const argument)
Visit integer expression argument.
This class encapsulates an objective.
void EnterSearch() override
Beginning of the search.
Definition: search.cc:2750
void BeginNextDecision(DecisionBuilder *const db) override
Before calling DecisionBuilder::Next.
Definition: search.cc:2759
OptimizeVar(Solver *const s, bool maximize, IntVar *const a, int64_t step)
Definition: search.cc:2729
IntVar * Var() const
Returns the variable that is optimized.
void Accept(ModelVisitor *const visitor) const override
Accepts the given model visitor.
Definition: search.cc:2854
bool AcceptSolution() override
This method is called when a solution is found.
Definition: search.cc:2777
virtual std::string Print() const
Definition: search.cc:2838
bool AtSolution() override
This method is called when a valid solution is found.
Definition: search.cc:2789
void RefuteDecision(Decision *const d) override
Before refuting the decision.
Definition: search.cc:2775
bool AcceptDelta(Assignment *delta, Assignment *deltadelta) override
Internal methods.
Definition: search.cc:2802
std::string DebugString() const override
Definition: search.cc:2842
Usual limit based on wall_time, number of explored branches and number of failures in the search tree...
bool Check() override
This method is called to check the status of the limit.
Definition: search.cc:4020
absl::Duration duration_limit() const
bool IsUncheckedSolutionLimitReached() override
Returns true if the limit of solutions has been reached including unchecked solutions.
Definition: search.cc:4071
void UpdateLimits(absl::Duration time, int64_t branches, int64_t failures, int64_t solutions)
Definition: search.cc:4063
void Init() override
This method is called when the search limit is initialized.
Definition: search.cc:4041
void ExitSearch() override
End of the search.
Definition: search.cc:4052
int ProgressPercent() override
Returns a percentage representing the propress of the search before reaching limits.
Definition: search.cc:4028
void Accept(ModelVisitor *const visitor) const override
Accepts the given model visitor.
Definition: search.cc:4085
void Copy(const SearchLimit *const limit) override
Copy a limit.
Definition: search.cc:4001
RegularLimit * MakeIdenticalClone() const
Definition: search.cc:4014
std::string DebugString() const override
Definition: search.cc:4077
SearchLimit * MakeClone() const override
Allocates a clone of the limit.
Definition: search.cc:4012
Base class of all search limits.
bool crossed() const
Returns true if the limit has been crossed.
The base class of all search logs that periodically outputs information when the search is running.
void BeginFail() override
Just when the failure occurs.
Definition: search.cc:180
virtual void OutputLine(const std::string &line)
Definition: search.cc:260
void EnterSearch() override
Beginning of the search.
Definition: search.cc:87
void RefuteDecision(Decision *const decision) override
Before refuting the decision.
Definition: search.cc:210
void ExitSearch() override
End of the search.
Definition: search.cc:95
SearchLog(Solver *const s, OptimizeVar *const obj, IntVar *const var, double scaling_factor, double offset, std::function< std::string()> display_callback, bool display_on_new_solutions_only, int period)
Definition: search.cc:58
void BeginInitialPropagation() override
Before the initial propagation.
Definition: search.cc:250
void NoMoreSolutions() override
When the search tree is finished.
Definition: search.cc:182
void ApplyDecision(Decision *const decision) override
Before applying the decision.
Definition: search.cc:202
bool AtSolution() override
This method is called when a valid solution is found.
Definition: search.cc:108
std::string DebugString() const override
Definition: search.cc:85
void AcceptUncheckedNeighbor() override
After accepting an unchecked neighbor during local search.
Definition: search.cc:178
void EndInitialPropagation() override
After the initial propagation.
Definition: search.cc:252
A search monitor is a simple set of callbacks to monitor all search events.
virtual void ExitSearch()
End of the search.
virtual bool AtSolution()
This method is called when a valid solution is found.
A sequence variable is a variable whose domain is a set of possible orderings of the interval variabl...
This iterator is not stable with respect to deletion.
This class represent a reversible FIFO structure.
This class is the root class of all solution collectors.
void EnterSearch() override
Beginning of the search.
Definition: search.cc:2272
void Push(const SolutionData &data)
void PushSolution()
Push the current state as a new solution.
Definition: search.cc:2281
void AddObjective(IntVar *const objective)
Definition: search.cc:2266
std::vector< Assignment * > recycle_solutions_
std::vector< SolutionData > solution_data_
void Add(IntVar *const var)
Add API.
Definition: search.cc:2230
int solution_count() const
Returns how many solutions were stored during the search.
Definition: search.cc:2334
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:2356
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:2386
SolutionData BuildSolutionDataForCurrentState()
Definition: search.cc:2293
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:2364
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:2360
Assignment * solution(int n) const
Returns the nth solution.
Definition: search.cc:2329
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:2368
int64_t objective_value(int n) const
Returns the objective value of the nth solution.
Definition: search.cc:2351
int64_t wall_time(int n) const
Returns the wall time in ms for the nth solution.
Definition: search.cc:2336
int64_t branches(int n) const
Returns the number of branches when the nth solution was found.
Definition: search.cc:2341
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:2372
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:2376
void FreeSolution(Assignment *solution)
Definition: search.cc:2318
int64_t failures(int n) const
Returns the number of failures encountered at the time of the nth solution.
Definition: search.cc:2346
std::unique_ptr< Assignment > prototype_
SolutionCollector(Solver *const solver, const Assignment *assignment)
Definition: search.cc:2214
void PopSolution()
Remove and delete the last popped solution.
Definition: search.cc:2285
std::string DebugString() const override
const std::vector< int > & BackwardSequence(int n, SequenceVar *const var) const
This is a shortcut to get the BackwardSequence of 'var' in the nth solution.
Definition: search.cc:2381
int64_t neighbors() const
The number of neighbors created.
SearchMonitor * MakeLubyRestart(int scale_factor)
This search monitor will restart the search periodically.
Definition: search.cc:4684
SolutionCollector * MakeAllSolutionCollector()
Collect all solutions of the search.
Definition: search.cc:2723
RegularLimit * MakeSolutionsLimit(int64_t solutions)
Creates a search limit that constrains the number of solutions found during the search.
Definition: search.cc:4143
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:2918
SolutionCollector * MakeLastSolutionCollector()
Collect the last solution of the search.
Definition: search.cc:2490
Decision * MakeAssignVariableValueOrDoNothing(IntVar *const var, int64_t value)
Definition: search.cc:1633
SearchMonitor * MakeAtSolutionCallback(std::function< void()> callback)
Definition: search.cc:422
int64_t branches() const
The number of branches explored since the creation of the solver.
SearchLimit * MakeCustomLimit(std::function< bool()> limiter)
Callback-based search limit.
Definition: search.cc:4411
Constraint * MakeEquality(IntExpr *const left, IntExpr *const right)
left == right
Definition: range_cst.cc:512
OptimizeVar * MakeOptimize(bool maximize, IntVar *const v, int64_t step)
Creates a objective with a given sense (true = maximization).
Definition: search.cc:2871
IntVar * MakeIsGreaterOrEqualCstVar(IntExpr *const var, int64_t value)
status var of (var >= value)
Definition: expr_cst.cc:679
ConstraintSolverParameters parameters() const
Stored Parameters.
SearchMonitor * MakeSymmetryManager(const std::vector< SymmetryBreaker * > &visitors)
Symmetry Breaking.
Definition: search.cc:4856
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:4136
absl::Time Now() const
The 'absolute time' as seen by the solver.
std::function< int64_t(int64_t, int64_t, int64_t)> IndexEvaluator3
Assignment * GetOrCreateLocalSearchState()
Returns (or creates) an assignment representing the state of local search.
DecisionBuilder * MakeNestedOptimize(DecisionBuilder *const db, Assignment *const solution, bool maximize, int64_t step)
NestedOptimize will collapse a search tree described by a decision builder 'db' and a set of monitors...
Definition: search.cc:4573
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
RegularLimit * MakeBranchesLimit(int64_t branches)
Creates a search limit that constrains the number of branches explored in the search tree.
Definition: search.cc:4129
OptimizeVar * MakeMaximize(IntVar *const v, int64_t step)
Creates a maximization objective.
Definition: search.cc:2867
SearchMonitor * MakeSearchLog(int branch_period)
The SearchMonitors below will display a periodic search log on LOG(INFO) every branch_period branches...
Definition: search.cc:288
IntValueStrategy
This enum describes the strategy used to select the next variable value to set.
@ INT_VALUE_SIMPLE
The simple selection is ASSIGN_MIN_VALUE.
@ ASSIGN_CENTER_VALUE
Selects the first possible value which is the closest to the center of the domain of the selected var...
@ SPLIT_UPPER_HALF
Split the domain in two around the center, and choose the lower part first.
@ ASSIGN_MIN_VALUE
Selects the min value of the selected variable.
@ ASSIGN_RANDOM_VALUE
Selects randomly one of the possible values of the selected variable.
@ INT_VALUE_DEFAULT
The default behavior is ASSIGN_MIN_VALUE.
@ ASSIGN_MAX_VALUE
Selects the max value of the selected variable.
@ SPLIT_LOWER_HALF
Split the domain in two around the center, and choose the lower part first.
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:4157
std::function< int64_t(Solver *solver, const std::vector< IntVar * > &vars, int64_t first_unbound, int64_t last_unbound)> VariableIndexSelector
std::function< int64_t(int64_t, int64_t)> IndexEvaluator2
OptimizeVar * MakeMinimize(IntVar *const v, int64_t step)
Creates a minimization objective.
Definition: search.cc:2863
void AddConstraint(Constraint *const c)
Adds the constraint 'c' to the model.
Decision * MakeAssignVariablesValues(const std::vector< IntVar * > &vars, const std::vector< int64_t > &values)
Definition: search.cc:1761
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:4454
int64_t wall_time() const
DEPRECATED: Use Now() instead.
OptimizeVar * MakeWeightedMaximize(const std::vector< IntVar * > &sub_objectives, const std::vector< int64_t > &weights, int64_t step)
Creates a maximization weigthed objective.
Definition: search.cc:2925
int SearchDepth() const
Gets the search depth of the current active search.
int64_t unchecked_solutions() const
The number of unchecked solutions found by local search.
int64_t failures() const
The number of failures encountered since the creation of the solver.
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:4300
SearchMonitor * MakeConstantRestart(int frequency)
This search monitor will restart the search periodically after 'frequency' failures.
Definition: search.cc:4717
EvaluatorStrategy
This enum is used by Solver::MakePhase to specify how to select variables and values during the searc...
@ CHOOSE_STATIC_GLOBAL_BEST
Pairs are compared at the first call of the selector, and results are cached.
@ CHOOSE_DYNAMIC_GLOBAL_BEST
Pairs are compared each time a variable is selected.
static int64_t MemoryUsage()
Current memory usage in bytes.
void set_optimization_direction(OptimizationDirection direction)
IntVar * MakeIsLessOrEqualCstVar(IntExpr *const var, int64_t value)
status var of (var <= value)
Definition: expr_cst.cc:779
SearchMonitor * MakeSimulatedAnnealing(bool maximize, IntVar *const v, int64_t step, int64_t initial_temperature)
Creates a Simulated Annealing monitor.
Definition: search.cc:3374
RegularLimitParameters MakeDefaultRegularLimitParameters() const
Creates a regular limit proto containing default values.
Definition: search.cc:4172
RegularLimit * MakeTimeLimit(absl::Duration time)
Creates a search limit that constrains the running time.
Definition: search.cc:4122
SearchMonitor * MakeSearchTrace(const std::string &prefix)
Creates a search monitor that will trace precisely the behavior of the search.
Definition: search.cc:398
int TopProgressPercent()
Returns a percentage representing the propress of the search before reaching the limits of the top-le...
T * RevAlloc(T *object)
Registers the given object as being reversible.
IntVarStrategy
This enum describes the strategy used to select the next branching variable at each node during the s...
@ CHOOSE_RANDOM
Randomly select one of the remaining unbound variables.
@ CHOOSE_MIN_SIZE
Among unbound variables, select the variable with the smallest size.
@ CHOOSE_FIRST_UNBOUND
Select the first unbound variable.
@ CHOOSE_PATH
Selects the next unbound variable on a path, the path being defined by the variables: var[i] correspo...
@ CHOOSE_HIGHEST_MAX
Among unbound variables, select the variable with the highest maximal value.
@ CHOOSE_MIN_SIZE_LOWEST_MIN
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ INT_VAR_DEFAULT
The default behavior is CHOOSE_FIRST_UNBOUND.
@ CHOOSE_MIN_SIZE_HIGHEST_MAX
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ CHOOSE_MAX_REGRET_ON_MIN
Among unbound variables, select the variable with the largest gap between the first and the second va...
@ CHOOSE_MIN_SIZE_HIGHEST_MIN
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ CHOOSE_MAX_SIZE
Among unbound variables, select the variable with the highest size.
@ INT_VAR_SIMPLE
The simple selection is CHOOSE_FIRST_UNBOUND.
@ CHOOSE_MIN_SIZE_LOWEST_MAX
Among unbound variables, select the variable with the smallest size, i.e., the smallest number of pos...
@ CHOOSE_LOWEST_MIN
Among unbound variables, select the variable with the smallest minimal value.
DecisionBuilder * MakePhase(const std::vector< IntVar * > &vars, IntVarStrategy var_str, IntValueStrategy val_str)
Phases on IntVar arrays.
Definition: search.cc:2017
std::function< int64_t(const IntVar *v, int64_t id)> VariableValueSelector
SearchMonitor * MakeEnterSearchCallback(std::function< void()> callback)
--— Callback-based search monitors --—
Definition: search.cc:442
std::function< void(Solver *)> Action
SolutionCollector * MakeFirstSolutionCollector()
Collect the first solution of the search.
Definition: search.cc:2444
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:2911
std::function< int64_t(int64_t)> IndexEvaluator1
Callback typedefs.
SearchMonitor * MakeExitSearchCallback(std::function< void()> callback)
Definition: search.cc:462
Decision * MakeSplitVariableDomain(IntVar *const var, int64_t val, bool start_with_lower_half)
Definition: search.cc:1687
DecisionBuilder * MakeDecisionBuilderFromAssignment(Assignment *const assignment, DecisionBuilder *const db, const std::vector< IntVar * > &vars)
Returns a decision builder for which the left-most leaf corresponds to assignment,...
Definition: search.cc:2204
Decision * MakeVariableLessOrEqualValue(IntVar *const var, int64_t value)
Definition: search.cc:1692
IntVar * MakeIsEqualCstVar(IntExpr *const var, int64_t value)
status var of (var == value)
Definition: expr_cst.cc:462
int64_t solutions() const
The number of solutions found since the start of the search.
std::function< bool(int64_t, int64_t, int64_t)> VariableValueComparator
Decision * MakeAssignVariableValueOrFail(IntVar *const var, int64_t value)
Definition: search.cc:1604
Decision * MakeVariableGreaterOrEqualValue(IntVar *const var, int64_t value)
Definition: search.cc:1697
A symmetry breaker is an object that will visit a decision and create the 'symmetrical' decision in r...
void AddIntegerVariableLessOrEqualValueClause(IntVar *const var, int64_t value)
Definition: search.cc:4846
void AddIntegerVariableEqualValueClause(IntVar *const var, int64_t value)
Definition: search.cc:4830
void AddIntegerVariableGreaterOrEqualValueClause(IntVar *const var, int64_t value)
Definition: search.cc:4838
void AddTermToClause(SymmetryBreaker *const visitor, IntVar *const term)
Definition: search.cc:4815
void EndNextDecision(DecisionBuilder *const db, Decision *const d) override
After calling DecisionBuilder::Next, along with the returned decision.
Definition: search.cc:4754
void RefuteDecision(Decision *d) override
Before refuting the decision.
Definition: search.cc:4768
SymmetryManager(Solver *const s, const std::vector< SymmetryBreaker * > &visitors)
Definition: search.cc:4740
std::string DebugString() const override
Definition: search.cc:4819
int64_t b
int64_t a
std::vector< IntVarIterator * > iterators_
Block * next
SatParameters parameters
CpModelProto proto
const std::string name
const Constraint * ct
MPCallback * callback
const int64_t offset_
Definition: interval.cc:2108
const int INFO
Definition: log_severity.h:31
const int FATAL
Definition: log_severity.h:32
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: macros.h:29
Definition: cleanup.h:22
void STLDeleteElements(T *container)
Definition: stl_util.h:372
bool FindCopy(const Collection &collection, const Key &key, Value *const value)
Definition: map_util.h:185
const Collection::value_type::second_type & FindWithDefault(const Collection &collection, const typename Collection::value_type::first_type &key, const typename Collection::value_type::second_type &value)
Definition: map_util.h:29
std::function< int64_t(const Model &)> Value(IntegerVariable v)
Definition: integer.h:1492
Collection of objects used to extend the Constraint Solver library.
int64_t CapAdd(int64_t x, int64_t y)
int64_t CapSub(int64_t x, int64_t y)
int64_t Zero()
NOLINT.
std::pair< int64_t, int64_t > Arc
Definition: search.cc:3383
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)
Definition: string_array.h:45
bool AcceptDelta(Search *const search, Assignment *delta, Assignment *deltadelta)
std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)
Definition: utilities.cc:828
void AcceptNeighbor(Search *const search)
BaseAssignVariables::Mode ChooseMode(Solver::IntValueStrategy val_str)
Definition: search.cc:2007
int index
Definition: pack.cc:509
int64_t time
Definition: resource.cc:1691
int64_t delta
Definition: resource.cc:1692
int64_t bound
std::priority_queue< std::pair< int64_t, SolutionData > > solutions_pq_
Definition: search.cc:2589
int64_t assignment_penalized_value_
Definition: search.cc:3511
const double penalty_factor_
Definition: search.cc:3515
int64_t step_
Definition: search.cc:2967
std::vector< DecisionBuilder * > builders_
Definition: search.cc:480
std::unique_ptr< int64_t[]> delta_cache_
Definition: search.cc:3518
BaseVariableAssignmentSelector *const selector_
Definition: search.cc:1865
int64_t best_
Definition: search.cc:2509
std::unique_ptr< int64_t[]> current_penalized_values_
Definition: search.cc:3517
const int solution_count_
Definition: search.cc:2590
int64_t var
Definition: search.cc:1360
int64_t current_
Definition: search.cc:2968
ABSL_FLAG(bool, cp_use_sparse_gls_penalties, false, "Use sparse implementation to store Guided Local Search penalties")
IntVar * penalized_objective_
Definition: search.cc:3509
const bool maximize_
Definition: search.cc:2508
std::vector< IntVar * > vars_
Definition: search.cc:790
IntVar *const objective_
Definition: search.cc:2966
Rev< int64_t > first_unbound_
Definition: search.cc:791
Rev< int64_t > last_unbound_
Definition: search.cc:792
std::function< int64_t(int64_t, int64_t)> evaluator_
Definition: search.cc:1368
Solver *const solver_
Definition: search.cc:789
int64_t value
Definition: search.cc:1361
int64_t old_penalized_value_
Definition: search.cc:3512
bool incremental_
Definition: search.cc:3519
absl::flat_hash_map< const IntVar *, int64_t > indices_
Definition: search.cc:3514
const int64_t stamp_
Definition: search.cc:3054
const Mode mode_
Definition: search.cc:1866
Creates a search monitor from logging parameters.