Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
constraint_solver.cc
Go to the documentation of this file.
1// Copyright 2010-2024 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//
15// This file implements the core objects of the constraint solver:
16// Solver, Search, Queue, ... along with the main resolution loop.
17
19
20#include <algorithm>
21#include <csetjmp>
22#include <cstdint>
23#include <deque>
24#include <iosfwd>
25#include <limits>
26#include <memory>
27#include <ostream>
28#include <string>
29#include <type_traits>
30#include <utility>
31#include <vector>
32
33#include "absl/flags/flag.h"
34#include "absl/log/check.h"
35#include "absl/time/time.h"
40#include "ortools/base/timer.h"
43#include "zconf.h"
44#include "zlib.h"
45
46// These flags are used to set the fields in the DefaultSolverParameters proto.
47ABSL_FLAG(bool, cp_trace_propagation, false,
48 "Trace propagation events (constraint and demon executions,"
49 " variable modifications).");
50ABSL_FLAG(bool, cp_trace_search, false, "Trace search events");
51ABSL_FLAG(bool, cp_print_added_constraints, false,
52 "show all constraints added to the solver.");
53ABSL_FLAG(bool, cp_print_model, false,
54 "use PrintModelVisitor on model before solving.");
55ABSL_FLAG(bool, cp_model_stats, false,
56 "use StatisticsModelVisitor on model before solving.");
57ABSL_FLAG(bool, cp_disable_solve, false,
58 "Force failure at the beginning of a search.");
59ABSL_FLAG(std::string, cp_profile_file, "",
60 "Export profiling overview to file.");
61ABSL_FLAG(bool, cp_print_local_search_profile, false,
62 "Print local search profiling data after solving.");
63ABSL_FLAG(bool, cp_name_variables, false, "Force all variables to have names.");
64ABSL_FLAG(bool, cp_name_cast_variables, false,
65 "Name variables casted from expressions");
66ABSL_FLAG(bool, cp_use_small_table, true,
67 "Use small compact table constraint when possible.");
68ABSL_FLAG(bool, cp_use_cumulative_edge_finder, true,
69 "Use the O(n log n) cumulative edge finding algorithm described "
70 "in 'Edge Finding Filtering Algorithm for Discrete Cumulative "
71 "Resources in O(kn log n)' by Petr Vilim, CP 2009.");
72ABSL_FLAG(bool, cp_use_cumulative_time_table, true,
73 "Use a O(n^2) cumulative time table propagation algorithm.");
74ABSL_FLAG(bool, cp_use_cumulative_time_table_sync, false,
75 "Use a synchronized O(n^2 log n) cumulative time table propagation "
76 "algorithm.");
77ABSL_FLAG(bool, cp_use_sequence_high_demand_tasks, true,
78 "Use a sequence constraints for cumulative tasks that have a "
79 "demand greater than half of the capacity of the resource.");
80ABSL_FLAG(bool, cp_use_all_possible_disjunctions, true,
81 "Post temporal disjunctions for all pairs of tasks sharing a "
82 "cumulative resource and that cannot overlap because the sum of "
83 "their demand exceeds the capacity.");
84ABSL_FLAG(int, cp_max_edge_finder_size, 50,
85 "Do not post the edge finder in the cumulative constraints if "
86 "it contains more than this number of tasks");
87ABSL_FLAG(bool, cp_diffn_use_cumulative, true,
88 "Diffn constraint adds redundant cumulative constraint");
89ABSL_FLAG(bool, cp_use_element_rmq, true,
90 "If true, rmq's will be used in element expressions.");
91ABSL_FLAG(int, cp_check_solution_period, 1,
92 "Number of solutions explored between two solution checks during "
93 "local search.");
94ABSL_FLAG(int64_t, cp_random_seed, 12345,
95 "Random seed used in several (but not all) random number "
96 "generators used by the CP solver. Use -1 to auto-generate an"
97 "undeterministic random seed.");
98
99void ConstraintSolverFailsHere() { VLOG(3) << "Fail"; }
100
101#if defined(_MSC_VER) // WINDOWS
102#pragma warning(disable : 4351 4355)
103#endif
104
105namespace operations_research {
106
107namespace {
108// Calls the given method with the provided arguments on all objects in the
109// collection.
110template <typename T, typename MethodPointer, typename... Args>
111void ForAll(const std::vector<T*>& objects, MethodPointer method,
112 const Args&... args) {
113 for (T* const object : objects) {
114 DCHECK(object != nullptr);
115 (object->*method)(args...);
116 }
117}
118
119// Converts a scoped enum to its underlying type.
120template <typename E>
121constexpr typename std::underlying_type<E>::type to_underlying(E e) {
122 return static_cast<typename std::underlying_type<E>::type>(e);
123}
124
125} // namespace
126
127// ----- ConstraintSolverParameters -----
128
129ConstraintSolverParameters Solver::DefaultSolverParameters() {
130 ConstraintSolverParameters params;
131 params.set_compress_trail(ConstraintSolverParameters::NO_COMPRESSION);
132 params.set_trail_block_size(8000);
133 params.set_array_split_size(16);
134 params.set_store_names(true);
135 params.set_profile_propagation(!absl::GetFlag(FLAGS_cp_profile_file).empty());
136 params.set_trace_propagation(absl::GetFlag(FLAGS_cp_trace_propagation));
137 params.set_trace_search(absl::GetFlag(FLAGS_cp_trace_search));
138 params.set_name_all_variables(absl::GetFlag(FLAGS_cp_name_variables));
139 params.set_profile_file(absl::GetFlag(FLAGS_cp_profile_file));
140 params.set_profile_local_search(
141 absl::GetFlag(FLAGS_cp_print_local_search_profile));
142 params.set_print_local_search_profile(
143 absl::GetFlag(FLAGS_cp_print_local_search_profile));
144 params.set_print_model(absl::GetFlag(FLAGS_cp_print_model));
145 params.set_print_model_stats(absl::GetFlag(FLAGS_cp_model_stats));
146 params.set_disable_solve(absl::GetFlag(FLAGS_cp_disable_solve));
147 params.set_name_cast_variables(absl::GetFlag(FLAGS_cp_name_cast_variables));
148 params.set_print_added_constraints(
149 absl::GetFlag(FLAGS_cp_print_added_constraints));
150 params.set_use_small_table(absl::GetFlag(FLAGS_cp_use_small_table));
151 params.set_use_cumulative_edge_finder(
152 absl::GetFlag(FLAGS_cp_use_cumulative_edge_finder));
153 params.set_use_cumulative_time_table(
154 absl::GetFlag(FLAGS_cp_use_cumulative_time_table));
155 params.set_use_cumulative_time_table_sync(
156 absl::GetFlag(FLAGS_cp_use_cumulative_time_table_sync));
157 params.set_use_sequence_high_demand_tasks(
158 absl::GetFlag(FLAGS_cp_use_sequence_high_demand_tasks));
159 params.set_use_all_possible_disjunctions(
160 absl::GetFlag(FLAGS_cp_use_all_possible_disjunctions));
161 params.set_max_edge_finder_size(absl::GetFlag(FLAGS_cp_max_edge_finder_size));
162 params.set_diffn_use_cumulative(absl::GetFlag(FLAGS_cp_diffn_use_cumulative));
163 params.set_use_element_rmq(absl::GetFlag(FLAGS_cp_use_element_rmq));
164 params.set_check_solution_period(
165 absl::GetFlag(FLAGS_cp_check_solution_period));
166 return params;
167}
168
169// ----- Forward Declarations and Profiling Support -----
170extern void InstallDemonProfiler(DemonProfiler* monitor);
172extern void DeleteDemonProfiler(DemonProfiler* monitor);
176
177// TODO(user): remove this complex logic.
178// We need the double test because parameters are set too late when using
179// python in the open source. This is the cheapest work-around.
183
185 return parameters_.profile_propagation() ||
186 !parameters_.profile_file().empty();
187}
188
190 return parameters_.profile_local_search() ||
191 parameters_.print_local_search_profile();
192}
193
195 return parameters_.trace_propagation();
196}
197
199 return parameters_.name_all_variables();
200}
201
202// ------------------ Demon class ----------------
203
207
208std::string Demon::DebugString() const { return "Demon"; }
209
210void Demon::inhibit(Solver* const s) {
211 if (stamp_ < std::numeric_limits<uint64_t>::max()) {
212 s->SaveAndSetValue(&stamp_, std::numeric_limits<uint64_t>::max());
213 }
214}
215
216void Demon::desinhibit(Solver* const s) {
217 if (stamp_ == std::numeric_limits<uint64_t>::max()) {
218 s->SaveAndSetValue(&stamp_, s->stamp() - 1);
219 }
220}
221
222// ------------------ Queue class ------------------
223
224extern void CleanVariableOnFail(IntVar* var);
225
226class Queue {
227 public:
228 static constexpr int64_t kTestPeriod = 10000;
229
230 explicit Queue(Solver* const s)
231 : solver_(s),
232 stamp_(1),
233 freeze_level_(0),
234 in_process_(false),
235 clean_action_(nullptr),
236 clean_variable_(nullptr),
237 in_add_(false),
238 instruments_demons_(s->InstrumentsDemons()) {}
239
241
242 void Freeze() {
243 freeze_level_++;
244 stamp_++;
245 }
246
247 void Unfreeze() {
248 if (--freeze_level_ == 0) {
249 Process();
250 }
251 }
252
253 void ProcessOneDemon(Demon* const demon) {
254 demon->set_stamp(stamp_ - 1);
255 if (!instruments_demons_) {
256 if (++solver_->demon_runs_[demon->priority()] % kTestPeriod == 0) {
257 solver_->TopPeriodicCheck();
258 }
259 demon->Run(solver_);
260 solver_->CheckFail();
261 } else {
262 solver_->GetPropagationMonitor()->BeginDemonRun(demon);
263 if (++solver_->demon_runs_[demon->priority()] % kTestPeriod == 0) {
264 solver_->TopPeriodicCheck();
265 }
266 demon->Run(solver_);
267 solver_->CheckFail();
268 solver_->GetPropagationMonitor()->EndDemonRun(demon);
269 }
270 }
271
272 void Process() {
273 if (!in_process_) {
274 in_process_ = true;
275 while (!var_queue_.empty() || !delayed_queue_.empty()) {
276 if (!var_queue_.empty()) {
277 Demon* const demon = var_queue_.front();
278 var_queue_.pop_front();
279 ProcessOneDemon(demon);
280 } else {
281 DCHECK(!delayed_queue_.empty());
282 Demon* const demon = delayed_queue_.front();
283 delayed_queue_.pop_front();
284 ProcessOneDemon(demon);
285 }
286 }
287 in_process_ = false;
288 }
289 }
290
291 void ExecuteAll(const SimpleRevFIFO<Demon*>& demons) {
292 if (!instruments_demons_) {
293 for (SimpleRevFIFO<Demon*>::Iterator it(&demons); it.ok(); ++it) {
294 Demon* const demon = *it;
295 if (demon->stamp() < stamp_) {
296 DCHECK_EQ(demon->priority(), Solver::NORMAL_PRIORITY);
297 if (++solver_->demon_runs_[Solver::NORMAL_PRIORITY] % kTestPeriod ==
298 0) {
299 solver_->TopPeriodicCheck();
300 }
301 demon->Run(solver_);
302 solver_->CheckFail();
303 }
304 }
305 } else {
306 for (SimpleRevFIFO<Demon*>::Iterator it(&demons); it.ok(); ++it) {
307 Demon* const demon = *it;
308 if (demon->stamp() < stamp_) {
309 DCHECK_EQ(demon->priority(), Solver::NORMAL_PRIORITY);
310 solver_->GetPropagationMonitor()->BeginDemonRun(demon);
311 if (++solver_->demon_runs_[Solver::NORMAL_PRIORITY] % kTestPeriod ==
312 0) {
313 solver_->TopPeriodicCheck();
314 }
315 demon->Run(solver_);
316 solver_->CheckFail();
317 solver_->GetPropagationMonitor()->EndDemonRun(demon);
318 }
319 }
320 }
321 }
322
323 void EnqueueAll(const SimpleRevFIFO<Demon*>& demons) {
324 for (SimpleRevFIFO<Demon*>::Iterator it(&demons); it.ok(); ++it) {
326 }
327 }
328
329 void EnqueueVar(Demon* const demon) {
330 DCHECK(demon->priority() == Solver::VAR_PRIORITY);
331 if (demon->stamp() < stamp_) {
332 demon->set_stamp(stamp_);
333 var_queue_.push_back(demon);
334 if (freeze_level_ == 0) {
335 Process();
336 }
337 }
338 }
339
340 void EnqueueDelayedDemon(Demon* const demon) {
341 DCHECK(demon->priority() == Solver::DELAYED_PRIORITY);
342 if (demon->stamp() < stamp_) {
343 demon->set_stamp(stamp_);
344 delayed_queue_.push_back(demon);
345 }
346 }
347
349 // Clean queue.
350 var_queue_.clear();
351 delayed_queue_.clear();
352
353 // Call cleaning actions on variables.
354 if (clean_action_ != nullptr) {
355 clean_action_(solver_);
356 clean_action_ = nullptr;
357 } else if (clean_variable_ != nullptr) {
358 CleanVariableOnFail(clean_variable_);
359 clean_variable_ = nullptr;
360 }
361
362 freeze_level_ = 0;
363 in_process_ = false;
364 in_add_ = false;
365 to_add_.clear();
366 }
367
368 void increase_stamp() { stamp_++; }
369
370 uint64_t stamp() const { return stamp_; }
371
373 DCHECK(clean_variable_ == nullptr);
374 clean_action_ = std::move(a);
375 }
376
378 DCHECK(clean_action_ == nullptr);
379 clean_variable_ = var;
380 }
381
383 DCHECK(clean_variable_ == nullptr);
384 clean_action_ = nullptr;
385 }
386
387 void AddConstraint(Constraint* const c) {
388 to_add_.push_back(c);
390 }
391
393 if (!in_add_) {
394 in_add_ = true;
395 // We cannot store to_add_.size() as constraints can add other
396 // constraints. For the same reason a range-based for loop cannot be used.
397 // TODO(user): Make to_add_ a queue to make the behavior more obvious.
398 for (int counter = 0; counter < to_add_.size(); ++counter) {
399 Constraint* const constraint = to_add_[counter];
400 // TODO(user): Add profiling to initial propagation
401 constraint->PostAndPropagate();
402 }
403 in_add_ = false;
404 to_add_.clear();
405 }
406 }
407
408 private:
409 Solver* const solver_;
410 std::deque<Demon*> var_queue_;
411 std::deque<Demon*> delayed_queue_;
412 uint64_t stamp_;
413 // The number of nested freeze levels. The queue is frozen if and only if
414 // freeze_level_ > 0.
415 uint32_t freeze_level_;
416 bool in_process_;
417 Solver::Action clean_action_;
418 IntVar* clean_variable_;
419 std::vector<Constraint*> to_add_;
420 bool in_add_;
421 const bool instruments_demons_;
422};
423
424// ------------------ StateMarker / StateInfo struct -----------
425
426struct StateInfo { // This is an internal structure to store
427 // additional information on the choice point.
428 public:
430 : ptr_info(nullptr),
431 int_info(0),
432 depth(0),
433 left_depth(0),
434 reversible_action(nullptr) {}
435 StateInfo(void* pinfo, int iinfo)
436 : ptr_info(pinfo),
437 int_info(iinfo),
438 depth(0),
439 left_depth(0),
440 reversible_action(nullptr) {}
441 StateInfo(void* pinfo, int iinfo, int d, int ld)
442 : ptr_info(pinfo),
443 int_info(iinfo),
444 depth(d),
445 left_depth(ld),
446 reversible_action(nullptr) {}
448 : ptr_info(nullptr),
449 int_info(static_cast<int>(fast)),
450 depth(0),
451 left_depth(0),
452 reversible_action(std::move(a)) {}
453
454 void* ptr_info;
456 int depth;
459};
460
462 public:
464 friend class Solver;
465 friend struct Trail;
466
467 private:
468 Solver::MarkerType type_;
469 int rev_int_index_;
470 int rev_int64_index_;
471 int rev_uint64_index_;
472 int rev_double_index_;
473 int rev_ptr_index_;
474 int rev_boolvar_list_index_;
475 int rev_bools_index_;
476 int rev_int_memory_index_;
477 int rev_int64_memory_index_;
478 int rev_double_memory_index_;
479 int rev_object_memory_index_;
480 int rev_object_array_memory_index_;
481 int rev_memory_index_;
482 int rev_memory_array_index_;
483 StateInfo info_;
484};
485
487 : type_(t),
488 rev_int_index_(0),
489 rev_int64_index_(0),
490 rev_uint64_index_(0),
491 rev_double_index_(0),
492 rev_ptr_index_(0),
493 rev_boolvar_list_index_(0),
494 rev_bools_index_(0),
495 rev_int_memory_index_(0),
496 rev_int64_memory_index_(0),
497 rev_double_memory_index_(0),
498 rev_object_memory_index_(0),
499 rev_object_array_memory_index_(0),
500 info_(info) {}
501
502// ---------- Trail and Reversibility ----------
503
504namespace {
505// ----- addrval struct -----
506
507// This template class is used internally to implement reversibility.
508// It stores an address and the value that was at the address.
509template <class T>
510struct addrval {
511 public:
512 addrval() : address_(nullptr) {}
513 explicit addrval(T* adr) : address_(adr), old_value_(*adr) {}
514 void restore() const { (*address_) = old_value_; }
515
516 private:
517 T* address_;
518 T old_value_;
519};
520
521// ----- Compressed trail -----
522
523// ---------- Trail Packer ---------
524// Abstract class to pack trail blocks.
525
526template <class T>
527class TrailPacker {
528 public:
529 explicit TrailPacker(int block_size) : block_size_(block_size) {}
530
531 // This type is neither copyable nor movable.
532 TrailPacker(const TrailPacker&) = delete;
533 TrailPacker& operator=(const TrailPacker&) = delete;
534 virtual ~TrailPacker() {}
535 int input_size() const { return block_size_ * sizeof(addrval<T>); }
536 virtual void Pack(const addrval<T>* block, std::string* packed_block) = 0;
537 virtual void Unpack(const std::string& packed_block, addrval<T>* block) = 0;
538
539 private:
540 const int block_size_;
541};
542
543template <class T>
544class NoCompressionTrailPacker : public TrailPacker<T> {
545 public:
546 explicit NoCompressionTrailPacker(int block_size)
547 : TrailPacker<T>(block_size) {}
548
549 // This type is neither copyable nor movable.
550 NoCompressionTrailPacker(const NoCompressionTrailPacker&) = delete;
551 NoCompressionTrailPacker& operator=(const NoCompressionTrailPacker&) = delete;
552 ~NoCompressionTrailPacker() override {}
553 void Pack(const addrval<T>* block, std::string* packed_block) override {
554 DCHECK(block != nullptr);
555 DCHECK(packed_block != nullptr);
556 absl::string_view block_str(reinterpret_cast<const char*>(block),
557 this->input_size());
558 packed_block->assign(block_str.data(), block_str.size());
559 }
560 void Unpack(const std::string& packed_block, addrval<T>* block) override {
561 DCHECK(block != nullptr);
562 memcpy(block, packed_block.c_str(), packed_block.size());
563 }
564};
565
566template <class T>
567class ZlibTrailPacker : public TrailPacker<T> {
568 public:
569 explicit ZlibTrailPacker(int block_size)
570 : TrailPacker<T>(block_size),
571 tmp_size_(compressBound(this->input_size())),
572 tmp_block_(new char[tmp_size_]) {}
573
574 // This type is neither copyable nor movable.
575 ZlibTrailPacker(const ZlibTrailPacker&) = delete;
576 ZlibTrailPacker& operator=(const ZlibTrailPacker&) = delete;
577
578 ~ZlibTrailPacker() override {}
579
580 void Pack(const addrval<T>* block, std::string* packed_block) override {
581 DCHECK(block != nullptr);
582 DCHECK(packed_block != nullptr);
583 uLongf size = tmp_size_;
584 const int result =
585 compress(reinterpret_cast<Bytef*>(tmp_block_.get()), &size,
586 reinterpret_cast<const Bytef*>(block), this->input_size());
587 CHECK_EQ(Z_OK, result);
588 absl::string_view block_str;
589 block_str = absl::string_view(tmp_block_.get(), size);
590 packed_block->assign(block_str.data(), block_str.size());
591 }
592
593 void Unpack(const std::string& packed_block, addrval<T>* block) override {
594 DCHECK(block != nullptr);
595 uLongf size = this->input_size();
596 const int result =
597 uncompress(reinterpret_cast<Bytef*>(block), &size,
598 reinterpret_cast<const Bytef*>(packed_block.c_str()),
599 packed_block.size());
600 CHECK_EQ(Z_OK, result);
601 }
602
603 private:
604 const uint64_t tmp_size_;
605 std::unique_ptr<char[]> tmp_block_;
606};
607
608template <class T>
609class CompressedTrail {
610 public:
611 CompressedTrail(
612 int block_size,
613 ConstraintSolverParameters::TrailCompression compression_level)
614 : block_size_(block_size),
615 blocks_(nullptr),
616 free_blocks_(nullptr),
617 data_(new addrval<T>[block_size]),
618 buffer_(new addrval<T>[block_size]),
619 buffer_used_(false),
620 current_(0),
621 size_(0) {
622 switch (compression_level) {
623 case ConstraintSolverParameters::NO_COMPRESSION: {
624 packer_.reset(new NoCompressionTrailPacker<T>(block_size));
625 break;
626 }
627 case ConstraintSolverParameters::COMPRESS_WITH_ZLIB: {
628 packer_.reset(new ZlibTrailPacker<T>(block_size));
629 break;
630 }
631 default: {
632 LOG(ERROR) << "Should not be here";
633 }
634 }
635
636 // We zero all memory used by addrval arrays.
637 // Because of padding, all bytes may not be initialized, while compression
638 // will read them all, even if the uninitialized bytes are never used.
639 // This makes valgrind happy.
640
641 memset(data_.get(), 0, sizeof(*data_.get()) * block_size);
642 memset(buffer_.get(), 0, sizeof(*buffer_.get()) * block_size);
643 }
644 ~CompressedTrail() {
645 FreeBlocks(blocks_);
646 FreeBlocks(free_blocks_);
647 }
648 const addrval<T>& Back() const {
649 // Back of empty trail.
650 DCHECK_GT(current_, 0);
651 return data_[current_ - 1];
652 }
653 void PopBack() {
654 if (size_ > 0) {
655 --current_;
656 if (current_ <= 0) {
657 if (buffer_used_) {
658 data_.swap(buffer_);
659 current_ = block_size_;
660 buffer_used_ = false;
661 } else if (blocks_ != nullptr) {
662 packer_->Unpack(blocks_->compressed, data_.get());
663 FreeTopBlock();
664 current_ = block_size_;
665 }
666 }
667 --size_;
668 }
669 }
670 void PushBack(const addrval<T>& addr_val) {
671 if (current_ >= block_size_) {
672 if (buffer_used_) { // Buffer is used.
673 NewTopBlock();
674 packer_->Pack(buffer_.get(), &blocks_->compressed);
675 // O(1) operation.
676 data_.swap(buffer_);
677 } else {
678 data_.swap(buffer_);
679 buffer_used_ = true;
680 }
681 current_ = 0;
682 }
683 data_[current_] = addr_val;
684 ++current_;
685 ++size_;
686 }
687 int64_t size() const { return size_; }
688
689 private:
690 struct Block {
691 std::string compressed;
692 Block* next;
693 };
694
695 void FreeTopBlock() {
696 Block* block = blocks_;
697 blocks_ = block->next;
698 block->compressed.clear();
699 block->next = free_blocks_;
700 free_blocks_ = block;
701 }
702 void NewTopBlock() {
703 Block* block = nullptr;
704 if (free_blocks_ != nullptr) {
705 block = free_blocks_;
706 free_blocks_ = block->next;
707 } else {
708 block = new Block;
709 }
710 block->next = blocks_;
711 blocks_ = block;
712 }
713 void FreeBlocks(Block* blocks) {
714 while (nullptr != blocks) {
715 Block* next = blocks->next;
716 delete blocks;
717 blocks = next;
718 }
719 }
720
721 std::unique_ptr<TrailPacker<T>> packer_;
722 const int block_size_;
723 Block* blocks_;
724 Block* free_blocks_;
725 std::unique_ptr<addrval<T>[]> data_;
726 std::unique_ptr<addrval<T>[]> buffer_;
727 bool buffer_used_;
728 int current_;
729 int size_;
730};
731} // namespace
732
733// ----- Trail -----
734
735// Object are explicitly copied using the copy ctor instead of
736// passing and storing a pointer. As objects are small, copying is
737// much faster than allocating (around 35% on a complete solve).
738
739extern void RestoreBoolValue(IntVar* var);
740
741struct Trail {
742 CompressedTrail<int> rev_ints_;
743 CompressedTrail<int64_t> rev_int64s_;
744 CompressedTrail<uint64_t> rev_uint64s_;
745 CompressedTrail<double> rev_doubles_;
746 CompressedTrail<void*> rev_ptrs_;
747 std::vector<IntVar*> rev_boolvar_list_;
748 std::vector<bool*> rev_bools_;
749 std::vector<bool> rev_bool_value_;
750 std::vector<int*> rev_int_memory_;
751 std::vector<int64_t*> rev_int64_memory_;
752 std::vector<double*> rev_double_memory_;
753 std::vector<BaseObject*> rev_object_memory_;
754 std::vector<BaseObject**> rev_object_array_memory_;
755 std::vector<void*> rev_memory_;
756 std::vector<void**> rev_memory_array_;
757
758 Trail(int block_size,
759 ConstraintSolverParameters::TrailCompression compression_level)
760 : rev_ints_(block_size, compression_level),
761 rev_int64s_(block_size, compression_level),
762 rev_uint64s_(block_size, compression_level),
763 rev_doubles_(block_size, compression_level),
764 rev_ptrs_(block_size, compression_level) {}
765
767 int target = m->rev_int_index_;
768 for (int curr = rev_ints_.size(); curr > target; --curr) {
769 const addrval<int>& cell = rev_ints_.Back();
770 cell.restore();
771 rev_ints_.PopBack();
772 }
773 DCHECK_EQ(rev_ints_.size(), target);
774 // Incorrect trail size after backtrack.
775 target = m->rev_int64_index_;
776 for (int curr = rev_int64s_.size(); curr > target; --curr) {
777 const addrval<int64_t>& cell = rev_int64s_.Back();
778 cell.restore();
779 rev_int64s_.PopBack();
780 }
781 DCHECK_EQ(rev_int64s_.size(), target);
782 // Incorrect trail size after backtrack.
783 target = m->rev_uint64_index_;
784 for (int curr = rev_uint64s_.size(); curr > target; --curr) {
785 const addrval<uint64_t>& cell = rev_uint64s_.Back();
786 cell.restore();
787 rev_uint64s_.PopBack();
788 }
789 DCHECK_EQ(rev_uint64s_.size(), target);
790 // Incorrect trail size after backtrack.
791 target = m->rev_double_index_;
792 for (int curr = rev_doubles_.size(); curr > target; --curr) {
793 const addrval<double>& cell = rev_doubles_.Back();
794 cell.restore();
795 rev_doubles_.PopBack();
796 }
797 DCHECK_EQ(rev_doubles_.size(), target);
798 // Incorrect trail size after backtrack.
799 target = m->rev_ptr_index_;
800 for (int curr = rev_ptrs_.size(); curr > target; --curr) {
801 const addrval<void*>& cell = rev_ptrs_.Back();
802 cell.restore();
803 rev_ptrs_.PopBack();
804 }
805 DCHECK_EQ(rev_ptrs_.size(), target);
806 // Incorrect trail size after backtrack.
807 target = m->rev_boolvar_list_index_;
808 for (int curr = rev_boolvar_list_.size() - 1; curr >= target; --curr) {
809 IntVar* const var = rev_boolvar_list_[curr];
811 }
812 rev_boolvar_list_.resize(target);
813
814 DCHECK_EQ(rev_bools_.size(), rev_bool_value_.size());
815 target = m->rev_bools_index_;
816 for (int curr = rev_bools_.size() - 1; curr >= target; --curr) {
817 *(rev_bools_[curr]) = rev_bool_value_[curr];
818 }
819 rev_bools_.resize(target);
820 rev_bool_value_.resize(target);
821
822 target = m->rev_int_memory_index_;
823 for (int curr = rev_int_memory_.size() - 1; curr >= target; --curr) {
824 delete[] rev_int_memory_[curr];
825 }
826 rev_int_memory_.resize(target);
827
828 target = m->rev_int64_memory_index_;
829 for (int curr = rev_int64_memory_.size() - 1; curr >= target; --curr) {
830 delete[] rev_int64_memory_[curr];
831 }
832 rev_int64_memory_.resize(target);
833
834 target = m->rev_double_memory_index_;
835 for (int curr = rev_double_memory_.size() - 1; curr >= target; --curr) {
836 delete[] rev_double_memory_[curr];
837 }
838 rev_double_memory_.resize(target);
839
840 target = m->rev_object_memory_index_;
841 for (int curr = rev_object_memory_.size() - 1; curr >= target; --curr) {
842 delete rev_object_memory_[curr];
843 }
844 rev_object_memory_.resize(target);
845
846 target = m->rev_object_array_memory_index_;
847 for (int curr = rev_object_array_memory_.size() - 1; curr >= target;
848 --curr) {
849 delete[] rev_object_array_memory_[curr];
850 }
851 rev_object_array_memory_.resize(target);
852
853 target = m->rev_memory_index_;
854 for (int curr = rev_memory_.size() - 1; curr >= target; --curr) {
855 // Explicitly call unsized delete
856 ::operator delete(reinterpret_cast<char*>(rev_memory_[curr]));
857 // The previous cast is necessary to deallocate generic memory
858 // described by a void* when passed to the RevAlloc procedure
859 // We cannot do a delete[] there
860 // This is useful for cells of RevFIFO and should not be used outside
861 // of the product
862 }
863 rev_memory_.resize(target);
864
865 target = m->rev_memory_array_index_;
866 for (int curr = rev_memory_array_.size() - 1; curr >= target; --curr) {
867 delete[] rev_memory_array_[curr];
868 // delete [] version of the previous unsafe case.
869 }
870 rev_memory_array_.resize(target);
871 }
872};
873
874void Solver::InternalSaveValue(int* valptr) {
875 trail_->rev_ints_.PushBack(addrval<int>(valptr));
876}
877
878void Solver::InternalSaveValue(int64_t* valptr) {
879 trail_->rev_int64s_.PushBack(addrval<int64_t>(valptr));
880}
881
882void Solver::InternalSaveValue(uint64_t* valptr) {
883 trail_->rev_uint64s_.PushBack(addrval<uint64_t>(valptr));
884}
885
886void Solver::InternalSaveValue(double* valptr) {
887 trail_->rev_doubles_.PushBack(addrval<double>(valptr));
888}
889
890void Solver::InternalSaveValue(void** valptr) {
891 trail_->rev_ptrs_.PushBack(addrval<void*>(valptr));
892}
893
894// TODO(user) : this code is unsafe if you save the same alternating
895// bool multiple times.
896// The correct code should use a bitset and a single list.
897void Solver::InternalSaveValue(bool* valptr) {
898 trail_->rev_bools_.push_back(valptr);
899 trail_->rev_bool_value_.push_back(*valptr);
900}
901
902BaseObject* Solver::SafeRevAlloc(BaseObject* ptr) {
903 check_alloc_state();
904 trail_->rev_object_memory_.push_back(ptr);
905 return ptr;
906}
907
908int* Solver::SafeRevAllocArray(int* ptr) {
909 check_alloc_state();
910 trail_->rev_int_memory_.push_back(ptr);
911 return ptr;
912}
913
914int64_t* Solver::SafeRevAllocArray(int64_t* ptr) {
915 check_alloc_state();
916 trail_->rev_int64_memory_.push_back(ptr);
917 return ptr;
918}
919
920double* Solver::SafeRevAllocArray(double* ptr) {
921 check_alloc_state();
922 trail_->rev_double_memory_.push_back(ptr);
923 return ptr;
924}
925
926uint64_t* Solver::SafeRevAllocArray(uint64_t* ptr) {
927 check_alloc_state();
928 trail_->rev_int64_memory_.push_back(reinterpret_cast<int64_t*>(ptr));
929 return ptr;
930}
931
932BaseObject** Solver::SafeRevAllocArray(BaseObject** ptr) {
933 check_alloc_state();
934 trail_->rev_object_array_memory_.push_back(ptr);
935 return ptr;
936}
937
938IntVar** Solver::SafeRevAllocArray(IntVar** ptr) {
939 BaseObject** in = SafeRevAllocArray(reinterpret_cast<BaseObject**>(ptr));
940 return reinterpret_cast<IntVar**>(in);
941}
942
943IntExpr** Solver::SafeRevAllocArray(IntExpr** ptr) {
944 BaseObject** in = SafeRevAllocArray(reinterpret_cast<BaseObject**>(ptr));
945 return reinterpret_cast<IntExpr**>(in);
946}
947
948Constraint** Solver::SafeRevAllocArray(Constraint** ptr) {
949 BaseObject** in = SafeRevAllocArray(reinterpret_cast<BaseObject**>(ptr));
950 return reinterpret_cast<Constraint**>(in);
951}
952
953void* Solver::UnsafeRevAllocAux(void* ptr) {
954 check_alloc_state();
955 trail_->rev_memory_.push_back(ptr);
956 return ptr;
957}
958
959void** Solver::UnsafeRevAllocArrayAux(void** ptr) {
960 check_alloc_state();
961 trail_->rev_memory_array_.push_back(ptr);
962 return ptr;
963}
964
965void InternalSaveBooleanVarValue(Solver* const solver, IntVar* const var) {
966 solver->trail_->rev_boolvar_list_.push_back(var);
967}
968
969// ------------------ Search class -----------------
970
971class Search {
972 public:
973 explicit Search(Solver* const s)
974 : solver_(s),
975 marker_stack_(),
976 monitor_event_listeners_(to_underlying(Solver::MonitorEvent::kLast)),
977 fail_buffer_(),
978 solution_counter_(0),
979 unchecked_solution_counter_(0),
980 decision_builder_(nullptr),
981 created_by_solve_(false),
982 search_depth_(0),
983 left_search_depth_(0),
984 should_restart_(false),
985 should_finish_(false),
986 sentinel_pushed_(0),
987 jmpbuf_filled_(false),
988 backtrack_at_the_end_of_the_search_(true) {}
989
990 // Constructor for a dummy search. The only difference between a dummy search
991 // and a regular one is that the search depth and left search depth is
992 // initialized to -1 instead of zero.
993 Search(Solver* const s, int /* dummy_argument */)
994 : solver_(s),
995 marker_stack_(),
996 monitor_event_listeners_(to_underlying(Solver::MonitorEvent::kLast)),
997 fail_buffer_(),
998 solution_counter_(0),
999 unchecked_solution_counter_(0),
1000 decision_builder_(nullptr),
1001 created_by_solve_(false),
1002 search_depth_(-1),
1003 left_search_depth_(-1),
1004 should_restart_(false),
1005 should_finish_(false),
1006 sentinel_pushed_(0),
1007 jmpbuf_filled_(false),
1008 backtrack_at_the_end_of_the_search_(true) {}
1009
1010 ~Search() { gtl::STLDeleteElements(&marker_stack_); }
1011
1012 void EnterSearch();
1013 void RestartSearch();
1014 void ExitSearch();
1017 void ApplyDecision(Decision* d);
1018 void AfterDecision(Decision* d, bool apply);
1019 void RefuteDecision(Decision* d);
1020 void BeginFail();
1021 void EndFail();
1023 void EndInitialPropagation();
1024 bool AtSolution();
1025 bool AcceptSolution();
1026 void NoMoreSolutions();
1027 bool LocalOptimum();
1028 bool AcceptDelta(Assignment* delta, Assignment* deltadelta);
1029 void AcceptNeighbor();
1032 void PeriodicCheck();
1033 int ProgressPercent();
1034 void Accept(ModelVisitor* visitor) const;
1036 if (monitor != nullptr) {
1037 monitor_event_listeners_[to_underlying(event)].push_back(monitor);
1038 }
1039 }
1040 const std::vector<SearchMonitor*>& GetEventListeners(
1041 Solver::MonitorEvent event) const {
1042 return monitor_event_listeners_[to_underlying(event)];
1043 }
1044 void Clear();
1045 void IncrementSolutionCounter() { ++solution_counter_; }
1046 int64_t solution_counter() const { return solution_counter_; }
1047 void IncrementUncheckedSolutionCounter() { ++unchecked_solution_counter_; }
1049 return unchecked_solution_counter_;
1050 }
1052 decision_builder_ = db;
1053 }
1054 DecisionBuilder* decision_builder() const { return decision_builder_; }
1055 void set_created_by_solve(bool c) { created_by_solve_ = c; }
1056 bool created_by_solve() const { return created_by_solve_; }
1059 void LeftMove() {
1060 search_depth_++;
1061 left_search_depth_++;
1062 }
1063 void RightMove() { search_depth_++; }
1065 return backtrack_at_the_end_of_the_search_;
1066 }
1068 backtrack_at_the_end_of_the_search_ = restore;
1069 }
1070 int search_depth() const { return search_depth_; }
1071 void set_search_depth(int d) { search_depth_ = d; }
1072 int left_search_depth() const { return left_search_depth_; }
1073 void set_search_left_depth(int d) { left_search_depth_ = d; }
1074 void set_should_restart(bool s) { should_restart_ = s; }
1075 bool should_restart() const { return should_restart_; }
1076 void set_should_finish(bool s) { should_finish_ = s; }
1077 bool should_finish() const { return should_finish_; }
1078 void CheckFail() {
1079 if (should_finish_ || should_restart_) {
1080 solver_->Fail();
1081 }
1082 }
1083 void set_search_context(absl::string_view search_context) {
1084 search_context_ = search_context;
1085 }
1086 std::string search_context() const { return search_context_; }
1087 friend class Solver;
1088
1089 private:
1090 // Jumps back to the previous choice point, Checks if it was correctly set.
1091 void JumpBack();
1092 void ClearBuffer() {
1093 CHECK(jmpbuf_filled_) << "Internal error in backtracking";
1094 jmpbuf_filled_ = false;
1095 }
1096
1097 Solver* const solver_;
1098 std::vector<StateMarker*> marker_stack_;
1099 std::vector<std::vector<SearchMonitor*>> monitor_event_listeners_;
1100 jmp_buf fail_buffer_;
1101 int64_t solution_counter_;
1102 int64_t unchecked_solution_counter_;
1103 DecisionBuilder* decision_builder_;
1104 bool created_by_solve_;
1105 Solver::BranchSelector selector_;
1106 int search_depth_;
1107 int left_search_depth_;
1108 bool should_restart_;
1109 bool should_finish_;
1110 int sentinel_pushed_;
1111 bool jmpbuf_filled_;
1112 bool backtrack_at_the_end_of_the_search_;
1113 std::string search_context_;
1114};
1115
1116// Backtrack is implemented using 3 primitives:
1117// CP_TRY to start searching
1118// CP_DO_FAIL to signal a failure. The program will continue on the CP_ON_FAIL
1119// primitive.
1120// Implementation of backtrack using setjmp/longjmp.
1121// The clean portable way is to use exceptions, unfortunately, it can be much
1122// slower. Thus we use ideas from Prolog, CP/CLP implementations,
1123// continuations in C and implement the default failing and backtracking
1124// using setjmp/longjmp. You can still use exceptions by defining
1125// CP_USE_EXCEPTIONS_FOR_BACKTRACK
1126#ifndef CP_USE_EXCEPTIONS_FOR_BACKTRACK
1127// We cannot use a method/function for this as we would lose the
1128// context in the setjmp implementation.
1129#define CP_TRY(search) \
1130 CHECK(!search->jmpbuf_filled_) << "Fail() called outside search"; \
1131 search->jmpbuf_filled_ = true; \
1132 if (setjmp(search->fail_buffer_) == 0)
1133#define CP_ON_FAIL else
1134#define CP_DO_FAIL(search) longjmp(search->fail_buffer_, 1)
1135#else // CP_USE_EXCEPTIONS_FOR_BACKTRACK
1136class FailException {};
1137#define CP_TRY(search) \
1138 CHECK(!search->jmpbuf_filled_) << "Fail() called outside search"; \
1139 search->jmpbuf_filled_ = true; \
1140 try
1141#define CP_ON_FAIL catch (FailException&)
1142#define CP_DO_FAIL(search) throw FailException()
1143#endif // CP_USE_EXCEPTIONS_FOR_BACKTRACK
1144
1145void Search::JumpBack() {
1146 if (jmpbuf_filled_) {
1147 jmpbuf_filled_ = false;
1148 CP_DO_FAIL(this);
1149 } else {
1150 std::string explanation = "Failure outside of search";
1151 solver_->AddConstraint(solver_->MakeFalseConstraint(explanation));
1152 }
1153}
1154
1155Search* Solver::ActiveSearch() const { return searches_.back(); }
1156
1157namespace {
1158class ApplyBranchSelector : public DecisionBuilder {
1159 public:
1160 explicit ApplyBranchSelector(Solver::BranchSelector bs)
1161 : selector_(std::move(bs)) {}
1162 ~ApplyBranchSelector() override {}
1163
1164 Decision* Next(Solver* const s) override {
1165 s->SetBranchSelector(selector_);
1166 return nullptr;
1167 }
1168
1169 std::string DebugString() const override { return "Apply(BranchSelector)"; }
1170
1171 private:
1172 Solver::BranchSelector const selector_;
1173};
1174} // namespace
1175
1177 selector_ = std::move(bs);
1178}
1179
1181 // We cannot use the trail as the search can be nested and thus
1182 // deleted upon backtrack. Thus we guard the undo action by a
1183 // check on the number of nesting of solve().
1184 const int solve_depth = SolveDepth();
1186 [solve_depth](Solver* s) {
1187 if (s->SolveDepth() == solve_depth) {
1188 s->ActiveSearch()->SetBranchSelector(nullptr);
1189 }
1190 },
1191 false);
1192 searches_.back()->SetBranchSelector(std::move(bs));
1193}
1194
1196 return RevAlloc(new ApplyBranchSelector(std::move(bs)));
1197}
1198
1200 return state_ == OUTSIDE_SEARCH ? 0 : searches_.size() - 1;
1201}
1202
1203int Solver::SearchDepth() const { return searches_.back()->search_depth(); }
1204
1206 return searches_.back()->left_search_depth();
1207}
1208
1210 if (selector_ != nullptr) {
1211 return selector_();
1212 }
1213 return Solver::NO_CHANGE;
1214}
1215
1217 for (auto& listeners : monitor_event_listeners_) listeners.clear();
1218 search_depth_ = 0;
1219 left_search_depth_ = 0;
1220 selector_ = nullptr;
1221 backtrack_at_the_end_of_the_search_ = true;
1222}
1223
1224#define CALL_EVENT_LISTENERS(Event) \
1225 do { \
1226 ForAll(GetEventListeners(Solver::MonitorEvent::k##Event), \
1227 &SearchMonitor::Event); \
1228 } while (false)
1229
1231 // The solution counter is reset when entering search and not when
1232 // leaving search. This enables the information to persist outside of
1233 // top-level search.
1234 solution_counter_ = 0;
1235 unchecked_solution_counter_ = 0;
1236
1238}
1239
1241 // Backtrack to the correct state.
1243}
1244
1246
1252
1258
1264
1270
1276
1278
1280
1284
1288
1290 bool valid = true;
1291 for (SearchMonitor* const monitor :
1293 if (!monitor->AcceptSolution()) {
1294 // Even though we know the return value, we cannot return yet: this would
1295 // break the contract we have with solution monitors. They all deserve
1296 // a chance to look at the solution.
1297 valid = false;
1298 }
1299 }
1300 return valid;
1301}
1302
1304 bool should_continue = false;
1305 for (SearchMonitor* const monitor :
1307 if (monitor->AtSolution()) {
1308 // Even though we know the return value, we cannot return yet: this would
1309 // break the contract we have with solution monitors. They all deserve
1310 // a chance to look at the solution.
1311 should_continue = true;
1312 }
1313 }
1314 return should_continue;
1315}
1316
1318
1320 bool at_local_optimum = false;
1321 for (SearchMonitor* const monitor :
1323 if (monitor->LocalOptimum()) {
1324 at_local_optimum = true;
1325 }
1326 }
1327 return at_local_optimum;
1328}
1329
1331 bool accept = true;
1332 for (SearchMonitor* const monitor :
1334 if (!monitor->AcceptDelta(delta, deltadelta)) {
1335 accept = false;
1336 }
1337 }
1338 return accept;
1339}
1340
1342
1346
1348 for (SearchMonitor* const monitor : GetEventListeners(
1350 if (monitor->IsUncheckedSolutionLimitReached()) {
1351 return true;
1352 }
1353 }
1354 return false;
1355}
1356
1358
1360 int progress = SearchMonitor::kNoProgress;
1361 for (SearchMonitor* const monitor :
1363 progress = std::max(progress, monitor->ProgressPercent());
1364 }
1365 return progress;
1366}
1367
1368void Search::Accept(ModelVisitor* const visitor) const {
1370 &SearchMonitor::Accept, visitor);
1371 if (decision_builder_ != nullptr) {
1372 decision_builder_->Accept(visitor);
1373 }
1374}
1375
1376#undef CALL_EVENT_LISTENERS
1377
1378bool LocalOptimumReached(Search* search) { return search->LocalOptimum(); }
1379
1380bool AcceptDelta(Search* search, Assignment* delta, Assignment* deltadelta) {
1381 return search->AcceptDelta(delta, deltadelta);
1382}
1383
1384void AcceptNeighbor(Search* search) { search->AcceptNeighbor(); }
1385
1387 search->AcceptUncheckedNeighbor();
1388}
1389
1390namespace {
1391
1392// ---------- Fail Decision ----------
1393
1394class FailDecision : public Decision {
1395 public:
1396 void Apply(Solver* const s) override { s->Fail(); }
1397 void Refute(Solver* const s) override { s->Fail(); }
1398};
1399
1400// Balancing decision
1401
1402class BalancingDecision : public Decision {
1403 public:
1404 ~BalancingDecision() override {}
1405 void Apply(Solver* const /*s*/) override {}
1406 void Refute(Solver* const /*s*/) override {}
1407};
1408} // namespace
1409
1410Decision* Solver::MakeFailDecision() { return fail_decision_.get(); }
1411
1412// ------------------ Solver class -----------------
1413
1414// These magic numbers are there to make sure we pop the correct
1415// sentinels throughout the search.
1416namespace {
1417enum SentinelMarker {
1418 INITIAL_SEARCH_SENTINEL = 10000000,
1419 ROOT_NODE_SENTINEL = 20000000,
1420 SOLVER_CTOR_SENTINEL = 40000000
1421};
1422} // namespace
1423
1424extern PropagationMonitor* BuildTrace(Solver* s);
1425extern LocalSearchMonitor* BuildLocalSearchMonitorPrimary(Solver* s);
1426extern ModelCache* BuildModelCache(Solver* solver);
1427
1428std::string Solver::model_name() const { return name_; }
1429
1430namespace {
1431void CheckSolverParameters(const ConstraintSolverParameters& parameters) {
1432 CHECK_GT(parameters.array_split_size(), 0)
1433 << "Were parameters built using Solver::DefaultSolverParameters() ?";
1434}
1435} // namespace
1436
1437Solver::Solver(const std::string& name,
1438 const ConstraintSolverParameters& parameters)
1439 : name_(name),
1440 parameters_(parameters),
1441 random_(CpRandomSeed()),
1442 demon_profiler_(BuildDemonProfiler(this)),
1443 use_fast_local_search_(true),
1444 local_search_profiler_(BuildLocalSearchProfiler(this)) {
1445 Init();
1446}
1447
1448Solver::Solver(const std::string& name)
1449 : name_(name),
1450 parameters_(DefaultSolverParameters()),
1451 random_(CpRandomSeed()),
1452 demon_profiler_(BuildDemonProfiler(this)),
1453 use_fast_local_search_(true),
1454 local_search_profiler_(BuildLocalSearchProfiler(this)) {
1455 Init();
1456}
1457
1458void Solver::Init() {
1459 CheckSolverParameters(parameters_);
1460 queue_ = std::make_unique<Queue>(this);
1461 trail_ = std::make_unique<Trail>(parameters_.trail_block_size(),
1462 parameters_.compress_trail());
1463 state_ = OUTSIDE_SEARCH;
1464 branches_ = 0;
1465 fails_ = 0;
1466 decisions_ = 0;
1467 neighbors_ = 0;
1468 filtered_neighbors_ = 0;
1469 accepted_neighbors_ = 0;
1470 optimization_direction_ = NOT_SET;
1471 timer_ = std::make_unique<ClockTimer>();
1472 searches_.assign(1, new Search(this, 0));
1473 fail_stamp_ = uint64_t{1};
1474 balancing_decision_ = std::make_unique<BalancingDecision>();
1475 fail_intercept_ = nullptr;
1476 true_constraint_ = nullptr;
1477 false_constraint_ = nullptr;
1478 fail_decision_ = std::make_unique<FailDecision>();
1479 constraint_index_ = 0;
1480 additional_constraint_index_ = 0;
1481 num_int_vars_ = 0;
1482 propagation_monitor_.reset(BuildTrace(this));
1483 local_search_monitor_.reset(BuildLocalSearchMonitorPrimary(this));
1484 print_trace_ = nullptr;
1485 anonymous_variable_index_ = 0;
1486 should_fail_ = false;
1487
1488 for (int i = 0; i < kNumPriorities; ++i) {
1489 demon_runs_[i] = 0;
1490 }
1491 searches_.push_back(new Search(this));
1492 PushSentinel(SOLVER_CTOR_SENTINEL);
1493 InitCachedIntConstants(); // to be called after the SENTINEL is set.
1494 InitCachedConstraint(); // Cache the true constraint.
1495 timer_->Restart();
1496 model_cache_.reset(BuildModelCache(this));
1497 AddPropagationMonitor(reinterpret_cast<PropagationMonitor*>(demon_profiler_));
1499 reinterpret_cast<LocalSearchMonitor*>(local_search_profiler_));
1500}
1501
1503 // solver destructor called with searches open.
1504 CHECK_EQ(2, searches_.size());
1505 BacktrackToSentinel(INITIAL_SEARCH_SENTINEL);
1506
1507 StateInfo info;
1508 Solver::MarkerType finalType = PopState(&info);
1509 // Not popping a SENTINEL in Solver destructor.
1510 DCHECK_EQ(finalType, SENTINEL);
1511 // Not popping initial SENTINEL in Solver destructor.
1512 DCHECK_EQ(info.int_info, SOLVER_CTOR_SENTINEL);
1513 gtl::STLDeleteElements(&searches_);
1514 DeleteDemonProfiler(demon_profiler_);
1515 DeleteLocalSearchProfiler(local_search_profiler_);
1516}
1517
1518std::string Solver::DebugString() const {
1519 std::string out = "Solver(name = \"" + name_ + "\", state = ";
1520 switch (state_) {
1521 case OUTSIDE_SEARCH:
1522 out += "OUTSIDE_SEARCH";
1523 break;
1524 case IN_ROOT_NODE:
1525 out += "IN_ROOT_NODE";
1526 break;
1527 case IN_SEARCH:
1528 out += "IN_SEARCH";
1529 break;
1530 case AT_SOLUTION:
1531 out += "AT_SOLUTION";
1532 break;
1533 case NO_MORE_SOLUTIONS:
1534 out += "NO_MORE_SOLUTIONS";
1535 break;
1536 case PROBLEM_INFEASIBLE:
1537 out += "PROBLEM_INFEASIBLE";
1538 break;
1539 }
1540 absl::StrAppendFormat(
1541 &out,
1542 ", branches = %d, fails = %d, decisions = %d, delayed demon runs = %d, "
1543 "var demon runs = %d, normal demon runs = %d, Run time = %d ms)",
1544 branches_, fails_, decisions_, demon_runs_[DELAYED_PRIORITY],
1545 demon_runs_[VAR_PRIORITY], demon_runs_[NORMAL_PRIORITY], wall_time());
1546 return out;
1547}
1548
1550
1551int64_t Solver::wall_time() const {
1552 return absl::ToInt64Milliseconds(timer_->GetDuration());
1553}
1554
1555absl::Time Solver::Now() const {
1556 return absl::FromUnixSeconds(0) + timer_->GetDuration();
1557}
1558
1559int64_t Solver::solutions() const {
1560 return TopLevelSearch()->solution_counter();
1561}
1562
1564 return TopLevelSearch()->unchecked_solution_counter();
1565}
1566
1567void Solver::IncrementUncheckedSolutionCounter() {
1568 TopLevelSearch()->IncrementUncheckedSolutionCounter();
1569}
1570
1571bool Solver::IsUncheckedSolutionLimitReached() {
1572 return TopLevelSearch()->IsUncheckedSolutionLimitReached();
1573}
1574
1575void Solver::TopPeriodicCheck() { TopLevelSearch()->PeriodicCheck(); }
1576
1577int Solver::TopProgressPercent() { return TopLevelSearch()->ProgressPercent(); }
1578
1579ConstraintSolverStatistics Solver::GetConstraintSolverStatistics() const {
1580 ConstraintSolverStatistics stats;
1581 stats.set_num_branches(branches());
1582 stats.set_num_failures(failures());
1583 stats.set_num_solutions(solutions());
1584 stats.set_bytes_used(MemoryUsage());
1585 stats.set_duration_seconds(absl::ToDoubleSeconds(timer_->GetDuration()));
1586 return stats;
1587}
1588
1590 StateInfo info;
1591 PushState(SIMPLE_MARKER, info);
1592}
1593
1595 StateInfo info;
1596 Solver::MarkerType t = PopState(&info);
1597 CHECK_EQ(SIMPLE_MARKER, t);
1598}
1599
1600void Solver::PushState(Solver::MarkerType t, const StateInfo& info) {
1601 StateMarker* m = new StateMarker(t, info);
1602 if (t != REVERSIBLE_ACTION || info.int_info == 0) {
1603 m->rev_int_index_ = trail_->rev_ints_.size();
1604 m->rev_int64_index_ = trail_->rev_int64s_.size();
1605 m->rev_uint64_index_ = trail_->rev_uint64s_.size();
1606 m->rev_double_index_ = trail_->rev_doubles_.size();
1607 m->rev_ptr_index_ = trail_->rev_ptrs_.size();
1608 m->rev_boolvar_list_index_ = trail_->rev_boolvar_list_.size();
1609 m->rev_bools_index_ = trail_->rev_bools_.size();
1610 m->rev_int_memory_index_ = trail_->rev_int_memory_.size();
1611 m->rev_int64_memory_index_ = trail_->rev_int64_memory_.size();
1612 m->rev_double_memory_index_ = trail_->rev_double_memory_.size();
1613 m->rev_object_memory_index_ = trail_->rev_object_memory_.size();
1614 m->rev_object_array_memory_index_ = trail_->rev_object_array_memory_.size();
1615 m->rev_memory_index_ = trail_->rev_memory_.size();
1616 m->rev_memory_array_index_ = trail_->rev_memory_array_.size();
1617 }
1618 searches_.back()->marker_stack_.push_back(m);
1619 queue_->increase_stamp();
1620}
1621
1623 StateInfo info(std::move(a), fast);
1625}
1626
1628 CHECK(!searches_.back()->marker_stack_.empty())
1629 << "PopState() on an empty stack";
1630 CHECK(info != nullptr);
1631 StateMarker* const m = searches_.back()->marker_stack_.back();
1632 if (m->type_ != REVERSIBLE_ACTION || m->info_.int_info == 0) {
1633 trail_->BacktrackTo(m);
1634 }
1635 Solver::MarkerType t = m->type_;
1636 (*info) = m->info_;
1637 searches_.back()->marker_stack_.pop_back();
1638 delete m;
1639 queue_->increase_stamp();
1640 return t;
1641}
1642
1643void Solver::check_alloc_state() {
1644 switch (state_) {
1645 case OUTSIDE_SEARCH:
1646 case IN_ROOT_NODE:
1647 case IN_SEARCH:
1648 case NO_MORE_SOLUTIONS:
1649 case PROBLEM_INFEASIBLE:
1650 break;
1651 case AT_SOLUTION:
1652 LOG(FATAL) << "allocating at a leaf node";
1653 default:
1654 LOG(FATAL) << "This switch was supposed to be exhaustive, but it is not!";
1655 }
1656}
1657
1658void Solver::FreezeQueue() { queue_->Freeze(); }
1659
1660void Solver::UnfreezeQueue() { queue_->Unfreeze(); }
1661
1662void Solver::EnqueueVar(Demon* const d) { queue_->EnqueueVar(d); }
1663
1664void Solver::EnqueueDelayedDemon(Demon* const d) {
1665 queue_->EnqueueDelayedDemon(d);
1666}
1667
1668void Solver::ExecuteAll(const SimpleRevFIFO<Demon*>& demons) {
1669 queue_->ExecuteAll(demons);
1670}
1671
1672void Solver::EnqueueAll(const SimpleRevFIFO<Demon*>& demons) {
1673 queue_->EnqueueAll(demons);
1674}
1675
1676uint64_t Solver::stamp() const { return queue_->stamp(); }
1677
1678uint64_t Solver::fail_stamp() const { return fail_stamp_; }
1679
1680void Solver::set_action_on_fail(Action a) {
1681 queue_->set_action_on_fail(std::move(a));
1682}
1683
1684void Solver::set_variable_to_clean_on_fail(IntVar* v) {
1685 queue_->set_variable_to_clean_on_fail(v);
1686}
1687
1688void Solver::reset_action_on_fail() { queue_->reset_action_on_fail(); }
1689
1691 DCHECK(c != nullptr);
1692 if (c == true_constraint_) {
1693 return;
1694 }
1695 if (state_ == IN_SEARCH) {
1696 queue_->AddConstraint(c);
1697 } else if (state_ == IN_ROOT_NODE) {
1698 DCHECK_GE(constraint_index_, 0);
1699 DCHECK_LE(constraint_index_, constraints_list_.size());
1700 const int constraint_parent =
1701 constraint_index_ == constraints_list_.size()
1702 ? additional_constraints_parent_list_[additional_constraint_index_]
1703 : constraint_index_;
1704 additional_constraints_list_.push_back(c);
1705 additional_constraints_parent_list_.push_back(constraint_parent);
1706 } else {
1707 if (parameters_.print_added_constraints()) {
1708 LOG(INFO) << c->DebugString();
1709 }
1710 constraints_list_.push_back(c);
1711 }
1712}
1713
1715 IntVar* const target_var, IntExpr* const expr) {
1716 if (constraint != nullptr) {
1717 if (state_ != IN_SEARCH) {
1718 cast_constraints_.insert(constraint);
1719 cast_information_[target_var] =
1720 Solver::IntegerCastInfo(target_var, expr, constraint);
1721 }
1722 AddConstraint(constraint);
1723 }
1724}
1725
1726void Solver::Accept(ModelVisitor* const visitor) const {
1727 visitor->BeginVisitModel(name_);
1728 ForAll(constraints_list_, &Constraint::Accept, visitor);
1729 visitor->EndVisitModel(name_);
1730}
1731
1732void Solver::ProcessConstraints() {
1733 // Both constraints_list_ and additional_constraints_list_ are used in
1734 // a FIFO way.
1735 if (parameters_.print_model()) {
1736 ModelVisitor* const visitor = MakePrintModelVisitor();
1737 Accept(visitor);
1738 }
1739 if (parameters_.print_model_stats()) {
1740 ModelVisitor* const visitor = MakeStatisticsModelVisitor();
1741 Accept(visitor);
1742 }
1743
1744 if (parameters_.disable_solve()) {
1745 LOG(INFO) << "Forcing early failure";
1746 Fail();
1747 }
1748
1749 // Clear state before processing constraints.
1750 const int constraints_size = constraints_list_.size();
1751 additional_constraints_list_.clear();
1752 additional_constraints_parent_list_.clear();
1753
1754 for (constraint_index_ = 0; constraint_index_ < constraints_size;
1755 ++constraint_index_) {
1756 Constraint* const constraint = constraints_list_[constraint_index_];
1757 propagation_monitor_->BeginConstraintInitialPropagation(constraint);
1758 constraint->PostAndPropagate();
1759 propagation_monitor_->EndConstraintInitialPropagation(constraint);
1760 }
1761 CHECK_EQ(constraints_list_.size(), constraints_size);
1762
1763 // Process nested constraints added during the previous step.
1764 for (int additional_constraint_index_ = 0;
1765 additional_constraint_index_ < additional_constraints_list_.size();
1766 ++additional_constraint_index_) {
1767 Constraint* const nested =
1768 additional_constraints_list_[additional_constraint_index_];
1769 const int parent_index =
1770 additional_constraints_parent_list_[additional_constraint_index_];
1771 Constraint* const parent = constraints_list_[parent_index];
1772 propagation_monitor_->BeginNestedConstraintInitialPropagation(parent,
1773 nested);
1774 nested->PostAndPropagate();
1775 propagation_monitor_->EndNestedConstraintInitialPropagation(parent, nested);
1776 }
1777}
1778
1780 DCHECK_GT(SolveDepth(), 0);
1781 DCHECK(searches_.back() != nullptr);
1782 return searches_.back()->created_by_solve();
1783}
1784
1785bool Solver::Solve(DecisionBuilder* const db, SearchMonitor* const m1) {
1786 return Solve(db, std::vector<SearchMonitor*>{m1});
1787}
1788
1789bool Solver::Solve(DecisionBuilder* const db) { return Solve(db, {}); }
1790
1792 SearchMonitor* const m2) {
1793 return Solve(db, {m1, m2});
1794}
1795
1797 SearchMonitor* const m2, SearchMonitor* const m3) {
1798 return Solve(db, {m1, m2, m3});
1799}
1800
1802 SearchMonitor* const m2, SearchMonitor* const m3,
1803 SearchMonitor* const m4) {
1804 return Solve(db, {m1, m2, m3, m4});
1805}
1806
1808 const std::vector<SearchMonitor*>& monitors) {
1809 NewSearch(db, monitors);
1810 searches_.back()->set_created_by_solve(true); // Overwrites default.
1811 NextSolution();
1812 const bool solution_found = searches_.back()->solution_counter() > 0;
1813 EndSearch();
1814 return solution_found;
1815}
1816
1818 return NewSearch(db, std::vector<SearchMonitor*>{m1});
1819}
1820
1821void Solver::NewSearch(DecisionBuilder* const db) { return NewSearch(db, {}); }
1822
1824 SearchMonitor* const m2) {
1825 return NewSearch(db, {m1, m2});
1826}
1827
1829 SearchMonitor* const m2, SearchMonitor* const m3) {
1830 return NewSearch(db, {m1, m2, m3});
1831}
1832
1834 SearchMonitor* const m2, SearchMonitor* const m3,
1835 SearchMonitor* const m4) {
1836 return NewSearch(db, {m1, m2, m3, m4});
1837}
1838
1840
1841// Opens a new top level search.
1843 const std::vector<SearchMonitor*>& monitors) {
1844 // TODO(user) : reset statistics
1845
1846 CHECK(db != nullptr);
1847 const bool nested = state_ == IN_SEARCH;
1848
1849 if (state_ == IN_ROOT_NODE) {
1850 LOG(FATAL) << "Cannot start new searches here.";
1851 }
1852
1853 Search* const search = nested ? new Search(this) : searches_.back();
1854 search->set_created_by_solve(false); // default behavior.
1855
1856 // ----- jumps to correct state -----
1857
1858 if (nested) {
1859 // Nested searches are created on demand, and deleted afterwards.
1860 DCHECK_GE(searches_.size(), 2);
1861 searches_.push_back(search);
1862 } else {
1863 // Top level search is persistent.
1864 // TODO(user): delete top level search after EndSearch().
1865 DCHECK_EQ(2, searches_.size());
1866 // TODO(user): Check if these two lines are still necessary.
1867 BacktrackToSentinel(INITIAL_SEARCH_SENTINEL);
1868 state_ = OUTSIDE_SEARCH;
1869 }
1870
1871 // ----- manages all monitors -----
1872
1873 // Always install the main propagation and local search monitors.
1874 propagation_monitor_->Install();
1875 if (demon_profiler_ != nullptr) {
1876 InstallDemonProfiler(demon_profiler_);
1877 }
1878 local_search_monitor_->Install();
1879 if (local_search_profiler_ != nullptr) {
1880 InstallLocalSearchProfiler(local_search_profiler_);
1881 }
1882
1883 // Push monitors and enter search.
1884 for (SearchMonitor* const monitor : monitors) {
1885 if (monitor != nullptr) {
1886 monitor->Install();
1887 }
1888 }
1889 std::vector<SearchMonitor*> extras;
1890 db->AppendMonitors(this, &extras);
1891 for (SearchMonitor* const monitor : extras) {
1892 if (monitor != nullptr) {
1893 monitor->Install();
1894 }
1895 }
1896 // Install the print trace if needed.
1897 // The print_trace needs to be last to detect propagation from the objective.
1898 if (nested) {
1899 if (print_trace_ != nullptr) { // Was installed at the top level?
1900 print_trace_->Install(); // Propagates to nested search.
1901 }
1902 } else { // Top level search
1903 print_trace_ = nullptr; // Clears it first.
1904 if (parameters_.trace_propagation()) {
1905 print_trace_ = BuildPrintTrace(this);
1906 print_trace_->Install();
1907 } else if (parameters_.trace_search()) {
1908 // This is useful to trace the exact behavior of the search.
1909 // The '######## ' prefix is the same as the progagation trace.
1910 // Search trace is subsumed by propagation trace, thus only one
1911 // is necessary.
1912 SearchMonitor* const trace = MakeSearchTrace("######## ");
1913 trace->Install();
1914 }
1915 }
1916
1917 // ----- enters search -----
1918
1919 search->EnterSearch();
1920
1921 // Push sentinel and set decision builder.
1922 PushSentinel(INITIAL_SEARCH_SENTINEL);
1923 search->set_decision_builder(db);
1924}
1925
1926// Backtrack to the last open right branch in the search tree.
1927// It returns true in case the search tree has been completely explored.
1928bool Solver::BacktrackOneLevel(Decision** const fail_decision) {
1929 bool no_more_solutions = false;
1930 bool end_loop = false;
1931 while (!end_loop) {
1932 StateInfo info;
1933 Solver::MarkerType t = PopState(&info);
1934 switch (t) {
1935 case SENTINEL:
1936 CHECK_EQ(info.ptr_info, this) << "Wrong sentinel found";
1937 CHECK((info.int_info == ROOT_NODE_SENTINEL && SolveDepth() == 1) ||
1938 (info.int_info == INITIAL_SEARCH_SENTINEL && SolveDepth() > 1));
1939 searches_.back()->sentinel_pushed_--;
1940 no_more_solutions = true;
1941 end_loop = true;
1942 break;
1943 case SIMPLE_MARKER:
1944 LOG(ERROR) << "Simple markers should not be encountered during search";
1945 break;
1946 case CHOICE_POINT:
1947 if (info.int_info == 0) { // was left branch
1948 (*fail_decision) = reinterpret_cast<Decision*>(info.ptr_info);
1949 end_loop = true;
1950 searches_.back()->set_search_depth(info.depth);
1951 searches_.back()->set_search_left_depth(info.left_depth);
1952 }
1953 break;
1954 case REVERSIBLE_ACTION: {
1955 if (info.reversible_action != nullptr) {
1956 info.reversible_action(this);
1957 }
1958 break;
1959 }
1960 }
1961 }
1962 Search* const search = searches_.back();
1963 search->EndFail();
1964 fail_stamp_++;
1965 if (no_more_solutions) {
1966 search->NoMoreSolutions();
1967 }
1968 return no_more_solutions;
1969}
1970
1971void Solver::PushSentinel(int magic_code) {
1972 StateInfo info(this, magic_code);
1973 PushState(SENTINEL, info);
1974 // We do not count the sentinel pushed in the ctor.
1975 if (magic_code != SOLVER_CTOR_SENTINEL) {
1976 searches_.back()->sentinel_pushed_++;
1977 }
1978 const int pushed = searches_.back()->sentinel_pushed_;
1979 DCHECK((magic_code == SOLVER_CTOR_SENTINEL) ||
1980 (magic_code == INITIAL_SEARCH_SENTINEL && pushed == 1) ||
1981 (magic_code == ROOT_NODE_SENTINEL && pushed == 2));
1982}
1983
1985 Search* const search = searches_.back();
1986 CHECK_NE(0, search->sentinel_pushed_);
1987 if (SolveDepth() == 1) { // top level.
1988 if (search->sentinel_pushed_ > 1) {
1989 BacktrackToSentinel(ROOT_NODE_SENTINEL);
1990 }
1991 CHECK_EQ(1, search->sentinel_pushed_);
1992 PushSentinel(ROOT_NODE_SENTINEL);
1993 state_ = IN_SEARCH;
1994 } else {
1995 CHECK_EQ(IN_SEARCH, state_);
1996 if (search->sentinel_pushed_ > 0) {
1997 BacktrackToSentinel(INITIAL_SEARCH_SENTINEL);
1998 }
1999 CHECK_EQ(0, search->sentinel_pushed_);
2000 PushSentinel(INITIAL_SEARCH_SENTINEL);
2001 }
2002
2003 search->RestartSearch();
2004}
2005
2006// Backtrack to the initial search sentinel.
2007// Does not change the state, this should be done by the caller.
2008void Solver::BacktrackToSentinel(int magic_code) {
2009 Search* const search = searches_.back();
2010 bool end_loop = search->sentinel_pushed_ == 0;
2011 while (!end_loop) {
2012 StateInfo info;
2013 Solver::MarkerType t = PopState(&info);
2014 switch (t) {
2015 case SENTINEL: {
2016 CHECK_EQ(info.ptr_info, this) << "Wrong sentinel found";
2017 CHECK_GE(--search->sentinel_pushed_, 0);
2018 search->set_search_depth(0);
2019 search->set_search_left_depth(0);
2020
2021 if (info.int_info == magic_code) {
2022 end_loop = true;
2023 }
2024 break;
2025 }
2026 case SIMPLE_MARKER:
2027 break;
2028 case CHOICE_POINT:
2029 break;
2030 case REVERSIBLE_ACTION: {
2031 info.reversible_action(this);
2032 break;
2033 }
2034 }
2035 }
2036 fail_stamp_++;
2037}
2038
2039// Closes the current search without backtrack.
2040void Solver::JumpToSentinelWhenNested() {
2041 CHECK_GT(SolveDepth(), 1) << "calling JumpToSentinel from top level";
2042 Search* c = searches_.back();
2043 Search* p = ParentSearch();
2044 bool found = false;
2045 while (!c->marker_stack_.empty()) {
2046 StateMarker* const m = c->marker_stack_.back();
2047 if (m->type_ == REVERSIBLE_ACTION) {
2048 p->marker_stack_.push_back(m);
2049 } else {
2050 if (m->type_ == SENTINEL) {
2051 CHECK_EQ(c->marker_stack_.size(), 1) << "Sentinel found too early";
2052 found = true;
2053 }
2054 delete m;
2055 }
2056 c->marker_stack_.pop_back();
2057 }
2058 c->set_search_depth(0);
2059 c->set_search_left_depth(0);
2060 CHECK_EQ(found, true) << "Sentinel not found";
2061}
2062
2063namespace {
2064class ReverseDecision : public Decision {
2065 public:
2066 explicit ReverseDecision(Decision* const d) : decision_(d) {
2067 CHECK(d != nullptr);
2068 }
2069 ~ReverseDecision() override {}
2070
2071 void Apply(Solver* const s) override { decision_->Refute(s); }
2072
2073 void Refute(Solver* const s) override { decision_->Apply(s); }
2074
2075 void Accept(DecisionVisitor* const visitor) const override {
2076 decision_->Accept(visitor);
2077 }
2078
2079 std::string DebugString() const override {
2080 std::string str = "Reverse(";
2081 str += decision_->DebugString();
2082 str += ")";
2083 return str;
2084 }
2085
2086 private:
2087 Decision* const decision_;
2088};
2089} // namespace
2090
2091// Search for the next solution in the search tree.
2093 Search* const search = searches_.back();
2094 Decision* fd = nullptr;
2095 const int solve_depth = SolveDepth();
2096 const bool top_level = solve_depth <= 1;
2097
2098 if (solve_depth == 0 && !search->decision_builder()) {
2099 LOG(WARNING) << "NextSolution() called without a NewSearch before";
2100 return false;
2101 }
2102
2103 if (top_level) { // Manage top level state.
2104 switch (state_) {
2105 case PROBLEM_INFEASIBLE:
2106 return false;
2107 case NO_MORE_SOLUTIONS:
2108 return false;
2109 case AT_SOLUTION: {
2110 if (BacktrackOneLevel(&fd)) { // No more solutions.
2111 state_ = NO_MORE_SOLUTIONS;
2112 return false;
2113 }
2114 state_ = IN_SEARCH;
2115 break;
2116 }
2117 case OUTSIDE_SEARCH: {
2118 state_ = IN_ROOT_NODE;
2119 search->BeginInitialPropagation();
2120 CP_TRY(search) {
2121 ProcessConstraints();
2122 search->EndInitialPropagation();
2123 PushSentinel(ROOT_NODE_SENTINEL);
2124 state_ = IN_SEARCH;
2125 search->ClearBuffer();
2126 }
2127 CP_ON_FAIL {
2128 queue_->AfterFailure();
2129 BacktrackToSentinel(INITIAL_SEARCH_SENTINEL);
2130 state_ = PROBLEM_INFEASIBLE;
2131 return false;
2132 }
2133 break;
2134 }
2135 case IN_SEARCH: // Usually after a RestartSearch
2136 break;
2137 case IN_ROOT_NODE:
2138 LOG(FATAL) << "Should not happen";
2139 break;
2140 }
2141 }
2142
2143 volatile bool finish = false;
2144 volatile bool result = false;
2145 DecisionBuilder* const db = search->decision_builder();
2146
2147 while (!finish) {
2148 CP_TRY(search) {
2149 if (fd != nullptr) {
2150 StateInfo i1(fd, 1, search->search_depth(),
2151 search->left_search_depth()); // 1 for right branch
2153 search->RefuteDecision(fd);
2154 branches_++;
2155 fd->Refute(this);
2156 // Check the fail state that could have been set in the python/java/C#
2157 // layer.
2158 CheckFail();
2159 search->AfterDecision(fd, false);
2160 search->RightMove();
2161 fd = nullptr;
2162 }
2163 Decision* d = nullptr;
2164 for (;;) {
2165 search->BeginNextDecision(db);
2166 d = db->Next(this);
2167 search->EndNextDecision(db, d);
2168 if (d == fail_decision_.get()) {
2169 Fail(); // fail now instead of after 2 branches.
2170 }
2171 if (d != nullptr) {
2172 DecisionModification modification = search->ModifyDecision();
2173 switch (modification) {
2174 case SWITCH_BRANCHES: {
2175 d = RevAlloc(new ReverseDecision(d));
2176 // We reverse the decision and fall through the normal code.
2177 ABSL_FALLTHROUGH_INTENDED;
2178 }
2179 case NO_CHANGE: {
2180 decisions_++;
2181 StateInfo i2(d, 0, search->search_depth(),
2182 search->left_search_depth()); // 0 for left branch
2184 search->ApplyDecision(d);
2185 branches_++;
2186 d->Apply(this);
2187 CheckFail();
2188 search->AfterDecision(d, true);
2189 search->LeftMove();
2190 break;
2191 }
2192 case KEEP_LEFT: {
2193 search->ApplyDecision(d);
2194 d->Apply(this);
2195 CheckFail();
2196 search->AfterDecision(d, true);
2197 break;
2198 }
2199 case KEEP_RIGHT: {
2200 search->RefuteDecision(d);
2201 d->Refute(this);
2202 CheckFail();
2203 search->AfterDecision(d, false);
2204 break;
2205 }
2206 case KILL_BOTH: {
2207 Fail();
2208 }
2209 }
2210 } else {
2211 break;
2212 }
2213 }
2214 if (search->AcceptSolution()) {
2215 search->IncrementSolutionCounter();
2216 if (!search->AtSolution() || !CurrentlyInSolve()) {
2217 result = true;
2218 finish = true;
2219 } else {
2220 Fail();
2221 }
2222 } else {
2223 Fail();
2224 }
2225 }
2226 CP_ON_FAIL {
2227 queue_->AfterFailure();
2228 if (search->should_finish()) {
2229 fd = nullptr;
2230 BacktrackToSentinel(top_level ? ROOT_NODE_SENTINEL
2231 : INITIAL_SEARCH_SENTINEL);
2232 result = false;
2233 finish = true;
2234 search->set_should_finish(false);
2235 search->set_should_restart(false);
2236 // We do not need to push back the sentinel as we are exiting anyway.
2237 } else if (search->should_restart()) {
2238 fd = nullptr;
2239 BacktrackToSentinel(top_level ? ROOT_NODE_SENTINEL
2240 : INITIAL_SEARCH_SENTINEL);
2241 search->set_should_finish(false);
2242 search->set_should_restart(false);
2243 PushSentinel(top_level ? ROOT_NODE_SENTINEL : INITIAL_SEARCH_SENTINEL);
2244 search->RestartSearch();
2245 } else {
2246 if (BacktrackOneLevel(&fd)) { // no more solutions.
2247 result = false;
2248 finish = true;
2249 }
2250 }
2251 }
2252 }
2253 if (result) {
2254 search->ClearBuffer();
2255 }
2256 if (top_level) { // Manage state after NextSolution().
2257 state_ = (result ? AT_SOLUTION : NO_MORE_SOLUTIONS);
2258 }
2259 return result;
2260}
2261
2263 Search* const search = searches_.back();
2264 if (search->backtrack_at_the_end_of_the_search()) {
2265 BacktrackToSentinel(INITIAL_SEARCH_SENTINEL);
2266 } else {
2267 CHECK_GT(searches_.size(), 2);
2268 if (search->sentinel_pushed_ > 0) {
2269 JumpToSentinelWhenNested();
2270 }
2271 }
2272 search->ExitSearch();
2273 search->Clear();
2274 if (2 == searches_.size()) { // Ending top level search.
2275 // Restores the state.
2276 state_ = OUTSIDE_SEARCH;
2277 // Checks if we want to export the profile info.
2278 if (!parameters_.profile_file().empty()) {
2279 const std::string& file_name = parameters_.profile_file();
2280 LOG(INFO) << "Exporting profile to " << file_name;
2281 ExportProfilingOverview(file_name);
2282 }
2283 if (parameters_.print_local_search_profile()) {
2284 const std::string profile = LocalSearchProfile();
2285 if (!profile.empty()) LOG(INFO) << profile;
2286 }
2287 } else { // We clean the nested Search.
2288 delete search;
2289 searches_.pop_back();
2290 }
2291}
2292
2294 CHECK(solution);
2295 if (state_ == IN_SEARCH || state_ == IN_ROOT_NODE) {
2296 LOG(FATAL) << "CheckAssignment is only available at the top level.";
2297 }
2298 // Check state and go to OUTSIDE_SEARCH.
2299 Search* const search = searches_.back();
2300 search->set_created_by_solve(false); // default behavior.
2301
2302 BacktrackToSentinel(INITIAL_SEARCH_SENTINEL);
2303 state_ = OUTSIDE_SEARCH;
2304
2305 // Push monitors and enter search.
2306 search->EnterSearch();
2307
2308 // Push sentinel and set decision builder.
2309 DCHECK_EQ(0, SolveDepth());
2310 DCHECK_EQ(2, searches_.size());
2311 PushSentinel(INITIAL_SEARCH_SENTINEL);
2312 search->BeginInitialPropagation();
2313 CP_TRY(search) {
2314 state_ = IN_ROOT_NODE;
2316 restore->Next(this);
2317 ProcessConstraints();
2318 search->EndInitialPropagation();
2319 BacktrackToSentinel(INITIAL_SEARCH_SENTINEL);
2320 search->ClearBuffer();
2321 state_ = OUTSIDE_SEARCH;
2322 return true;
2323 }
2324 CP_ON_FAIL {
2325 const int index =
2326 constraint_index_ < constraints_list_.size()
2327 ? constraint_index_
2328 : additional_constraints_parent_list_[additional_constraint_index_];
2329 Constraint* const ct = constraints_list_[index];
2330 if (ct->name().empty()) {
2331 LOG(INFO) << "Failing constraint = " << ct->DebugString();
2332 } else {
2333 LOG(INFO) << "Failing constraint = " << ct->name() << ":"
2334 << ct->DebugString();
2335 }
2336 queue_->AfterFailure();
2337 BacktrackToSentinel(INITIAL_SEARCH_SENTINEL);
2338 state_ = PROBLEM_INFEASIBLE;
2339 return false;
2340 }
2341}
2342
2343namespace {
2344class AddConstraintDecisionBuilder : public DecisionBuilder {
2345 public:
2346 explicit AddConstraintDecisionBuilder(Constraint* const ct)
2347 : constraint_(ct) {
2348 CHECK(ct != nullptr);
2349 }
2350
2351 ~AddConstraintDecisionBuilder() override {}
2352
2353 Decision* Next(Solver* const solver) override {
2354 solver->AddConstraint(constraint_);
2355 return nullptr;
2356 }
2357
2358 std::string DebugString() const override {
2359 return absl::StrFormat("AddConstraintDecisionBuilder(%s)",
2360 constraint_->DebugString());
2361 }
2362
2363 private:
2364 Constraint* const constraint_;
2365};
2366} // namespace
2367
2369 return RevAlloc(new AddConstraintDecisionBuilder(ct));
2370}
2371
2375
2377 SearchMonitor* const m1) {
2378 return SolveAndCommit(db, std::vector<SearchMonitor*>{m1});
2379}
2380
2382 return SolveAndCommit(db, {});
2383}
2384
2386 SearchMonitor* const m2) {
2387 return SolveAndCommit(db, {m1, m2});
2388}
2389
2391 SearchMonitor* const m2, SearchMonitor* const m3) {
2392 return SolveAndCommit(db, {m1, m2, m3});
2393}
2394
2396 const std::vector<SearchMonitor*>& monitors) {
2397 NewSearch(db, monitors);
2398 searches_.back()->set_created_by_solve(true); // Overwrites default.
2399 searches_.back()->set_backtrack_at_the_end_of_the_search(false);
2400 NextSolution();
2401 const bool solution_found = searches_.back()->solution_counter() > 0;
2402 EndSearch();
2403 return solution_found;
2404}
2405
2407 if (fail_intercept_) {
2408 fail_intercept_();
2409 return;
2410 }
2412 fails_++;
2413 searches_.back()->BeginFail();
2414 searches_.back()->JumpBack();
2415}
2416
2418 searches_.back()->set_should_finish(true);
2419}
2420
2422 searches_.back()->set_should_restart(true);
2423}
2424
2425// ----- Cast Expression -----
2426
2428 const IntegerCastInfo* const cast_info =
2429 gtl::FindOrNull(cast_information_, var);
2430 if (cast_info != nullptr) {
2431 return cast_info->expression;
2432 }
2433 return nullptr;
2434}
2435
2436// --- Propagation object names ---
2437
2438std::string Solver::GetName(const PropagationBaseObject* object) {
2439 const std::string* name = gtl::FindOrNull(propagation_object_names_, object);
2440 if (name != nullptr) {
2441 return *name;
2442 }
2443 const IntegerCastInfo* const cast_info =
2444 gtl::FindOrNull(cast_information_, object);
2445 if (cast_info != nullptr && cast_info->expression != nullptr) {
2446 if (cast_info->expression->HasName()) {
2447 return absl::StrFormat("Var<%s>", cast_info->expression->name());
2448 } else if (parameters_.name_cast_variables()) {
2449 return absl::StrFormat("Var<%s>", cast_info->expression->DebugString());
2450 } else {
2451 const std::string new_name =
2452 absl::StrFormat("CastVar<%d>", anonymous_variable_index_++);
2453 propagation_object_names_[object] = new_name;
2454 return new_name;
2455 }
2456 }
2457 const std::string base_name = object->BaseName();
2458 if (parameters_.name_all_variables() && !base_name.empty()) {
2459 const std::string new_name =
2460 absl::StrFormat("%s_%d", base_name, anonymous_variable_index_++);
2461 propagation_object_names_[object] = new_name;
2462 return new_name;
2463 }
2464 return empty_name_;
2465}
2466
2467void Solver::SetName(const PropagationBaseObject* object,
2468 absl::string_view name) {
2469 if (parameters_.store_names() &&
2470 GetName(object) != name) { // in particular if name.empty()
2471 propagation_object_names_[object] = name;
2472 }
2473}
2474
2475bool Solver::HasName(const PropagationBaseObject* const object) const {
2476 return propagation_object_names_.contains(
2477 const_cast<PropagationBaseObject*>(object)) ||
2478 (!object->BaseName().empty() && parameters_.name_all_variables());
2479}
2480
2481// ------------------ Useful Operators ------------------
2482
2483std::ostream& operator<<(std::ostream& out, const Solver* const s) {
2484 out << s->DebugString();
2485 return out;
2486}
2487
2488std::ostream& operator<<(std::ostream& out, const BaseObject* const o) {
2489 out << o->DebugString();
2490 return out;
2491}
2492
2493// ---------- PropagationBaseObject ---------
2494
2495std::string PropagationBaseObject::name() const {
2496 return solver_->GetName(this);
2497}
2498
2499void PropagationBaseObject::set_name(absl::string_view name) {
2500 solver_->SetName(this, name);
2501}
2502
2503bool PropagationBaseObject::HasName() const { return solver_->HasName(this); }
2504
2505std::string PropagationBaseObject::BaseName() const { return ""; }
2506
2508 solver_->ExecuteAll(demons);
2509}
2510
2512 solver_->EnqueueAll(demons);
2513}
2514
2515// ---------- Decision Builder ----------
2516
2517std::string DecisionBuilder::DebugString() const { return "DecisionBuilder"; }
2518
2519std::string DecisionBuilder::GetName() const {
2520 return name_.empty() ? DebugString() : name_;
2521}
2522
2524 Solver* const /*solver*/, std::vector<SearchMonitor*>* const /*extras*/) {}
2525
2526void DecisionBuilder::Accept(ModelVisitor* const /*visitor*/) const {}
2527
2528// ---------- Decision and DecisionVisitor ----------
2529
2530void Decision::Accept(DecisionVisitor* const visitor) const {
2531 visitor->VisitUnknownDecision();
2532}
2533
2535 [[maybe_unused]] int64_t value) {}
2537 [[maybe_unused]] IntVar* const var, [[maybe_unused]] int64_t value,
2538 [[maybe_unused]] bool start_with_lower_half) {}
2541 [[maybe_unused]] IntervalVar* const var, [[maybe_unused]] int64_t est) {}
2543 [[maybe_unused]] IntervalVar* const var, [[maybe_unused]] int64_t est) {}
2545 [[maybe_unused]] SequenceVar* const sequence, [[maybe_unused]] int index) {}
2546
2548 [[maybe_unused]] SequenceVar* const sequence, [[maybe_unused]] int index) {}
2549
2550// ---------- ModelVisitor ----------
2551
2552// Tags for constraints, arguments, extensions.
2553
2554const char ModelVisitor::kAbs[] = "Abs";
2555const char ModelVisitor::kAbsEqual[] = "AbsEqual";
2556const char ModelVisitor::kAllDifferent[] = "AllDifferent";
2557const char ModelVisitor::kAllowedAssignments[] = "AllowedAssignments";
2558const char ModelVisitor::kAtMost[] = "AtMost";
2559const char ModelVisitor::kBetween[] = "Between";
2560const char ModelVisitor::kConditionalExpr[] = "ConditionalExpr";
2561const char ModelVisitor::kCircuit[] = "Circuit";
2562const char ModelVisitor::kConvexPiecewise[] = "ConvexPiecewise";
2563const char ModelVisitor::kCountEqual[] = "CountEqual";
2564const char ModelVisitor::kCover[] = "Cover";
2565const char ModelVisitor::kCumulative[] = "Cumulative";
2566const char ModelVisitor::kDeviation[] = "Deviation";
2567const char ModelVisitor::kDifference[] = "Difference";
2568const char ModelVisitor::kDisjunctive[] = "Disjunctive";
2569const char ModelVisitor::kDistribute[] = "Distribute";
2570const char ModelVisitor::kDivide[] = "Divide";
2571const char ModelVisitor::kDurationExpr[] = "DurationExpression";
2572const char ModelVisitor::kElement[] = "Element";
2573const char ModelVisitor::kLightElementEqual[] = "LightElementEqual";
2574const char ModelVisitor::kElementEqual[] = "ElementEqual";
2575const char ModelVisitor::kEndExpr[] = "EndExpression";
2576const char ModelVisitor::kEquality[] = "Equal";
2577const char ModelVisitor::kFalseConstraint[] = "FalseConstraint";
2578const char ModelVisitor::kGlobalCardinality[] = "GlobalCardinality";
2579const char ModelVisitor::kGreater[] = "Greater";
2580const char ModelVisitor::kGreaterOrEqual[] = "GreaterOrEqual";
2581const char ModelVisitor::kIndexOf[] = "IndexOf";
2582const char ModelVisitor::kIntegerVariable[] = "IntegerVariable";
2583const char ModelVisitor::kIntervalBinaryRelation[] = "IntervalBinaryRelation";
2584const char ModelVisitor::kIntervalDisjunction[] = "IntervalDisjunction";
2585const char ModelVisitor::kIntervalUnaryRelation[] = "IntervalUnaryRelation";
2586const char ModelVisitor::kIntervalVariable[] = "IntervalVariable";
2587const char ModelVisitor::kInversePermutation[] = "InversePermutation";
2588const char ModelVisitor::kIsBetween[] = "IsBetween;";
2589const char ModelVisitor::kIsDifferent[] = "IsDifferent";
2590const char ModelVisitor::kIsEqual[] = "IsEqual";
2591const char ModelVisitor::kIsGreater[] = "IsGreater";
2592const char ModelVisitor::kIsGreaterOrEqual[] = "IsGreaterOrEqual";
2593const char ModelVisitor::kIsLess[] = "IsLess";
2594const char ModelVisitor::kIsLessOrEqual[] = "IsLessOrEqual";
2595const char ModelVisitor::kIsMember[] = "IsMember;";
2596const char ModelVisitor::kLess[] = "Less";
2597const char ModelVisitor::kLessOrEqual[] = "LessOrEqual";
2598const char ModelVisitor::kLexLess[] = "LexLess";
2599const char ModelVisitor::kLinkExprVar[] = "CastExpressionIntoVariable";
2600const char ModelVisitor::kMapDomain[] = "MapDomain";
2601const char ModelVisitor::kMax[] = "Max";
2602const char ModelVisitor::kMaxEqual[] = "MaxEqual";
2603const char ModelVisitor::kMember[] = "Member";
2604const char ModelVisitor::kMin[] = "Min";
2605const char ModelVisitor::kMinEqual[] = "MinEqual";
2606const char ModelVisitor::kModulo[] = "Modulo";
2607const char ModelVisitor::kNoCycle[] = "NoCycle";
2608const char ModelVisitor::kNonEqual[] = "NonEqual";
2609const char ModelVisitor::kNotBetween[] = "NotBetween";
2610const char ModelVisitor::kNotMember[] = "NotMember";
2611const char ModelVisitor::kNullIntersect[] = "NullIntersect";
2612const char ModelVisitor::kOpposite[] = "Opposite";
2613const char ModelVisitor::kPack[] = "Pack";
2614const char ModelVisitor::kPathCumul[] = "PathCumul";
2615const char ModelVisitor::kDelayedPathCumul[] = "DelayedPathCumul";
2616const char ModelVisitor::kPerformedExpr[] = "PerformedExpression";
2617const char ModelVisitor::kPower[] = "Power";
2618const char ModelVisitor::kProduct[] = "Product";
2619const char ModelVisitor::kScalProd[] = "ScalarProduct";
2620const char ModelVisitor::kScalProdEqual[] = "ScalarProductEqual";
2622 "ScalarProductGreaterOrEqual";
2623const char ModelVisitor::kScalProdLessOrEqual[] = "ScalarProductLessOrEqual";
2624const char ModelVisitor::kSemiContinuous[] = "SemiContinuous";
2625const char ModelVisitor::kSequenceVariable[] = "SequenceVariable";
2626const char ModelVisitor::kSortingConstraint[] = "SortingConstraint";
2627const char ModelVisitor::kSquare[] = "Square";
2628const char ModelVisitor::kStartExpr[] = "StartExpression";
2629const char ModelVisitor::kSum[] = "Sum";
2630const char ModelVisitor::kSumEqual[] = "SumEqual";
2631const char ModelVisitor::kSumGreaterOrEqual[] = "SumGreaterOrEqual";
2632const char ModelVisitor::kSumLessOrEqual[] = "SumLessOrEqual";
2633const char ModelVisitor::kTransition[] = "Transition";
2634const char ModelVisitor::kTrace[] = "Trace";
2635const char ModelVisitor::kTrueConstraint[] = "TrueConstraint";
2636const char ModelVisitor::kVarBoundWatcher[] = "VarBoundWatcher";
2637const char ModelVisitor::kVarValueWatcher[] = "VarValueWatcher";
2638
2639const char ModelVisitor::kCountAssignedItemsExtension[] = "CountAssignedItems";
2640const char ModelVisitor::kCountUsedBinsExtension[] = "CountUsedBins";
2641const char ModelVisitor::kInt64ToBoolExtension[] = "Int64ToBoolFunction";
2642const char ModelVisitor::kInt64ToInt64Extension[] = "Int64ToInt64Function";
2643const char ModelVisitor::kObjectiveExtension[] = "Objective";
2644const char ModelVisitor::kSearchLimitExtension[] = "SearchLimit";
2645const char ModelVisitor::kUsageEqualVariableExtension[] = "UsageEqualVariable";
2646
2647const char ModelVisitor::kUsageLessConstantExtension[] = "UsageLessConstant";
2648const char ModelVisitor::kVariableGroupExtension[] = "VariableGroup";
2650 "VariableUsageLessConstant";
2652 "WeightedSumOfAssignedEqualVariable";
2653
2654const char ModelVisitor::kActiveArgument[] = "active";
2655const char ModelVisitor::kAssumePathsArgument[] = "assume_paths";
2656const char ModelVisitor::kBranchesLimitArgument[] = "branches_limit";
2657const char ModelVisitor::kCapacityArgument[] = "capacity";
2658const char ModelVisitor::kCardsArgument[] = "cardinalities";
2659const char ModelVisitor::kCoefficientsArgument[] = "coefficients";
2660const char ModelVisitor::kCountArgument[] = "count";
2661const char ModelVisitor::kCumulativeArgument[] = "cumulative";
2662const char ModelVisitor::kCumulsArgument[] = "cumuls";
2663const char ModelVisitor::kDemandsArgument[] = "demands";
2664const char ModelVisitor::kDurationMinArgument[] = "duration_min";
2665const char ModelVisitor::kDurationMaxArgument[] = "duration_max";
2666const char ModelVisitor::kEarlyCostArgument[] = "early_cost";
2667const char ModelVisitor::kEarlyDateArgument[] = "early_date";
2668const char ModelVisitor::kEndMinArgument[] = "end_min";
2669const char ModelVisitor::kEndMaxArgument[] = "end_max";
2670const char ModelVisitor::kEndsArgument[] = "ends";
2671const char ModelVisitor::kExpressionArgument[] = "expression";
2672const char ModelVisitor::kFailuresLimitArgument[] = "failures_limit";
2673const char ModelVisitor::kFinalStatesArgument[] = "final_states";
2674const char ModelVisitor::kFixedChargeArgument[] = "fixed_charge";
2675const char ModelVisitor::kIndex2Argument[] = "index2";
2676const char ModelVisitor::kIndexArgument[] = "index";
2677const char ModelVisitor::kInitialState[] = "initial_state";
2678const char ModelVisitor::kIntervalArgument[] = "interval";
2679const char ModelVisitor::kIntervalsArgument[] = "intervals";
2680const char ModelVisitor::kLateCostArgument[] = "late_cost";
2681const char ModelVisitor::kLateDateArgument[] = "late_date";
2682const char ModelVisitor::kLeftArgument[] = "left";
2683const char ModelVisitor::kMaxArgument[] = "max_value";
2684const char ModelVisitor::kMaximizeArgument[] = "maximize";
2685const char ModelVisitor::kMinArgument[] = "min_value";
2686const char ModelVisitor::kModuloArgument[] = "modulo";
2687const char ModelVisitor::kNextsArgument[] = "nexts";
2688const char ModelVisitor::kOptionalArgument[] = "optional";
2689const char ModelVisitor::kPartialArgument[] = "partial";
2690const char ModelVisitor::kPositionXArgument[] = "position_x";
2691const char ModelVisitor::kPositionYArgument[] = "position_y";
2692const char ModelVisitor::kRangeArgument[] = "range";
2693const char ModelVisitor::kRelationArgument[] = "relation";
2694const char ModelVisitor::kRightArgument[] = "right";
2695const char ModelVisitor::kSequenceArgument[] = "sequence";
2696const char ModelVisitor::kSequencesArgument[] = "sequences";
2697const char ModelVisitor::kSmartTimeCheckArgument[] = "smart_time_check";
2698const char ModelVisitor::kSizeArgument[] = "size";
2699const char ModelVisitor::kSizeXArgument[] = "size_x";
2700const char ModelVisitor::kSizeYArgument[] = "size_y";
2701const char ModelVisitor::kSolutionLimitArgument[] = "solutions_limit";
2702const char ModelVisitor::kStartMinArgument[] = "start_min";
2703const char ModelVisitor::kStartMaxArgument[] = "start_max";
2704const char ModelVisitor::kStartsArgument[] = "starts";
2705const char ModelVisitor::kStepArgument[] = "step";
2706const char ModelVisitor::kTargetArgument[] = "target_variable";
2707const char ModelVisitor::kTimeLimitArgument[] = "time_limit";
2708const char ModelVisitor::kTransitsArgument[] = "transits";
2709const char ModelVisitor::kTuplesArgument[] = "tuples";
2710const char ModelVisitor::kValueArgument[] = "value";
2711const char ModelVisitor::kValuesArgument[] = "values";
2712const char ModelVisitor::kVarsArgument[] = "variables";
2713const char ModelVisitor::kEvaluatorArgument[] = "evaluator";
2714
2715const char ModelVisitor::kVariableArgument[] = "variable";
2716
2717const char ModelVisitor::kMirrorOperation[] = "mirror";
2718const char ModelVisitor::kRelaxedMaxOperation[] = "relaxed_max";
2719const char ModelVisitor::kRelaxedMinOperation[] = "relaxed_min";
2720const char ModelVisitor::kSumOperation[] = "sum";
2721const char ModelVisitor::kDifferenceOperation[] = "difference";
2722const char ModelVisitor::kProductOperation[] = "product";
2723const char ModelVisitor::kStartSyncOnStartOperation[] = "start_synced_on_start";
2724const char ModelVisitor::kStartSyncOnEndOperation[] = "start_synced_on_end";
2725const char ModelVisitor::kTraceOperation[] = "trace";
2726
2727// Methods
2728
2730
2732 [[maybe_unused]] const std::string& type_name) {}
2734 [[maybe_unused]] const std::string& type_name) {}
2735
2737 [[maybe_unused]] const std::string& type_name,
2738 [[maybe_unused]] const Constraint* const constraint) {}
2740 [[maybe_unused]] const std::string& type_name,
2741 [[maybe_unused]] const Constraint* const constraint) {}
2742
2744 [[maybe_unused]] const std::string& type) {}
2745void ModelVisitor::EndVisitExtension([[maybe_unused]] const std::string& type) {
2746}
2747
2749 [[maybe_unused]] const std::string& type_name,
2750 [[maybe_unused]] const IntExpr* const expr) {}
2752 [[maybe_unused]] const std::string& type_name,
2753 [[maybe_unused]] const IntExpr* const expr) {}
2754
2756 [[maybe_unused]] const IntVar* const variable, IntExpr* const delegate) {
2757 if (delegate != nullptr) {
2758 delegate->Accept(this);
2759 }
2760}
2761
2763 [[maybe_unused]] const IntVar* const variable,
2764 [[maybe_unused]] const std::string& operation,
2765 [[maybe_unused]] int64_t value, IntVar* const delegate) {
2766 if (delegate != nullptr) {
2767 delegate->Accept(this);
2768 }
2769}
2770
2772 [[maybe_unused]] const IntervalVar* const variable,
2773 [[maybe_unused]] const std::string& operation,
2774 [[maybe_unused]] int64_t value, IntervalVar* const delegate) {
2775 if (delegate != nullptr) {
2776 delegate->Accept(this);
2777 }
2778}
2779
2781 for (int i = 0; i < variable->size(); ++i) {
2782 variable->Interval(i)->Accept(this);
2783 }
2784}
2785
2787 [[maybe_unused]] const std::string& arg_name,
2788 [[maybe_unused]] int64_t value) {}
2789
2791 [[maybe_unused]] const std::string& arg_name,
2792 [[maybe_unused]] const std::vector<int64_t>& values) {}
2793
2795 [[maybe_unused]] const std::string& arg_name,
2796 [[maybe_unused]] const IntTupleSet& tuples) {}
2797
2799 [[maybe_unused]] const std::string& arg_name, IntExpr* const argument) {
2800 argument->Accept(this);
2801}
2802
2804 [[maybe_unused]] const std::string& arg_name,
2805 [[maybe_unused]] const Solver::Int64ToIntVar& arguments) {}
2806
2808 [[maybe_unused]] const std::string& arg_name,
2809 const std::vector<IntVar*>& arguments) {
2810 ForAll(arguments, &IntVar::Accept, this);
2811}
2812
2814 [[maybe_unused]] const std::string& arg_name, IntervalVar* const argument) {
2815 argument->Accept(this);
2816}
2817
2819 [[maybe_unused]] const std::string& arg_name,
2820 const std::vector<IntervalVar*>& arguments) {
2821 ForAll(arguments, &IntervalVar::Accept, this);
2822}
2823
2825 [[maybe_unused]] const std::string& arg_name, SequenceVar* const argument) {
2826 argument->Accept(this);
2827}
2828
2830 [[maybe_unused]] const std::string& arg_name,
2831 const std::vector<SequenceVar*>& arguments) {
2832 ForAll(arguments, &SequenceVar::Accept, this);
2833}
2834
2835// ----- Helpers -----
2836
2838 int64_t index_min,
2839 int64_t index_max) {
2840 if (filter != nullptr) {
2841 std::vector<int64_t> cached_results;
2842 for (int i = index_min; i <= index_max; ++i) {
2843 cached_results.push_back(filter(i));
2844 }
2850 }
2851}
2852
2854 const Solver::IndexEvaluator1& eval, int64_t index_min, int64_t index_max) {
2855 CHECK(eval != nullptr);
2856 std::vector<int64_t> cached_results;
2857 for (int i = index_min; i <= index_max; ++i) {
2858 cached_results.push_back(eval(i));
2859 }
2865}
2866
2868 const std::string& arg_name,
2869 int64_t index_max) {
2870 CHECK(eval != nullptr);
2871 std::vector<int64_t> cached_results;
2872 for (int i = 0; i <= index_max; ++i) {
2873 cached_results.push_back(eval(i));
2874 }
2875 VisitIntegerArrayArgument(arg_name, cached_results);
2876}
2877
2878// ---------- Search Monitor ----------
2879
2888 [[maybe_unused]] bool apply) {}
2893bool SearchMonitor::AcceptSolution() { return true; }
2894bool SearchMonitor::AtSolution() { return false; }
2896bool SearchMonitor::LocalOptimum() { return false; }
2898 [[maybe_unused]] Assignment* deltadelta) {
2899 return true;
2900}
2904void SearchMonitor::Accept([[maybe_unused]] ModelVisitor* const visitor) const {
2905}
2906// A search monitors adds itself on the active search.
2908 for (std::underlying_type<Solver::MonitorEvent>::type event = 0;
2909 event != to_underlying(Solver::MonitorEvent::kLast); ++event) {
2910 ListenToEvent(static_cast<Solver::MonitorEvent>(event));
2911 }
2912}
2913
2915 solver()->searches_.back()->AddEventListener(event, this);
2916}
2917
2918// ---------- Propagation Monitor -----------
2921
2923
2924// A propagation monitor listens to search events as well as propagation events.
2929
2930// ---------- Local Search Monitor -----------
2933
2935
2936// A local search monitor listens to search events as well as local search
2937// events.
2942
2943// ---------- Trace ----------
2944
2946 public:
2947 explicit Trace(Solver* const s) : PropagationMonitor(s) {}
2948
2949 ~Trace() override {}
2950
2952 Constraint* const constraint) override {
2954 constraint);
2955 }
2956
2957 void EndConstraintInitialPropagation(Constraint* const constraint) override {
2959 constraint);
2960 }
2961
2963 Constraint* const parent, Constraint* const nested) override {
2964 ForAll(monitors_,
2966 nested);
2967 }
2968
2970 Constraint* const parent, Constraint* const nested) override {
2971 ForAll(monitors_,
2973 nested);
2974 }
2975
2976 void RegisterDemon(Demon* const demon) override {
2977 ForAll(monitors_, &PropagationMonitor::RegisterDemon, demon);
2978 }
2979
2980 void BeginDemonRun(Demon* const demon) override {
2981 ForAll(monitors_, &PropagationMonitor::BeginDemonRun, demon);
2982 }
2983
2984 void EndDemonRun(Demon* const demon) override {
2985 ForAll(monitors_, &PropagationMonitor::EndDemonRun, demon);
2986 }
2987
2991
2994 }
2995
2996 void PushContext(const std::string& context) override {
2997 ForAll(monitors_, &PropagationMonitor::PushContext, context);
2998 }
2999
3000 void PopContext() override {
3001 ForAll(monitors_, &PropagationMonitor::PopContext);
3002 }
3003
3004 // IntExpr modifiers.
3005 void SetMin(IntExpr* const expr, int64_t new_min) override {
3006 for (PropagationMonitor* const monitor : monitors_) {
3007 monitor->SetMin(expr, new_min);
3008 }
3009 }
3010
3011 void SetMax(IntExpr* const expr, int64_t new_max) override {
3012 for (PropagationMonitor* const monitor : monitors_) {
3013 monitor->SetMax(expr, new_max);
3014 }
3015 }
3016
3017 void SetRange(IntExpr* const expr, int64_t new_min,
3018 int64_t new_max) override {
3019 for (PropagationMonitor* const monitor : monitors_) {
3020 monitor->SetRange(expr, new_min, new_max);
3021 }
3022 }
3023
3024 // IntVar modifiers.
3025 void SetMin(IntVar* const var, int64_t new_min) override {
3026 for (PropagationMonitor* const monitor : monitors_) {
3027 monitor->SetMin(var, new_min);
3028 }
3029 }
3030
3031 void SetMax(IntVar* const var, int64_t new_max) override {
3032 for (PropagationMonitor* const monitor : monitors_) {
3033 monitor->SetMax(var, new_max);
3034 }
3035 }
3036
3037 void SetRange(IntVar* const var, int64_t new_min, int64_t new_max) override {
3038 for (PropagationMonitor* const monitor : monitors_) {
3039 monitor->SetRange(var, new_min, new_max);
3040 }
3041 }
3042
3043 void RemoveValue(IntVar* const var, int64_t value) override {
3044 ForAll(monitors_, &PropagationMonitor::RemoveValue, var, value);
3045 }
3046
3047 void SetValue(IntVar* const var, int64_t value) override {
3048 ForAll(monitors_, &PropagationMonitor::SetValue, var, value);
3049 }
3050
3051 void RemoveInterval(IntVar* const var, int64_t imin, int64_t imax) override {
3052 ForAll(monitors_, &PropagationMonitor::RemoveInterval, var, imin, imax);
3053 }
3054
3055 void SetValues(IntVar* const var,
3056 const std::vector<int64_t>& values) override {
3057 ForAll(monitors_, &PropagationMonitor::SetValues, var, values);
3058 }
3059
3061 const std::vector<int64_t>& values) override {
3062 ForAll(monitors_, &PropagationMonitor::RemoveValues, var, values);
3063 }
3064
3065 // IntervalVar modifiers.
3066 void SetStartMin(IntervalVar* const var, int64_t new_min) override {
3067 ForAll(monitors_, &PropagationMonitor::SetStartMin, var, new_min);
3068 }
3069
3070 void SetStartMax(IntervalVar* const var, int64_t new_max) override {
3071 ForAll(monitors_, &PropagationMonitor::SetStartMax, var, new_max);
3072 }
3073
3074 void SetStartRange(IntervalVar* const var, int64_t new_min,
3075 int64_t new_max) override {
3076 ForAll(monitors_, &PropagationMonitor::SetStartRange, var, new_min,
3077 new_max);
3078 }
3079
3080 void SetEndMin(IntervalVar* const var, int64_t new_min) override {
3081 ForAll(monitors_, &PropagationMonitor::SetEndMin, var, new_min);
3082 }
3083
3084 void SetEndMax(IntervalVar* const var, int64_t new_max) override {
3085 ForAll(monitors_, &PropagationMonitor::SetEndMax, var, new_max);
3086 }
3087
3088 void SetEndRange(IntervalVar* const var, int64_t new_min,
3089 int64_t new_max) override {
3090 ForAll(monitors_, &PropagationMonitor::SetEndRange, var, new_min, new_max);
3091 }
3092
3093 void SetDurationMin(IntervalVar* const var, int64_t new_min) override {
3094 ForAll(monitors_, &PropagationMonitor::SetDurationMin, var, new_min);
3095 }
3096
3097 void SetDurationMax(IntervalVar* const var, int64_t new_max) override {
3098 ForAll(monitors_, &PropagationMonitor::SetDurationMax, var, new_max);
3099 }
3100
3101 void SetDurationRange(IntervalVar* const var, int64_t new_min,
3102 int64_t new_max) override {
3103 ForAll(monitors_, &PropagationMonitor::SetDurationRange, var, new_min,
3104 new_max);
3105 }
3106
3107 void SetPerformed(IntervalVar* const var, bool value) override {
3108 ForAll(monitors_, &PropagationMonitor::SetPerformed, var, value);
3109 }
3110
3111 void RankFirst(SequenceVar* const var, int index) override {
3112 ForAll(monitors_, &PropagationMonitor::RankFirst, var, index);
3113 }
3114
3115 void RankNotFirst(SequenceVar* const var, int index) override {
3116 ForAll(monitors_, &PropagationMonitor::RankNotFirst, var, index);
3117 }
3118
3119 void RankLast(SequenceVar* const var, int index) override {
3120 ForAll(monitors_, &PropagationMonitor::RankLast, var, index);
3121 }
3122
3123 void RankNotLast(SequenceVar* const var, int index) override {
3124 ForAll(monitors_, &PropagationMonitor::RankNotLast, var, index);
3125 }
3126
3127 void RankSequence(SequenceVar* const var, const std::vector<int>& rank_first,
3128 const std::vector<int>& rank_last,
3129 const std::vector<int>& unperformed) override {
3130 ForAll(monitors_, &PropagationMonitor::RankSequence, var, rank_first,
3131 rank_last, unperformed);
3132 }
3133
3134 // Does not take ownership of monitor.
3135 void Add(PropagationMonitor* const monitor) {
3136 if (monitor != nullptr) {
3137 monitors_.push_back(monitor);
3138 }
3139 }
3140
3141 // The trace will dispatch propagation events. It needs to listen to search
3142 // events.
3143 void Install() override { SearchMonitor::Install(); }
3144
3145 std::string DebugString() const override { return "Trace"; }
3146
3147 private:
3148 std::vector<PropagationMonitor*> monitors_;
3149};
3150
3151PropagationMonitor* BuildTrace(Solver* const s) { return new Trace(s); }
3152
3154 // TODO(user): Check solver state?
3155 reinterpret_cast<class Trace*>(propagation_monitor_.get())->Add(monitor);
3156}
3157
3159 return propagation_monitor_.get();
3160}
3161
3162// ---------- Local Search Monitor Primary ----------
3163
3165 public:
3168
3169 void BeginOperatorStart() override {
3170 ForAll(monitors_, &LocalSearchMonitor::BeginOperatorStart);
3171 }
3172 void EndOperatorStart() override {
3173 ForAll(monitors_, &LocalSearchMonitor::EndOperatorStart);
3174 }
3176 ForAll(monitors_, &LocalSearchMonitor::BeginMakeNextNeighbor, op);
3177 }
3178 void EndMakeNextNeighbor(const LocalSearchOperator* op, bool neighbor_found,
3179 const Assignment* delta,
3180 const Assignment* deltadelta) override {
3181 ForAll(monitors_, &LocalSearchMonitor::EndMakeNextNeighbor, op,
3182 neighbor_found, delta, deltadelta);
3183 }
3184 void BeginFilterNeighbor(const LocalSearchOperator* op) override {
3185 ForAll(monitors_, &LocalSearchMonitor::BeginFilterNeighbor, op);
3186 }
3188 bool neighbor_found) override {
3189 ForAll(monitors_, &LocalSearchMonitor::EndFilterNeighbor, op,
3190 neighbor_found);
3191 }
3192 void BeginAcceptNeighbor(const LocalSearchOperator* op) override {
3193 ForAll(monitors_, &LocalSearchMonitor::BeginAcceptNeighbor, op);
3194 }
3196 bool neighbor_found) override {
3197 ForAll(monitors_, &LocalSearchMonitor::EndAcceptNeighbor, op,
3198 neighbor_found);
3199 }
3200 void BeginFiltering(const LocalSearchFilter* filter) override {
3201 ForAll(monitors_, &LocalSearchMonitor::BeginFiltering, filter);
3202 }
3203 void EndFiltering(const LocalSearchFilter* filter, bool reject) override {
3204 ForAll(monitors_, &LocalSearchMonitor::EndFiltering, filter, reject);
3205 }
3206 bool IsActive() const override { return !monitors_.empty(); }
3207
3208 // Does not take ownership of monitor.
3209 void Add(LocalSearchMonitor* monitor) {
3210 if (monitor != nullptr) {
3211 monitors_.push_back(monitor);
3212 }
3213 }
3214
3215 // The trace will dispatch propagation events. It needs to listen to search
3216 // events.
3217 void Install() override { SearchMonitor::Install(); }
3218
3219 std::string DebugString() const override {
3220 return "LocalSearchMonitorPrimary";
3221 }
3222
3223 private:
3224 std::vector<LocalSearchMonitor*> monitors_;
3225};
3226
3230
3232 reinterpret_cast<class LocalSearchMonitorPrimary*>(
3233 local_search_monitor_.get())
3234 ->Add(monitor);
3235}
3236
3238 return local_search_monitor_.get();
3239}
3240
3242 absl::string_view search_context) {
3243 search->set_search_context(search_context);
3244}
3245
3246std::string Solver::SearchContext() const {
3247 return ActiveSearch()->search_context();
3248}
3249
3250std::string Solver::SearchContext(const Search* search) const {
3251 return search->search_context();
3252}
3253
3255 if (local_search_state_ == nullptr) {
3256 local_search_state_ = std::make_unique<Assignment>(this);
3257 }
3258 return local_search_state_.get();
3259}
3260
3261// ----------------- ProfiledDecisionBuilder ------------
3262
3264 : db_(db), name_(db_->GetName()), seconds_(0) {}
3265
3267 timer_.Start();
3268 solver->set_context(name());
3269 // In case db_->Next() fails, gathering the running time on backtrack.
3270 solver->AddBacktrackAction(
3271 [this](Solver* solver) {
3272 if (timer_.IsRunning()) {
3273 timer_.Stop();
3274 seconds_ += timer_.Get();
3275 }
3276 solver->set_context("");
3277 },
3278 true);
3279 Decision* const decision = db_->Next(solver);
3280 timer_.Stop();
3281 seconds_ += timer_.Get();
3282 return decision;
3283}
3284
3286 return db_->DebugString();
3287}
3288
3290 Solver* const solver, std::vector<SearchMonitor*>* const extras) {
3291 db_->AppendMonitors(solver, extras);
3292}
3293
3295 db_->Accept(visitor);
3296}
3297
3298// ----------------- Constraint class -------------------
3299
3300std::string Constraint::DebugString() const { return "Constraint"; }
3301
3303 FreezeQueue();
3304 Post();
3306 solver()->CheckFail();
3307 UnfreezeQueue();
3308}
3309
3310void Constraint::Accept(ModelVisitor* const visitor) const {
3311 visitor->BeginVisitConstraint("unknown", this);
3312 VLOG(3) << "Unknown constraint " << DebugString();
3313 visitor->EndVisitConstraint("unknown", this);
3314}
3315
3317 return solver()->cast_constraints_.contains(this);
3318}
3319
3320IntVar* Constraint::Var() { return nullptr; }
3321
3322// ----- Class IntExpr -----
3323
3324void IntExpr::Accept(ModelVisitor* const visitor) const {
3325 visitor->BeginVisitIntegerExpression("unknown", this);
3326 VLOG(3) << "Unknown expression " << DebugString();
3327 visitor->EndVisitIntegerExpression("unknown", this);
3328}
3329
3330#undef CP_TRY // We no longer need those.
3331#undef CP_ON_FAIL
3332#undef CP_DO_FAIL
3333
3334} // namespace operations_research
IntegerValue size
bool IsRunning() const
Definition timer.h:52
double Get() const
Definition timer.h:46
void Start()
When Start() is called multiple times, only the most recent is used.
Definition timer.h:32
void Stop()
Definition timer.h:40
virtual std::string DebugString() const
std::string DebugString() const override
--------------— Constraint class ----------------—
virtual void InitialPropagate()=0
bool IsCastConstraint() const
Is the constraint created by a cast from expression to integer variable?
virtual void Accept(ModelVisitor *visitor) const
Accepts the given visitor.
virtual Decision * Next(Solver *s)=0
virtual void Accept(ModelVisitor *visitor) const
virtual void AppendMonitors(Solver *solver, std::vector< SearchMonitor * > *extras)
std::string DebugString() const override
-------— Decision Builder -------—
virtual void VisitRankFirstInterval(SequenceVar *sequence, int index)
virtual void VisitSetVariableValue(IntVar *var, int64_t value)
virtual void VisitScheduleOrPostpone(IntervalVar *var, int64_t est)
virtual void VisitRankLastInterval(SequenceVar *sequence, int index)
virtual void VisitScheduleOrExpedite(IntervalVar *var, int64_t est)
virtual void VisitSplitVariableDomain(IntVar *var, int64_t value, bool start_with_lower_half)
virtual void Refute(Solver *s)=0
Refute will be called after a backtrack.
virtual void Apply(Solver *s)=0
Apply will be called first when the decision is executed.
virtual void Accept(DecisionVisitor *visitor) const
Accepts the given visitor.
virtual void Run(Solver *s)=0
This is the main callback of the demon.
virtual Solver::DemonPriority priority() const
---------------— Demon class -------------—
std::string DebugString() const override
void desinhibit(Solver *s)
This method un-inhibits the demon that was previously inhibited.
virtual void Accept(ModelVisitor *visitor) const
Accepts the given visitor.
--— Main IntTupleSet class --—
Definition tuple_set.h:47
void Accept(ModelVisitor *visitor) const override
Accepts the given visitor.
virtual void Accept(ModelVisitor *visitor) const =0
Accepts the given visitor.
-------— Local Search Monitor Primary -------—
void EndMakeNextNeighbor(const LocalSearchOperator *op, bool neighbor_found, const Assignment *delta, const Assignment *deltadelta) override
void BeginOperatorStart() override
Local search operator events.
void EndAcceptNeighbor(const LocalSearchOperator *op, bool neighbor_found) override
void EndFilterNeighbor(const LocalSearchOperator *op, bool neighbor_found) override
void BeginMakeNextNeighbor(const LocalSearchOperator *op) override
void BeginAcceptNeighbor(const LocalSearchOperator *op) override
void Add(LocalSearchMonitor *monitor)
Does not take ownership of monitor.
void BeginFilterNeighbor(const LocalSearchOperator *op) override
void EndFiltering(const LocalSearchFilter *filter, bool reject) override
void BeginFiltering(const LocalSearchFilter *filter) override
LocalSearchMonitor(Solver *solver)
-------— Local Search Monitor --------—
virtual void EndAcceptNeighbor(const LocalSearchOperator *op, bool neighbor_found)=0
virtual void BeginAcceptNeighbor(const LocalSearchOperator *op)=0
virtual void BeginMakeNextNeighbor(const LocalSearchOperator *op)=0
virtual void BeginOperatorStart()=0
Local search operator events.
virtual void BeginFilterNeighbor(const LocalSearchOperator *op)=0
void Install() override
Install itself on the solver.
virtual void BeginFiltering(const LocalSearchFilter *filter)=0
virtual void EndFilterNeighbor(const LocalSearchOperator *op, bool neighbor_found)=0
virtual void EndMakeNextNeighbor(const LocalSearchOperator *op, bool neighbor_found, const Assignment *delta, const Assignment *deltadelta)=0
virtual void EndFiltering(const LocalSearchFilter *filter, bool reject)=0
--— LocalSearchProfiler --—
virtual void VisitSequenceVariable(const SequenceVar *variable)
virtual void VisitIntervalArrayArgument(const std::string &arg_name, const std::vector< IntervalVar * > &arguments)
virtual void VisitIntervalArgument(const std::string &arg_name, IntervalVar *argument)
Visit interval argument.
static const char kVariableUsageLessConstantExtension[]
void VisitInt64ToBoolExtension(Solver::IndexFilter1 filter, int64_t index_min, int64_t index_max)
--— Helpers --—
void VisitInt64ToInt64AsArray(const Solver::IndexEvaluator1 &eval, const std::string &arg_name, int64_t index_max)
Expands function as array when index min is 0.
static const char kMirrorOperation[]
Operations.
static const char kActiveArgument[]
argument names:
virtual void BeginVisitModel(const std::string &type_name)
--— Virtual methods for visitors --—
virtual void BeginVisitIntegerExpression(const std::string &type_name, const IntExpr *expr)
virtual void VisitIntegerArgument(const std::string &arg_name, int64_t value)
Visit integer arguments.
virtual void VisitIntegerVariable(const IntVar *variable, IntExpr *delegate)
virtual void VisitSequenceArrayArgument(const std::string &arg_name, const std::vector< SequenceVar * > &arguments)
virtual void VisitIntegerMatrixArgument(const std::string &arg_name, const IntTupleSet &tuples)
virtual void VisitIntegerVariableEvaluatorArgument(const std::string &arg_name, const Solver::Int64ToIntVar &arguments)
Helpers.
static const char kStartSyncOnStartOperation[]
virtual void EndVisitModel(const std::string &type_name)
virtual void VisitIntegerExpressionArgument(const std::string &arg_name, IntExpr *argument)
Visit integer expression argument.
virtual void VisitIntegerVariableArrayArgument(const std::string &arg_name, const std::vector< IntVar * > &arguments)
virtual void VisitIntegerArrayArgument(const std::string &arg_name, const std::vector< int64_t > &values)
static const char kUsageLessConstantExtension[]
virtual void BeginVisitConstraint(const std::string &type_name, const Constraint *constraint)
virtual void EndVisitExtension(const std::string &type)
static const char kUsageEqualVariableExtension[]
static const char kCountAssignedItemsExtension[]
Extension names:
virtual void VisitIntervalVariable(const IntervalVar *variable, const std::string &operation, int64_t value, IntervalVar *delegate)
void VisitInt64ToInt64Extension(const Solver::IndexEvaluator1 &eval, int64_t index_min, int64_t index_max)
virtual void BeginVisitExtension(const std::string &type)
static const char kWeightedSumOfAssignedEqualVariableExtension[]
virtual void VisitSequenceArgument(const std::string &arg_name, SequenceVar *argument)
Visit sequence argument.
virtual void EndVisitIntegerExpression(const std::string &type_name, const IntExpr *expr)
static const char kAbs[]
Constraint and Expression types.
virtual void EndVisitConstraint(const std::string &type_name, const Constraint *constraint)
ProfiledDecisionBuilder(DecisionBuilder *db)
--------------— ProfiledDecisionBuilder ---------—
std::string DebugString() const override
-------— Decision Builder -------—
Decision * Next(Solver *solver) override
void Accept(ModelVisitor *visitor) const override
void AppendMonitors(Solver *solver, std::vector< SearchMonitor * > *extras) override
void ExecuteAll(const SimpleRevFIFO< Demon * > &demons)
virtual std::string name() const
Object naming.
void EnqueueAll(const SimpleRevFIFO< Demon * > &demons)
virtual std::string BaseName() const
Returns a base name for automatic naming.
bool HasName() const
Returns whether the object has been named or not.
virtual void SetValues(IntVar *var, const std::vector< int64_t > &values)=0
virtual void SetDurationMax(IntervalVar *var, int64_t new_max)=0
virtual void SetStartMax(IntervalVar *var, int64_t new_max)=0
virtual void SetStartMin(IntervalVar *var, int64_t new_min)=0
IntervalVar modifiers.
virtual void RankSequence(SequenceVar *var, const std::vector< int > &rank_first, const std::vector< int > &rank_last, const std::vector< int > &unperformed)=0
virtual void RankNotFirst(SequenceVar *var, int index)=0
virtual void BeginNestedConstraintInitialPropagation(Constraint *parent, Constraint *nested)=0
virtual void RankNotLast(SequenceVar *var, int index)=0
virtual void PushContext(const std::string &context)=0
virtual void SetPerformed(IntervalVar *var, bool value)=0
virtual void SetEndMax(IntervalVar *var, int64_t new_max)=0
virtual void RemoveValue(IntVar *var, int64_t value)=0
virtual void BeginConstraintInitialPropagation(Constraint *constraint)=0
Propagation events.
virtual void EndDemonRun(Demon *demon)=0
virtual void SetDurationMin(IntervalVar *var, int64_t new_min)=0
virtual void RegisterDemon(Demon *demon)=0
virtual void SetEndMin(IntervalVar *var, int64_t new_min)=0
virtual void RankFirst(SequenceVar *var, int index)=0
SequenceVar modifiers.
virtual void RankLast(SequenceVar *var, int index)=0
virtual void SetDurationRange(IntervalVar *var, int64_t new_min, int64_t new_max)=0
virtual void EndNestedConstraintInitialPropagation(Constraint *parent, Constraint *nested)=0
PropagationMonitor(Solver *solver)
-------— Propagation Monitor --------—
virtual void StartProcessingIntegerVariable(IntVar *var)=0
virtual void EndProcessingIntegerVariable(IntVar *var)=0
void Install() override
Install itself on the solver.
virtual void RemoveInterval(IntVar *var, int64_t imin, int64_t imax)=0
virtual void BeginDemonRun(Demon *demon)=0
virtual void RemoveValues(IntVar *var, const std::vector< int64_t > &values)=0
virtual void SetStartRange(IntervalVar *var, int64_t new_min, int64_t new_max)=0
virtual void EndConstraintInitialPropagation(Constraint *constraint)=0
virtual void SetValue(IntVar *var, int64_t value)=0
virtual void SetEndRange(IntervalVar *var, int64_t new_min, int64_t new_max)=0
void ProcessOneDemon(Demon *const demon)
void EnqueueDelayedDemon(Demon *const demon)
void EnqueueVar(Demon *const demon)
void AddConstraint(Constraint *const c)
static constexpr int64_t kTestPeriod
void set_action_on_fail(Solver::Action a)
void ExecuteAll(const SimpleRevFIFO< Demon * > &demons)
void set_variable_to_clean_on_fail(IntVar *var)
void EnqueueAll(const SimpleRevFIFO< Demon * > &demons)
A search monitor is a simple set of callbacks to monitor all search events.
virtual void Install()
A search monitors adds itself on the active search.
virtual void BeginInitialPropagation()
Before the initial propagation.
virtual void EndFail()
After completing the backtrack.
virtual void RestartSearch()
Restart the search.
virtual void EndInitialPropagation()
After the initial propagation.
virtual bool AcceptDelta(Assignment *delta, Assignment *deltadelta)
virtual void BeginNextDecision(DecisionBuilder *b)
Before calling DecisionBuilder::Next.
virtual void RefuteDecision(Decision *d)
Before refuting the decision.
virtual void EndNextDecision(DecisionBuilder *b, Decision *d)
After calling DecisionBuilder::Next, along with the returned decision.
virtual void ApplyDecision(Decision *d)
Before applying the decision.
virtual void Accept(ModelVisitor *visitor) const
Accepts the given model visitor.
virtual void ExitSearch()
End of the search.
virtual void PeriodicCheck()
Periodic call to check limits in long running methods.
virtual void NoMoreSolutions()
When the search tree is finished.
void ListenToEvent(Solver::MonitorEvent event)
virtual void BeginFail()
Just when the failure occurs.
virtual void EnterSearch()
Beginning of the search.
virtual void AfterDecision(Decision *d, bool apply)
virtual void AcceptNeighbor()
After accepting a neighbor during local search.
virtual void AcceptUncheckedNeighbor()
After accepting an unchecked neighbor during local search.
---------------— Search class --------------—
void set_search_context(absl::string_view search_context)
void AddEventListener(Solver::MonitorEvent event, SearchMonitor *monitor)
bool AcceptDelta(Assignment *delta, Assignment *deltadelta)
void set_decision_builder(DecisionBuilder *const db)
void BeginNextDecision(DecisionBuilder *db)
void set_backtrack_at_the_end_of_the_search(bool restore)
void Accept(ModelVisitor *visitor) const
DecisionBuilder * decision_builder() const
Solver::DecisionModification ModifyDecision()
const std::vector< SearchMonitor * > & GetEventListeners(Solver::MonitorEvent event) const
void EndNextDecision(DecisionBuilder *db, Decision *d)
void SetBranchSelector(Solver::BranchSelector bs)
void AfterDecision(Decision *d, bool apply)
virtual void Accept(ModelVisitor *visitor) const
Accepts the given visitor.
IntervalVar * Interval(int index) const
Returns the index_th interval of the sequence.
int64_t size() const
Returns the number of interval vars in the sequence.
This iterator is not stable with respect to deletion.
For the time being, Solver is neither MT_SAFE nor MT_HOT.
static ConstraintSolverParameters DefaultSolverParameters()
--— ConstraintSolverParameters --—
void SetBranchSelector(BranchSelector bs)
Sets the given branch selector on the current active search.
Search * ActiveSearch() const
Returns the active search, nullptr outside search.
bool IsLocalSearchProfilingEnabled() const
Returns whether we are profiling local search.
void ExportProfilingOverview(const std::string &filename)
bool NextSolution()
Search for the next solution in the search tree.
uint64_t fail_stamp() const
The fail_stamp() is incremented after each backtrack.
DecisionBuilder * MakeApplyBranchSelector(BranchSelector bs)
Creates a decision builder that will set the branch selector.
DecisionBuilder * MakeRestoreAssignment(Assignment *assignment)
int64_t branches() const
The number of branches explored since the creation of the solver.
std::function< DecisionModification()> BranchSelector
int64_t solutions() const
The number of solutions found since the start of the search.
bool NameAllVariables() const
Returns whether all variables should be named.
void AddPropagationMonitor(PropagationMonitor *monitor)
static constexpr int kNumPriorities
Number of priorities for demons.
void Fail()
Abandon the current branch in the search tree. A backtrack will follow.
@ NORMAL_PRIORITY
NORMAL_PRIORITY is the highest priority: Demons will be processed first.
@ VAR_PRIORITY
VAR_PRIORITY is between DELAYED_PRIORITY and NORMAL_PRIORITY.
std::function< void(Solver *)> Action
void NewSearch(DecisionBuilder *db, const std::vector< SearchMonitor * > &monitors)
Opens a new top level search.
std::function< bool(int64_t)> IndexFilter1
LocalSearchMonitor * GetLocalSearchMonitor() const
Returns the local search monitor.
@ IN_SEARCH
Executing the search code.
@ IN_ROOT_NODE
Executing the root node.
@ PROBLEM_INFEASIBLE
After search, the model is infeasible.
@ NO_MORE_SOLUTIONS
After failed NextSolution and before EndSearch.
@ OUTSIDE_SEARCH
Before search, after search.
@ AT_SOLUTION
After successful NextSolution and before EndSearch.
void set_context(absl::string_view context)
Sets the current context of the search.
std::string LocalSearchProfile() const
bool CheckAssignment(Assignment *solution)
Checks whether the given assignment satisfies all relevant constraints.
void AddBacktrackAction(Action a, bool fast)
void SaveAndSetValue(T *adr, T val)
All-in-one SaveAndSetValue.
std::string model_name() const
Returns the name of the model.
ConstraintSolverStatistics GetConstraintSolverStatistics() const
Returns detailed cp search statistics.
IntExpr * CastExpression(const IntVar *var) const
!defined(SWIG)
DecisionBuilder * MakeConstraintAdder(Constraint *ct)
int64_t unchecked_solutions() const
The number of unchecked solutions found by local search.
void FinishCurrentSearch()
Tells the solver to kill or restart the current search.
void Accept(ModelVisitor *visitor) const
Accepts the given model visitor.
bool IsProfilingEnabled() const
Returns whether we are profiling the solver.
MonitorEvent
Search monitor events.
@ kLast
Dummy event whose underlying int is the number of MonitorEvent enums.
SearchMonitor * MakeSearchTrace(const std::string &prefix)
Definition search.cc:436
std::function< IntVar *(int64_t)> Int64ToIntVar
bool HasName(const PropagationBaseObject *object) const
Returns whether the object has been named or not.
void SetSearchContext(Search *search, absl::string_view search_context)
std::string DebugString() const
!defined(SWIG)
bool Solve(DecisionBuilder *db, const std::vector< SearchMonitor * > &monitors)
ModelVisitor * MakePrintModelVisitor()
Prints the model.
Definition utilities.cc:814
Constraint * MakeFalseConstraint()
This constraint always fails.
std::function< int64_t(int64_t)> IndexEvaluator1
Callback typedefs.
int64_t failures() const
The number of failures encountered since the creation of the solver.
bool CheckConstraint(Constraint *ct)
bool InstrumentsDemons() const
Returns whether we are instrumenting demons.
PropagationMonitor * GetPropagationMonitor() const
Returns the propagation monitor.
Solver(const std::string &name)
Solver API.
bool InstrumentsVariables() const
Returns whether we are tracing variables.
void AddLocalSearchMonitor(LocalSearchMonitor *monitor)
static int64_t MemoryUsage()
Current memory usage in bytes.
ModelVisitor * MakeStatisticsModelVisitor()
Displays some nice statistics on the model.
Definition utilities.cc:818
bool SolveAndCommit(DecisionBuilder *db, const std::vector< SearchMonitor * > &monitors)
void AddCastConstraint(CastConstraint *constraint, IntVar *target_var, IntExpr *expr)
-------— Trace -------—
void BeginDemonRun(Demon *const demon) override
void RegisterDemon(Demon *const demon) override
void RemoveInterval(IntVar *const var, int64_t imin, int64_t imax) override
void RemoveValues(IntVar *const var, const std::vector< int64_t > &values) override
void RankNotFirst(SequenceVar *const var, int index) override
void BeginNestedConstraintInitialPropagation(Constraint *const parent, Constraint *const nested) override
void RankLast(SequenceVar *const var, int index) override
void SetMax(IntExpr *const expr, int64_t new_max) override
void SetEndMin(IntervalVar *const var, int64_t new_min) override
void SetMin(IntExpr *const expr, int64_t new_min) override
IntExpr modifiers.
void SetMax(IntVar *const var, int64_t new_max) override
void Add(PropagationMonitor *const monitor)
Does not take ownership of monitor.
void BeginConstraintInitialPropagation(Constraint *const constraint) override
Propagation events.
void RankSequence(SequenceVar *const var, const std::vector< int > &rank_first, const std::vector< int > &rank_last, const std::vector< int > &unperformed) override
void SetMin(IntVar *const var, int64_t new_min) override
IntVar modifiers.
void SetRange(IntExpr *const expr, int64_t new_min, int64_t new_max) override
void SetStartRange(IntervalVar *const var, int64_t new_min, int64_t new_max) override
void SetValue(IntVar *const var, int64_t value) override
std::string DebugString() const override
void SetRange(IntVar *const var, int64_t new_min, int64_t new_max) override
void SetStartMin(IntervalVar *const var, int64_t new_min) override
IntervalVar modifiers.
void SetEndRange(IntervalVar *const var, int64_t new_min, int64_t new_max) override
void SetPerformed(IntervalVar *const var, bool value) override
void SetValues(IntVar *const var, const std::vector< int64_t > &values) override
void PushContext(const std::string &context) override
void RemoveValue(IntVar *const var, int64_t value) override
void EndConstraintInitialPropagation(Constraint *const constraint) override
void RankFirst(SequenceVar *const var, int index) override
SequenceVar modifiers.
void SetStartMax(IntervalVar *const var, int64_t new_max) override
void EndProcessingIntegerVariable(IntVar *const var) override
void EndDemonRun(Demon *const demon) override
void SetDurationMax(IntervalVar *const var, int64_t new_max) override
void SetDurationRange(IntervalVar *const var, int64_t new_min, int64_t new_max) override
void EndNestedConstraintInitialPropagation(Constraint *const parent, Constraint *const nested) override
void SetDurationMin(IntervalVar *const var, int64_t new_min) override
void SetEndMax(IntervalVar *const var, int64_t new_max) override
void StartProcessingIntegerVariable(IntVar *const var) override
void RankNotLast(SequenceVar *const var, int index) override
int64_t a
Definition table.cc:44
Block * next
#define CP_ON_FAIL
#define CP_TRY(search)
#define CP_DO_FAIL(search)
ABSL_FLAG(bool, cp_trace_propagation, false, "Trace propagation events (constraint and demon executions," " variable modifications).")
These flags are used to set the fields in the DefaultSolverParameters proto.
void ConstraintSolverFailsHere()
#define CALL_EVENT_LISTENERS(Event)
std::string compressed
SatParameters parameters
const std::string name
A name for logging purposes.
const Constraint * ct
int64_t value
IntVar * var
GurobiMPCallbackContext * context
int index
double solution
void STLDeleteElements(T *container)
Definition stl_util.h:372
const Collection::value_type::second_type * FindOrNull(const Collection &collection, const typename Collection::value_type::first_type &key)
Definition map_util.h:65
For infeasible and unbounded see Not checked if options check_solutions_if_inf_or_unbounded and the If options first_solution_only is false
problem is infeasible or unbounded (default).
Definition matchers.h:468
In SWIG mode, we don't want anything besides these top-level includes.
void DeleteLocalSearchProfiler(LocalSearchProfiler *monitor)
void InternalSaveBooleanVarValue(Solver *const solver, IntVar *const var)
void DeleteDemonProfiler(DemonProfiler *monitor)
int64_t GetProcessMemoryUsage()
GetProcessMemoryUsage.
Definition sysinfo.cc:88
void RestoreBoolValue(IntVar *var)
--— Trail --—
ModelCache * BuildModelCache(Solver *solver)
PropagationMonitor * BuildTrace(Solver *s)
void AcceptNeighbor(Search *search)
Notifies the search that a neighbor has been accepted by local search.
void AcceptUncheckedNeighbor(Search *search)
DemonProfiler * BuildDemonProfiler(Solver *solver)
bool LocalOptimumReached(Search *search)
Returns true if a local optimum has been reached and cannot be improved.
std::ostream & operator<<(std::ostream &out, const Assignment &assignment)
LocalSearchMonitor * BuildLocalSearchMonitorPrimary(Solver *s)
void InstallLocalSearchProfiler(LocalSearchProfiler *monitor)
LocalSearchProfiler * BuildLocalSearchProfiler(Solver *solver)
PropagationMonitor * BuildPrintTrace(Solver *s)
Definition trace.cc:877
void InstallDemonProfiler(DemonProfiler *monitor)
--— Forward Declarations and Profiling Support --—
void CleanVariableOnFail(IntVar *var)
---------------— Queue class ---------------—
bool AcceptDelta(Search *search, Assignment *delta, Assignment *deltadelta)
STL namespace.
bool Next()
int64_t delta
Definition resource.cc:1709
---------------— StateMarker / StateInfo struct --------—
StateInfo(Solver::Action a, bool fast)
StateInfo(void *pinfo, int iinfo)
StateInfo(void *pinfo, int iinfo, int d, int ld)
StateInfo()
additional information on the choice point.
StateMarker(Solver::MarkerType t, const StateInfo &info)
std::vector< int * > rev_int_memory_
std::vector< IntVar * > rev_boolvar_list_
CompressedTrail< int64_t > rev_int64s_
CompressedTrail< int > rev_ints_
std::vector< BaseObject * > rev_object_memory_
CompressedTrail< double > rev_doubles_
std::vector< double * > rev_double_memory_
std::vector< void ** > rev_memory_array_
void BacktrackTo(StateMarker *m)
std::vector< int64_t * > rev_int64_memory_
std::vector< void * > rev_memory_
CompressedTrail< uint64_t > rev_uint64s_
std::vector< bool * > rev_bools_
Trail(int block_size, ConstraintSolverParameters::TrailCompression compression_level)
std::vector< bool > rev_bool_value_
CompressedTrail< void * > rev_ptrs_
std::vector< BaseObject ** > rev_object_array_memory_