Google OR-Tools v9.15
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-2025 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// This file implements the core objects of the constraint solver:
15// Solver, Search, Queue, ... along with the main resolution loop.
16
18
19#include <algorithm>
20#include <csetjmp>
21#include <cstdint>
22#include <deque>
23#include <iosfwd>
24#include <limits>
25#include <memory>
26#include <ostream>
27#include <string>
28#include <type_traits>
29#include <utility>
30#include <vector>
31
32#include "absl/flags/flag.h"
33#include "absl/log/check.h"
34#include "absl/time/time.h"
39#include "ortools/base/timer.h"
42#include "zlib.h"
43
44// These flags are used to set the fields in the DefaultSolverParameters proto.
45ABSL_FLAG(bool, cp_trace_propagation, false,
46 "Trace propagation events (constraint and demon executions,"
47 " variable modifications).");
48ABSL_FLAG(bool, cp_trace_search, false, "Trace search events");
49ABSL_FLAG(bool, cp_print_added_constraints, false,
50 "show all constraints added to the solver.");
51ABSL_FLAG(bool, cp_print_model, false,
52 "use PrintModelVisitor on model before solving.");
53ABSL_FLAG(bool, cp_model_stats, false,
54 "use StatisticsModelVisitor on model before solving.");
55ABSL_FLAG(bool, cp_disable_solve, false,
56 "Force failure at the beginning of a search.");
57ABSL_FLAG(std::string, cp_profile_file, "",
58 "Export profiling overview to file.");
59ABSL_FLAG(bool, cp_print_local_search_profile, false,
60 "Print local search profiling data after solving.");
61ABSL_FLAG(bool, cp_name_variables, false, "Force all variables to have names.");
62ABSL_FLAG(bool, cp_name_cast_variables, false,
63 "Name variables casted from expressions");
64ABSL_FLAG(bool, cp_use_small_table, true,
65 "Use small compact table constraint when possible.");
66ABSL_FLAG(bool, cp_use_cumulative_edge_finder, true,
67 "Use the O(n log n) cumulative edge finding algorithm described "
68 "in 'Edge Finding Filtering Algorithm for Discrete Cumulative "
69 "Resources in O(kn log n)' by Petr Vilim, CP 2009.");
70ABSL_FLAG(bool, cp_use_cumulative_time_table, true,
71 "Use a O(n^2) cumulative time table propagation algorithm.");
72ABSL_FLAG(bool, cp_use_cumulative_time_table_sync, false,
73 "Use a synchronized O(n^2 log n) cumulative time table propagation "
74 "algorithm.");
75ABSL_FLAG(bool, cp_use_sequence_high_demand_tasks, true,
76 "Use a sequence constraints for cumulative tasks that have a "
77 "demand greater than half of the capacity of the resource.");
78ABSL_FLAG(bool, cp_use_all_possible_disjunctions, true,
79 "Post temporal disjunctions for all pairs of tasks sharing a "
80 "cumulative resource and that cannot overlap because the sum of "
81 "their demand exceeds the capacity.");
82ABSL_FLAG(int, cp_max_edge_finder_size, 50,
83 "Do not post the edge finder in the cumulative constraints if "
84 "it contains more than this number of tasks");
85ABSL_FLAG(bool, cp_diffn_use_cumulative, true,
86 "Diffn constraint adds redundant cumulative constraint");
87ABSL_FLAG(bool, cp_use_element_rmq, true,
88 "If true, rmq's will be used in element expressions.");
89ABSL_FLAG(int, cp_check_solution_period, 1,
90 "Number of solutions explored between two solution checks during "
91 "local search.");
92ABSL_FLAG(int64_t, cp_random_seed, 12345,
93 "Random seed used in several (but not all) random number "
94 "generators used by the CP solver. Use -1 to auto-generate an"
95 "undeterministic random seed.");
96
97void ConstraintSolverFailsHere() { VLOG(3) << "Fail"; }
98
99#if defined(_MSC_VER) // WINDOWS
100#pragma warning(disable : 4351 4355)
101#endif
102
103namespace operations_research {
104
105namespace {
106// Calls the given method with the provided arguments on all objects in the
107// collection.
108template <typename T, typename MethodPointer, typename... Args>
109void ForAll(const std::vector<T*>& objects, MethodPointer method,
110 const Args&... args) {
111 for (T* const object : objects) {
112 DCHECK(object != nullptr);
113 (object->*method)(args...);
114 }
115}
116
117// Converts a scoped enum to its underlying type.
118template <typename E>
119constexpr typename std::underlying_type<E>::type to_underlying(E e) {
120 return static_cast<typename std::underlying_type<E>::type>(e);
121}
122
123} // namespace
124
125// ----- ConstraintSolverParameters -----
126
130 params.set_trail_block_size(8000);
131 params.set_array_split_size(16);
132 params.set_store_names(true);
133 params.set_profile_propagation(!absl::GetFlag(FLAGS_cp_profile_file).empty());
134 params.set_trace_propagation(absl::GetFlag(FLAGS_cp_trace_propagation));
135 params.set_trace_search(absl::GetFlag(FLAGS_cp_trace_search));
136 params.set_name_all_variables(absl::GetFlag(FLAGS_cp_name_variables));
137 params.set_profile_file(absl::GetFlag(FLAGS_cp_profile_file));
139 absl::GetFlag(FLAGS_cp_print_local_search_profile));
141 absl::GetFlag(FLAGS_cp_print_local_search_profile));
142 params.set_print_model(absl::GetFlag(FLAGS_cp_print_model));
143 params.set_print_model_stats(absl::GetFlag(FLAGS_cp_model_stats));
144 params.set_disable_solve(absl::GetFlag(FLAGS_cp_disable_solve));
145 params.set_name_cast_variables(absl::GetFlag(FLAGS_cp_name_cast_variables));
147 absl::GetFlag(FLAGS_cp_print_added_constraints));
148 params.set_use_small_table(absl::GetFlag(FLAGS_cp_use_small_table));
150 absl::GetFlag(FLAGS_cp_use_cumulative_edge_finder));
152 absl::GetFlag(FLAGS_cp_use_cumulative_time_table));
154 absl::GetFlag(FLAGS_cp_use_cumulative_time_table_sync));
156 absl::GetFlag(FLAGS_cp_use_sequence_high_demand_tasks));
158 absl::GetFlag(FLAGS_cp_use_all_possible_disjunctions));
159 params.set_max_edge_finder_size(absl::GetFlag(FLAGS_cp_max_edge_finder_size));
160 params.set_diffn_use_cumulative(absl::GetFlag(FLAGS_cp_diffn_use_cumulative));
161 params.set_use_element_rmq(absl::GetFlag(FLAGS_cp_use_element_rmq));
163 absl::GetFlag(FLAGS_cp_check_solution_period));
164 return params;
165}
166
167// ----- Forward Declarations and Profiling Support -----
168extern void InstallDemonProfiler(DemonProfiler* monitor);
170extern void DeleteDemonProfiler(DemonProfiler* monitor);
174
175// TODO(user): remove this complex logic.
176// We need the double test because parameters are set too late when using
177// python in the open source. This is the cheapest work-around.
181
183 return parameters_.profile_propagation() ||
184 !parameters_.profile_file().empty();
185}
186
188 return parameters_.profile_local_search() ||
189 parameters_.print_local_search_profile();
190}
191
193 return parameters_.trace_propagation();
194}
195
197 return parameters_.name_all_variables();
198}
199
200// ------------------ Demon class ----------------
201
205
206std::string Demon::DebugString() const { return "Demon"; }
207
208void Demon::inhibit(Solver* const s) {
209 if (stamp_ < std::numeric_limits<uint64_t>::max()) {
210 s->SaveAndSetValue(&stamp_, std::numeric_limits<uint64_t>::max());
211 }
212}
213
214void Demon::desinhibit(Solver* const s) {
215 if (stamp_ == std::numeric_limits<uint64_t>::max()) {
216 s->SaveAndSetValue(&stamp_, s->stamp() - 1);
217 }
218}
219
220// ------------------ Queue class ------------------
221
222extern void CleanVariableOnFail(IntVar* var);
223
224class Queue {
225 public:
226 static constexpr int64_t kTestPeriod = 10000;
227
228 explicit Queue(Solver* const s)
229 : solver_(s),
230 stamp_(1),
231 freeze_level_(0),
232 in_process_(false),
233 clean_action_(nullptr),
234 clean_variable_(nullptr),
235 in_add_(false),
236 instruments_demons_(s->InstrumentsDemons()) {}
237
239
240 void Freeze() {
241 freeze_level_++;
242 stamp_++;
243 }
244
245 void Unfreeze() {
246 if (--freeze_level_ == 0) {
247 Process();
248 }
249 }
250
251 void ProcessOneDemon(Demon* const demon) {
252 demon->set_stamp(stamp_ - 1);
253 if (!instruments_demons_) {
254 if (++solver_->demon_runs_[demon->priority()] % kTestPeriod == 0) {
255 solver_->TopPeriodicCheck();
256 }
257 demon->Run(solver_);
258 solver_->CheckFail();
259 } else {
260 solver_->GetPropagationMonitor()->BeginDemonRun(demon);
261 if (++solver_->demon_runs_[demon->priority()] % kTestPeriod == 0) {
262 solver_->TopPeriodicCheck();
263 }
264 demon->Run(solver_);
265 solver_->CheckFail();
266 solver_->GetPropagationMonitor()->EndDemonRun(demon);
267 }
268 }
269
270 void Process() {
271 if (!in_process_) {
272 in_process_ = true;
273 while (!var_queue_.empty() || !delayed_queue_.empty()) {
274 if (!var_queue_.empty()) {
275 Demon* const demon = var_queue_.front();
276 var_queue_.pop_front();
277 ProcessOneDemon(demon);
278 } else {
279 DCHECK(!delayed_queue_.empty());
280 Demon* const demon = delayed_queue_.front();
281 delayed_queue_.pop_front();
282 ProcessOneDemon(demon);
283 }
284 }
285 in_process_ = false;
286 }
287 }
288
289 void ExecuteAll(const SimpleRevFIFO<Demon*>& demons) {
290 if (!instruments_demons_) {
291 for (SimpleRevFIFO<Demon*>::Iterator it(&demons); it.ok(); ++it) {
292 Demon* const demon = *it;
293 if (demon->stamp() < stamp_) {
294 DCHECK_EQ(demon->priority(), Solver::NORMAL_PRIORITY);
295 if (++solver_->demon_runs_[Solver::NORMAL_PRIORITY] % kTestPeriod ==
296 0) {
297 solver_->TopPeriodicCheck();
298 }
299 demon->Run(solver_);
300 solver_->CheckFail();
301 }
302 }
303 } else {
304 for (SimpleRevFIFO<Demon*>::Iterator it(&demons); it.ok(); ++it) {
305 Demon* const demon = *it;
306 if (demon->stamp() < stamp_) {
307 DCHECK_EQ(demon->priority(), Solver::NORMAL_PRIORITY);
308 solver_->GetPropagationMonitor()->BeginDemonRun(demon);
309 if (++solver_->demon_runs_[Solver::NORMAL_PRIORITY] % kTestPeriod ==
310 0) {
311 solver_->TopPeriodicCheck();
312 }
313 demon->Run(solver_);
314 solver_->CheckFail();
315 solver_->GetPropagationMonitor()->EndDemonRun(demon);
316 }
317 }
318 }
319 }
320
321 void EnqueueAll(const SimpleRevFIFO<Demon*>& demons) {
322 for (SimpleRevFIFO<Demon*>::Iterator it(&demons); it.ok(); ++it) {
324 }
325 }
326
327 void EnqueueVar(Demon* const demon) {
328 DCHECK(demon->priority() == Solver::VAR_PRIORITY);
329 if (demon->stamp() < stamp_) {
330 demon->set_stamp(stamp_);
331 var_queue_.push_back(demon);
332 if (freeze_level_ == 0) {
333 Process();
334 }
335 }
336 }
337
338 void EnqueueDelayedDemon(Demon* const demon) {
339 DCHECK(demon->priority() == Solver::DELAYED_PRIORITY);
340 if (demon->stamp() < stamp_) {
341 demon->set_stamp(stamp_);
342 delayed_queue_.push_back(demon);
343 }
344 }
345
347 // Clean queue.
348 var_queue_.clear();
349 delayed_queue_.clear();
350
351 // Call cleaning actions on variables.
352 if (clean_action_ != nullptr) {
353 clean_action_(solver_);
354 clean_action_ = nullptr;
355 } else if (clean_variable_ != nullptr) {
356 CleanVariableOnFail(clean_variable_);
357 clean_variable_ = nullptr;
358 }
359
360 freeze_level_ = 0;
361 in_process_ = false;
362 in_add_ = false;
363 to_add_.clear();
364 }
365
366 void increase_stamp() { stamp_++; }
367
368 uint64_t stamp() const { return stamp_; }
369
371 DCHECK(clean_variable_ == nullptr);
372 clean_action_ = std::move(a);
373 }
374
376 DCHECK(clean_action_ == nullptr);
377 clean_variable_ = var;
378 }
379
381 DCHECK(clean_variable_ == nullptr);
382 clean_action_ = nullptr;
383 }
384
385 void AddConstraint(Constraint* const c) {
386 to_add_.push_back(c);
388 }
389
391 if (!in_add_) {
392 in_add_ = true;
393 // We cannot store to_add_.size() as constraints can add other
394 // constraints. For the same reason a range-based for loop cannot be used.
395 // TODO(user): Make to_add_ a queue to make the behavior more obvious.
396 for (int counter = 0; counter < to_add_.size(); ++counter) {
397 Constraint* const constraint = to_add_[counter];
398 // TODO(user): Add profiling to initial propagation
399 constraint->PostAndPropagate();
400 }
401 in_add_ = false;
402 to_add_.clear();
403 }
404 }
405
406 private:
407 Solver* const solver_;
408 std::deque<Demon*> var_queue_;
409 std::deque<Demon*> delayed_queue_;
410 uint64_t stamp_;
411 // The number of nested freeze levels. The queue is frozen if and only if
412 // freeze_level_ > 0.
413 uint32_t freeze_level_;
414 bool in_process_;
415 Solver::Action clean_action_;
416 IntVar* clean_variable_;
417 std::vector<Constraint*> to_add_;
418 bool in_add_;
419 const bool instruments_demons_;
420};
421
422// ------------------ StateMarker / StateInfo struct -----------
423
424struct StateInfo { // This is an internal structure to store
425 // additional information on the choice point.
426 public:
428 : ptr_info(nullptr),
429 int_info(0),
430 depth(0),
431 left_depth(0),
432 reversible_action(nullptr) {}
433 StateInfo(void* pinfo, int iinfo)
434 : ptr_info(pinfo),
435 int_info(iinfo),
436 depth(0),
437 left_depth(0),
438 reversible_action(nullptr) {}
439 StateInfo(void* pinfo, int iinfo, int d, int ld)
440 : ptr_info(pinfo),
441 int_info(iinfo),
442 depth(d),
443 left_depth(ld),
444 reversible_action(nullptr) {}
446 : ptr_info(nullptr),
447 int_info(static_cast<int>(fast)),
448 depth(0),
449 left_depth(0),
450 reversible_action(std::move(a)) {}
451
452 void* ptr_info;
454 int depth;
457};
458
460 public:
462 friend class Solver;
463 friend struct Trail;
464
465 private:
466 Solver::MarkerType type_;
467 int rev_int_index_;
468 int rev_int64_index_;
469 int rev_uint64_index_;
470 int rev_double_index_;
471 int rev_ptr_index_;
472 int rev_boolvar_list_index_;
473 int rev_bools_index_;
474 int rev_int_memory_index_;
475 int rev_int64_memory_index_;
476 int rev_double_memory_index_;
477 int rev_object_memory_index_;
478 int rev_object_array_memory_index_;
479 int rev_memory_index_;
480 int rev_memory_array_index_;
481 StateInfo info_;
482};
483
485 : type_(t),
486 rev_int_index_(0),
487 rev_int64_index_(0),
488 rev_uint64_index_(0),
489 rev_double_index_(0),
490 rev_ptr_index_(0),
491 rev_boolvar_list_index_(0),
492 rev_bools_index_(0),
493 rev_int_memory_index_(0),
494 rev_int64_memory_index_(0),
495 rev_double_memory_index_(0),
496 rev_object_memory_index_(0),
497 rev_object_array_memory_index_(0),
498 info_(info) {}
499
500// ---------- Trail and Reversibility ----------
501
502namespace {
503// ----- addrval struct -----
504
505// This template class is used internally to implement reversibility.
506// It stores an address and the value that was at the address.
507template <class T>
508struct addrval {
509 public:
510 addrval() : address_(nullptr) {}
511 explicit addrval(T* adr) : address_(adr), old_value_(*adr) {}
512 void restore() const { (*address_) = old_value_; }
513
514 private:
515 T* address_;
516 T old_value_;
517};
518
519// ----- Compressed trail -----
520
521// ---------- Trail Packer ---------
522// Abstract class to pack trail blocks.
523
524template <class T>
525class TrailPacker {
526 public:
527 explicit TrailPacker(int block_size) : block_size_(block_size) {}
528
529 // This type is neither copyable nor movable.
530 TrailPacker(const TrailPacker&) = delete;
531 TrailPacker& operator=(const TrailPacker&) = delete;
532 virtual ~TrailPacker() {}
533 int input_size() const { return block_size_ * sizeof(addrval<T>); }
534 virtual void Pack(const addrval<T>* block, std::string* packed_block) = 0;
535 virtual void Unpack(const std::string& packed_block, addrval<T>* block) = 0;
536
537 private:
538 const int block_size_;
539};
540
541template <class T>
542class NoCompressionTrailPacker : public TrailPacker<T> {
543 public:
544 explicit NoCompressionTrailPacker(int block_size)
545 : TrailPacker<T>(block_size) {}
546
547 // This type is neither copyable nor movable.
548 NoCompressionTrailPacker(const NoCompressionTrailPacker&) = delete;
549 NoCompressionTrailPacker& operator=(const NoCompressionTrailPacker&) = delete;
550 ~NoCompressionTrailPacker() override {}
551 void Pack(const addrval<T>* block, std::string* packed_block) override {
552 DCHECK(block != nullptr);
553 DCHECK(packed_block != nullptr);
554 absl::string_view block_str(reinterpret_cast<const char*>(block),
555 this->input_size());
556 packed_block->assign(block_str.data(), block_str.size());
557 }
558 void Unpack(const std::string& packed_block, addrval<T>* block) override {
559 DCHECK(block != nullptr);
560 memcpy(block, packed_block.c_str(), packed_block.size());
561 }
562};
563
564template <class T>
565class ZlibTrailPacker : public TrailPacker<T> {
566 public:
567 explicit ZlibTrailPacker(int block_size)
568 : TrailPacker<T>(block_size),
569 tmp_size_(compressBound(this->input_size())),
570 tmp_block_(new char[tmp_size_]) {}
571
572 // This type is neither copyable nor movable.
573 ZlibTrailPacker(const ZlibTrailPacker&) = delete;
574 ZlibTrailPacker& operator=(const ZlibTrailPacker&) = delete;
575
576 ~ZlibTrailPacker() override {}
577
578 void Pack(const addrval<T>* block, std::string* packed_block) override {
579 DCHECK(block != nullptr);
580 DCHECK(packed_block != nullptr);
581 uLongf size = tmp_size_;
582 const int result =
583 compress(reinterpret_cast<Bytef*>(tmp_block_.get()), &size,
584 reinterpret_cast<const Bytef*>(block), this->input_size());
585 CHECK_EQ(Z_OK, result);
586 absl::string_view block_str;
587 block_str = absl::string_view(tmp_block_.get(), size);
588 packed_block->assign(block_str.data(), block_str.size());
589 }
590
591 void Unpack(const std::string& packed_block, addrval<T>* block) override {
592 DCHECK(block != nullptr);
593 uLongf size = this->input_size();
594 const int result =
595 uncompress(reinterpret_cast<Bytef*>(block), &size,
596 reinterpret_cast<const Bytef*>(packed_block.c_str()),
597 packed_block.size());
598 CHECK_EQ(Z_OK, result);
599 }
600
601 private:
602 const uint64_t tmp_size_;
603 std::unique_ptr<char[]> tmp_block_;
604};
605
606template <class T>
607class CompressedTrail {
608 public:
609 CompressedTrail(
610 int block_size,
611 ConstraintSolverParameters::TrailCompression compression_level)
612 : block_size_(block_size),
613 blocks_(nullptr),
614 free_blocks_(nullptr),
615 data_(new addrval<T>[block_size]),
616 buffer_(new addrval<T>[block_size]),
617 buffer_used_(false),
618 current_(0),
619 size_(0) {
620 switch (compression_level) {
621 case ConstraintSolverParameters::NO_COMPRESSION: {
622 packer_.reset(new NoCompressionTrailPacker<T>(block_size));
623 break;
624 }
625 case ConstraintSolverParameters::COMPRESS_WITH_ZLIB: {
626 packer_.reset(new ZlibTrailPacker<T>(block_size));
627 break;
628 }
629 default: {
630 LOG(ERROR) << "Should not be here";
631 }
632 }
633
634 // We zero all memory used by addrval arrays.
635 // Because of padding, all bytes may not be initialized, while compression
636 // will read them all, even if the uninitialized bytes are never used.
637 // This makes valgrind happy.
638
639 memset(data_.get(), 0, sizeof(*data_.get()) * block_size);
640 memset(buffer_.get(), 0, sizeof(*buffer_.get()) * block_size);
641 }
642 ~CompressedTrail() {
643 FreeBlocks(blocks_);
644 FreeBlocks(free_blocks_);
645 }
646 const addrval<T>& Back() const {
647 // Back of empty trail.
648 DCHECK_GT(current_, 0);
649 return data_[current_ - 1];
650 }
651 void PopBack() {
652 if (size_ > 0) {
653 --current_;
654 if (current_ <= 0) {
655 if (buffer_used_) {
656 data_.swap(buffer_);
657 current_ = block_size_;
658 buffer_used_ = false;
659 } else if (blocks_ != nullptr) {
660 packer_->Unpack(blocks_->compressed, data_.get());
661 FreeTopBlock();
662 current_ = block_size_;
663 }
664 }
665 --size_;
666 }
667 }
668 void PushBack(const addrval<T>& addr_val) {
669 if (current_ >= block_size_) {
670 if (buffer_used_) { // Buffer is used.
671 NewTopBlock();
672 packer_->Pack(buffer_.get(), &blocks_->compressed);
673 // O(1) operation.
674 data_.swap(buffer_);
675 } else {
676 data_.swap(buffer_);
677 buffer_used_ = true;
678 }
679 current_ = 0;
680 }
681 data_[current_] = addr_val;
682 ++current_;
683 ++size_;
684 }
685 int64_t size() const { return size_; }
686
687 private:
688 struct Block {
689 std::string compressed;
690 Block* next;
691 };
692
693 void FreeTopBlock() {
694 Block* block = blocks_;
695 blocks_ = block->next;
696 block->compressed.clear();
697 block->next = free_blocks_;
698 free_blocks_ = block;
699 }
700 void NewTopBlock() {
701 Block* block = nullptr;
702 if (free_blocks_ != nullptr) {
703 block = free_blocks_;
704 free_blocks_ = block->next;
705 } else {
706 block = new Block;
707 }
708 block->next = blocks_;
709 blocks_ = block;
710 }
711 void FreeBlocks(Block* blocks) {
712 while (nullptr != blocks) {
713 Block* next = blocks->next;
714 delete blocks;
715 blocks = next;
716 }
717 }
718
719 std::unique_ptr<TrailPacker<T>> packer_;
720 const int block_size_;
721 Block* blocks_;
722 Block* free_blocks_;
723 std::unique_ptr<addrval<T>[]> data_;
724 std::unique_ptr<addrval<T>[]> buffer_;
725 bool buffer_used_;
726 int current_;
727 int size_;
728};
729} // namespace
730
731// ----- Trail -----
732
733// Object are explicitly copied using the copy ctor instead of
734// passing and storing a pointer. As objects are small, copying is
735// much faster than allocating (around 35% on a complete solve).
736
737extern void RestoreBoolValue(IntVar* var);
738
739struct Trail {
740 CompressedTrail<int> rev_ints_;
741 CompressedTrail<int64_t> rev_int64s_;
742 CompressedTrail<uint64_t> rev_uint64s_;
743 CompressedTrail<double> rev_doubles_;
744 CompressedTrail<void*> rev_ptrs_;
745 std::vector<IntVar*> rev_boolvar_list_;
746 std::vector<bool*> rev_bools_;
747 std::vector<bool> rev_bool_value_;
748 std::vector<int*> rev_int_memory_;
749 std::vector<int64_t*> rev_int64_memory_;
750 std::vector<double*> rev_double_memory_;
751 std::vector<BaseObject*> rev_object_memory_;
752 std::vector<BaseObject**> rev_object_array_memory_;
753 std::vector<void*> rev_memory_;
754 std::vector<void**> rev_memory_array_;
755
756 Trail(int block_size,
758 : rev_ints_(block_size, compression_level),
759 rev_int64s_(block_size, compression_level),
760 rev_uint64s_(block_size, compression_level),
761 rev_doubles_(block_size, compression_level),
762 rev_ptrs_(block_size, compression_level) {}
763
765 int target = m->rev_int_index_;
766 for (int curr = rev_ints_.size(); curr > target; --curr) {
767 const addrval<int>& cell = rev_ints_.Back();
768 cell.restore();
769 rev_ints_.PopBack();
770 }
771 DCHECK_EQ(rev_ints_.size(), target);
772 // Incorrect trail size after backtrack.
773 target = m->rev_int64_index_;
774 for (int curr = rev_int64s_.size(); curr > target; --curr) {
775 const addrval<int64_t>& cell = rev_int64s_.Back();
776 cell.restore();
777 rev_int64s_.PopBack();
778 }
779 DCHECK_EQ(rev_int64s_.size(), target);
780 // Incorrect trail size after backtrack.
781 target = m->rev_uint64_index_;
782 for (int curr = rev_uint64s_.size(); curr > target; --curr) {
783 const addrval<uint64_t>& cell = rev_uint64s_.Back();
784 cell.restore();
785 rev_uint64s_.PopBack();
786 }
787 DCHECK_EQ(rev_uint64s_.size(), target);
788 // Incorrect trail size after backtrack.
789 target = m->rev_double_index_;
790 for (int curr = rev_doubles_.size(); curr > target; --curr) {
791 const addrval<double>& cell = rev_doubles_.Back();
792 cell.restore();
793 rev_doubles_.PopBack();
794 }
795 DCHECK_EQ(rev_doubles_.size(), target);
796 // Incorrect trail size after backtrack.
797 target = m->rev_ptr_index_;
798 for (int curr = rev_ptrs_.size(); curr > target; --curr) {
799 const addrval<void*>& cell = rev_ptrs_.Back();
800 cell.restore();
801 rev_ptrs_.PopBack();
802 }
803 DCHECK_EQ(rev_ptrs_.size(), target);
804 // Incorrect trail size after backtrack.
805 target = m->rev_boolvar_list_index_;
806 for (int curr = rev_boolvar_list_.size() - 1; curr >= target; --curr) {
807 IntVar* const var = rev_boolvar_list_[curr];
808 RestoreBoolValue(var);
809 }
810 rev_boolvar_list_.resize(target);
811
812 DCHECK_EQ(rev_bools_.size(), rev_bool_value_.size());
813 target = m->rev_bools_index_;
814 for (int curr = rev_bools_.size() - 1; curr >= target; --curr) {
815 *(rev_bools_[curr]) = rev_bool_value_[curr];
816 }
817 rev_bools_.resize(target);
818 rev_bool_value_.resize(target);
819
820 target = m->rev_int_memory_index_;
821 for (int curr = rev_int_memory_.size() - 1; curr >= target; --curr) {
822 delete[] rev_int_memory_[curr];
823 }
824 rev_int_memory_.resize(target);
825
826 target = m->rev_int64_memory_index_;
827 for (int curr = rev_int64_memory_.size() - 1; curr >= target; --curr) {
828 delete[] rev_int64_memory_[curr];
829 }
830 rev_int64_memory_.resize(target);
831
832 target = m->rev_double_memory_index_;
833 for (int curr = rev_double_memory_.size() - 1; curr >= target; --curr) {
834 delete[] rev_double_memory_[curr];
835 }
836 rev_double_memory_.resize(target);
837
838 target = m->rev_object_memory_index_;
839 for (int curr = rev_object_memory_.size() - 1; curr >= target; --curr) {
840 delete rev_object_memory_[curr];
841 }
842 rev_object_memory_.resize(target);
843
844 target = m->rev_object_array_memory_index_;
845 for (int curr = rev_object_array_memory_.size() - 1; curr >= target;
846 --curr) {
847 delete[] rev_object_array_memory_[curr];
848 }
849 rev_object_array_memory_.resize(target);
850
851 target = m->rev_memory_index_;
852 for (int curr = rev_memory_.size() - 1; curr >= target; --curr) {
853 // Explicitly call unsized delete
854 ::operator delete(reinterpret_cast<char*>(rev_memory_[curr]));
855 // The previous cast is necessary to deallocate generic memory
856 // described by a void* when passed to the RevAlloc procedure
857 // We cannot do a delete[] there
858 // This is useful for cells of RevFIFO and should not be used outside
859 // of the product
860 }
861 rev_memory_.resize(target);
862
863 target = m->rev_memory_array_index_;
864 for (int curr = rev_memory_array_.size() - 1; curr >= target; --curr) {
865 delete[] rev_memory_array_[curr];
866 // delete [] version of the previous unsafe case.
867 }
868 rev_memory_array_.resize(target);
869 }
870};
871
872void Solver::InternalSaveValue(int* valptr) {
873 trail_->rev_ints_.PushBack(addrval<int>(valptr));
874}
875
876void Solver::InternalSaveValue(int64_t* valptr) {
877 trail_->rev_int64s_.PushBack(addrval<int64_t>(valptr));
878}
879
880void Solver::InternalSaveValue(uint64_t* valptr) {
881 trail_->rev_uint64s_.PushBack(addrval<uint64_t>(valptr));
882}
883
884void Solver::InternalSaveValue(double* valptr) {
885 trail_->rev_doubles_.PushBack(addrval<double>(valptr));
886}
887
888void Solver::InternalSaveValue(void** valptr) {
889 trail_->rev_ptrs_.PushBack(addrval<void*>(valptr));
890}
891
892// TODO(user) : this code is unsafe if you save the same alternating
893// bool multiple times.
894// The correct code should use a bitset and a single list.
895void Solver::InternalSaveValue(bool* valptr) {
896 trail_->rev_bools_.push_back(valptr);
897 trail_->rev_bool_value_.push_back(*valptr);
898}
899
900BaseObject* Solver::SafeRevAlloc(BaseObject* ptr) {
901 check_alloc_state();
902 trail_->rev_object_memory_.push_back(ptr);
903 return ptr;
904}
905
906int* Solver::SafeRevAllocArray(int* ptr) {
907 check_alloc_state();
908 trail_->rev_int_memory_.push_back(ptr);
909 return ptr;
910}
911
912int64_t* Solver::SafeRevAllocArray(int64_t* ptr) {
913 check_alloc_state();
914 trail_->rev_int64_memory_.push_back(ptr);
915 return ptr;
916}
917
918double* Solver::SafeRevAllocArray(double* ptr) {
919 check_alloc_state();
920 trail_->rev_double_memory_.push_back(ptr);
921 return ptr;
922}
923
924uint64_t* Solver::SafeRevAllocArray(uint64_t* ptr) {
925 check_alloc_state();
926 trail_->rev_int64_memory_.push_back(reinterpret_cast<int64_t*>(ptr));
927 return ptr;
928}
929
930BaseObject** Solver::SafeRevAllocArray(BaseObject** ptr) {
931 check_alloc_state();
932 trail_->rev_object_array_memory_.push_back(ptr);
933 return ptr;
934}
935
936IntVar** Solver::SafeRevAllocArray(IntVar** ptr) {
937 BaseObject** in = SafeRevAllocArray(reinterpret_cast<BaseObject**>(ptr));
938 return reinterpret_cast<IntVar**>(in);
939}
940
941IntExpr** Solver::SafeRevAllocArray(IntExpr** ptr) {
942 BaseObject** in = SafeRevAllocArray(reinterpret_cast<BaseObject**>(ptr));
943 return reinterpret_cast<IntExpr**>(in);
944}
945
946Constraint** Solver::SafeRevAllocArray(Constraint** ptr) {
947 BaseObject** in = SafeRevAllocArray(reinterpret_cast<BaseObject**>(ptr));
948 return reinterpret_cast<Constraint**>(in);
949}
950
951void* Solver::UnsafeRevAllocAux(void* ptr) {
952 check_alloc_state();
953 trail_->rev_memory_.push_back(ptr);
954 return ptr;
955}
956
957void** Solver::UnsafeRevAllocArrayAux(void** ptr) {
958 check_alloc_state();
959 trail_->rev_memory_array_.push_back(ptr);
960 return ptr;
961}
962
963void InternalSaveBooleanVarValue(Solver* const solver, IntVar* const var) {
964 solver->trail_->rev_boolvar_list_.push_back(var);
965}
966
967// ------------------ Search class -----------------
968
969class Search {
970 public:
971 explicit Search(Solver* const s)
972 : solver_(s),
973 marker_stack_(),
974 monitor_event_listeners_(to_underlying(Solver::MonitorEvent::kLast)),
975 fail_buffer_(),
976 solution_counter_(0),
977 unchecked_solution_counter_(0),
978 decision_builder_(nullptr),
979 created_by_solve_(false),
980 search_depth_(0),
981 left_search_depth_(0),
982 should_restart_(false),
983 should_finish_(false),
984 sentinel_pushed_(0),
985 jmpbuf_filled_(false),
986 backtrack_at_the_end_of_the_search_(true) {}
987
988 // Constructor for a dummy search. The only difference between a dummy search
989 // and a regular one is that the search depth and left search depth is
990 // initialized to -1 instead of zero.
991 Search(Solver* const s, int /* dummy_argument */)
992 : solver_(s),
993 marker_stack_(),
994 monitor_event_listeners_(to_underlying(Solver::MonitorEvent::kLast)),
995 fail_buffer_(),
996 solution_counter_(0),
997 unchecked_solution_counter_(0),
998 decision_builder_(nullptr),
999 created_by_solve_(false),
1000 search_depth_(-1),
1001 left_search_depth_(-1),
1002 should_restart_(false),
1003 should_finish_(false),
1004 sentinel_pushed_(0),
1005 jmpbuf_filled_(false),
1006 backtrack_at_the_end_of_the_search_(true) {}
1007
1008 ~Search() { gtl::STLDeleteElements(&marker_stack_); }
1009
1010 void EnterSearch();
1011 void RestartSearch();
1012 void ExitSearch();
1015 void ApplyDecision(Decision* d);
1016 void AfterDecision(Decision* d, bool apply);
1017 void RefuteDecision(Decision* d);
1018 void BeginFail();
1019 void EndFail();
1021 void EndInitialPropagation();
1022 bool AtSolution();
1023 bool AcceptSolution();
1024 void NoMoreSolutions();
1026 bool AcceptDelta(Assignment* delta, Assignment* deltadelta);
1027 void AcceptNeighbor();
1030 void PeriodicCheck();
1031 int ProgressPercent();
1032 void Accept(ModelVisitor* visitor) const;
1034 if (monitor != nullptr) {
1035 monitor_event_listeners_[to_underlying(event)].push_back(monitor);
1036 }
1037 }
1038 const std::vector<SearchMonitor*>& GetEventListeners(
1039 Solver::MonitorEvent event) const {
1040 return monitor_event_listeners_[to_underlying(event)];
1041 }
1042 void Clear();
1043 void IncrementSolutionCounter() { ++solution_counter_; }
1044 int64_t solution_counter() const { return solution_counter_; }
1045 void IncrementUncheckedSolutionCounter() { ++unchecked_solution_counter_; }
1047 return unchecked_solution_counter_;
1048 }
1050 decision_builder_ = db;
1051 }
1052 DecisionBuilder* decision_builder() const { return decision_builder_; }
1053 void set_created_by_solve(bool c) { created_by_solve_ = c; }
1054 bool created_by_solve() const { return created_by_solve_; }
1057 void LeftMove() {
1058 search_depth_++;
1059 left_search_depth_++;
1060 }
1061 void RightMove() { search_depth_++; }
1063 return backtrack_at_the_end_of_the_search_;
1064 }
1066 backtrack_at_the_end_of_the_search_ = restore;
1067 }
1068 int search_depth() const { return search_depth_; }
1069 void set_search_depth(int d) { search_depth_ = d; }
1070 int left_search_depth() const { return left_search_depth_; }
1071 void set_search_left_depth(int d) { left_search_depth_ = d; }
1072 void set_should_restart(bool s) { should_restart_ = s; }
1073 bool should_restart() const { return should_restart_; }
1074 void set_should_finish(bool s) { should_finish_ = s; }
1075 bool should_finish() const { return should_finish_; }
1076 void CheckFail() {
1077 if (should_finish_ || should_restart_) {
1078 solver_->Fail();
1079 }
1080 }
1081 void set_search_context(absl::string_view search_context) {
1082 search_context_ = search_context;
1083 }
1084 std::string search_context() const { return search_context_; }
1085 friend class Solver;
1086
1087 private:
1088 // Jumps back to the previous choice point, Checks if it was correctly set.
1089 void JumpBack();
1090 void ClearBuffer() {
1091 CHECK(jmpbuf_filled_) << "Internal error in backtracking";
1092 jmpbuf_filled_ = false;
1093 }
1094
1095 Solver* const solver_;
1096 std::vector<StateMarker*> marker_stack_;
1097 std::vector<std::vector<SearchMonitor*>> monitor_event_listeners_;
1098 jmp_buf fail_buffer_;
1099 int64_t solution_counter_;
1100 int64_t unchecked_solution_counter_;
1101 DecisionBuilder* decision_builder_;
1102 bool created_by_solve_;
1103 Solver::BranchSelector selector_;
1104 int search_depth_;
1105 int left_search_depth_;
1106 bool should_restart_;
1107 bool should_finish_;
1108 int sentinel_pushed_;
1109 bool jmpbuf_filled_;
1110 bool backtrack_at_the_end_of_the_search_;
1111 std::string search_context_;
1112};
1113
1114// Backtrack is implemented using 3 primitives:
1115// CP_TRY to start searching
1116// CP_DO_FAIL to signal a failure. The program will continue on the CP_ON_FAIL
1117// primitive.
1118// Implementation of backtrack using setjmp/longjmp.
1119// The clean portable way is to use exceptions, unfortunately, it can be much
1120// slower. Thus we use ideas from Prolog, CP/CLP implementations,
1121// continuations in C and implement the default failing and backtracking
1122// using setjmp/longjmp. You can still use exceptions by defining
1123// CP_USE_EXCEPTIONS_FOR_BACKTRACK
1124#ifndef CP_USE_EXCEPTIONS_FOR_BACKTRACK
1125// We cannot use a method/function for this as we would lose the
1126// context in the setjmp implementation.
1127#define CP_TRY(search) \
1128 CHECK(!search->jmpbuf_filled_) << "Fail() called outside search"; \
1129 search->jmpbuf_filled_ = true; \
1130 if (setjmp(search->fail_buffer_) == 0)
1131#define CP_ON_FAIL else
1132#define CP_DO_FAIL(search) longjmp(search->fail_buffer_, 1)
1133#else // CP_USE_EXCEPTIONS_FOR_BACKTRACK
1134class FailException {};
1135#define CP_TRY(search) \
1136 CHECK(!search->jmpbuf_filled_) << "Fail() called outside search"; \
1137 search->jmpbuf_filled_ = true; \
1138 try
1139#define CP_ON_FAIL catch (FailException&)
1140#define CP_DO_FAIL(search) throw FailException()
1141#endif // CP_USE_EXCEPTIONS_FOR_BACKTRACK
1142
1143void Search::JumpBack() {
1144 if (jmpbuf_filled_) {
1145 jmpbuf_filled_ = false;
1146 CP_DO_FAIL(this);
1147 } else {
1148 std::string explanation = "Failure outside of search";
1149 solver_->AddConstraint(solver_->MakeFalseConstraint(explanation));
1150 }
1151}
1152
1153Search* Solver::ActiveSearch() const { return searches_.back(); }
1154
1155namespace {
1156class ApplyBranchSelector : public DecisionBuilder {
1157 public:
1158 explicit ApplyBranchSelector(Solver::BranchSelector bs)
1159 : selector_(std::move(bs)) {}
1160 ~ApplyBranchSelector() override {}
1161
1162 Decision* Next(Solver* const s) override {
1163 s->SetBranchSelector(selector_);
1164 return nullptr;
1165 }
1166
1167 std::string DebugString() const override { return "Apply(BranchSelector)"; }
1168
1169 private:
1170 Solver::BranchSelector const selector_;
1171};
1172} // namespace
1173
1175 selector_ = std::move(bs);
1176}
1177
1179 // We cannot use the trail as the search can be nested and thus
1180 // deleted upon backtrack. Thus we guard the undo action by a
1181 // check on the number of nesting of solve().
1182 const int solve_depth = SolveDepth();
1184 [solve_depth](Solver* s) {
1185 if (s->SolveDepth() == solve_depth) {
1186 s->ActiveSearch()->SetBranchSelector(nullptr);
1187 }
1188 },
1189 false);
1190 searches_.back()->SetBranchSelector(std::move(bs));
1191}
1192
1194 return RevAlloc(new ApplyBranchSelector(std::move(bs)));
1195}
1196
1198 return state_ == OUTSIDE_SEARCH ? 0 : searches_.size() - 1;
1199}
1200
1201int Solver::SearchDepth() const { return searches_.back()->search_depth(); }
1202
1204 return searches_.back()->left_search_depth();
1205}
1206
1208 if (selector_ != nullptr) {
1209 return selector_();
1210 }
1211 return Solver::NO_CHANGE;
1212}
1213
1215 for (auto& listeners : monitor_event_listeners_) listeners.clear();
1216 search_depth_ = 0;
1217 left_search_depth_ = 0;
1218 selector_ = nullptr;
1219 backtrack_at_the_end_of_the_search_ = true;
1220}
1221
1222#define CALL_EVENT_LISTENERS(Event) \
1223 do { \
1224 ForAll(GetEventListeners(Solver::MonitorEvent::k##Event), \
1225 &SearchMonitor::Event); \
1226 } while (false)
1227
1229 // The solution counter is reset when entering search and not when
1230 // leaving search. This enables the information to persist outside of
1231 // top-level search.
1232 solution_counter_ = 0;
1233 unchecked_solution_counter_ = 0;
1234
1236}
1237
1239 // Backtrack to the correct state.
1241}
1242
1244
1250
1256
1262
1268
1274
1276
1278
1282
1286
1288 bool valid = true;
1289 for (SearchMonitor* const monitor :
1291 if (!monitor->AcceptSolution()) {
1292 // Even though we know the return value, we cannot return yet: this would
1293 // break the contract we have with solution monitors. They all deserve
1294 // a chance to look at the solution.
1295 valid = false;
1296 }
1297 }
1298 return valid;
1299}
1300
1302 bool should_continue = false;
1303 for (SearchMonitor* const monitor :
1305 if (monitor->AtSolution()) {
1306 // Even though we know the return value, we cannot return yet: this would
1307 // break the contract we have with solution monitors. They all deserve
1308 // a chance to look at the solution.
1309 should_continue = true;
1310 }
1311 }
1312 return should_continue;
1313}
1314
1316
1318 bool continue_at_local_optimum = false;
1319 for (SearchMonitor* const monitor :
1321 if (monitor->AtLocalOptimum()) {
1322 continue_at_local_optimum = true;
1323 }
1324 }
1325 return continue_at_local_optimum;
1326}
1327
1328bool Search::AcceptDelta(Assignment* delta, Assignment* deltadelta) {
1329 bool accept = true;
1330 for (SearchMonitor* const monitor :
1332 if (!monitor->AcceptDelta(delta, deltadelta)) {
1333 accept = false;
1334 }
1335 }
1336 return accept;
1337}
1338
1340
1344
1346 for (SearchMonitor* const monitor : GetEventListeners(
1348 if (monitor->IsUncheckedSolutionLimitReached()) {
1349 return true;
1350 }
1351 }
1352 return false;
1353}
1354
1356
1358 int progress = SearchMonitor::kNoProgress;
1359 for (SearchMonitor* const monitor :
1361 progress = std::max(progress, monitor->ProgressPercent());
1362 }
1363 return progress;
1364}
1365
1366void Search::Accept(ModelVisitor* const visitor) const {
1368 &SearchMonitor::Accept, visitor);
1369 if (decision_builder_ != nullptr) {
1370 decision_builder_->Accept(visitor);
1371 }
1372}
1373
1374#undef CALL_EVENT_LISTENERS
1375
1377 return search->ContinueAtLocalOptimum();
1378}
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
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,
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
1581 stats.set_num_branches(branches());
1582 stats.set_num_failures(failures());
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
2373 return Solve(MakeConstraintAdder(ct));
2374}
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
2427IntExpr* Solver::CastExpression(const IntVar* const var) const {
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
2534void DecisionVisitor::VisitSetVariableValue([[maybe_unused]] IntVar* const var,
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::kIndex3Argument[] = "index3";
2677const char ModelVisitor::kIndexArgument[] = "index";
2678const char ModelVisitor::kInitialState[] = "initial_state";
2679const char ModelVisitor::kIntervalArgument[] = "interval";
2680const char ModelVisitor::kIntervalsArgument[] = "intervals";
2681const char ModelVisitor::kLateCostArgument[] = "late_cost";
2682const char ModelVisitor::kLateDateArgument[] = "late_date";
2683const char ModelVisitor::kLeftArgument[] = "left";
2684const char ModelVisitor::kMaxArgument[] = "max_value";
2685const char ModelVisitor::kMaximizeArgument[] = "maximize";
2686const char ModelVisitor::kMinArgument[] = "min_value";
2687const char ModelVisitor::kModuloArgument[] = "modulo";
2688const char ModelVisitor::kNextsArgument[] = "nexts";
2689const char ModelVisitor::kOptionalArgument[] = "optional";
2690const char ModelVisitor::kPartialArgument[] = "partial";
2691const char ModelVisitor::kPositionXArgument[] = "position_x";
2692const char ModelVisitor::kPositionYArgument[] = "position_y";
2693const char ModelVisitor::kRangeArgument[] = "range";
2694const char ModelVisitor::kRelationArgument[] = "relation";
2695const char ModelVisitor::kRightArgument[] = "right";
2696const char ModelVisitor::kSequenceArgument[] = "sequence";
2697const char ModelVisitor::kSequencesArgument[] = "sequences";
2698const char ModelVisitor::kSmartTimeCheckArgument[] = "smart_time_check";
2699const char ModelVisitor::kSizeArgument[] = "size";
2700const char ModelVisitor::kSizeXArgument[] = "size_x";
2701const char ModelVisitor::kSizeYArgument[] = "size_y";
2702const char ModelVisitor::kSolutionLimitArgument[] = "solutions_limit";
2703const char ModelVisitor::kStartMinArgument[] = "start_min";
2704const char ModelVisitor::kStartMaxArgument[] = "start_max";
2705const char ModelVisitor::kStartsArgument[] = "starts";
2706const char ModelVisitor::kStepArgument[] = "step";
2707const char ModelVisitor::kTargetArgument[] = "target_variable";
2708const char ModelVisitor::kTimeLimitArgument[] = "time_limit";
2709const char ModelVisitor::kTransitsArgument[] = "transits";
2710const char ModelVisitor::kTuplesArgument[] = "tuples";
2711const char ModelVisitor::kValueArgument[] = "value";
2712const char ModelVisitor::kValuesArgument[] = "values";
2713const char ModelVisitor::kVarsArgument[] = "variables";
2714const char ModelVisitor::kEvaluatorArgument[] = "evaluator";
2715
2716const char ModelVisitor::kVariableArgument[] = "variable";
2717
2718const char ModelVisitor::kMirrorOperation[] = "mirror";
2719const char ModelVisitor::kRelaxedMaxOperation[] = "relaxed_max";
2720const char ModelVisitor::kRelaxedMinOperation[] = "relaxed_min";
2721const char ModelVisitor::kSumOperation[] = "sum";
2722const char ModelVisitor::kDifferenceOperation[] = "difference";
2723const char ModelVisitor::kProductOperation[] = "product";
2724const char ModelVisitor::kStartSyncOnStartOperation[] = "start_synced_on_start";
2725const char ModelVisitor::kStartSyncOnEndOperation[] = "start_synced_on_end";
2726const char ModelVisitor::kTraceOperation[] = "trace";
2727
2728// Methods
2729
2731
2733 [[maybe_unused]] const std::string& type_name) {}
2735 [[maybe_unused]] const std::string& type_name) {}
2736
2738 [[maybe_unused]] const std::string& type_name,
2739 [[maybe_unused]] const Constraint* const constraint) {}
2741 [[maybe_unused]] const std::string& type_name,
2742 [[maybe_unused]] const Constraint* const constraint) {}
2743
2745 [[maybe_unused]] const std::string& type) {}
2746void ModelVisitor::EndVisitExtension([[maybe_unused]] const std::string& type) {
2747}
2748
2750 [[maybe_unused]] const std::string& type_name,
2751 [[maybe_unused]] const IntExpr* const expr) {}
2753 [[maybe_unused]] const std::string& type_name,
2754 [[maybe_unused]] const IntExpr* const expr) {}
2755
2757 [[maybe_unused]] const IntVar* const variable, IntExpr* const delegate) {
2758 if (delegate != nullptr) {
2759 delegate->Accept(this);
2760 }
2761}
2762
2764 [[maybe_unused]] const IntVar* const variable,
2765 [[maybe_unused]] const std::string& operation,
2766 [[maybe_unused]] int64_t value, IntVar* const delegate) {
2767 if (delegate != nullptr) {
2768 delegate->Accept(this);
2769 }
2770}
2771
2773 [[maybe_unused]] const IntervalVar* const variable,
2774 [[maybe_unused]] const std::string& operation,
2775 [[maybe_unused]] int64_t value, IntervalVar* const delegate) {
2776 if (delegate != nullptr) {
2777 delegate->Accept(this);
2778 }
2779}
2780
2782 for (int i = 0; i < variable->size(); ++i) {
2783 variable->Interval(i)->Accept(this);
2784 }
2785}
2786
2788 [[maybe_unused]] const std::string& arg_name,
2789 [[maybe_unused]] int64_t value) {}
2790
2792 [[maybe_unused]] const std::string& arg_name,
2793 [[maybe_unused]] const std::vector<int64_t>& values) {}
2794
2796 [[maybe_unused]] const std::string& arg_name,
2797 [[maybe_unused]] const IntTupleSet& tuples) {}
2798
2800 [[maybe_unused]] const std::string& arg_name, IntExpr* const argument) {
2801 argument->Accept(this);
2802}
2803
2805 [[maybe_unused]] const std::string& arg_name,
2806 [[maybe_unused]] const Solver::Int64ToIntVar& arguments) {}
2807
2809 [[maybe_unused]] const std::string& arg_name,
2810 const std::vector<IntVar*>& arguments) {
2811 ForAll(arguments, &IntVar::Accept, this);
2812}
2813
2815 [[maybe_unused]] const std::string& arg_name, IntervalVar* const argument) {
2816 argument->Accept(this);
2817}
2818
2820 [[maybe_unused]] const std::string& arg_name,
2821 const std::vector<IntervalVar*>& arguments) {
2822 ForAll(arguments, &IntervalVar::Accept, this);
2823}
2824
2826 [[maybe_unused]] const std::string& arg_name, SequenceVar* const argument) {
2827 argument->Accept(this);
2828}
2829
2831 [[maybe_unused]] const std::string& arg_name,
2832 const std::vector<SequenceVar*>& arguments) {
2833 ForAll(arguments, &SequenceVar::Accept, this);
2834}
2835
2836// ----- Helpers -----
2837
2839 int64_t index_min,
2840 int64_t index_max) {
2841 if (filter != nullptr) {
2842 std::vector<int64_t> cached_results;
2843 for (int i = index_min; i <= index_max; ++i) {
2844 cached_results.push_back(filter(i));
2845 }
2851 }
2852}
2853
2855 const Solver::IndexEvaluator1& eval, int64_t index_min, int64_t index_max) {
2856 CHECK(eval != nullptr);
2857 std::vector<int64_t> cached_results;
2858 for (int i = index_min; i <= index_max; ++i) {
2859 cached_results.push_back(eval(i));
2860 }
2866}
2867
2869 const std::string& arg_name,
2870 int64_t index_max) {
2871 CHECK(eval != nullptr);
2872 std::vector<int64_t> cached_results;
2873 for (int i = 0; i <= index_max; ++i) {
2874 cached_results.push_back(eval(i));
2875 }
2876 VisitIntegerArrayArgument(arg_name, cached_results);
2877}
2878
2879// ---------- Search Monitor ----------
2880
2889 [[maybe_unused]] bool apply) {}
2894bool SearchMonitor::AcceptSolution() { return true; }
2895bool SearchMonitor::AtSolution() { return false; }
2897bool SearchMonitor::AtLocalOptimum() { return false; }
2898bool SearchMonitor::AcceptDelta([[maybe_unused]] Assignment* delta,
2899 [[maybe_unused]] Assignment* deltadelta) {
2900 return true;
2901}
2905void SearchMonitor::Accept([[maybe_unused]] ModelVisitor* const visitor) const {
2906}
2907// A search monitors adds itself on the active search.
2909 for (std::underlying_type<Solver::MonitorEvent>::type event = 0;
2910 event != to_underlying(Solver::MonitorEvent::kLast); ++event) {
2911 ListenToEvent(static_cast<Solver::MonitorEvent>(event));
2912 }
2913}
2914
2916 solver()->searches_.back()->AddEventListener(event, this);
2917}
2918
2919// ---------- Propagation Monitor -----------
2922
2924
2925// A propagation monitor listens to search events as well as propagation events.
2930
2931// ---------- Local Search Monitor -----------
2934
2936
2937// A local search monitor listens to search events as well as local search
2938// events.
2943
2944// ---------- Trace ----------
2945
2947 public:
2948 explicit Trace(Solver* const s) : PropagationMonitor(s) {}
2949
2950 ~Trace() override {}
2951
2953 Constraint* const constraint) override {
2955 constraint);
2956 }
2957
2958 void EndConstraintInitialPropagation(Constraint* const constraint) override {
2960 constraint);
2961 }
2962
2964 Constraint* const parent, Constraint* const nested) override {
2965 ForAll(monitors_,
2967 nested);
2968 }
2969
2971 Constraint* const parent, Constraint* const nested) override {
2972 ForAll(monitors_,
2974 nested);
2975 }
2976
2977 void RegisterDemon(Demon* const demon) override {
2978 ForAll(monitors_, &PropagationMonitor::RegisterDemon, demon);
2979 }
2980
2981 void BeginDemonRun(Demon* const demon) override {
2982 ForAll(monitors_, &PropagationMonitor::BeginDemonRun, demon);
2983 }
2984
2985 void EndDemonRun(Demon* const demon) override {
2986 ForAll(monitors_, &PropagationMonitor::EndDemonRun, demon);
2987 }
2988
2989 void StartProcessingIntegerVariable(IntVar* const var) override {
2991 }
2992
2993 void EndProcessingIntegerVariable(IntVar* const var) override {
2994 ForAll(monitors_, &PropagationMonitor::EndProcessingIntegerVariable, var);
2995 }
2996
2997 void PushContext(const std::string& context) override {
2998 ForAll(monitors_, &PropagationMonitor::PushContext, context);
2999 }
3000
3001 void PopContext() override {
3002 ForAll(monitors_, &PropagationMonitor::PopContext);
3003 }
3004
3005 // IntExpr modifiers.
3006 void SetMin(IntExpr* const expr, int64_t new_min) override {
3007 for (PropagationMonitor* const monitor : monitors_) {
3008 monitor->SetMin(expr, new_min);
3009 }
3010 }
3011
3012 void SetMax(IntExpr* const expr, int64_t new_max) override {
3013 for (PropagationMonitor* const monitor : monitors_) {
3014 monitor->SetMax(expr, new_max);
3015 }
3016 }
3017
3018 void SetRange(IntExpr* const expr, int64_t new_min,
3019 int64_t new_max) override {
3020 for (PropagationMonitor* const monitor : monitors_) {
3021 monitor->SetRange(expr, new_min, new_max);
3022 }
3023 }
3024
3025 // IntVar modifiers.
3026 void SetMin(IntVar* const var, int64_t new_min) override {
3027 for (PropagationMonitor* const monitor : monitors_) {
3028 monitor->SetMin(var, new_min);
3029 }
3030 }
3031
3032 void SetMax(IntVar* const var, int64_t new_max) override {
3033 for (PropagationMonitor* const monitor : monitors_) {
3034 monitor->SetMax(var, new_max);
3035 }
3036 }
3037
3038 void SetRange(IntVar* const var, int64_t new_min, int64_t new_max) override {
3039 for (PropagationMonitor* const monitor : monitors_) {
3040 monitor->SetRange(var, new_min, new_max);
3041 }
3042 }
3043
3044 void RemoveValue(IntVar* const var, int64_t value) override {
3045 ForAll(monitors_, &PropagationMonitor::RemoveValue, var, value);
3046 }
3047
3048 void SetValue(IntVar* const var, int64_t value) override {
3049 ForAll(monitors_, &PropagationMonitor::SetValue, var, value);
3050 }
3051
3052 void RemoveInterval(IntVar* const var, int64_t imin, int64_t imax) override {
3053 ForAll(monitors_, &PropagationMonitor::RemoveInterval, var, imin, imax);
3054 }
3055
3056 void SetValues(IntVar* const var,
3057 const std::vector<int64_t>& values) override {
3058 ForAll(monitors_, &PropagationMonitor::SetValues, var, values);
3059 }
3060
3061 void RemoveValues(IntVar* const var,
3062 const std::vector<int64_t>& values) override {
3063 ForAll(monitors_, &PropagationMonitor::RemoveValues, var, values);
3064 }
3065
3066 // IntervalVar modifiers.
3067 void SetStartMin(IntervalVar* const var, int64_t new_min) override {
3068 ForAll(monitors_, &PropagationMonitor::SetStartMin, var, new_min);
3069 }
3070
3071 void SetStartMax(IntervalVar* const var, int64_t new_max) override {
3072 ForAll(monitors_, &PropagationMonitor::SetStartMax, var, new_max);
3073 }
3074
3075 void SetStartRange(IntervalVar* const var, int64_t new_min,
3076 int64_t new_max) override {
3077 ForAll(monitors_, &PropagationMonitor::SetStartRange, var, new_min,
3078 new_max);
3079 }
3080
3081 void SetEndMin(IntervalVar* const var, int64_t new_min) override {
3082 ForAll(monitors_, &PropagationMonitor::SetEndMin, var, new_min);
3083 }
3084
3085 void SetEndMax(IntervalVar* const var, int64_t new_max) override {
3086 ForAll(monitors_, &PropagationMonitor::SetEndMax, var, new_max);
3087 }
3088
3089 void SetEndRange(IntervalVar* const var, int64_t new_min,
3090 int64_t new_max) override {
3091 ForAll(monitors_, &PropagationMonitor::SetEndRange, var, new_min, new_max);
3092 }
3093
3094 void SetDurationMin(IntervalVar* const var, int64_t new_min) override {
3095 ForAll(monitors_, &PropagationMonitor::SetDurationMin, var, new_min);
3096 }
3097
3098 void SetDurationMax(IntervalVar* const var, int64_t new_max) override {
3099 ForAll(monitors_, &PropagationMonitor::SetDurationMax, var, new_max);
3100 }
3101
3102 void SetDurationRange(IntervalVar* const var, int64_t new_min,
3103 int64_t new_max) override {
3104 ForAll(monitors_, &PropagationMonitor::SetDurationRange, var, new_min,
3105 new_max);
3106 }
3107
3108 void SetPerformed(IntervalVar* const var, bool value) override {
3109 ForAll(monitors_, &PropagationMonitor::SetPerformed, var, value);
3110 }
3111
3112 void RankFirst(SequenceVar* const var, int index) override {
3113 ForAll(monitors_, &PropagationMonitor::RankFirst, var, index);
3114 }
3115
3116 void RankNotFirst(SequenceVar* const var, int index) override {
3117 ForAll(monitors_, &PropagationMonitor::RankNotFirst, var, index);
3118 }
3119
3120 void RankLast(SequenceVar* const var, int index) override {
3121 ForAll(monitors_, &PropagationMonitor::RankLast, var, index);
3122 }
3123
3124 void RankNotLast(SequenceVar* const var, int index) override {
3125 ForAll(monitors_, &PropagationMonitor::RankNotLast, var, index);
3126 }
3127
3128 void RankSequence(SequenceVar* const var, const std::vector<int>& rank_first,
3129 const std::vector<int>& rank_last,
3130 const std::vector<int>& unperformed) override {
3131 ForAll(monitors_, &PropagationMonitor::RankSequence, var, rank_first,
3132 rank_last, unperformed);
3133 }
3134
3135 // Does not take ownership of monitor.
3136 void Add(PropagationMonitor* const monitor) {
3137 if (monitor != nullptr) {
3138 monitors_.push_back(monitor);
3139 }
3140 }
3141
3142 // The trace will dispatch propagation events. It needs to listen to search
3143 // events.
3144 void Install() override { SearchMonitor::Install(); }
3145
3146 std::string DebugString() const override { return "Trace"; }
3147
3148 private:
3149 std::vector<PropagationMonitor*> monitors_;
3150};
3151
3152PropagationMonitor* BuildTrace(Solver* const s) { return new Trace(s); }
3153
3155 // TODO(user): Check solver state?
3156 reinterpret_cast<class Trace*>(propagation_monitor_.get())->Add(monitor);
3157}
3158
3160 return propagation_monitor_.get();
3161}
3162
3163// ---------- Local Search Monitor Primary ----------
3164
3166 public:
3169
3170 void BeginOperatorStart() override {
3171 ForAll(monitors_, &LocalSearchMonitor::BeginOperatorStart);
3172 }
3173 void EndOperatorStart() override {
3174 ForAll(monitors_, &LocalSearchMonitor::EndOperatorStart);
3175 }
3177 ForAll(monitors_, &LocalSearchMonitor::BeginMakeNextNeighbor, op);
3178 }
3179 void EndMakeNextNeighbor(const LocalSearchOperator* op, bool neighbor_found,
3180 const Assignment* delta,
3181 const Assignment* deltadelta) override {
3182 ForAll(monitors_, &LocalSearchMonitor::EndMakeNextNeighbor, op,
3183 neighbor_found, delta, deltadelta);
3184 }
3185 void BeginFilterNeighbor(const LocalSearchOperator* op) override {
3186 ForAll(monitors_, &LocalSearchMonitor::BeginFilterNeighbor, op);
3187 }
3189 bool neighbor_found) override {
3190 ForAll(monitors_, &LocalSearchMonitor::EndFilterNeighbor, op,
3191 neighbor_found);
3192 }
3193 void BeginAcceptNeighbor(const LocalSearchOperator* op) override {
3194 ForAll(monitors_, &LocalSearchMonitor::BeginAcceptNeighbor, op);
3195 }
3197 bool neighbor_found) override {
3198 ForAll(monitors_, &LocalSearchMonitor::EndAcceptNeighbor, op,
3199 neighbor_found);
3200 }
3201 void BeginFiltering(const LocalSearchFilter* filter) override {
3202 ForAll(monitors_, &LocalSearchMonitor::BeginFiltering, filter);
3203 }
3204 void EndFiltering(const LocalSearchFilter* filter, bool reject) override {
3205 ForAll(monitors_, &LocalSearchMonitor::EndFiltering, filter, reject);
3206 }
3207 bool IsActive() const override { return !monitors_.empty(); }
3208
3209 // Does not take ownership of monitor.
3210 void Add(LocalSearchMonitor* monitor) {
3211 if (monitor != nullptr) {
3212 monitors_.push_back(monitor);
3213 }
3214 }
3215
3216 // The trace will dispatch propagation events. It needs to listen to search
3217 // events.
3218 void Install() override { SearchMonitor::Install(); }
3219
3220 std::string DebugString() const override {
3221 return "LocalSearchMonitorPrimary";
3222 }
3223
3224 private:
3225 std::vector<LocalSearchMonitor*> monitors_;
3226};
3227
3231
3233 reinterpret_cast<class LocalSearchMonitorPrimary*>(
3234 local_search_monitor_.get())
3235 ->Add(monitor);
3236}
3237
3239 return local_search_monitor_.get();
3240}
3241
3243 absl::string_view search_context) {
3244 search->set_search_context(search_context);
3245}
3246
3247std::string Solver::SearchContext() const {
3248 return ActiveSearch()->search_context();
3249}
3250
3251std::string Solver::SearchContext(const Search* search) const {
3252 return search->search_context();
3253}
3254
3255bool Solver::AcceptSolution(Search* search) const {
3256 return search->AcceptSolution();
3257}
3258
3260 if (local_search_state_ == nullptr) {
3261 local_search_state_ = std::make_unique<Assignment>(this);
3262 }
3263 return local_search_state_.get();
3264}
3265
3266// ----------------- ProfiledDecisionBuilder ------------
3267
3269 : db_(db), name_(db_->GetName()), seconds_(0) {}
3270
3272 timer_.Start();
3273 solver->set_context(name());
3274 // In case db_->Next() fails, gathering the running time on backtrack.
3275 solver->AddBacktrackAction(
3276 [this](Solver* solver) {
3277 if (timer_.IsRunning()) {
3278 timer_.Stop();
3279 seconds_ += timer_.Get();
3280 }
3281 solver->set_context("");
3282 },
3283 true);
3284 Decision* const decision = db_->Next(solver);
3285 timer_.Stop();
3286 seconds_ += timer_.Get();
3287 solver->set_context("");
3288 return decision;
3289}
3290
3292 return db_->DebugString();
3293}
3294
3296 Solver* const solver, std::vector<SearchMonitor*>* const extras) {
3297 db_->AppendMonitors(solver, extras);
3298}
3299
3301 db_->Accept(visitor);
3302}
3303
3304// ----------------- Constraint class -------------------
3305
3306std::string Constraint::DebugString() const { return "Constraint"; }
3307
3309 FreezeQueue();
3310 Post();
3312 solver()->CheckFail();
3313 UnfreezeQueue();
3314}
3315
3316void Constraint::Accept(ModelVisitor* const visitor) const {
3317 visitor->BeginVisitConstraint("unknown", this);
3318 VLOG(3) << "Unknown constraint " << DebugString();
3319 visitor->EndVisitConstraint("unknown", this);
3320}
3321
3323 return solver()->cast_constraints_.contains(this);
3324}
3325
3326IntVar* Constraint::Var() { return nullptr; }
3327
3328// ----- Class IntExpr -----
3329
3330void IntExpr::Accept(ModelVisitor* const visitor) const {
3331 visitor->BeginVisitIntegerExpression("unknown", this);
3332 VLOG(3) << "Unknown expression " << DebugString();
3333 visitor->EndVisitIntegerExpression("unknown", this);
3334}
3335
3336#undef CP_TRY // We no longer need those.
3337#undef CP_ON_FAIL
3338#undef CP_DO_FAIL
3339
3340} // namespace operations_research
virtual std::string DebugString() const
::operations_research::ConstraintSolverParameters_TrailCompression compress_trail() const
void set_profile_file(Arg_ &&arg, Args_... args)
ConstraintSolverParameters_TrailCompression TrailCompression
void set_compress_trail(::operations_research::ConstraintSolverParameters_TrailCompression value)
std::string DebugString() const override
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
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
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.
void Accept(ModelVisitor *visitor) const override
Accepts the given visitor.
virtual void Accept(ModelVisitor *visitor) const =0
Accepts the given visitor.
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 Install() override
Install itself on the solver.
void BeginFilterNeighbor(const LocalSearchOperator *op) override
void EndFiltering(const LocalSearchFilter *filter, bool reject) override
void BeginFiltering(const LocalSearchFilter *filter) override
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
The base class for all local search operators.
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)
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)
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
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 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.
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.
static ConstraintSolverParameters DefaultSolverParameters()
Create a ConstraintSolverParameters proto with all the default values.
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)
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.
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.
void NewSearch(DecisionBuilder *db, const std::vector< SearchMonitor * > &monitors)
LocalSearchMonitor * GetLocalSearchMonitor() const
Returns the local search monitor.
std::function< int64_t(int64_t)> IndexEvaluator1
Callback typedefs.
@ 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
Returns local search profiling information in a human readable format.
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.
std::function< DecisionModification()> BranchSelector
ConstraintSolverStatistics GetConstraintSolverStatistics() const
Returns detailed cp search statistics.
IntExpr * CastExpression(const IntVar *var) const
!defined(SWIG)
DecisionBuilder * MakeConstraintAdder(Constraint *ct)
std::function< void(Solver *)> Action
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.
std::function< bool(int64_t)> IndexFilter1
void Accept(ModelVisitor *visitor) const
Accepts the given model visitor.
bool IsProfilingEnabled() const
Returns whether we are profiling the solver.
MonitorEvent
Search monitor events.
SearchMonitor * MakeSearchTrace(const std::string &prefix)
Definition search.cc:462
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)
ConstraintSolverParameters parameters() const
Stored Parameters.
bool Solve(DecisionBuilder *db, const std::vector< SearchMonitor * > &monitors)
ModelVisitor * MakePrintModelVisitor()
Prints the model.
Definition utilities.cc:809
Assignment * GetOrCreateLocalSearchState()
Returns (or creates) an assignment representing the state of local search.
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.
bool AcceptSolution(Search *search) const
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.
void AddConstraint(Constraint *c)
Adds the constraint 'c' to the model.
ModelVisitor * MakeStatisticsModelVisitor()
Displays some nice statistics on the model.
Definition utilities.cc:813
bool SolveAndCommit(DecisionBuilder *db, const std::vector< SearchMonitor * > &monitors)
void AddCastConstraint(CastConstraint *constraint, IntVar *target_var, IntExpr *expr)
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)
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 Install() override
Install itself on the solver.
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
#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).")
void ConstraintSolverFailsHere()
#define CALL_EVENT_LISTENERS(Event)
void STLDeleteElements(T *container)
Definition stl_util.h:369
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
Definition matchers.h:467
dual_gradient T(y - `dual_solution`) class DiagonalTrustRegionProblemFromQp
OR-Tools root namespace.
void DeleteLocalSearchProfiler(LocalSearchProfiler *monitor)
void InternalSaveBooleanVarValue(Solver *const solver, IntVar *const var)
void DeleteDemonProfiler(DemonProfiler *monitor)
int64_t GetProcessMemoryUsage()
Definition sysinfo.cc:91
void RestoreBoolValue(IntVar *var)
ModelCache * BuildModelCache(Solver *solver)
PropagationMonitor * BuildTrace(Solver *s)
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
void AcceptNeighbor(Search *search)
void AcceptUncheckedNeighbor(Search *search)
DemonProfiler * BuildDemonProfiler(Solver *solver)
std::ostream & operator<<(std::ostream &out, const Assignment &assignment)
LocalSearchMonitor * BuildLocalSearchMonitorPrimary(Solver *s)
void InstallLocalSearchProfiler(LocalSearchProfiler *monitor)
LocalSearchProfiler * BuildLocalSearchProfiler(Solver *solver)
bool ContinueAtLocalOptimum(Search *search)
PropagationMonitor * BuildPrintTrace(Solver *s)
Definition trace.cc:877
void InstallDemonProfiler(DemonProfiler *monitor)
void CleanVariableOnFail(IntVar *var)
bool AcceptDelta(Search *search, Assignment *delta, Assignment *deltadelta)
STL namespace.
bool Next()
StateInfo(Solver::Action a, bool fast)
StateInfo(void *pinfo, int iinfo)
StateInfo(void *pinfo, int iinfo, int d, int ld)
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_