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