OR-Tools  9.0
graph_constraints.cc
Go to the documentation of this file.
1 // Copyright 2010-2021 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #include <algorithm>
15 #include <cstdint>
16 #include <deque>
17 #include <memory>
18 #include <string>
19 #include <utility>
20 #include <vector>
21 
22 #include "absl/container/flat_hash_set.h"
23 #include "absl/strings/str_cat.h"
24 #include "absl/strings/str_format.h"
25 #include "absl/strings/str_join.h"
27 #include "ortools/base/logging.h"
32 
33 namespace operations_research {
34 // ---------- No cycle ----------
35 
36 // This constraint ensures there are no cycles in the variable/value graph.
37 // "Sink" values are values outside the range of the array of variables; they
38 // are used to end paths.
39 // The constraint does essentially two things:
40 // - forbid partial paths from looping back to themselves
41 // - ensure each variable/node can be connected to a "sink".
42 // If assume_paths is true, the constraint assumes the 'next' variables
43 // represent paths (and performs a faster propagation); otherwise the
44 // constraint assumes the 'next' variables represent a forest.
45 // TODO(user): improve code when assume_paths is false (currently does an
46 // expensive n^2 loop).
47 
48 namespace {
49 class NoCycle : public Constraint {
50  public:
51  NoCycle(Solver* const s, const std::vector<IntVar*>& nexts,
52  const std::vector<IntVar*>& active, Solver::IndexFilter1 sink_handler,
53  bool assume_paths);
54  ~NoCycle() override {}
55  void Post() override;
56  void InitialPropagate() override;
57  void NextChange(int index);
58  void ActiveBound(int index);
59  void NextBound(int index);
60  void ComputeSupports();
61  void ComputeSupport(int index);
62  std::string DebugString() const override;
63 
64  void Accept(ModelVisitor* const visitor) const override {
65  visitor->BeginVisitConstraint(ModelVisitor::kNoCycle, this);
66  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
67  nexts_);
68  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kActiveArgument,
69  active_);
70  visitor->VisitIntegerArgument("assume_paths", assume_paths_);
71  visitor->VisitInt64ToBoolExtension(sink_handler_, -size(), size());
72  visitor->EndVisitConstraint(ModelVisitor::kNoCycle, this);
73  }
74 
75  private:
76  int64_t size() const { return nexts_.size(); }
77 
78  const std::vector<IntVar*> nexts_;
79  const std::vector<IntVar*> active_;
80  std::vector<IntVarIterator*> iterators_;
81  RevArray<int64_t> starts_;
82  RevArray<int64_t> ends_;
83  RevArray<bool> marked_;
84  bool all_nexts_bound_;
85  std::vector<int64_t> outbound_supports_;
86  std::vector<int64_t> support_leaves_;
87  std::vector<int64_t> unsupported_;
88  Solver::IndexFilter1 sink_handler_;
89  std::vector<int64_t> sinks_;
90  bool assume_paths_;
91 };
92 
93 NoCycle::NoCycle(Solver* const s, const std::vector<IntVar*>& nexts,
94  const std::vector<IntVar*>& active,
95  Solver::IndexFilter1 sink_handler, bool assume_paths)
96  : Constraint(s),
97  nexts_(nexts),
98  active_(active),
99  iterators_(nexts.size(), nullptr),
100  starts_(nexts.size(), -1),
101  ends_(nexts.size(), -1),
102  marked_(nexts.size(), false),
103  all_nexts_bound_(false),
104  outbound_supports_(nexts.size(), -1),
105  sink_handler_(std::move(sink_handler)),
106  assume_paths_(assume_paths) {
107  support_leaves_.reserve(size());
108  unsupported_.reserve(size());
109  for (int i = 0; i < size(); ++i) {
110  starts_.SetValue(s, i, i);
111  ends_.SetValue(s, i, i);
112  iterators_[i] = nexts_[i]->MakeDomainIterator(true);
113  }
114 }
115 
116 void NoCycle::InitialPropagate() {
117  // Reduce next domains to sinks + range of nexts
118  for (int i = 0; i < size(); ++i) {
119  outbound_supports_[i] = -1;
120  IntVar* next = nexts_[i];
121  for (int j = next->Min(); j < 0; ++j) {
122  if (!sink_handler_(j)) {
123  next->RemoveValue(j);
124  }
125  }
126  for (int j = next->Max(); j >= size(); --j) {
127  if (!sink_handler_(j)) {
128  next->RemoveValue(j);
129  }
130  }
131  }
132  solver()->SaveAndSetValue(&all_nexts_bound_, true);
133  for (int i = 0; i < size(); ++i) {
134  if (nexts_[i]->Bound()) {
135  NextBound(i);
136  } else {
137  solver()->SaveAndSetValue(&all_nexts_bound_, false);
138  }
139  }
140  ComputeSupports();
141 }
142 
143 void NoCycle::Post() {
144  if (size() == 0) return;
145  for (int i = 0; i < size(); ++i) {
146  IntVar* next = nexts_[i];
147  Demon* support_demon = MakeConstraintDemon1(
148  solver(), this, &NoCycle::NextChange, "NextChange", i);
149  next->WhenDomain(support_demon);
150  Demon* active_demon = MakeConstraintDemon1(
151  solver(), this, &NoCycle::ActiveBound, "ActiveBound", i);
152  active_[i]->WhenBound(active_demon);
153  }
154  // Setting up sinks
155  int64_t min_min = nexts_[0]->Min();
156  int64_t max_max = nexts_[0]->Max();
157  for (int i = 1; i < size(); ++i) {
158  const IntVar* next = nexts_[i];
159  min_min = std::min(min_min, next->Min());
160  max_max = std::max(max_max, next->Max());
161  }
162  sinks_.clear();
163  for (int i = min_min; i <= max_max; ++i) {
164  if (sink_handler_(i)) {
165  sinks_.push_back(i);
166  }
167  }
168 }
169 
170 void NoCycle::NextChange(int index) {
171  IntVar* const next_var = nexts_[index];
172  if (next_var->Bound()) {
173  NextBound(index);
174  }
175  if (!all_nexts_bound_) {
176  bool all_nexts_bound = true;
177  for (int i = 0; i < size(); ++i) {
178  if (!nexts_[i]->Bound()) {
179  all_nexts_bound = false;
180  break;
181  }
182  }
183  solver()->SaveAndSetValue(&all_nexts_bound_, all_nexts_bound);
184  }
185  if (all_nexts_bound_) {
186  return;
187  }
188  if (!next_var->Contains(outbound_supports_[index])) {
189  ComputeSupport(index);
190  }
191 }
192 
193 void NoCycle::ActiveBound(int index) {
194  if (nexts_[index]->Bound()) {
195  NextBound(index);
196  }
197 }
198 
199 void NoCycle::NextBound(int index) {
200  if (active_[index]->Min() == 0) return;
201  if (marked_[index]) return;
202  Solver* const s = solver();
203  // Subtle: marking indices to avoid overwriting chain starts and ends if
204  // propagation for active_[index] or nexts_[index] has already been done.
205  marked_.SetValue(s, index, true);
206  const int64_t next = nexts_[index]->Value();
207  const int64_t chain_start = starts_[index];
208  const int64_t chain_end = !sink_handler_(next) ? ends_[next] : next;
209  if (!sink_handler_(chain_start)) {
210  ends_.SetValue(s, chain_start, chain_end);
211  if (!sink_handler_(chain_end)) {
212  starts_.SetValue(s, chain_end, chain_start);
213  nexts_[chain_end]->RemoveValue(chain_start);
214  if (!assume_paths_) {
215  for (int i = 0; i < size(); ++i) {
216  int64_t current = i;
217  bool found = (current == chain_end);
218  // Counter to detect implicit cycles.
219  int count = 0;
220  while (!found && count < size() && !sink_handler_(current) &&
221  nexts_[current]->Bound()) {
222  current = nexts_[current]->Value();
223  found = (current == chain_end);
224  ++count;
225  }
226  if (found) {
227  nexts_[chain_end]->RemoveValue(i);
228  }
229  }
230  }
231  }
232  }
233 }
234 
235 // Compute the support tree. For each variable, find a path connecting to a
236 // sink. Starts partial paths from the sinks down to all unconnected variables.
237 // If some variables remain unconnected, make the corresponding active_
238 // variable false.
239 // Resulting tree is used as supports for next variables.
240 // TODO(user): Try to see if we can find an algorithm which is less than
241 // quadratic to do this (note that if the tree is flat we are already linear
242 // for a given number of sinks).
243 void NoCycle::ComputeSupports() {
244  // unsupported_ contains nodes not connected to sinks.
245  unsupported_.clear();
246  // supported_leaves_ contains the current frontier containing nodes surely
247  // connected to sinks.
248  support_leaves_.clear();
249  // Initial phase: find direct connections to sinks and initialize
250  // support_leaves_ and unsupported_ accordingly.
251  const int sink_size = sinks_.size();
252  for (int i = 0; i < size(); ++i) {
253  const IntVar* next = nexts_[i];
254  // If node is not active, no need to try to connect it to a sink.
255  if (active_[i]->Max() != 0) {
256  const int64_t current_support = outbound_supports_[i];
257  // Optimization: if this node was already supported by a sink, check if
258  // it's still a valid support.
259  if (current_support >= 0 && sink_handler_(current_support) &&
260  next->Contains(current_support)) {
261  support_leaves_.push_back(i);
262  } else {
263  // Optimization: iterate on sinks or next domain depending on which is
264  // smaller.
265  outbound_supports_[i] = -1;
266  if (sink_size < next->Size()) {
267  for (int j = 0; j < sink_size; ++j) {
268  if (next->Contains(sinks_[j])) {
269  outbound_supports_[i] = sinks_[j];
270  support_leaves_.push_back(i);
271  break;
272  }
273  }
274  } else {
275  for (const int64_t value : InitAndGetValues(iterators_[i])) {
276  if (sink_handler_(value)) {
277  outbound_supports_[i] = value;
278  support_leaves_.push_back(i);
279  break;
280  }
281  }
282  }
283  }
284  if (outbound_supports_[i] == -1) {
285  unsupported_.push_back(i);
286  }
287  }
288  }
289  // No need to iterate on all nodes connected to sinks but just on the ones
290  // added in the last iteration; leaves_begin and leaves_end mark the block
291  // in support_leaves_ corresponding to such nodes.
292  size_t leaves_begin = 0;
293  size_t leaves_end = support_leaves_.size();
294  while (!unsupported_.empty()) {
295  // Try to connected unsupported nodes to nodes connected to sinks.
296  for (int64_t unsupported_index = 0; unsupported_index < unsupported_.size();
297  ++unsupported_index) {
298  const int64_t unsupported = unsupported_[unsupported_index];
299  const IntVar* const next = nexts_[unsupported];
300  for (int i = leaves_begin; i < leaves_end; ++i) {
301  if (next->Contains(support_leaves_[i])) {
302  outbound_supports_[unsupported] = support_leaves_[i];
303  support_leaves_.push_back(unsupported);
304  // Remove current node from unsupported vector.
305  unsupported_[unsupported_index] = unsupported_.back();
306  unsupported_.pop_back();
307  --unsupported_index;
308  break;
309  }
310  // TODO(user): evaluate same trick as with the sinks by keeping a
311  // bitmap with supported nodes.
312  }
313  }
314  // No new leaves were added, we can bail out.
315  if (leaves_end == support_leaves_.size()) {
316  break;
317  }
318  leaves_begin = leaves_end;
319  leaves_end = support_leaves_.size();
320  }
321  // Mark as inactive any unsupported node.
322  for (int64_t unsupported_index = 0; unsupported_index < unsupported_.size();
323  ++unsupported_index) {
324  active_[unsupported_[unsupported_index]]->SetMax(0);
325  }
326 }
327 
328 void NoCycle::ComputeSupport(int index) {
329  // Try to reconnect the node to the support tree by finding a next node
330  // which is both supported and was not a descendant of the node in the tree.
331  if (active_[index]->Max() != 0) {
332  for (const int64_t next : InitAndGetValues(iterators_[index])) {
333  if (sink_handler_(next)) {
334  outbound_supports_[index] = next;
335  return;
336  }
337  if (next != index && next < outbound_supports_.size()) {
338  int64_t next_support = outbound_supports_[next];
339  if (next_support >= 0) {
340  // Check if next is not already a descendant of index.
341  bool ancestor_found = false;
342  while (next_support < outbound_supports_.size() &&
343  !sink_handler_(next_support)) {
344  if (next_support == index) {
345  ancestor_found = true;
346  break;
347  }
348  next_support = outbound_supports_[next_support];
349  }
350  if (!ancestor_found) {
351  outbound_supports_[index] = next;
352  return;
353  }
354  }
355  }
356  }
357  }
358  // No support was found, rebuild the support tree.
359  ComputeSupports();
360 }
361 
362 std::string NoCycle::DebugString() const {
363  return absl::StrFormat("NoCycle(%s)", JoinDebugStringPtr(nexts_, ", "));
364 }
365 
366 // ----- Circuit constraint -----
367 
368 class Circuit : public Constraint {
369  public:
370  Circuit(Solver* const s, const std::vector<IntVar*>& nexts, bool sub_circuit)
371  : Constraint(s),
372  nexts_(nexts),
373  size_(nexts_.size()),
374  starts_(size_, -1),
375  ends_(size_, -1),
376  lengths_(size_, 1),
377  domains_(size_),
378  outbound_support_(size_, -1),
379  inbound_support_(size_, -1),
380  temp_support_(size_, -1),
381  inbound_demon_(nullptr),
382  outbound_demon_(nullptr),
383  root_(-1),
384  num_inactives_(0),
385  sub_circuit_(sub_circuit) {
386  for (int i = 0; i < size_; ++i) {
387  domains_[i] = nexts_[i]->MakeDomainIterator(true);
388  }
389  }
390 
391  ~Circuit() override {}
392 
393  void Post() override {
394  inbound_demon_ = MakeDelayedConstraintDemon0(
395  solver(), this, &Circuit::CheckReachabilityToRoot,
396  "CheckReachabilityToRoot");
397  outbound_demon_ = MakeDelayedConstraintDemon0(
398  solver(), this, &Circuit::CheckReachabilityFromRoot,
399  "CheckReachabilityFromRoot");
400  for (int i = 0; i < size_; ++i) {
401  if (!nexts_[i]->Bound()) {
402  Demon* const bound_demon = MakeConstraintDemon1(
403  solver(), this, &Circuit::NextBound, "NextBound", i);
404  nexts_[i]->WhenBound(bound_demon);
405  Demon* const domain_demon = MakeConstraintDemon1(
406  solver(), this, &Circuit::NextDomain, "NextDomain", i);
407  nexts_[i]->WhenDomain(domain_demon);
408  }
409  }
410  solver()->AddConstraint(solver()->MakeAllDifferent(nexts_));
411  }
412 
413  void InitialPropagate() override {
414  Solver* const s = solver();
415  if (!sub_circuit_) {
416  root_.SetValue(solver(), 0);
417  }
418  for (int i = 0; i < size_; ++i) {
419  nexts_[i]->SetRange(0, size_ - 1);
420  if (!sub_circuit_) {
421  nexts_[i]->RemoveValue(i);
422  }
423  }
424  for (int i = 0; i < size_; ++i) {
425  starts_.SetValue(s, i, i);
426  ends_.SetValue(s, i, i);
427  lengths_.SetValue(s, i, 1);
428  }
429  for (int i = 0; i < size_; ++i) {
430  if (nexts_[i]->Bound()) {
431  NextBound(i);
432  }
433  }
434  CheckReachabilityFromRoot();
435  CheckReachabilityToRoot();
436  }
437 
438  std::string DebugString() const override {
439  return absl::StrFormat("%sCircuit(%s)", sub_circuit_ ? "Sub" : "",
440  JoinDebugStringPtr(nexts_, " "));
441  }
442 
443  void Accept(ModelVisitor* const visitor) const override {
444  visitor->BeginVisitConstraint(ModelVisitor::kCircuit, this);
445  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
446  nexts_);
447  visitor->VisitIntegerArgument(ModelVisitor::kPartialArgument, sub_circuit_);
448  visitor->EndVisitConstraint(ModelVisitor::kCircuit, this);
449  }
450 
451  private:
452  bool Inactive(int index) const {
453  return nexts_[index]->Bound() && nexts_[index]->Min() == index;
454  }
455 
456  void NextBound(int index) {
457  Solver* const s = solver();
458  const int destination = nexts_[index]->Value();
459  const int root = root_.Value();
460  if (destination != index) {
461  if (root == -1) {
462  root_.SetValue(s, index);
463  }
464  const int new_end = ends_.Value(destination);
465  const int new_start = starts_.Value(index);
466  starts_.SetValue(s, new_end, new_start);
467  ends_.SetValue(s, new_start, new_end);
468  lengths_.SetValue(
469  s, new_start,
470  lengths_.Value(new_start) + lengths_.Value(destination));
471  if (sub_circuit_) {
472  // You are creating the only path. Nexts can no longer loop upon itself.
473  nexts_[destination]->RemoveValue(destination);
474  } else {
475  if (lengths_.Value(new_start) < size_ - 1 - num_inactives_.Value()) {
476  nexts_[new_end]->RemoveValue(new_start);
477  }
478  }
479  } else {
480  num_inactives_.Incr(solver());
481  }
482  // TODO(user): You might get more propagation if you maintain
483  // num_undecided_actives_;
484  // then
485  // if (num_undecided_actives_ == 0 &&
486  // lengths_.Value(new_start) < size_ - 1 - num_inactives_.Value()) {
487  // nexts_[new_end]->RemoveValue(new_start);
488  // }
489  // for both complete == true and false.
490  }
491 
492  void NextDomain(int index) {
493  if (root_.Value() == -1) {
494  return;
495  }
496  if (!nexts_[index]->Contains(outbound_support_[index])) {
497  EnqueueDelayedDemon(outbound_demon_);
498  }
499  if (!nexts_[index]->Contains(inbound_support_[index])) {
500  EnqueueDelayedDemon(inbound_demon_);
501  }
502  }
503 
504  void TryInsertReached(int candidate, int64_t after) {
505  if (!reached_[after]) {
506  reached_[after] = true;
507  insertion_queue_.push_back(after);
508  temp_support_[candidate] = after;
509  }
510  }
511 
512  void CheckReachabilityFromRoot() {
513  if (root_.Value() == -1) { // Root is not yet defined. Nothing to deduce.
514  return;
515  }
516 
517  // Assign temp_support_ to a dummy value.
518  temp_support_.assign(size_, -1);
519  // Clear the spanning tree.
520  int processed = 0;
521  reached_.assign(size_, false);
522  insertion_queue_.clear();
523  // Add the root node.
524  const int root_value = root_.Value();
525  reached_[root_value] = true;
526  insertion_queue_.push_back(root_value);
527  // Compute reachable nodes.
528  while (processed < insertion_queue_.size() &&
529  insertion_queue_.size() + num_inactives_.Value() < size_) {
530  const int candidate = insertion_queue_[processed++];
531  IntVar* const var = nexts_[candidate];
532  switch (var->Size()) {
533  case 1: {
534  TryInsertReached(candidate, var->Min());
535  break;
536  }
537  case 2: {
538  TryInsertReached(candidate, var->Min());
539  TryInsertReached(candidate, var->Max());
540  break;
541  }
542  default: {
543  IntVarIterator* const domain = domains_[candidate];
544  for (const int64_t value : InitAndGetValues(domain)) {
545  TryInsertReached(candidate, value);
546  }
547  }
548  }
549  }
550  // All non reachable nodes should point to themselves in the incomplete
551  // case
552  for (int i = 0; i < size_; ++i) {
553  if (!reached_[i]) {
554  nexts_[i]->SetValue(i);
555  }
556  }
557  // Update the outbound_support_ vector.
558  outbound_support_.swap(temp_support_);
559  }
560 
561  void CheckReachabilityToRoot() {
562  // TODO(user): Improve with prev_ data structure.
563  if (root_.Value() == -1) {
564  return;
565  }
566 
567  insertion_queue_.clear();
568  insertion_queue_.push_back(root_.Value());
569  temp_support_[root_.Value()] = nexts_[root_.Value()]->Min();
570  int processed = 0;
571  to_visit_.clear();
572  for (int i = 0; i < size_; ++i) {
573  if (!Inactive(i) && i != root_.Value()) {
574  to_visit_.push_back(i);
575  }
576  }
577  const int inactive = num_inactives_.Value();
578  while (processed < insertion_queue_.size() &&
579  insertion_queue_.size() + inactive < size_) {
580  const int inserted = insertion_queue_[processed++];
581  std::vector<int> rejected;
582  for (int index = 0; index < to_visit_.size(); ++index) {
583  const int candidate = to_visit_[index];
584  if (nexts_[candidate]->Contains(inserted)) {
585  insertion_queue_.push_back(candidate);
586  temp_support_[candidate] = inserted;
587  } else {
588  rejected.push_back(candidate);
589  }
590  }
591  to_visit_.swap(rejected);
592  }
593  for (int i = 0; i < to_visit_.size(); ++i) {
594  const int node = to_visit_[i];
595  nexts_[node]->SetValue(node);
596  }
597  temp_support_.swap(inbound_support_);
598  }
599 
600  const std::vector<IntVar*> nexts_;
601  const int size_;
602  std::vector<int> insertion_queue_;
603  std::vector<int> to_visit_;
604  std::vector<bool> reached_;
605  RevArray<int> starts_;
606  RevArray<int> ends_;
607  RevArray<int> lengths_;
608  std::vector<IntVarIterator*> domains_;
609  std::vector<int> outbound_support_;
610  std::vector<int> inbound_support_;
611  std::vector<int> temp_support_;
612  Demon* inbound_demon_;
613  Demon* outbound_demon_;
614  Rev<int> root_;
615  NumericalRev<int> num_inactives_;
616  const bool sub_circuit_;
617 };
618 } // namespace
619 
620 Constraint* Solver::MakeNoCycle(const std::vector<IntVar*>& nexts,
621  const std::vector<IntVar*>& active,
622  Solver::IndexFilter1 sink_handler,
623  bool assume_paths) {
624  CHECK_EQ(nexts.size(), active.size());
625  if (sink_handler == nullptr) {
626  const int64_t size = nexts.size();
627  sink_handler = [size](int64_t index) { return index >= size; };
628  }
629  return RevAlloc(new NoCycle(this, nexts, active, sink_handler, assume_paths));
630 }
631 
632 Constraint* Solver::MakeNoCycle(const std::vector<IntVar*>& nexts,
633  const std::vector<IntVar*>& active,
634  Solver::IndexFilter1 sink_handler) {
635  return MakeNoCycle(nexts, active, std::move(sink_handler), true);
636 }
637 
638 // TODO(user): Merge NoCycle and Circuit.
639 Constraint* Solver::MakeCircuit(const std::vector<IntVar*>& nexts) {
640  return RevAlloc(new Circuit(this, nexts, false));
641 }
642 
643 Constraint* Solver::MakeSubCircuit(const std::vector<IntVar*>& nexts) {
644  return RevAlloc(new Circuit(this, nexts, true));
645 }
646 
647 // ----- Path cumul constraints -----
648 
649 namespace {
650 class BasePathCumul : public Constraint {
651  public:
652  BasePathCumul(Solver* const s, const std::vector<IntVar*>& nexts,
653  const std::vector<IntVar*>& active,
654  const std::vector<IntVar*>& cumuls);
655  ~BasePathCumul() override {}
656  void Post() override;
657  void InitialPropagate() override;
658  void ActiveBound(int index);
659  virtual void NextBound(int index) = 0;
660  virtual bool AcceptLink(int i, int j) const = 0;
661  void UpdateSupport(int index);
662  void CumulRange(int index);
663  std::string DebugString() const override;
664 
665  protected:
666  int64_t size() const { return nexts_.size(); }
667  int cumul_size() const { return cumuls_.size(); }
668 
669  const std::vector<IntVar*> nexts_;
670  const std::vector<IntVar*> active_;
671  const std::vector<IntVar*> cumuls_;
672  RevArray<int> prevs_;
673  std::vector<int> supports_;
674 };
675 
676 BasePathCumul::BasePathCumul(Solver* const s, const std::vector<IntVar*>& nexts,
677  const std::vector<IntVar*>& active,
678  const std::vector<IntVar*>& cumuls)
679  : Constraint(s),
680  nexts_(nexts),
681  active_(active),
682  cumuls_(cumuls),
683  prevs_(cumuls.size(), -1),
684  supports_(nexts.size()) {
685  CHECK_GE(cumul_size(), size());
686  for (int i = 0; i < size(); ++i) {
687  supports_[i] = -1;
688  }
689 }
690 
691 void BasePathCumul::InitialPropagate() {
692  for (int i = 0; i < size(); ++i) {
693  if (nexts_[i]->Bound()) {
694  NextBound(i);
695  } else {
696  UpdateSupport(i);
697  }
698  }
699 }
700 
701 void BasePathCumul::Post() {
702  for (int i = 0; i < size(); ++i) {
703  IntVar* var = nexts_[i];
704  Demon* d = MakeConstraintDemon1(solver(), this, &BasePathCumul::NextBound,
705  "NextBound", i);
706  var->WhenBound(d);
707  Demon* ds = MakeConstraintDemon1(
708  solver(), this, &BasePathCumul::UpdateSupport, "UpdateSupport", i);
709  var->WhenDomain(ds);
710  Demon* active_demon = MakeConstraintDemon1(
711  solver(), this, &BasePathCumul::ActiveBound, "ActiveBound", i);
712  active_[i]->WhenBound(active_demon);
713  }
714  for (int i = 0; i < cumul_size(); ++i) {
715  IntVar* cumul = cumuls_[i];
716  Demon* d = MakeConstraintDemon1(solver(), this, &BasePathCumul::CumulRange,
717  "CumulRange", i);
718  cumul->WhenRange(d);
719  }
720 }
721 
722 void BasePathCumul::ActiveBound(int index) {
723  if (nexts_[index]->Bound()) {
724  NextBound(index);
725  }
726 }
727 
728 void BasePathCumul::CumulRange(int index) {
729  if (index < size()) {
730  if (nexts_[index]->Bound()) {
731  NextBound(index);
732  } else {
733  UpdateSupport(index);
734  }
735  }
736  if (prevs_[index] >= 0) {
737  NextBound(prevs_[index]);
738  } else {
739  for (int i = 0; i < size(); ++i) {
740  if (index == supports_[i]) {
741  UpdateSupport(i);
742  }
743  }
744  }
745 }
746 
747 void BasePathCumul::UpdateSupport(int index) {
748  int support = supports_[index];
749  if (support < 0 || !AcceptLink(index, support)) {
750  IntVar* var = nexts_[index];
751  for (int i = var->Min(); i <= var->Max(); ++i) {
752  if (i != support && AcceptLink(index, i)) {
753  supports_[index] = i;
754  return;
755  }
756  }
757  active_[index]->SetMax(0);
758  }
759 }
760 
761 std::string BasePathCumul::DebugString() const {
762  std::string out = "PathCumul(";
763  for (int i = 0; i < size(); ++i) {
764  out += nexts_[i]->DebugString() + " " + cumuls_[i]->DebugString();
765  }
766  out += ")";
767  return out;
768 }
769 
770 // cumuls[next[i]] = cumuls[i] + transits[i]
771 
772 class PathCumul : public BasePathCumul {
773  public:
774  PathCumul(Solver* const s, const std::vector<IntVar*>& nexts,
775  const std::vector<IntVar*>& active,
776  const std::vector<IntVar*>& cumuls,
777  const std::vector<IntVar*>& transits)
778  : BasePathCumul(s, nexts, active, cumuls), transits_(transits) {}
779  ~PathCumul() override {}
780  void Post() override;
781  void NextBound(int index) override;
782  bool AcceptLink(int i, int j) const override;
783  void TransitRange(int index);
784 
785  void Accept(ModelVisitor* const visitor) const override {
786  visitor->BeginVisitConstraint(ModelVisitor::kPathCumul, this);
787  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
788  nexts_);
789  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kActiveArgument,
790  active_);
791  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kCumulsArgument,
792  cumuls_);
793  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kTransitsArgument,
794  transits_);
795  visitor->EndVisitConstraint(ModelVisitor::kPathCumul, this);
796  }
797 
798  private:
799  const std::vector<IntVar*> transits_;
800 };
801 
802 void PathCumul::Post() {
803  BasePathCumul::Post();
804  for (int i = 0; i < size(); ++i) {
805  Demon* transit_demon = MakeConstraintDemon1(
806  solver(), this, &PathCumul::TransitRange, "TransitRange", i);
807  transits_[i]->WhenRange(transit_demon);
808  }
809 }
810 
811 void PathCumul::NextBound(int index) {
812  if (active_[index]->Min() == 0) return;
813  const int64_t next = nexts_[index]->Value();
814  IntVar* cumul = cumuls_[index];
815  IntVar* cumul_next = cumuls_[next];
816  IntVar* transit = transits_[index];
817  cumul_next->SetMin(cumul->Min() + transit->Min());
818  cumul_next->SetMax(CapAdd(cumul->Max(), transit->Max()));
819  cumul->SetMin(CapSub(cumul_next->Min(), transit->Max()));
820  cumul->SetMax(CapSub(cumul_next->Max(), transit->Min()));
821  transit->SetMin(CapSub(cumul_next->Min(), cumul->Max()));
822  transit->SetMax(CapSub(cumul_next->Max(), cumul->Min()));
823  if (prevs_[next] < 0) {
824  prevs_.SetValue(solver(), next, index);
825  }
826 }
827 
828 void PathCumul::TransitRange(int index) {
829  if (nexts_[index]->Bound()) {
830  NextBound(index);
831  } else {
832  UpdateSupport(index);
833  }
834  if (prevs_[index] >= 0) {
835  NextBound(prevs_[index]);
836  } else {
837  for (int i = 0; i < size(); ++i) {
838  if (index == supports_[i]) {
839  UpdateSupport(i);
840  }
841  }
842  }
843 }
844 
845 bool PathCumul::AcceptLink(int i, int j) const {
846  const IntVar* const cumul_i = cumuls_[i];
847  const IntVar* const cumul_j = cumuls_[j];
848  const IntVar* const transit_i = transits_[i];
849  return transit_i->Min() <= CapSub(cumul_j->Max(), cumul_i->Min()) &&
850  CapSub(cumul_j->Min(), cumul_i->Max()) <= transit_i->Max();
851 }
852 
853 namespace {
854 template <class T>
855 class StampedVector {
856  public:
857  StampedVector() : stamp_(0) {}
858  const std::vector<T>& Values(Solver* solver) {
859  CheckStamp(solver);
860  return values_;
861  }
862  void PushBack(Solver* solver, const T& value) {
863  CheckStamp(solver);
864  values_.push_back(value);
865  }
866  void Clear(Solver* solver) {
867  values_.clear();
868  stamp_ = solver->fail_stamp();
869  }
870 
871  private:
872  void CheckStamp(Solver* solver) {
873  if (solver->fail_stamp() > stamp_) {
874  Clear(solver);
875  }
876  }
877 
878  std::vector<T> values_;
879  uint64_t stamp_;
880 };
881 } // namespace
882 
883 class DelayedPathCumul : public Constraint {
884  public:
885  DelayedPathCumul(Solver* const solver, const std::vector<IntVar*>& nexts,
886  const std::vector<IntVar*>& active,
887  const std::vector<IntVar*>& cumuls,
888  const std::vector<IntVar*>& transits)
889  : Constraint(solver),
890  nexts_(nexts),
891  active_(active),
892  cumuls_(cumuls),
893  transits_(transits),
894  cumul_transit_demons_(cumuls.size(), nullptr),
895  path_demon_(nullptr),
896  touched_(),
897  chain_starts_(cumuls.size(), -1),
898  chain_ends_(cumuls.size(), -1),
899  is_chain_start_(cumuls.size(), false),
900  prevs_(cumuls.size(), -1),
901  supports_(nexts.size()),
902  was_bound_(nexts.size(), false),
903  has_cumul_demon_(cumuls.size(), false) {
904  for (int64_t i = 0; i < cumuls_.size(); ++i) {
905  cumul_transit_demons_[i] = MakeDelayedConstraintDemon1(
906  solver, this, &DelayedPathCumul::CumulRange, "CumulRange", i);
907  chain_starts_[i] = i;
908  chain_ends_[i] = i;
909  }
910  path_demon_ = MakeDelayedConstraintDemon0(
911  solver, this, &DelayedPathCumul::PropagatePaths, "PropagatePaths");
912  for (int i = 0; i < nexts_.size(); ++i) {
913  supports_[i] = -1;
914  }
915  }
916  ~DelayedPathCumul() override {}
917  void Post() override {
918  solver()->RegisterDemon(path_demon_);
919  for (int i = 0; i < nexts_.size(); ++i) {
920  if (!nexts_[i]->Bound()) {
921  Demon* const demon = MakeConstraintDemon1(
922  solver(), this, &DelayedPathCumul::NextBound, "NextBound", i);
923  nexts_[i]->WhenBound(demon);
924  }
925  }
926  for (int i = 0; i < active_.size(); ++i) {
927  if (!active_[i]->Bound()) {
928  Demon* const demon = MakeConstraintDemon1(
929  solver(), this, &DelayedPathCumul::ActiveBound, "ActiveBound", i);
930  active_[i]->WhenBound(demon);
931  }
932  }
933  }
934  void InitialPropagate() override {
935  touched_.Clear(solver());
936  for (int i = 0; i < nexts_.size(); ++i) {
937  if (nexts_[i]->Bound()) {
938  NextBound(i);
939  }
940  }
941  for (int i = 0; i < active_.size(); ++i) {
942  if (active_[i]->Bound()) {
943  ActiveBound(i);
944  }
945  }
946  }
947  // TODO(user): Merge NextBound and ActiveBound to re-use the same demon
948  // for next and active variables.
949  void NextBound(int index) {
950  if (active_[index]->Min() > 0) {
951  const int next = nexts_[index]->Min();
952  PropagateLink(index, next);
953  touched_.PushBack(solver(), index);
954  EnqueueDelayedDemon(path_demon_);
955  }
956  }
957  void ActiveBound(int index) {
958  if (nexts_[index]->Bound()) {
959  NextBound(index);
960  }
961  }
962  void PropagatePaths() {
963  // Detecting new chains.
964  const std::vector<int>& touched_values = touched_.Values(solver());
965  for (const int touched : touched_values) {
966  chain_starts_[touched] = touched;
967  chain_ends_[touched] = touched;
968  is_chain_start_[touched] = false;
969  const int next = nexts_[touched]->Min();
970  chain_starts_[next] = next;
971  chain_ends_[next] = next;
972  is_chain_start_[next] = false;
973  }
974  for (const int touched : touched_values) {
975  if (touched >= nexts_.size()) continue;
976  IntVar* const next_var = nexts_[touched];
977  if (!was_bound_[touched] && next_var->Bound() &&
978  active_[touched]->Min() > 0) {
979  const int64_t next = next_var->Min();
980  was_bound_.SetValue(solver(), touched, true);
981  chain_starts_[chain_ends_[next]] = chain_starts_[touched];
982  chain_ends_[chain_starts_[touched]] = chain_ends_[next];
983  is_chain_start_[next] = false;
984  is_chain_start_[chain_starts_[touched]] = true;
985  }
986  }
987  // Propagating new chains.
988  for (const int touched : touched_values) {
989  // Is touched the start of a chain ?
990  if (is_chain_start_[touched]) {
991  // Propagate min cumuls from chain_starts[touch] to chain_ends_[touch].
992  int64_t current = touched;
993  int64_t next = nexts_[current]->Min();
994  while (current != chain_ends_[touched]) {
995  prevs_.SetValue(solver(), next, current);
996  PropagateLink(current, next);
997  current = next;
998  if (current != chain_ends_[touched]) {
999  next = nexts_[current]->Min();
1000  }
1001  }
1002  // Propagate max cumuls from chain_ends_[i] to chain_starts_[i].
1003  int64_t prev = prevs_[current];
1004  while (current != touched) {
1005  PropagateLink(prev, current);
1006  current = prev;
1007  if (current != touched) {
1008  prev = prevs_[current];
1009  }
1010  }
1011  // Now that the chain has been propagated in both directions, adding
1012  // demons for the corresponding cumul and transit variables for
1013  // future changes in their range.
1014  current = touched;
1015  while (current != chain_ends_[touched]) {
1016  if (!has_cumul_demon_[current]) {
1017  Demon* const demon = cumul_transit_demons_[current];
1018  cumuls_[current]->WhenRange(demon);
1019  transits_[current]->WhenRange(demon);
1020  has_cumul_demon_.SetValue(solver(), current, true);
1021  }
1022  current = nexts_[current]->Min();
1023  }
1024  if (!has_cumul_demon_[current]) {
1025  Demon* const demon = cumul_transit_demons_[current];
1026  cumuls_[current]->WhenRange(demon);
1027  if (current < transits_.size()) {
1028  transits_[current]->WhenRange(demon);
1029  UpdateSupport(current);
1030  }
1031  has_cumul_demon_.SetValue(solver(), current, true);
1032  }
1033  }
1034  }
1035  touched_.Clear(solver());
1036  }
1037 
1038  void Accept(ModelVisitor* const visitor) const override {
1039  visitor->BeginVisitConstraint(ModelVisitor::kDelayedPathCumul, this);
1040  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
1041  nexts_);
1042  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kActiveArgument,
1043  active_);
1044  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kCumulsArgument,
1045  cumuls_);
1046  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kTransitsArgument,
1047  transits_);
1048  visitor->EndVisitConstraint(ModelVisitor::kDelayedPathCumul, this);
1049  }
1050 
1051  std::string DebugString() const override {
1052  std::string out = "DelayedPathCumul(";
1053  for (int i = 0; i < nexts_.size(); ++i) {
1054  out += nexts_[i]->DebugString() + " " + cumuls_[i]->DebugString();
1055  }
1056  out += ")";
1057  return out;
1058  }
1059 
1060  private:
1061  void CumulRange(int64_t index) {
1062  if (index < nexts_.size()) {
1063  if (nexts_[index]->Bound()) {
1064  if (active_[index]->Min() > 0) {
1065  PropagateLink(index, nexts_[index]->Min());
1066  }
1067  } else {
1068  UpdateSupport(index);
1069  }
1070  }
1071  if (prevs_[index] >= 0) {
1072  PropagateLink(prevs_[index], index);
1073  } else {
1074  for (int i = 0; i < nexts_.size(); ++i) {
1075  if (index == supports_[i]) {
1076  UpdateSupport(i);
1077  }
1078  }
1079  }
1080  }
1081  void UpdateSupport(int index) {
1082  int support = supports_[index];
1083  if (support < 0 || !AcceptLink(index, support)) {
1084  IntVar* const next = nexts_[index];
1085  for (int i = next->Min(); i <= next->Max(); ++i) {
1086  if (i != support && AcceptLink(index, i)) {
1087  supports_[index] = i;
1088  return;
1089  }
1090  }
1091  active_[index]->SetMax(0);
1092  }
1093  }
1094  void PropagateLink(int64_t index, int64_t next) {
1095  IntVar* const cumul_var = cumuls_[index];
1096  IntVar* const next_cumul_var = cumuls_[next];
1097  IntVar* const transit = transits_[index];
1098  const int64_t transit_min = transit->Min();
1099  const int64_t transit_max = transit->Max();
1100  next_cumul_var->SetMin(CapAdd(cumul_var->Min(), transit_min));
1101  next_cumul_var->SetMax(CapAdd(cumul_var->Max(), transit_max));
1102  const int64_t next_cumul_min = next_cumul_var->Min();
1103  const int64_t next_cumul_max = next_cumul_var->Max();
1104  cumul_var->SetMin(CapSub(next_cumul_min, transit_max));
1105  cumul_var->SetMax(CapSub(next_cumul_max, transit_min));
1106  transit->SetMin(CapSub(next_cumul_min, cumul_var->Max()));
1107  transit->SetMax(CapSub(next_cumul_max, cumul_var->Min()));
1108  }
1109  bool AcceptLink(int index, int next) const {
1110  IntVar* const cumul_var = cumuls_[index];
1111  IntVar* const next_cumul_var = cumuls_[next];
1112  IntVar* const transit = transits_[index];
1113  return transit->Min() <= CapSub(next_cumul_var->Max(), cumul_var->Min()) &&
1114  CapSub(next_cumul_var->Min(), cumul_var->Max()) <= transit->Max();
1115  }
1116 
1117  const std::vector<IntVar*> nexts_;
1118  const std::vector<IntVar*> active_;
1119  const std::vector<IntVar*> cumuls_;
1120  const std::vector<IntVar*> transits_;
1121  std::vector<Demon*> cumul_transit_demons_;
1122  Demon* path_demon_;
1123  StampedVector<int> touched_;
1124  std::vector<int64_t> chain_starts_;
1125  std::vector<int64_t> chain_ends_;
1126  std::vector<bool> is_chain_start_;
1127  RevArray<int> prevs_;
1128  std::vector<int> supports_;
1129  RevArray<bool> was_bound_;
1130  RevArray<bool> has_cumul_demon_;
1131 };
1132 
1133 // cumuls[next[i]] = cumuls[i] + transit_evaluator(i, next[i])
1134 
1135 class IndexEvaluator2PathCumul : public BasePathCumul {
1136  public:
1137  IndexEvaluator2PathCumul(Solver* const s, const std::vector<IntVar*>& nexts,
1138  const std::vector<IntVar*>& active,
1139  const std::vector<IntVar*>& cumuls,
1140  Solver::IndexEvaluator2 transit_evaluator);
1141  ~IndexEvaluator2PathCumul() override {}
1142  void NextBound(int index) override;
1143  bool AcceptLink(int i, int j) const override;
1144 
1145  void Accept(ModelVisitor* const visitor) const override {
1146  visitor->BeginVisitConstraint(ModelVisitor::kPathCumul, this);
1147  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
1148  nexts_);
1149  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kActiveArgument,
1150  active_);
1151  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kCumulsArgument,
1152  cumuls_);
1153  // TODO(user): Visit transit correctly.
1154  // visitor->VisitIntegerVariableArrayArgument(
1155  // ModelVisitor::kTransitsArgument,
1156  // transit_evaluator);
1157  visitor->EndVisitConstraint(ModelVisitor::kPathCumul, this);
1158  }
1159 
1160  private:
1161  Solver::IndexEvaluator2 transits_evaluator_;
1162 };
1163 
1164 IndexEvaluator2PathCumul::IndexEvaluator2PathCumul(
1165  Solver* const s, const std::vector<IntVar*>& nexts,
1166  const std::vector<IntVar*>& active, const std::vector<IntVar*>& cumuls,
1167  Solver::IndexEvaluator2 transit_evaluator)
1168  : BasePathCumul(s, nexts, active, cumuls),
1169  transits_evaluator_(std::move(transit_evaluator)) {}
1170 
1171 void IndexEvaluator2PathCumul::NextBound(int index) {
1172  if (active_[index]->Min() == 0) return;
1173  const int64_t next = nexts_[index]->Value();
1174  IntVar* cumul = cumuls_[index];
1175  IntVar* cumul_next = cumuls_[next];
1176  const int64_t transit = transits_evaluator_(index, next);
1177  cumul_next->SetMin(cumul->Min() + transit);
1178  cumul_next->SetMax(CapAdd(cumul->Max(), transit));
1179  cumul->SetMin(CapSub(cumul_next->Min(), transit));
1180  cumul->SetMax(CapSub(cumul_next->Max(), transit));
1181  if (prevs_[next] < 0) {
1182  prevs_.SetValue(solver(), next, index);
1183  }
1184 }
1185 
1186 bool IndexEvaluator2PathCumul::AcceptLink(int i, int j) const {
1187  const IntVar* const cumul_i = cumuls_[i];
1188  const IntVar* const cumul_j = cumuls_[j];
1189  const int64_t transit = transits_evaluator_(i, j);
1190  return transit <= CapSub(cumul_j->Max(), cumul_i->Min()) &&
1191  CapSub(cumul_j->Min(), cumul_i->Max()) <= transit;
1192 }
1193 
1194 // ----- ResulatCallback2SlackPathCumul -----
1195 
1196 class IndexEvaluator2SlackPathCumul : public BasePathCumul {
1197  public:
1198  IndexEvaluator2SlackPathCumul(Solver* const s,
1199  const std::vector<IntVar*>& nexts,
1200  const std::vector<IntVar*>& active,
1201  const std::vector<IntVar*>& cumuls,
1202  const std::vector<IntVar*>& slacks,
1203  Solver::IndexEvaluator2 transit_evaluator);
1204  ~IndexEvaluator2SlackPathCumul() override {}
1205  void Post() override;
1206  void NextBound(int index) override;
1207  bool AcceptLink(int i, int j) const override;
1208  void SlackRange(int index);
1209 
1210  void Accept(ModelVisitor* const visitor) const override {
1211  visitor->BeginVisitConstraint(ModelVisitor::kPathCumul, this);
1212  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kNextsArgument,
1213  nexts_);
1214  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kActiveArgument,
1215  active_);
1216  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kCumulsArgument,
1217  cumuls_);
1218  // TODO(user): Visit transit correctly.
1219  // visitor->VisitIntegerVariableArrayArgument(
1220  // ModelVisitor::kTransitsArgument,
1221  // transit_evaluator);
1222  visitor->EndVisitConstraint(ModelVisitor::kPathCumul, this);
1223  }
1224 
1225  private:
1226  const std::vector<IntVar*> slacks_;
1227  Solver::IndexEvaluator2 transits_evaluator_;
1228 };
1229 
1230 IndexEvaluator2SlackPathCumul::IndexEvaluator2SlackPathCumul(
1231  Solver* const s, const std::vector<IntVar*>& nexts,
1232  const std::vector<IntVar*>& active, const std::vector<IntVar*>& cumuls,
1233  const std::vector<IntVar*>& slacks,
1234  Solver::IndexEvaluator2 transit_evaluator)
1235  : BasePathCumul(s, nexts, active, cumuls),
1236  slacks_(slacks),
1237  transits_evaluator_(std::move(transit_evaluator)) {}
1238 
1239 void IndexEvaluator2SlackPathCumul::Post() {
1240  BasePathCumul::Post();
1241  for (int i = 0; i < size(); ++i) {
1242  Demon* slack_demon = MakeConstraintDemon1(
1243  solver(), this, &IndexEvaluator2SlackPathCumul::SlackRange,
1244  "SlackRange", i);
1245  slacks_[i]->WhenRange(slack_demon);
1246  }
1247 }
1248 
1249 void IndexEvaluator2SlackPathCumul::SlackRange(int index) {
1250  if (nexts_[index]->Bound()) {
1251  NextBound(index);
1252  } else {
1253  UpdateSupport(index);
1254  }
1255  if (prevs_[index] >= 0) {
1256  NextBound(prevs_[index]);
1257  } else {
1258  for (int i = 0; i < size(); ++i) {
1259  if (index == supports_[i]) {
1260  UpdateSupport(i);
1261  }
1262  }
1263  }
1264 }
1265 
1266 void IndexEvaluator2SlackPathCumul::NextBound(int index) {
1267  if (active_[index]->Min() == 0) return;
1268  const int64_t next = nexts_[index]->Value();
1269  IntVar* const cumul = cumuls_[index];
1270  IntVar* const cumul_next = cumuls_[next];
1271  IntVar* const slack = slacks_[index];
1272  const int64_t transit = transits_evaluator_(index, next);
1273  const int64_t cumul_next_minus_transit_min =
1274  CapSub(cumul_next->Min(), transit);
1275  const int64_t cumul_next_minus_transit_max =
1276  CapSub(cumul_next->Max(), transit);
1277  cumul_next->SetMin(CapAdd(CapAdd(cumul->Min(), transit), slack->Min()));
1278  cumul_next->SetMax(CapAdd(CapAdd(cumul->Max(), transit), slack->Max()));
1279  cumul->SetMin(CapSub(cumul_next_minus_transit_min, slack->Max()));
1280  cumul->SetMax(CapSub(cumul_next_minus_transit_max, slack->Min()));
1281  slack->SetMin(CapSub(cumul_next_minus_transit_min, cumul->Max()));
1282  slack->SetMax(CapSub(cumul_next_minus_transit_max, cumul->Min()));
1283  if (prevs_[next] < 0) {
1284  prevs_.SetValue(solver(), next, index);
1285  }
1286 }
1287 
1288 bool IndexEvaluator2SlackPathCumul::AcceptLink(int i, int j) const {
1289  const IntVar* const cumul_i = cumuls_[i];
1290  const IntVar* const cumul_j = cumuls_[j];
1291  const IntVar* const slack = slacks_[i];
1292  const int64_t transit = transits_evaluator_(i, j);
1293  return CapAdd(transit, slack->Min()) <=
1294  CapSub(cumul_j->Max(), cumul_i->Min()) &&
1295  CapSub(cumul_j->Min(), cumul_i->Max()) <=
1296  CapAdd(slack->Max(), transit);
1297 }
1298 } // namespace
1299 
1300 Constraint* Solver::MakePathCumul(const std::vector<IntVar*>& nexts,
1301  const std::vector<IntVar*>& active,
1302  const std::vector<IntVar*>& cumuls,
1303  const std::vector<IntVar*>& transits) {
1304  CHECK_EQ(nexts.size(), active.size());
1305  CHECK_EQ(transits.size(), nexts.size());
1306  return RevAlloc(new PathCumul(this, nexts, active, cumuls, transits));
1307 }
1308 
1309 Constraint* Solver::MakePathCumul(const std::vector<IntVar*>& nexts,
1310  const std::vector<IntVar*>& active,
1311  const std::vector<IntVar*>& cumuls,
1312  Solver::IndexEvaluator2 transit_evaluator) {
1313  CHECK_EQ(nexts.size(), active.size());
1314  return RevAlloc(new IndexEvaluator2PathCumul(this, nexts, active, cumuls,
1315  std::move(transit_evaluator)));
1316 }
1317 
1318 Constraint* Solver::MakePathCumul(const std::vector<IntVar*>& nexts,
1319  const std::vector<IntVar*>& active,
1320  const std::vector<IntVar*>& cumuls,
1321  const std::vector<IntVar*>& slacks,
1322  Solver::IndexEvaluator2 transit_evaluator) {
1323  CHECK_EQ(nexts.size(), active.size());
1324  return RevAlloc(new IndexEvaluator2SlackPathCumul(
1325  this, nexts, active, cumuls, slacks, std::move(transit_evaluator)));
1326 }
1327 
1328 Constraint* Solver::MakeDelayedPathCumul(const std::vector<IntVar*>& nexts,
1329  const std::vector<IntVar*>& active,
1330  const std::vector<IntVar*>& cumuls,
1331  const std::vector<IntVar*>& transits) {
1332  CHECK_EQ(nexts.size(), active.size());
1333  CHECK_EQ(transits.size(), nexts.size());
1334  return RevAlloc(new DelayedPathCumul(this, nexts, active, cumuls, transits));
1335 }
1336 
1337 // Constraint enforcing that status[i] is true iff there's a path defined on
1338 // next variables from sources[i] to sinks[i].
1339 namespace {
1340 class PathConnectedConstraint : public Constraint {
1341  public:
1342  PathConnectedConstraint(Solver* solver, std::vector<IntVar*> nexts,
1343  const std::vector<int64_t>& sources,
1344  std::vector<int64_t> sinks,
1345  std::vector<IntVar*> status)
1346  : Constraint(solver),
1347  sources_(sources.size(), -1),
1348  index_to_path_(nexts.size(), -1),
1349  sinks_(std::move(sinks)),
1350  nexts_(std::move(nexts)),
1351  status_(std::move(status)),
1352  touched_(nexts_.size()) {
1353  CHECK_EQ(status_.size(), sources_.size());
1354  CHECK_EQ(status_.size(), sinks_.size());
1355  for (int i = 0; i < status_.size(); ++i) {
1356  const int64_t source = sources[i];
1357  sources_.SetValue(solver, i, source);
1358  if (source < index_to_path_.size()) {
1359  index_to_path_.SetValue(solver, source, i);
1360  }
1361  }
1362  }
1363  void Post() override {
1364  for (int i = 0; i < nexts_.size(); ++i) {
1365  nexts_[i]->WhenBound(MakeConstraintDemon1(
1366  solver(), this, &PathConnectedConstraint::NextBound, "NextValue", i));
1367  }
1368  for (int i = 0; i < status_.size(); ++i) {
1369  if (sources_[i] < nexts_.size()) {
1370  status_[i]->SetRange(0, 1);
1371  } else {
1372  status_[i]->SetValue(0);
1373  }
1374  }
1375  }
1376  void InitialPropagate() override {
1377  for (int i = 0; i < status_.size(); ++i) {
1378  EvaluatePath(i);
1379  }
1380  }
1381  std::string DebugString() const override {
1382  std::string output = "PathConnected(";
1383  std::vector<std::string> elements;
1384  for (IntVar* const next : nexts_) {
1385  elements.push_back(next->DebugString());
1386  }
1387  for (int i = 0; i < sources_.size(); ++i) {
1388  elements.push_back(absl::StrCat(sources_[i]));
1389  }
1390  for (int64_t sink : sinks_) {
1391  elements.push_back(absl::StrCat(sink));
1392  }
1393  for (IntVar* const status : status_) {
1394  elements.push_back(status->DebugString());
1395  }
1396  output += absl::StrJoin(elements, ",") + ")";
1397  return output;
1398  }
1399 
1400  private:
1401  void NextBound(int index) {
1402  const int path = index_to_path_[index];
1403  if (path >= 0) {
1404  EvaluatePath(path);
1405  }
1406  }
1407  void EvaluatePath(int path) {
1408  touched_.SparseClearAll();
1409  int64_t source = sources_[path];
1410  const int64_t end = sinks_[path];
1411  while (source != end) {
1412  if (source >= nexts_.size() || touched_[source]) {
1413  status_[path]->SetValue(0);
1414  return;
1415  }
1416  touched_.Set(source);
1417  IntVar* const next = nexts_[source];
1418  if (next->Bound()) {
1419  source = next->Min();
1420  } else {
1421  sources_.SetValue(solver(), path, source);
1422  index_to_path_.SetValue(solver(), source, path);
1423  return;
1424  }
1425  }
1426  status_[path]->SetValue(1);
1427  }
1428 
1429  RevArray<int64_t> sources_;
1430  RevArray<int> index_to_path_;
1431  const std::vector<int64_t> sinks_;
1432  const std::vector<IntVar*> nexts_;
1433  const std::vector<IntVar*> status_;
1434  SparseBitset<int64_t> touched_;
1435 };
1436 } // namespace
1437 
1438 Constraint* Solver::MakePathConnected(std::vector<IntVar*> nexts,
1439  std::vector<int64_t> sources,
1440  std::vector<int64_t> sinks,
1441  std::vector<IntVar*> status) {
1442  return RevAlloc(new PathConnectedConstraint(
1443  this, std::move(nexts), sources, std::move(sinks), std::move(status)));
1444 }
1445 
1446 namespace {
1447 class PathTransitPrecedenceConstraint : public Constraint {
1448  public:
1449  enum PrecedenceType {
1450  ANY,
1451  LIFO,
1452  FIFO,
1453  };
1454  PathTransitPrecedenceConstraint(
1455  Solver* solver, std::vector<IntVar*> nexts, std::vector<IntVar*> transits,
1456  const std::vector<std::pair<int, int>>& precedences,
1457  absl::flat_hash_map<int, PrecedenceType> precedence_types)
1458  : Constraint(solver),
1459  nexts_(std::move(nexts)),
1460  transits_(std::move(transits)),
1461  predecessors_(nexts_.size()),
1462  successors_(nexts_.size()),
1463  precedence_types_(std::move(precedence_types)),
1464  starts_(nexts_.size(), -1),
1465  ends_(nexts_.size(), -1),
1466  transit_cumuls_(nexts_.size(), 0) {
1467  for (int i = 0; i < nexts_.size(); ++i) {
1468  starts_.SetValue(solver, i, i);
1469  ends_.SetValue(solver, i, i);
1470  }
1471  for (const auto& precedence : precedences) {
1472  if (precedence.second < nexts_.size()) {
1473  predecessors_[precedence.second].push_back(precedence.first);
1474  }
1475  if (precedence.first < nexts_.size()) {
1476  successors_[precedence.first].push_back(precedence.second);
1477  }
1478  }
1479  }
1480  ~PathTransitPrecedenceConstraint() override {}
1481  void Post() override {
1482  for (int i = 0; i < nexts_.size(); ++i) {
1483  nexts_[i]->WhenBound(MakeDelayedConstraintDemon1(
1484  solver(), this, &PathTransitPrecedenceConstraint::NextBound,
1485  "NextBound", i));
1486  }
1487  for (int i = 0; i < transits_.size(); ++i) {
1488  transits_[i]->WhenRange(MakeDelayedConstraintDemon1(
1489  solver(), this, &PathTransitPrecedenceConstraint::NextBound,
1490  "TransitRange", i));
1491  }
1492  }
1493  void InitialPropagate() override {
1494  for (int i = 0; i < nexts_.size(); ++i) {
1495  if (nexts_[i]->Bound()) {
1496  NextBound(i);
1497  }
1498  }
1499  }
1500  std::string DebugString() const override {
1501  std::string output = "PathPrecedence(";
1502  std::vector<std::string> elements = {JoinDebugStringPtr(nexts_, ",")};
1503  if (!transits_.empty()) {
1504  elements.push_back(JoinDebugStringPtr(transits_, ","));
1505  }
1506  for (int i = 0; i < predecessors_.size(); ++i) {
1507  for (const int predecessor : predecessors_[i]) {
1508  elements.push_back(absl::StrCat("(", predecessor, ", ", i, ")"));
1509  }
1510  }
1511  output += absl::StrJoin(elements, ",") + ")";
1512  return output;
1513  }
1514  void Accept(ModelVisitor* const visitor) const override {
1515  // TODO(user): Implement.
1516  }
1517 
1518  private:
1519  void NextBound(int index) {
1520  if (!nexts_[index]->Bound()) return;
1521  const int next = nexts_[index]->Min();
1522  const int start = starts_[index];
1523  const int end = (next < nexts_.size()) ? ends_[next] : next;
1524  if (end < nexts_.size()) starts_.SetValue(solver(), end, start);
1525  ends_.SetValue(solver(), start, end);
1526  int current = start;
1527  PrecedenceType type = ANY;
1528  auto it = precedence_types_.find(start);
1529  if (it != precedence_types_.end()) {
1530  type = it->second;
1531  }
1532  forbidden_.clear();
1533  marked_.clear();
1534  pushed_.clear();
1535  int64_t transit_cumul = 0;
1536  const bool has_transits = !transits_.empty();
1537  while (current < nexts_.size() && current != end) {
1538  transit_cumuls_[current] = transit_cumul;
1539  marked_.insert(current);
1540  // If current has predecessors and we are in LIFO/FIFO mode.
1541  if (!predecessors_[current].empty() && !pushed_.empty()) {
1542  bool found = false;
1543  // One of the predecessors must be at the top of the stack.
1544  for (const int predecessor : predecessors_[current]) {
1545  if (pushed_.back() == predecessor) {
1546  found = true;
1547  break;
1548  }
1549  }
1550  if (!found) solver()->Fail();
1551  pushed_.pop_back();
1552  }
1553  if (forbidden_.find(current) != forbidden_.end()) {
1554  for (const int successor : successors_[current]) {
1555  if (marked_.find(successor) != marked_.end()) {
1556  if (!has_transits ||
1557  CapSub(transit_cumul, transit_cumuls_[successor]) > 0) {
1558  solver()->Fail();
1559  }
1560  }
1561  }
1562  }
1563  if (!successors_[current].empty()) {
1564  switch (type) {
1565  case LIFO:
1566  pushed_.push_back(current);
1567  break;
1568  case FIFO:
1569  pushed_.push_front(current);
1570  break;
1571  case ANY:
1572  break;
1573  }
1574  }
1575  for (const int predecessor : predecessors_[current]) {
1576  forbidden_.insert(predecessor);
1577  }
1578  if (has_transits) {
1579  transit_cumul = CapAdd(transit_cumul, transits_[current]->Min());
1580  }
1581  current = nexts_[current]->Min();
1582  }
1583  if (forbidden_.find(current) != forbidden_.end()) {
1584  for (const int successor : successors_[current]) {
1585  if (marked_.find(successor) != marked_.end()) {
1586  if (!has_transits ||
1587  CapSub(transit_cumul, transit_cumuls_[successor]) > 0) {
1588  solver()->Fail();
1589  }
1590  }
1591  }
1592  }
1593  }
1594 
1595  const std::vector<IntVar*> nexts_;
1596  const std::vector<IntVar*> transits_;
1597  std::vector<std::vector<int>> predecessors_;
1598  std::vector<std::vector<int>> successors_;
1599  const absl::flat_hash_map<int, PrecedenceType> precedence_types_;
1600  RevArray<int> starts_;
1601  RevArray<int> ends_;
1602  absl::flat_hash_set<int> forbidden_;
1603  absl::flat_hash_set<int> marked_;
1604  std::deque<int> pushed_;
1605  std::vector<int64_t> transit_cumuls_;
1606 };
1607 
1608 Constraint* MakePathTransitTypedPrecedenceConstraint(
1609  Solver* solver, std::vector<IntVar*> nexts, std::vector<IntVar*> transits,
1610  const std::vector<std::pair<int, int>>& precedences,
1611  absl::flat_hash_map<int, PathTransitPrecedenceConstraint::PrecedenceType>
1612  precedence_types) {
1613  if (precedences.empty()) {
1614  return solver->MakeTrueConstraint();
1615  }
1616  return solver->RevAlloc(new PathTransitPrecedenceConstraint(
1617  solver, std::move(nexts), std::move(transits), precedences,
1618  std::move(precedence_types)));
1619 }
1620 
1621 } // namespace
1622 
1623 Constraint* Solver::MakePathPrecedenceConstraint(
1624  std::vector<IntVar*> nexts,
1625  const std::vector<std::pair<int, int>>& precedences) {
1626  return MakePathTransitPrecedenceConstraint(std::move(nexts), {}, precedences);
1627 }
1628 
1629 Constraint* Solver::MakePathPrecedenceConstraint(
1630  std::vector<IntVar*> nexts,
1631  const std::vector<std::pair<int, int>>& precedences,
1632  const std::vector<int>& lifo_path_starts,
1633  const std::vector<int>& fifo_path_starts) {
1634  absl::flat_hash_map<int, PathTransitPrecedenceConstraint::PrecedenceType>
1635  precedence_types;
1636  for (int start : lifo_path_starts) {
1637  precedence_types[start] = PathTransitPrecedenceConstraint::LIFO;
1638  }
1639  for (int start : fifo_path_starts) {
1640  precedence_types[start] = PathTransitPrecedenceConstraint::FIFO;
1641  }
1642  return MakePathTransitTypedPrecedenceConstraint(
1643  this, std::move(nexts), {}, precedences, std::move(precedence_types));
1644 }
1645 
1646 Constraint* Solver::MakePathTransitPrecedenceConstraint(
1647  std::vector<IntVar*> nexts, std::vector<IntVar*> transits,
1648  const std::vector<std::pair<int, int>>& precedences) {
1649  return MakePathTransitTypedPrecedenceConstraint(
1650  this, std::move(nexts), std::move(transits), precedences, {{}});
1651 }
1652 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:705
#define CHECK_GE(val1, val2)
Definition: base/logging.h:709
A constraint is the main modeling object.
virtual void InitialPropagate()=0
This method performs the initial propagation of the constraint.
virtual void Accept(ModelVisitor *const visitor) const
Accepts the given visitor.
std::string DebugString() const override
virtual void Post()=0
This method is called when the constraint is processed by the solver.
static const char kActiveArgument[]
argument names:
std::function< int64_t(int64_t, int64_t)> IndexEvaluator2
std::function< bool(int64_t)> IndexFilter1
void Fail()
Abandon the current branch in the search tree. A backtrack will follow.
std::vector< IntVarIterator * > iterators_
Block * next
int64_t value
IntVar * var
Definition: expr_array.cc:1874
const std::vector< IntVar * > cumuls_
RevArray< int > prevs_
std::vector< int > supports_
Collection of objects used to extend the Constraint Solver library.
int64_t CapAdd(int64_t x, int64_t y)
Demon * MakeDelayedConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
int64_t CapSub(int64_t x, int64_t y)
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
Demon * MakeDelayedConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)
Definition: string_array.h:45
int index
Definition: pack.cc:509
const int64_t stamp_
Definition: search.cc:3054