OR-Tools  9.6
resource.cc
Go to the documentation of this file.
1 // Copyright 2010-2022 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 // This file contains implementations of several resource constraints.
15 // The implemented constraints are:
16 // * Disjunctive: forces a set of intervals to be non-overlapping
17 // * Cumulative: forces a set of intervals with associated demands to be such
18 // that the sum of demands of the intervals containing any given integer
19 // does not exceed a capacity.
20 // In addition, it implements the SequenceVar that allows ranking decisions
21 // on a set of interval variables.
22 
23 #include <algorithm>
24 #include <cstdint>
25 #include <functional>
26 #include <limits>
27 #include <queue>
28 #include <string>
29 #include <utility>
30 #include <vector>
31 
32 #include "absl/container/flat_hash_map.h"
33 #include "absl/strings/str_cat.h"
34 #include "absl/strings/str_format.h"
35 #include "absl/strings/str_join.h"
38 #include "ortools/base/logging.h"
39 #include "ortools/base/macros.h"
40 #include "ortools/base/mathutil.h"
41 #include "ortools/base/stl_util.h"
44 #include "ortools/util/bitset.h"
48 
49 namespace operations_research {
50 namespace {
51 // ----- Comparison functions -----
52 
53 // TODO(user): Tie breaking.
54 
55 // Comparison methods, used by the STL sort.
56 template <class Task>
57 bool StartMinLessThan(Task* const w1, Task* const w2) {
58  return (w1->interval->StartMin() < w2->interval->StartMin());
59 }
60 
61 // A comparator that sorts the tasks by their effective earliest start time when
62 // using the shortest duration possible. This comparator can be used when
63 // sorting the tasks before they are inserted to a Theta-tree.
64 template <class Task>
65 bool ShortestDurationStartMinLessThan(Task* const w1, Task* const w2) {
66  return w1->interval->EndMin() - w1->interval->DurationMin() <
67  w2->interval->EndMin() - w2->interval->DurationMin();
68 }
69 
70 template <class Task>
71 bool StartMaxLessThan(Task* const w1, Task* const w2) {
72  return (w1->interval->StartMax() < w2->interval->StartMax());
73 }
74 
75 template <class Task>
76 bool EndMinLessThan(Task* const w1, Task* const w2) {
77  return (w1->interval->EndMin() < w2->interval->EndMin());
78 }
79 
80 template <class Task>
81 bool EndMaxLessThan(Task* const w1, Task* const w2) {
82  return (w1->interval->EndMax() < w2->interval->EndMax());
83 }
84 
85 bool IntervalStartMinLessThan(IntervalVar* i1, IntervalVar* i2) {
86  return i1->StartMin() < i2->StartMin();
87 }
88 
89 // ----- Wrappers around intervals -----
90 
91 // A DisjunctiveTask is a non-preemptive task sharing a disjunctive resource.
92 // That is, it corresponds to an interval, and this interval cannot overlap with
93 // any other interval of a DisjunctiveTask sharing the same resource.
94 // It is indexed, that is it is aware of its position in a reference array.
95 struct DisjunctiveTask {
96  explicit DisjunctiveTask(IntervalVar* const interval_)
97  : interval(interval_), index(-1) {}
98 
99  std::string DebugString() const { return interval->DebugString(); }
100 
101  IntervalVar* interval;
102  int index;
103 };
104 
105 // A CumulativeTask is a non-preemptive task sharing a cumulative resource.
106 // That is, it corresponds to an interval and a demand. The sum of demands of
107 // all cumulative tasks CumulativeTasks sharing a resource of capacity c those
108 // intervals contain any integer t cannot exceed c.
109 // It is indexed, that is it is aware of its position in a reference array.
110 struct CumulativeTask {
111  CumulativeTask(IntervalVar* const interval_, int64_t demand_)
112  : interval(interval_), demand(demand_), index(-1) {}
113 
114  int64_t EnergyMin() const { return interval->DurationMin() * demand; }
115 
116  int64_t DemandMin() const { return demand; }
117 
118  void WhenAnything(Demon* const demon) { interval->WhenAnything(demon); }
119 
120  std::string DebugString() const {
121  return absl::StrFormat("Task{ %s, demand: %d }", interval->DebugString(),
122  demand);
123  }
124 
125  IntervalVar* interval;
126  int64_t demand;
127  int index;
128 };
129 
130 // A VariableCumulativeTask is a non-preemptive task sharing a
131 // cumulative resource. That is, it corresponds to an interval and a
132 // demand. The sum of demands of all cumulative tasks
133 // VariableCumulativeTasks sharing a resource of capacity c whose
134 // intervals contain any integer t cannot exceed c. It is indexed,
135 // that is it is aware of its position in a reference array.
136 struct VariableCumulativeTask {
137  VariableCumulativeTask(IntervalVar* const interval_, IntVar* demand_)
138  : interval(interval_), demand(demand_), index(-1) {}
139 
140  int64_t EnergyMin() const { return interval->DurationMin() * demand->Min(); }
141 
142  int64_t DemandMin() const { return demand->Min(); }
143 
144  void WhenAnything(Demon* const demon) {
145  interval->WhenAnything(demon);
146  demand->WhenRange(demon);
147  }
148 
149  std::string DebugString() const {
150  return absl::StrFormat("Task{ %s, demand: %s }", interval->DebugString(),
151  demand->DebugString());
152  }
153 
154  IntervalVar* const interval;
155  IntVar* const demand;
156  int index;
157 };
158 
159 // ---------- Theta-Trees ----------
160 
161 // This is based on Petr Vilim (public) PhD work.
162 // All names comes from his work. See http://vilim.eu/petr.
163 
164 // Node of a Theta-tree
165 struct ThetaNode {
166  // Identity element
167  ThetaNode()
168  : total_processing(0), total_ect(std::numeric_limits<int64_t>::min()) {}
169 
170  // Single interval element
171  explicit ThetaNode(const IntervalVar* const interval)
172  : total_processing(interval->DurationMin()),
173  total_ect(interval->EndMin()) {
174  // NOTE(user): Petr Vilim's thesis assumes that all tasks in the
175  // scheduling problem have fixed duration and that propagation already
176  // updated the bounds of the start/end times accordingly.
177  // The problem in this case is that the recursive formula for computing
178  // total_ect was only proved for the case where the duration is fixed; in
179  // our case, we use StartMin() + DurationMin() for the earliest completion
180  // time of a task, which should not break any assumptions, but may give
181  // bounds that are too loose.
182  }
183 
184  void Compute(const ThetaNode& left, const ThetaNode& right) {
185  total_processing = CapAdd(left.total_processing, right.total_processing);
186  total_ect = std::max(CapAdd(left.total_ect, right.total_processing),
187  right.total_ect);
188  }
189 
190  bool IsIdentity() const {
191  return total_processing == 0LL &&
193  }
194 
195  std::string DebugString() const {
196  return absl::StrCat("ThetaNode{ p = ", total_processing,
197  ", e = ", total_ect < 0LL ? -1LL : total_ect, " }");
198  }
199 
201  int64_t total_ect;
202 };
203 
204 // A theta-tree is a container for a set of intervals supporting the following
205 // operations:
206 // * Insertions and deletion in O(log size_), with size_ the maximal number of
207 // tasks the tree may contain;
208 // * Querying the following quantity in O(1):
209 // Max_{subset S of the set of contained intervals} (
210 // Min_{i in S}(i.StartMin) + Sum_{i in S}(i.DurationMin) )
211 class ThetaTree : public MonoidOperationTree<ThetaNode> {
212  public:
213  explicit ThetaTree(int size) : MonoidOperationTree<ThetaNode>(size) {}
214 
215  int64_t Ect() const { return result().total_ect; }
216 
217  void Insert(const DisjunctiveTask* const task) {
218  Set(task->index, ThetaNode(task->interval));
219  }
220 
221  void Remove(const DisjunctiveTask* const task) { Reset(task->index); }
222 
223  bool IsInserted(const DisjunctiveTask* const task) const {
224  return !GetOperand(task->index).IsIdentity();
225  }
226 };
227 
228 // ----------------- Lambda Theta Tree -----------------------
229 
230 // Lambda-theta-node
231 // These nodes are cumulative lambda theta-node. This is reflected in the
232 // terminology. They can also be used in the disjunctive case, and this incurs
233 // no performance penalty.
234 struct LambdaThetaNode {
235  // Special value for task indices meaning 'no such task'.
236  static const int kNone;
237 
238  // Identity constructor
239  LambdaThetaNode()
240  : energy(0LL),
241  energetic_end_min(std::numeric_limits<int64_t>::min()),
242  energy_opt(0LL),
244  energetic_end_min_opt(std::numeric_limits<int64_t>::min()),
246 
247  // Constructor for a single cumulative task in the Theta set
248  LambdaThetaNode(int64_t capacity, const CumulativeTask& task)
249  : energy(task.EnergyMin()),
250  energetic_end_min(CapAdd(capacity * task.interval->StartMin(), energy)),
255 
256  // Constructor for a single cumulative task in the Lambda set
257  LambdaThetaNode(int64_t capacity, const CumulativeTask& task, int index)
258  : energy(0LL),
259  energetic_end_min(std::numeric_limits<int64_t>::min()),
260  energy_opt(task.EnergyMin()),
262  energetic_end_min_opt(capacity * task.interval->StartMin() +
263  energy_opt),
265  DCHECK_GE(index, 0);
266  }
267 
268  // Constructor for a single cumulative task in the Theta set
269  LambdaThetaNode(int64_t capacity, const VariableCumulativeTask& task)
270  : energy(task.EnergyMin()),
271  energetic_end_min(CapAdd(capacity * task.interval->StartMin(), energy)),
276 
277  // Constructor for a single cumulative task in the Lambda set
278  LambdaThetaNode(int64_t capacity, const VariableCumulativeTask& task,
279  int index)
280  : energy(0LL),
281  energetic_end_min(std::numeric_limits<int64_t>::min()),
282  energy_opt(task.EnergyMin()),
284  energetic_end_min_opt(capacity * task.interval->StartMin() +
285  energy_opt),
287  DCHECK_GE(index, 0);
288  }
289 
290  // Constructor for a single interval in the Theta set
291  explicit LambdaThetaNode(const IntervalVar* const interval)
292  : energy(interval->DurationMin()),
293  energetic_end_min(interval->EndMin()),
294  energy_opt(interval->DurationMin()),
296  energetic_end_min_opt(interval->EndMin()),
298 
299  // Constructor for a single interval in the Lambda set
300  // 'index' is the index of the given interval in the est vector
301  LambdaThetaNode(const IntervalVar* const interval, int index)
302  : energy(0LL),
303  energetic_end_min(std::numeric_limits<int64_t>::min()),
304  energy_opt(interval->DurationMin()),
306  energetic_end_min_opt(interval->EndMin()),
308  DCHECK_GE(index, 0);
309  }
310 
311  // Sets this LambdaThetaNode to the result of the natural binary operations
312  // over the two given operands, corresponding to the following set operations:
313  // Theta = left.Theta union right.Theta
314  // Lambda = left.Lambda union right.Lambda
315  //
316  // No set operation actually occur: we only maintain the relevant quantities
317  // associated with such sets.
318  void Compute(const LambdaThetaNode& left, const LambdaThetaNode& right) {
319  energy = CapAdd(left.energy, right.energy);
320  energetic_end_min = std::max(right.energetic_end_min,
321  CapAdd(left.energetic_end_min, right.energy));
322  const int64_t energy_left_opt = CapAdd(left.energy_opt, right.energy);
323  const int64_t energy_right_opt = CapAdd(left.energy, right.energy_opt);
324  if (energy_left_opt > energy_right_opt) {
325  energy_opt = energy_left_opt;
326  argmax_energy_opt = left.argmax_energy_opt;
327  } else {
328  energy_opt = energy_right_opt;
329  argmax_energy_opt = right.argmax_energy_opt;
330  }
331  const int64_t ect1 = right.energetic_end_min_opt;
332  const int64_t ect2 = CapAdd(left.energetic_end_min, right.energy_opt);
333  const int64_t ect3 = CapAdd(left.energetic_end_min_opt, right.energy);
334  if (ect1 >= ect2 && ect1 >= ect3) { // ect1 max
335  energetic_end_min_opt = ect1;
336  argmax_energetic_end_min_opt = right.argmax_energetic_end_min_opt;
337  } else if (ect2 >= ect1 && ect2 >= ect3) { // ect2 max
338  energetic_end_min_opt = ect2;
339  argmax_energetic_end_min_opt = right.argmax_energy_opt;
340  } else { // ect3 max
341  energetic_end_min_opt = ect3;
342  argmax_energetic_end_min_opt = left.argmax_energetic_end_min_opt;
343  }
344  // The processing time, with one grey interval, should be no less than
345  // without any grey interval.
346  DCHECK(energy_opt >= energy);
347  // If there is no responsible grey interval for the processing time,
348  // the processing time with a grey interval should equal the one
349  // without.
350  DCHECK((argmax_energy_opt != kNone) || (energy_opt == energy));
351  }
352 
353  // Amount of resource consumed by the Theta set, in units of demand X time.
354  // This is energy(Theta).
355  int64_t energy;
356 
357  // Max_{subset S of Theta} (capacity * start_min(S) + energy(S))
359 
360  // Max_{i in Lambda} (energy(Theta union {i}))
361  int64_t energy_opt;
362 
363  // The argmax in energy_opt_. It is the index of the chosen task in the Lambda
364  // set, if any, or kNone if none.
366 
367  // Max_{subset S of Theta, i in Lambda}
368  // (capacity * start_min(S union {i}) + energy(S union {i}))
370 
371  // The argmax in energetic_end_min_opt_. It is the index of the chosen task in
372  // the Lambda set, if any, or kNone if none.
374 };
375 
376 const int LambdaThetaNode::kNone = -1;
377 
378 // Disjunctive Lambda-Theta tree
379 class DisjunctiveLambdaThetaTree : public MonoidOperationTree<LambdaThetaNode> {
380  public:
381  explicit DisjunctiveLambdaThetaTree(int size)
382  : MonoidOperationTree<LambdaThetaNode>(size) {}
383 
384  void Insert(const DisjunctiveTask& task) {
385  Set(task.index, LambdaThetaNode(task.interval));
386  }
387 
388  void Grey(const DisjunctiveTask& task) {
389  const int index = task.index;
390  Set(index, LambdaThetaNode(task.interval, index));
391  }
392 
393  int64_t Ect() const { return result().energetic_end_min; }
394  int64_t EctOpt() const { return result().energetic_end_min_opt; }
395  int ResponsibleOpt() const { return result().argmax_energetic_end_min_opt; }
396 };
397 
398 // A cumulative lambda-theta tree
399 class CumulativeLambdaThetaTree : public MonoidOperationTree<LambdaThetaNode> {
400  public:
401  CumulativeLambdaThetaTree(int size, int64_t capacity_max)
402  : MonoidOperationTree<LambdaThetaNode>(size),
403  capacity_max_(capacity_max) {}
404 
405  void Init(int64_t capacity_max) {
406  Clear();
407  capacity_max_ = capacity_max;
408  }
409 
410  void Insert(const CumulativeTask& task) {
411  Set(task.index, LambdaThetaNode(capacity_max_, task));
412  }
413 
414  void Grey(const CumulativeTask& task) {
415  const int index = task.index;
416  Set(index, LambdaThetaNode(capacity_max_, task, index));
417  }
418 
419  void Insert(const VariableCumulativeTask& task) {
420  Set(task.index, LambdaThetaNode(capacity_max_, task));
421  }
422 
423  void Grey(const VariableCumulativeTask& task) {
424  const int index = task.index;
425  Set(index, LambdaThetaNode(capacity_max_, task, index));
426  }
427 
428  int64_t energetic_end_min() const { return result().energetic_end_min; }
429  int64_t energetic_end_min_opt() const {
430  return result().energetic_end_min_opt;
431  }
432  int64_t Ect() const {
433  return MathUtil::CeilOfRatio(energetic_end_min(), capacity_max_);
434  }
435  int64_t EctOpt() const {
436  return MathUtil::CeilOfRatio(result().energetic_end_min_opt, capacity_max_);
437  }
438  int argmax_energetic_end_min_opt() const {
439  return result().argmax_energetic_end_min_opt;
440  }
441 
442  private:
443  int64_t capacity_max_;
444 };
445 
446 // -------------- Not Last -----------------------------------------
447 
448 // A class that implements the 'Not-Last' propagation algorithm for the unary
449 // resource constraint.
450 class NotLast {
451  public:
452  NotLast(Solver* const solver, const std::vector<IntervalVar*>& intervals,
453  bool mirror, bool strict);
454 
455  ~NotLast() { gtl::STLDeleteElements(&by_start_min_); }
456 
457  bool Propagate();
458 
459  private:
460  ThetaTree theta_tree_;
461  std::vector<DisjunctiveTask*> by_start_min_;
462  std::vector<DisjunctiveTask*> by_end_max_;
463  std::vector<DisjunctiveTask*> by_start_max_;
464  std::vector<int64_t> new_lct_;
465  const bool strict_;
466 };
467 
468 NotLast::NotLast(Solver* const solver,
469  const std::vector<IntervalVar*>& intervals, bool mirror,
470  bool strict)
471  : theta_tree_(intervals.size()),
472  by_start_min_(intervals.size()),
473  by_end_max_(intervals.size()),
474  by_start_max_(intervals.size()),
475  new_lct_(intervals.size(), -1LL),
476  strict_(strict) {
477  // Populate the different vectors.
478  for (int i = 0; i < intervals.size(); ++i) {
479  IntervalVar* const underlying =
480  mirror ? solver->MakeMirrorInterval(intervals[i]) : intervals[i];
481  IntervalVar* const relaxed = solver->MakeIntervalRelaxedMin(underlying);
482  by_start_min_[i] = new DisjunctiveTask(relaxed);
483  by_end_max_[i] = by_start_min_[i];
484  by_start_max_[i] = by_start_min_[i];
485  }
486 }
487 
488 bool NotLast::Propagate() {
489  // ---- Init ----
490  std::sort(by_start_max_.begin(), by_start_max_.end(),
491  StartMaxLessThan<DisjunctiveTask>);
492  std::sort(by_end_max_.begin(), by_end_max_.end(),
493  EndMaxLessThan<DisjunctiveTask>);
494  // Update start min positions
495  std::sort(by_start_min_.begin(), by_start_min_.end(),
496  StartMinLessThan<DisjunctiveTask>);
497  for (int i = 0; i < by_start_min_.size(); ++i) {
498  by_start_min_[i]->index = i;
499  }
500  theta_tree_.Clear();
501  for (int i = 0; i < by_start_min_.size(); ++i) {
502  new_lct_[i] = by_start_min_[i]->interval->EndMax();
503  }
504 
505  // --- Execute ----
506  int j = 0;
507  for (DisjunctiveTask* const twi : by_end_max_) {
508  while (j < by_start_max_.size() &&
509  twi->interval->EndMax() > by_start_max_[j]->interval->StartMax()) {
510  if (j > 0 && theta_tree_.Ect() > by_start_max_[j]->interval->StartMax()) {
511  const int64_t new_end_max = by_start_max_[j - 1]->interval->StartMax();
512  new_lct_[by_start_max_[j]->index] =
513  std::min(new_lct_[by_start_max_[j]->index], new_end_max);
514  }
515  theta_tree_.Insert(by_start_max_[j]);
516  j++;
517  }
518  const bool inserted = theta_tree_.IsInserted(twi);
519  if (inserted) {
520  theta_tree_.Remove(twi);
521  }
522  const int64_t ect_theta_less_i = theta_tree_.Ect();
523  if (inserted) {
524  theta_tree_.Insert(twi);
525  }
526 
527  if (ect_theta_less_i > twi->interval->StartMax() && j > 0) {
528  const int64_t new_end_max = by_start_max_[j - 1]->interval->StartMax();
529  if (new_end_max < new_lct_[twi->index]) {
530  new_lct_[twi->index] = new_end_max;
531  }
532  }
533  }
534 
535  // Apply modifications
536  bool modified = false;
537  for (int i = 0; i < by_start_min_.size(); ++i) {
538  IntervalVar* const var = by_start_min_[i]->interval;
539  if ((strict_ || var->DurationMin() > 0) && var->EndMax() > new_lct_[i]) {
540  modified = true;
541  var->SetEndMax(new_lct_[i]);
542  }
543  }
544  return modified;
545 }
546 
547 // ------ Edge finder + detectable precedences -------------
548 
549 // A class that implements two propagation algorithms: edge finding and
550 // detectable precedences. These algorithms both push intervals to the right,
551 // which is why they are grouped together.
552 class EdgeFinderAndDetectablePrecedences {
553  public:
554  EdgeFinderAndDetectablePrecedences(Solver* const solver,
555  const std::vector<IntervalVar*>& intervals,
556  bool mirror, bool strict);
557  ~EdgeFinderAndDetectablePrecedences() {
558  gtl::STLDeleteElements(&by_start_min_);
559  }
560  int64_t size() const { return by_start_min_.size(); }
561  IntervalVar* interval(int index) { return by_start_min_[index]->interval; }
562  void UpdateEst();
563  void OverloadChecking();
564  bool DetectablePrecedences();
565  bool EdgeFinder();
566 
567  private:
568  Solver* const solver_;
569 
570  // --- All the following member variables are essentially used as local ones:
571  // no invariant is maintained about them, except for the fact that the vectors
572  // always contains all the considered intervals, so any function that wants to
573  // use them must first sort them in the right order.
574 
575  // All of these vectors store the same set of objects. Therefore, at
576  // destruction time, STLDeleteElements should be called on only one of them.
577  // It does not matter which one.
578 
579  ThetaTree theta_tree_;
580  std::vector<DisjunctiveTask*> by_end_min_;
581  std::vector<DisjunctiveTask*> by_start_min_;
582  std::vector<DisjunctiveTask*> by_end_max_;
583  std::vector<DisjunctiveTask*> by_start_max_;
584  // new_est_[i] is the new start min for interval est_[i]->interval.
585  std::vector<int64_t> new_est_;
586  // new_lct_[i] is the new end max for interval est_[i]->interval.
587  std::vector<int64_t> new_lct_;
588  DisjunctiveLambdaThetaTree lt_tree_;
589  const bool strict_;
590 };
591 
592 EdgeFinderAndDetectablePrecedences::EdgeFinderAndDetectablePrecedences(
593  Solver* const solver, const std::vector<IntervalVar*>& intervals,
594  bool mirror, bool strict)
595  : solver_(solver),
596  theta_tree_(intervals.size()),
597  lt_tree_(intervals.size()),
598  strict_(strict) {
599  // Populate of the array of intervals
600  for (IntervalVar* const interval : intervals) {
601  IntervalVar* const underlying =
602  mirror ? solver->MakeMirrorInterval(interval) : interval;
603  IntervalVar* const relaxed = solver->MakeIntervalRelaxedMax(underlying);
604  DisjunctiveTask* const task = new DisjunctiveTask(relaxed);
605  by_end_min_.push_back(task);
606  by_start_min_.push_back(task);
607  by_end_max_.push_back(task);
608  by_start_max_.push_back(task);
609  new_est_.push_back(std::numeric_limits<int64_t>::min());
610  }
611 }
612 
613 void EdgeFinderAndDetectablePrecedences::UpdateEst() {
614  std::sort(by_start_min_.begin(), by_start_min_.end(),
615  ShortestDurationStartMinLessThan<DisjunctiveTask>);
616  for (int i = 0; i < size(); ++i) {
617  by_start_min_[i]->index = i;
618  }
619 }
620 
621 void EdgeFinderAndDetectablePrecedences::OverloadChecking() {
622  // Initialization.
623  UpdateEst();
624  std::sort(by_end_max_.begin(), by_end_max_.end(),
625  EndMaxLessThan<DisjunctiveTask>);
626  theta_tree_.Clear();
627 
628  for (DisjunctiveTask* const task : by_end_max_) {
629  theta_tree_.Insert(task);
630  if (theta_tree_.Ect() > task->interval->EndMax()) {
631  solver_->Fail();
632  }
633  }
634 }
635 
636 bool EdgeFinderAndDetectablePrecedences::DetectablePrecedences() {
637  // Initialization.
638  UpdateEst();
639  new_est_.assign(size(), std::numeric_limits<int64_t>::min());
640 
641  // Propagate in one direction
642  std::sort(by_end_min_.begin(), by_end_min_.end(),
643  EndMinLessThan<DisjunctiveTask>);
644  std::sort(by_start_max_.begin(), by_start_max_.end(),
645  StartMaxLessThan<DisjunctiveTask>);
646  theta_tree_.Clear();
647  int j = 0;
648  for (DisjunctiveTask* const task_i : by_end_min_) {
649  if (j < size()) {
650  DisjunctiveTask* task_j = by_start_max_[j];
651  while (task_i->interval->EndMin() > task_j->interval->StartMax()) {
652  theta_tree_.Insert(task_j);
653  j++;
654  if (j == size()) break;
655  task_j = by_start_max_[j];
656  }
657  }
658  const int64_t esti = task_i->interval->StartMin();
659  bool inserted = theta_tree_.IsInserted(task_i);
660  if (inserted) {
661  theta_tree_.Remove(task_i);
662  }
663  const int64_t oesti = theta_tree_.Ect();
664  if (inserted) {
665  theta_tree_.Insert(task_i);
666  }
667  if (oesti > esti) {
668  new_est_[task_i->index] = oesti;
669  } else {
670  new_est_[task_i->index] = std::numeric_limits<int64_t>::min();
671  }
672  }
673 
674  // Apply modifications
675  bool modified = false;
676  for (int i = 0; i < size(); ++i) {
677  IntervalVar* const var = by_start_min_[i]->interval;
678  if (new_est_[i] != std::numeric_limits<int64_t>::min() &&
679  (strict_ || var->DurationMin() > 0)) {
680  modified = true;
681  by_start_min_[i]->interval->SetStartMin(new_est_[i]);
682  }
683  }
684  return modified;
685 }
686 
687 bool EdgeFinderAndDetectablePrecedences::EdgeFinder() {
688  // Initialization.
689  UpdateEst();
690  for (int i = 0; i < size(); ++i) {
691  new_est_[i] = by_start_min_[i]->interval->StartMin();
692  }
693 
694  // Push in one direction.
695  std::sort(by_end_max_.begin(), by_end_max_.end(),
696  EndMaxLessThan<DisjunctiveTask>);
697  lt_tree_.Clear();
698  for (int i = 0; i < size(); ++i) {
699  lt_tree_.Insert(*by_start_min_[i]);
700  DCHECK_EQ(i, by_start_min_[i]->index);
701  }
702  for (int j = size() - 2; j >= 0; --j) {
703  lt_tree_.Grey(*by_end_max_[j + 1]);
704  DisjunctiveTask* const twj = by_end_max_[j];
705  // We should have checked for overloading earlier.
706  DCHECK_LE(lt_tree_.Ect(), twj->interval->EndMax());
707  while (lt_tree_.EctOpt() > twj->interval->EndMax()) {
708  const int i = lt_tree_.ResponsibleOpt();
709  DCHECK_GE(i, 0);
710  if (lt_tree_.Ect() > new_est_[i]) {
711  new_est_[i] = lt_tree_.Ect();
712  }
713  lt_tree_.Reset(i);
714  }
715  }
716 
717  // Apply modifications.
718  bool modified = false;
719  for (int i = 0; i < size(); ++i) {
720  IntervalVar* const var = by_start_min_[i]->interval;
721  if (var->StartMin() < new_est_[i] && (strict_ || var->DurationMin() > 0)) {
722  modified = true;
723  var->SetStartMin(new_est_[i]);
724  }
725  }
726  return modified;
727 }
728 
729 // --------- Disjunctive Constraint ----------
730 
731 // ----- Propagation on ranked activities -----
732 
733 class RankedPropagator : public Constraint {
734  public:
735  RankedPropagator(Solver* const solver, const std::vector<IntVar*>& nexts,
736  const std::vector<IntervalVar*>& intervals,
737  const std::vector<IntVar*>& slacks,
738  DisjunctiveConstraint* const disjunctive)
739  : Constraint(solver),
740  nexts_(nexts),
741  intervals_(intervals),
742  slacks_(slacks),
743  disjunctive_(disjunctive),
744  partial_sequence_(intervals.size()),
745  previous_(intervals.size() + 2, 0) {}
746 
747  ~RankedPropagator() override {}
748 
749  void Post() override {
750  Demon* const delayed =
751  solver()->MakeDelayedConstraintInitialPropagateCallback(this);
752  for (int i = 0; i < intervals_.size(); ++i) {
753  nexts_[i]->WhenBound(delayed);
754  intervals_[i]->WhenAnything(delayed);
755  slacks_[i]->WhenRange(delayed);
756  }
757  nexts_.back()->WhenBound(delayed);
758  }
759 
760  void InitialPropagate() override {
761  PropagateNexts();
762  PropagateSequence();
763  }
764 
765  void PropagateNexts() {
766  Solver* const s = solver();
767  const int ranked_first = partial_sequence_.NumFirstRanked();
768  const int ranked_last = partial_sequence_.NumLastRanked();
769  const int sentinel =
770  ranked_last == 0
771  ? nexts_.size()
772  : partial_sequence_[intervals_.size() - ranked_last] + 1;
773  int first = 0;
774  int counter = 0;
775  while (nexts_[first]->Bound()) {
776  DCHECK_NE(first, nexts_[first]->Min());
777  first = nexts_[first]->Min();
778  if (first == sentinel) {
779  return;
780  }
781  if (++counter > ranked_first) {
782  DCHECK(intervals_[first - 1]->MayBePerformed());
783  partial_sequence_.RankFirst(s, first - 1);
784  VLOG(2) << "RankFirst " << first - 1 << " -> "
785  << partial_sequence_.DebugString();
786  }
787  }
788  previous_.assign(previous_.size(), -1);
789  for (int i = 0; i < nexts_.size(); ++i) {
790  if (nexts_[i]->Bound()) {
791  previous_[nexts_[i]->Min()] = i;
792  }
793  }
794  int last = previous_.size() - 1;
795  counter = 0;
796  while (previous_[last] != -1) {
797  last = previous_[last];
798  if (++counter > ranked_last) {
799  partial_sequence_.RankLast(s, last - 1);
800  VLOG(2) << "RankLast " << last - 1 << " -> "
801  << partial_sequence_.DebugString();
802  }
803  }
804  }
805 
806  void PropagateSequence() {
807  const int last_position = intervals_.size() - 1;
808  const int first_sentinel = partial_sequence_.NumFirstRanked();
809  const int last_sentinel = last_position - partial_sequence_.NumLastRanked();
810  // Propagates on ranked first from left to right.
811  for (int i = 0; i < first_sentinel - 1; ++i) {
812  IntervalVar* const interval = RankedInterval(i);
813  IntervalVar* const next_interval = RankedInterval(i + 1);
814  IntVar* const slack = RankedSlack(i);
815  const int64_t transition_time = RankedTransitionTime(i, i + 1);
816  next_interval->SetStartRange(
817  CapAdd(interval->StartMin(), CapAdd(slack->Min(), transition_time)),
818  CapAdd(interval->StartMax(), CapAdd(slack->Max(), transition_time)));
819  }
820  // Propagates on ranked last from right to left.
821  for (int i = last_position; i > last_sentinel + 1; --i) {
822  IntervalVar* const interval = RankedInterval(i - 1);
823  IntervalVar* const next_interval = RankedInterval(i);
824  IntVar* const slack = RankedSlack(i - 1);
825  const int64_t transition_time = RankedTransitionTime(i - 1, i);
826  interval->SetStartRange(CapSub(next_interval->StartMin(),
827  CapAdd(slack->Max(), transition_time)),
828  CapSub(next_interval->StartMax(),
829  CapAdd(slack->Min(), transition_time)));
830  }
831  // Propagate across.
832  IntervalVar* const first_interval =
833  first_sentinel > 0 ? RankedInterval(first_sentinel - 1) : nullptr;
834  IntVar* const first_slack =
835  first_sentinel > 0 ? RankedSlack(first_sentinel - 1) : nullptr;
836  IntervalVar* const last_interval = last_sentinel < last_position
837  ? RankedInterval(last_sentinel + 1)
838  : nullptr;
839 
840  // Nothing to do afterwards, exiting.
841  if (first_interval == nullptr && last_interval == nullptr) {
842  return;
843  }
844  // Propagates to the middle part.
845  // This assumes triangular inequality in the transition times.
846  for (int i = first_sentinel; i <= last_sentinel; ++i) {
847  IntervalVar* const interval = RankedInterval(i);
848  IntVar* const slack = RankedSlack(i);
849  if (interval->MayBePerformed()) {
850  const bool performed = interval->MustBePerformed();
851  if (first_interval != nullptr) {
852  const int64_t transition_time =
853  RankedTransitionTime(first_sentinel - 1, i);
854  interval->SetStartRange(
855  CapAdd(first_interval->StartMin(),
856  CapAdd(first_slack->Min(), transition_time)),
857  CapAdd(first_interval->StartMax(),
858  CapAdd(first_slack->Max(), transition_time)));
859  if (performed) {
860  first_interval->SetStartRange(
861  CapSub(interval->StartMin(),
862  CapAdd(first_slack->Max(), transition_time)),
863  CapSub(interval->StartMax(),
864  CapAdd(first_slack->Min(), transition_time)));
865  }
866  }
867  if (last_interval != nullptr) {
868  const int64_t transition_time =
869  RankedTransitionTime(i, last_sentinel + 1);
870  interval->SetStartRange(
871  CapSub(last_interval->StartMin(),
872  CapAdd(slack->Max(), transition_time)),
873  CapSub(last_interval->StartMax(),
874  CapAdd(slack->Min(), transition_time)));
875  if (performed) {
876  last_interval->SetStartRange(
877  CapAdd(interval->StartMin(),
878  CapAdd(slack->Min(), transition_time)),
879  CapAdd(interval->StartMax(),
880  CapAdd(slack->Max(), transition_time)));
881  }
882  }
883  }
884  }
885  // TODO(user): cache transition on ranked intervals in a vector.
886  // Propagates on ranked first from right to left.
887  for (int i = std::min(first_sentinel - 2, last_position - 1); i >= 0; --i) {
888  IntervalVar* const interval = RankedInterval(i);
889  IntervalVar* const next_interval = RankedInterval(i + 1);
890  IntVar* const slack = RankedSlack(i);
891  const int64_t transition_time = RankedTransitionTime(i, i + 1);
892  interval->SetStartRange(CapSub(next_interval->StartMin(),
893  CapAdd(slack->Max(), transition_time)),
894  CapSub(next_interval->StartMax(),
895  CapAdd(slack->Min(), transition_time)));
896  }
897  // Propagates on ranked last from left to right.
898  for (int i = last_sentinel + 1; i < last_position - 1; ++i) {
899  IntervalVar* const interval = RankedInterval(i);
900  IntervalVar* const next_interval = RankedInterval(i + 1);
901  IntVar* const slack = RankedSlack(i);
902  const int64_t transition_time = RankedTransitionTime(i, i + 1);
903  next_interval->SetStartRange(
904  CapAdd(interval->StartMin(), CapAdd(slack->Min(), transition_time)),
905  CapAdd(interval->StartMax(), CapAdd(slack->Max(), transition_time)));
906  }
907  // TODO(user) : Propagate on slacks.
908  }
909 
910  IntervalVar* RankedInterval(int i) const {
911  const int index = partial_sequence_[i];
912  return intervals_[index];
913  }
914 
915  IntVar* RankedSlack(int i) const {
916  const int index = partial_sequence_[i];
917  return slacks_[index];
918  }
919 
920  int64_t RankedTransitionTime(int before, int after) const {
921  const int before_index = partial_sequence_[before];
922  const int after_index = partial_sequence_[after];
923 
924  return disjunctive_->TransitionTime(before_index, after_index);
925  }
926 
927  std::string DebugString() const override {
928  return absl::StrFormat(
929  "RankedPropagator([%s], nexts = [%s], intervals = [%s])",
930  partial_sequence_.DebugString(), JoinDebugStringPtr(nexts_, ", "),
931  JoinDebugStringPtr(intervals_, ", "));
932  }
933 
934  void Accept(ModelVisitor* const visitor) const override {
935  LOG(FATAL) << "Not yet implemented";
936  // TODO(user): IMPLEMENT ME.
937  }
938 
939  private:
940  std::vector<IntVar*> nexts_;
941  std::vector<IntervalVar*> intervals_;
942  std::vector<IntVar*> slacks_;
943  DisjunctiveConstraint* const disjunctive_;
944  RevPartialSequence partial_sequence_;
945  std::vector<int> previous_;
946 };
947 
948 // A class that stores several propagators for the sequence constraint, and
949 // calls them until a fixpoint is reached.
950 
951 class FullDisjunctiveConstraint : public DisjunctiveConstraint {
952  public:
953  FullDisjunctiveConstraint(Solver* const s,
954  const std::vector<IntervalVar*>& intervals,
955  const std::string& name, bool strict)
956  : DisjunctiveConstraint(s, intervals, name),
957  sequence_var_(nullptr),
958  straight_(s, intervals, false, strict),
959  mirror_(s, intervals, true, strict),
960  straight_not_last_(s, intervals, false, strict),
961  mirror_not_last_(s, intervals, true, strict),
962  strict_(strict) {}
963 
964  ~FullDisjunctiveConstraint() override {}
965 
966  void Post() override {
967  Demon* const d = MakeDelayedConstraintDemon0(
968  solver(), this, &FullDisjunctiveConstraint::InitialPropagate,
969  "InitialPropagate");
970  for (int32_t i = 0; i < straight_.size(); ++i) {
971  straight_.interval(i)->WhenAnything(d);
972  }
973  }
974 
975  void InitialPropagate() override {
976  bool all_optional_or_unperformed = true;
977  for (const IntervalVar* const interval : intervals_) {
978  if (interval->MustBePerformed()) {
979  all_optional_or_unperformed = false;
980  break;
981  }
982  }
983  if (all_optional_or_unperformed) { // Nothing to deduce
984  return;
985  }
986 
987  bool all_times_fixed = true;
988  for (const IntervalVar* const interval : intervals_) {
989  if (interval->MayBePerformed() &&
990  (interval->StartMin() != interval->StartMax() ||
991  interval->DurationMin() != interval->DurationMax() ||
992  interval->EndMin() != interval->EndMax())) {
993  all_times_fixed = false;
994  break;
995  }
996  }
997 
998  if (all_times_fixed) {
999  PropagatePerformed();
1000  } else {
1001  do {
1002  do {
1003  do {
1004  // OverloadChecking is symmetrical. It has the same effect on the
1005  // straight and the mirrored version.
1006  straight_.OverloadChecking();
1007  } while (straight_.DetectablePrecedences() ||
1008  mirror_.DetectablePrecedences());
1009  } while (straight_not_last_.Propagate() ||
1010  mirror_not_last_.Propagate());
1011  } while (straight_.EdgeFinder() || mirror_.EdgeFinder());
1012  }
1013  }
1014 
1015  bool Intersect(IntervalVar* const i1, IntervalVar* const i2) const {
1016  return i1->StartMin() < i2->EndMax() && i2->StartMin() < i1->EndMax();
1017  }
1018 
1019  void PropagatePerformed() {
1020  performed_.clear();
1021  optional_.clear();
1022  for (IntervalVar* const interval : intervals_) {
1023  if (interval->MustBePerformed()) {
1024  performed_.push_back(interval);
1025  } else if (interval->MayBePerformed()) {
1026  optional_.push_back(interval);
1027  }
1028  }
1029  // Checks feasibility of performed;
1030  if (performed_.empty()) return;
1031  std::sort(performed_.begin(), performed_.end(), IntervalStartMinLessThan);
1032  for (int i = 0; i < performed_.size() - 1; ++i) {
1033  if (performed_[i]->EndMax() > performed_[i + 1]->StartMin()) {
1034  solver()->Fail();
1035  }
1036  }
1037 
1038  // Checks if optional intervals can be inserted.
1039  if (optional_.empty()) return;
1040  int index = 0;
1041  const int num_performed = performed_.size();
1042  std::sort(optional_.begin(), optional_.end(), IntervalStartMinLessThan);
1043  for (IntervalVar* const candidate : optional_) {
1044  const int64_t start = candidate->StartMin();
1045  while (index < num_performed && start >= performed_[index]->EndMax()) {
1046  index++;
1047  }
1048  if (index == num_performed) return;
1049  if (Intersect(candidate, performed_[index]) ||
1050  (index < num_performed - 1 &&
1051  Intersect(candidate, performed_[index + 1]))) {
1052  candidate->SetPerformed(false);
1053  }
1054  }
1055  }
1056 
1057  void Accept(ModelVisitor* const visitor) const override {
1058  visitor->BeginVisitConstraint(ModelVisitor::kDisjunctive, this);
1059  visitor->VisitIntervalArrayArgument(ModelVisitor::kIntervalsArgument,
1060  intervals_);
1061  if (sequence_var_ != nullptr) {
1062  visitor->VisitSequenceArgument(ModelVisitor::kSequenceArgument,
1063  sequence_var_);
1064  }
1065  visitor->EndVisitConstraint(ModelVisitor::kDisjunctive, this);
1066  }
1067 
1068  SequenceVar* MakeSequenceVar() override {
1069  BuildNextModelIfNeeded();
1070  if (sequence_var_ == nullptr) {
1071  solver()->SaveValue(reinterpret_cast<void**>(&sequence_var_));
1072  sequence_var_ = solver()->RevAlloc(
1073  new SequenceVar(solver(), intervals_, nexts_, name()));
1074  }
1075  return sequence_var_;
1076  }
1077 
1078  std::string DebugString() const override {
1079  return absl::StrFormat("FullDisjunctiveConstraint([%s], %i)",
1080  JoinDebugStringPtr(intervals_, ", "), strict_);
1081  }
1082 
1083  const std::vector<IntVar*>& nexts() const override { return nexts_; }
1084 
1085  const std::vector<IntVar*>& actives() const override { return actives_; }
1086 
1087  const std::vector<IntVar*>& time_cumuls() const override {
1088  return time_cumuls_;
1089  }
1090 
1091  const std::vector<IntVar*>& time_slacks() const override {
1092  return time_slacks_;
1093  }
1094 
1095  private:
1096  int64_t Distance(int64_t activity_plus_one, int64_t next_activity_plus_one) {
1097  return (activity_plus_one == 0 ||
1098  next_activity_plus_one > intervals_.size())
1099  ? 0
1100  : transition_time_(activity_plus_one - 1,
1101  next_activity_plus_one - 1);
1102  }
1103 
1104  void BuildNextModelIfNeeded() {
1105  if (!nexts_.empty()) {
1106  return;
1107  }
1108  Solver* const s = solver();
1109  const std::string& ct_name = name();
1110  const int num_intervals = intervals_.size();
1111  const int num_nodes = intervals_.size() + 1;
1112  int64_t horizon = 0;
1113  for (int i = 0; i < intervals_.size(); ++i) {
1114  if (intervals_[i]->MayBePerformed()) {
1115  horizon = std::max(horizon, intervals_[i]->EndMax());
1116  }
1117  }
1118 
1119  // Create the next model.
1120  s->MakeIntVarArray(num_nodes, 1, num_nodes, ct_name + "_nexts", &nexts_);
1121  // Alldifferent on the nexts variable (the equivalent problem is a tsp).
1122  s->AddConstraint(s->MakeAllDifferent(nexts_));
1123 
1124  actives_.resize(num_nodes);
1125  for (int i = 0; i < num_intervals; ++i) {
1126  actives_[i + 1] = intervals_[i]->PerformedExpr()->Var();
1127  s->AddConstraint(
1128  s->MakeIsDifferentCstCt(nexts_[i + 1], i + 1, actives_[i + 1]));
1129  }
1130  std::vector<IntVar*> short_actives(actives_.begin() + 1, actives_.end());
1131  actives_[0] = s->MakeMax(short_actives)->Var();
1132 
1133  // No Cycle on the corresponding tsp.
1134  s->AddConstraint(s->MakeNoCycle(nexts_, actives_));
1135 
1136  // Cumul on time.
1137  time_cumuls_.resize(num_nodes + 1);
1138  // Slacks between activities.
1139  time_slacks_.resize(num_nodes);
1140 
1141  time_slacks_[0] = s->MakeIntVar(0, horizon, "initial_slack");
1142  // TODO(user): check this.
1143  time_cumuls_[0] = s->MakeIntConst(0);
1144 
1145  for (int64_t i = 0; i < num_intervals; ++i) {
1146  IntervalVar* const var = intervals_[i];
1147  if (var->MayBePerformed()) {
1148  const int64_t duration_min = var->DurationMin();
1149  time_slacks_[i + 1] = s->MakeIntVar(
1150  duration_min, horizon, absl::StrFormat("time_slacks(%d)", i + 1));
1151  // TODO(user): Check SafeStartExpr();
1152  time_cumuls_[i + 1] = var->SafeStartExpr(var->StartMin())->Var();
1153  if (var->DurationMax() != duration_min) {
1154  s->AddConstraint(s->MakeGreaterOrEqual(
1155  time_slacks_[i + 1], var->SafeDurationExpr(duration_min)));
1156  }
1157  } else {
1158  time_slacks_[i + 1] = s->MakeIntVar(
1159  0, horizon, absl::StrFormat("time_slacks(%d)", i + 1));
1160  time_cumuls_[i + 1] = s->MakeIntConst(horizon);
1161  }
1162  }
1163  // TODO(user): Find a better UB for the last time cumul.
1164  time_cumuls_[num_nodes] = s->MakeIntVar(0, 2 * horizon, ct_name + "_ect");
1165  s->AddConstraint(s->MakePathCumul(
1166  nexts_, actives_, time_cumuls_, time_slacks_,
1167  [this](int64_t x, int64_t y) { return Distance(x, y); }));
1168 
1169  std::vector<IntVar*> short_slacks(time_slacks_.begin() + 1,
1170  time_slacks_.end());
1171  s->AddConstraint(s->RevAlloc(
1172  new RankedPropagator(s, nexts_, intervals_, short_slacks, this)));
1173  }
1174 
1175  SequenceVar* sequence_var_;
1176  EdgeFinderAndDetectablePrecedences straight_;
1177  EdgeFinderAndDetectablePrecedences mirror_;
1178  NotLast straight_not_last_;
1179  NotLast mirror_not_last_;
1180  std::vector<IntVar*> nexts_;
1181  std::vector<IntVar*> actives_;
1182  std::vector<IntVar*> time_cumuls_;
1183  std::vector<IntVar*> time_slacks_;
1184  std::vector<IntervalVar*> performed_;
1185  std::vector<IntervalVar*> optional_;
1186  const bool strict_;
1187  DISALLOW_COPY_AND_ASSIGN(FullDisjunctiveConstraint);
1188 };
1189 
1190 // =====================================================================
1191 // Cumulative
1192 // =====================================================================
1193 
1194 // A cumulative Theta node, where two energies, corresponding to 2 capacities,
1195 // are stored.
1196 struct DualCapacityThetaNode {
1197  // Special value for task indices meaning 'no such task'.
1198  static const int kNone;
1199 
1200  // Identity constructor
1201  DualCapacityThetaNode()
1202  : energy(0LL),
1203  energetic_end_min(std::numeric_limits<int64_t>::min()),
1204  residual_energetic_end_min(std::numeric_limits<int64_t>::min()) {}
1205 
1206  // Constructor for a single cumulative task in the Theta set.
1207  DualCapacityThetaNode(int64_t capacity, int64_t residual_capacity,
1208  const CumulativeTask& task)
1209  : energy(task.EnergyMin()),
1210  energetic_end_min(CapAdd(capacity * task.interval->StartMin(), energy)),
1212  CapAdd(residual_capacity * task.interval->StartMin(), energy)) {}
1213 
1214  // Constructor for a single variable cumulative task in the Theta set.
1215  DualCapacityThetaNode(int64_t capacity, int64_t residual_capacity,
1216  const VariableCumulativeTask& task)
1217  : energy(task.EnergyMin()),
1218  energetic_end_min(CapAdd(capacity * task.interval->StartMin(), energy)),
1220  CapAdd(residual_capacity * task.interval->StartMin(), energy)) {}
1221 
1222  // Sets this DualCapacityThetaNode to the result of the natural binary
1223  // operation over the two given operands, corresponding to the following set
1224  // operation: Theta = left.Theta union right.Theta
1225  //
1226  // No set operation actually occur: we only maintain the relevant quantities
1227  // associated with such sets.
1228  void Compute(const DualCapacityThetaNode& left,
1229  const DualCapacityThetaNode& right) {
1230  energy = CapAdd(left.energy, right.energy);
1231  energetic_end_min = std::max(CapAdd(left.energetic_end_min, right.energy),
1232  right.energetic_end_min);
1234  std::max(CapAdd(left.residual_energetic_end_min, right.energy),
1235  right.residual_energetic_end_min);
1236  }
1237 
1238  // Amount of resource consumed by the Theta set, in units of demand X time.
1239  // This is energy(Theta).
1240  int64_t energy;
1241 
1242  // Max_{subset S of Theta} (capacity * start_min(S) + energy(S))
1243  int64_t energetic_end_min;
1244 
1245  // Max_{subset S of Theta} (residual_capacity * start_min(S) + energy(S))
1247 };
1248 
1249 const int DualCapacityThetaNode::kNone = -1;
1250 
1251 // A tree for dual capacity theta nodes
1252 class DualCapacityThetaTree
1253  : public MonoidOperationTree<DualCapacityThetaNode> {
1254  public:
1255  static const int64_t kNotInitialized;
1256 
1257  explicit DualCapacityThetaTree(int size)
1258  : MonoidOperationTree<DualCapacityThetaNode>(size),
1259  capacity_max_(-1),
1260  residual_capacity_(-1) {}
1261 
1262  virtual ~DualCapacityThetaTree() {}
1263 
1264  void Init(int64_t capacity_max, int64_t residual_capacity) {
1265  DCHECK_LE(0, residual_capacity);
1266  DCHECK_LE(residual_capacity, capacity_max);
1267  Clear();
1268  capacity_max_ = capacity_max;
1269  residual_capacity_ = residual_capacity;
1270  }
1271 
1272  void Insert(const CumulativeTask* task) {
1273  Set(task->index,
1274  DualCapacityThetaNode(capacity_max_, residual_capacity_, *task));
1275  }
1276 
1277  void Insert(const VariableCumulativeTask* task) {
1278  Set(task->index,
1279  DualCapacityThetaNode(capacity_max_, residual_capacity_, *task));
1280  }
1281 
1282  private:
1283  int64_t capacity_max_;
1284  int64_t residual_capacity_;
1285  DISALLOW_COPY_AND_ASSIGN(DualCapacityThetaTree);
1286 };
1287 
1288 const int64_t DualCapacityThetaTree::kNotInitialized = -1LL;
1289 
1290 // An object that can dive down a branch of a DualCapacityThetaTree to compute
1291 // Env(j, c) in Petr Vilim's notations.
1292 //
1293 // In 'Edge finding filtering algorithm for discrete cumulative resources in
1294 // O(kn log n)' by Petr Vilim, this corresponds to line 6--8 in algorithm 1.3,
1295 // plus all of algorithm 1.2.
1296 //
1297 // http://vilim.eu/petr/cp2009.pdf
1298 // Note: use the version pointed to by this pointer, not the version from the
1299 // conference proceedings, which has a few errors.
1300 class EnvJCComputeDiver {
1301  public:
1302  static const int64_t kNotAvailable;
1303  explicit EnvJCComputeDiver(int energy_threshold)
1304  : energy_threshold_(energy_threshold),
1305  energy_alpha_(kNotAvailable),
1306  energetic_end_min_alpha_(kNotAvailable) {}
1307  void OnArgumentReached(int index, const DualCapacityThetaNode& argument) {
1308  energy_alpha_ = argument.energy;
1309  energetic_end_min_alpha_ = argument.energetic_end_min;
1310  // We should reach a leaf that is not the identity
1311  // DCHECK_GT(energetic_end_min_alpha_, kint64min);
1312  // TODO(user): Check me.
1313  }
1314  bool ChooseGoLeft(const DualCapacityThetaNode& current,
1315  const DualCapacityThetaNode& left_child,
1316  const DualCapacityThetaNode& right_child) {
1317  if (right_child.residual_energetic_end_min > energy_threshold_) {
1318  return false; // enough energy on right
1319  } else {
1320  energy_threshold_ -= right_child.energy;
1321  return true;
1322  }
1323  }
1324  void OnComeBackFromLeft(const DualCapacityThetaNode& current,
1325  const DualCapacityThetaNode& left_child,
1326  const DualCapacityThetaNode& right_child) {
1327  // The left subtree intersects the alpha set.
1328  // The right subtree does not intersect the alpha set.
1329  // The energy_alpha_ and energetic_end_min_alpha_ previously
1330  // computed are valid for this node too: there's nothing to do.
1331  }
1332  void OnComeBackFromRight(const DualCapacityThetaNode& current,
1333  const DualCapacityThetaNode& left_child,
1334  const DualCapacityThetaNode& right_child) {
1335  // The left subtree is included in the alpha set.
1336  // The right subtree intersects the alpha set.
1337  energetic_end_min_alpha_ =
1338  std::max(energetic_end_min_alpha_,
1339  CapAdd(left_child.energetic_end_min, energy_alpha_));
1340  energy_alpha_ += left_child.energy;
1341  }
1342  int64_t GetEnvJC(const DualCapacityThetaNode& root) const {
1343  const int64_t energy = root.energy;
1344  const int64_t energy_beta = CapSub(energy, energy_alpha_);
1345  return CapAdd(energetic_end_min_alpha_, energy_beta);
1346  }
1347 
1348  private:
1349  // Energy threshold such that if a set has an energetic_end_min greater than
1350  // the threshold, then it can push tasks that must end at or after the
1351  // currently considered end max.
1352  //
1353  // Used when diving down only.
1354  int64_t energy_threshold_;
1355 
1356  // Energy of the alpha set, that is, the set of tasks whose start min does not
1357  // exceed the max start min of a set with excess residual energy.
1358  //
1359  // Used when swimming up only.
1360  int64_t energy_alpha_;
1361 
1362  // Energetic end min of the alpha set.
1363  //
1364  // Used when swimming up only.
1365  int64_t energetic_end_min_alpha_;
1366 };
1367 
1368 const int64_t EnvJCComputeDiver::kNotAvailable = -1LL;
1369 
1370 // In all the following, the term 'update' means 'a potential new start min for
1371 // a task'. The edge-finding algorithm is in two phase: one compute potential
1372 // new start mins, the other detects whether they are applicable or not for each
1373 // task.
1374 
1375 // Collection of all updates (i.e., potential new start mins) for a given value
1376 // of the demand.
1377 class UpdatesForADemand {
1378  public:
1379  explicit UpdatesForADemand(int size)
1380  : updates_(size, 0), up_to_date_(false) {}
1381 
1382  const int64_t Update(int index) { return updates_[index]; }
1383  void Reset() { up_to_date_ = false; }
1384  void SetUpdate(int index, int64_t update) {
1385  DCHECK(!up_to_date_);
1386  DCHECK_LT(index, updates_.size());
1387  updates_[index] = update;
1388  }
1389  bool up_to_date() const { return up_to_date_; }
1390  void set_up_to_date() { up_to_date_ = true; }
1391 
1392  private:
1393  std::vector<int64_t> updates_;
1394  bool up_to_date_;
1395  DISALLOW_COPY_AND_ASSIGN(UpdatesForADemand);
1396 };
1397 
1398 // One-sided cumulative edge finder.
1399 template <class Task>
1400 class EdgeFinder : public Constraint {
1401  public:
1402  EdgeFinder(Solver* const solver, const std::vector<Task*>& tasks,
1403  IntVar* const capacity)
1404  : Constraint(solver),
1405  capacity_(capacity),
1406  tasks_(tasks),
1407  by_start_min_(tasks.size()),
1408  by_end_max_(tasks.size()),
1409  by_end_min_(tasks.size()),
1410  lt_tree_(tasks.size(), capacity_->Max()),
1411  dual_capacity_tree_(tasks.size()),
1412  has_zero_demand_tasks_(true) {}
1413 
1414  ~EdgeFinder() override {
1415  gtl::STLDeleteElements(&tasks_);
1416  gtl::STLDeleteValues(&update_map_);
1417  }
1418 
1419  void Post() override {
1420  // Add the demons
1421  Demon* const demon = MakeDelayedConstraintDemon0(
1422  solver(), this, &EdgeFinder::InitialPropagate, "RangeChanged");
1423  for (Task* const task : tasks_) {
1424  // Delay propagation, as this constraint is not incremental: we pay
1425  // O(n log n) each time the constraint is awakened.
1426  task->WhenAnything(demon);
1427  }
1428  capacity_->WhenRange(demon);
1429  }
1430 
1431  // The propagation algorithms: checks for overloading, computes new start mins
1432  // according to the edge-finding rules, and applies them.
1433  void InitialPropagate() override {
1434  InitPropagation();
1435  PropagateBasedOnEndMinGreaterThanEndMax();
1436  FillInTree();
1437  PropagateBasedOnEnergy();
1438  ApplyNewBounds();
1439  }
1440 
1441  void Accept(ModelVisitor* const visitor) const override {
1442  LOG(FATAL) << "Should Not Be Visited";
1443  }
1444 
1445  std::string DebugString() const override { return "EdgeFinder"; }
1446 
1447  private:
1448  UpdatesForADemand* GetOrMakeUpdate(int64_t demand_min) {
1449  UpdatesForADemand* update = gtl::FindPtrOrNull(update_map_, demand_min);
1450  if (update == nullptr) {
1451  update = new UpdatesForADemand(tasks_.size());
1452  update_map_[demand_min] = update;
1453  }
1454  return update;
1455  }
1456 
1457  // Sets the fields in a proper state to run the propagation algorithm.
1458  void InitPropagation() {
1459  // Clear the update stack
1460  start_min_update_.clear();
1461  // Re_init vectors if has_zero_demand_tasks_ is true
1462  if (has_zero_demand_tasks_.Value()) {
1463  by_start_min_.clear();
1464  by_end_min_.clear();
1465  by_end_max_.clear();
1466  // Only populate tasks with demand_min > 0.
1467  bool zero_demand = false;
1468  for (Task* const task : tasks_) {
1469  if (task->DemandMin() > 0) {
1470  by_start_min_.push_back(task);
1471  by_end_min_.push_back(task);
1472  by_end_max_.push_back(task);
1473  } else {
1474  zero_demand = true;
1475  }
1476  }
1477  if (!zero_demand) {
1478  has_zero_demand_tasks_.SetValue(solver(), false);
1479  }
1480  }
1481 
1482  // sort by start min.
1483  std::sort(by_start_min_.begin(), by_start_min_.end(),
1484  StartMinLessThan<Task>);
1485  for (int i = 0; i < by_start_min_.size(); ++i) {
1486  by_start_min_[i]->index = i;
1487  }
1488  // Sort by end max.
1489  std::sort(by_end_max_.begin(), by_end_max_.end(), EndMaxLessThan<Task>);
1490  // Sort by end min.
1491  std::sort(by_end_min_.begin(), by_end_min_.end(), EndMinLessThan<Task>);
1492  // Initialize the tree with the new capacity.
1493  lt_tree_.Init(capacity_->Max());
1494  // Clear updates
1495  for (const auto& entry : update_map_) {
1496  entry.second->Reset();
1497  }
1498  }
1499 
1500  // Computes all possible update values for tasks of given demand, and stores
1501  // these values in update_map_[demand].
1502  // Runs in O(n log n).
1503  // This corresponds to lines 2--13 in algorithm 1.3 in Petr Vilim's paper.
1504  void ComputeConditionalStartMins(UpdatesForADemand* updates,
1505  int64_t demand_min) {
1506  DCHECK_GT(demand_min, 0);
1507  DCHECK(updates != nullptr);
1508  const int64_t capacity_max = capacity_->Max();
1509  const int64_t residual_capacity = CapSub(capacity_max, demand_min);
1510  dual_capacity_tree_.Init(capacity_max, residual_capacity);
1511  // It's important to initialize the update at IntervalVar::kMinValidValue
1512  // rather than at kInt64min, because its opposite may be used if it's a
1513  // mirror variable, and
1514  // -kInt64min = -(-kInt64max - 1) = kInt64max + 1 = -kInt64min
1515  int64_t update = IntervalVar::kMinValidValue;
1516  for (int i = 0; i < by_end_max_.size(); ++i) {
1517  Task* const task = by_end_max_[i];
1518  if (task->EnergyMin() == 0) continue;
1519  const int64_t current_end_max = task->interval->EndMax();
1520  dual_capacity_tree_.Insert(task);
1521  const int64_t energy_threshold = residual_capacity * current_end_max;
1522  const DualCapacityThetaNode& root = dual_capacity_tree_.result();
1523  const int64_t res_energetic_end_min = root.residual_energetic_end_min;
1524  if (res_energetic_end_min > energy_threshold) {
1525  EnvJCComputeDiver diver(energy_threshold);
1526  dual_capacity_tree_.DiveInTree(&diver);
1527  const int64_t enjv = diver.GetEnvJC(dual_capacity_tree_.result());
1528  const int64_t numerator = CapSub(enjv, energy_threshold);
1529  const int64_t diff = MathUtil::CeilOfRatio(numerator, demand_min);
1530  update = std::max(update, diff);
1531  }
1532  updates->SetUpdate(i, update);
1533  }
1534  updates->set_up_to_date();
1535  }
1536 
1537  // Returns the new start min that can be inferred for task_to_push if it is
1538  // proved that it cannot end before by_end_max[end_max_index] does.
1539  int64_t ConditionalStartMin(const Task& task_to_push, int end_max_index) {
1540  if (task_to_push.EnergyMin() == 0) {
1541  return task_to_push.interval->StartMin();
1542  }
1543  const int64_t demand_min = task_to_push.DemandMin();
1544  UpdatesForADemand* const updates = GetOrMakeUpdate(demand_min);
1545  if (!updates->up_to_date()) {
1546  ComputeConditionalStartMins(updates, demand_min);
1547  }
1548  DCHECK(updates->up_to_date());
1549  return updates->Update(end_max_index);
1550  }
1551 
1552  // Propagates by discovering all end-after-end relationships purely based on
1553  // comparisons between end mins and end maxes: there is no energetic reasoning
1554  // here, but this allow updates that the standard edge-finding detection rule
1555  // misses.
1556  // See paragraph 6.2 in http://vilim.eu/petr/cp2009.pdf.
1557  void PropagateBasedOnEndMinGreaterThanEndMax() {
1558  int end_max_index = 0;
1559  int64_t max_start_min = std::numeric_limits<int64_t>::min();
1560  for (Task* const task : by_end_min_) {
1561  const int64_t end_min = task->interval->EndMin();
1562  while (end_max_index < by_start_min_.size() &&
1563  by_end_max_[end_max_index]->interval->EndMax() <= end_min) {
1564  max_start_min = std::max(
1565  max_start_min, by_end_max_[end_max_index]->interval->StartMin());
1566  ++end_max_index;
1567  }
1568  if (end_max_index > 0 && task->interval->StartMin() <= max_start_min &&
1569  task->interval->EndMax() > task->interval->EndMin()) {
1570  DCHECK_LE(by_end_max_[end_max_index - 1]->interval->EndMax(), end_min);
1571  // The update is valid and may be interesting:
1572  // * If task->StartMin() > max_start_min, then all tasks whose end_max
1573  // is less than or equal to end_min have a start min that is less
1574  // than task->StartMin(). In this case, any update we could
1575  // compute would also be computed by the standard edge-finding
1576  // rule. It's better not to compute it, then: it may not be
1577  // needed.
1578  // * If task->EndMax() <= task->EndMin(), that means the end max is
1579  // bound. In that case, 'task' itself belong to the set of tasks
1580  // that must end before end_min, which may cause the result of
1581  // ConditionalStartMin(task, end_max_index - 1) not to be a valid
1582  // update.
1583  const int64_t update = ConditionalStartMin(*task, end_max_index - 1);
1584  start_min_update_.push_back(std::make_pair(task->interval, update));
1585  }
1586  }
1587  }
1588 
1589  // Fill the theta-lambda-tree, and check for overloading.
1590  void FillInTree() {
1591  for (Task* const task : by_end_max_) {
1592  lt_tree_.Insert(*task);
1593  // Maximum energetic end min without overload.
1594  const int64_t max_feasible =
1595  CapProd(capacity_->Max(), task->interval->EndMax());
1596  if (lt_tree_.energetic_end_min() > max_feasible) {
1597  solver()->Fail();
1598  }
1599  }
1600  }
1601 
1602  // The heart of the propagation algorithm. Should be called with all tasks
1603  // being in the Theta set. It detects tasks that need to be pushed.
1604  void PropagateBasedOnEnergy() {
1605  for (int j = by_start_min_.size() - 2; j >= 0; --j) {
1606  lt_tree_.Grey(*by_end_max_[j + 1]);
1607  Task* const twj = by_end_max_[j];
1608  // We should have checked for overload earlier.
1609  const int64_t max_feasible =
1610  CapProd(capacity_->Max(), twj->interval->EndMax());
1611  DCHECK_LE(lt_tree_.energetic_end_min(), max_feasible);
1612  while (lt_tree_.energetic_end_min_opt() > max_feasible) {
1613  const int i = lt_tree_.argmax_energetic_end_min_opt();
1614  DCHECK_GE(i, 0);
1615  PropagateTaskCannotEndBefore(i, j);
1616  lt_tree_.Reset(i);
1617  }
1618  }
1619  }
1620 
1621  // Takes into account the fact that the task of given index cannot end before
1622  // the given new end min.
1623  void PropagateTaskCannotEndBefore(int index, int end_max_index) {
1624  Task* const task_to_push = by_start_min_[index];
1625  const int64_t update = ConditionalStartMin(*task_to_push, end_max_index);
1626  start_min_update_.push_back(std::make_pair(task_to_push->interval, update));
1627  }
1628 
1629  // Applies the previously computed updates.
1630  void ApplyNewBounds() {
1631  for (const std::pair<IntervalVar*, int64_t>& update : start_min_update_) {
1632  update.first->SetStartMin(update.second);
1633  }
1634  }
1635 
1636  // Capacity of the cumulative resource.
1637  IntVar* const capacity_;
1638 
1639  // Initial vector of tasks
1640  std::vector<Task*> tasks_;
1641 
1642  // Cumulative tasks, ordered by non-decreasing start min.
1643  std::vector<Task*> by_start_min_;
1644 
1645  // Cumulative tasks, ordered by non-decreasing end max.
1646  std::vector<Task*> by_end_max_;
1647 
1648  // Cumulative tasks, ordered by non-decreasing end min.
1649  std::vector<Task*> by_end_min_;
1650 
1651  // Cumulative theta-lamba tree.
1652  CumulativeLambdaThetaTree lt_tree_;
1653 
1654  // Needed by ComputeConditionalStartMins.
1655  DualCapacityThetaTree dual_capacity_tree_;
1656 
1657  // Stack of updates to the new start min to do.
1658  std::vector<std::pair<IntervalVar*, int64_t>> start_min_update_;
1659 
1660  // update_map_[d][i] is an integer such that if a task
1661  // whose demand is d cannot end before by_end_max_[i], then it cannot start
1662  // before update_map_[d][i].
1663  absl::flat_hash_map<int64_t, UpdatesForADemand*> update_map_;
1664 
1665  // Has one task a demand min == 0
1666  Rev<bool> has_zero_demand_tasks_;
1667 
1668  DISALLOW_COPY_AND_ASSIGN(EdgeFinder);
1669 };
1670 
1671 // A point in time where the usage profile changes.
1672 // Starting from time (included), the usage is what it was immediately before
1673 // time, plus the delta.
1674 //
1675 // Example:
1676 // Consider the following vector of ProfileDelta's:
1677 // { t=1, d=+3}, { t=4, d=+1 }, { t=5, d=-2}, { t=8, d=-1}
1678 // This represents the following usage profile:
1679 //
1680 // usage
1681 // 4 | ****.
1682 // 3 | ************. .
1683 // 2 | . . ************.
1684 // 1 | . . . .
1685 // 0 |*******----------------------------*******************-> time
1686 // 0 1 2 3 4 5 6 7 8 9
1687 //
1688 // Note that the usage profile is right-continuous (see
1689 // http://en.wikipedia.org/wiki/Left-continuous#Directional_continuity).
1690 // This is because intervals for tasks are always closed on the start side
1691 // and open on the end side.
1692 struct ProfileDelta {
1693  ProfileDelta(int64_t _time, int64_t _delta) : time(_time), delta(_delta) {}
1694  int64_t time;
1695  int64_t delta;
1696 };
1697 
1698 bool TimeLessThan(const ProfileDelta& delta1, const ProfileDelta& delta2) {
1699  return delta1.time < delta2.time;
1700 }
1701 
1702 // Cumulative time-table.
1703 //
1704 // This class implements a propagator for the CumulativeConstraint which is not
1705 // incremental, and where a call to InitialPropagate() takes time which is
1706 // O(n^2) and Omega(n log n) with n the number of cumulative tasks.
1707 //
1708 // Despite the high complexity, this propagator is needed, because of those
1709 // implemented, it is the only one that satisfy that if all instantiated, no
1710 // contradiction will be detected if and only if the constraint is satisfied.
1711 //
1712 // The implementation is quite naive, and could certainly be improved, for
1713 // example by maintaining the profile incrementally.
1714 template <class Task>
1715 class CumulativeTimeTable : public Constraint {
1716  public:
1717  CumulativeTimeTable(Solver* const solver, const std::vector<Task*>& tasks,
1718  IntVar* const capacity)
1719  : Constraint(solver), by_start_min_(tasks), capacity_(capacity) {
1720  // There may be up to 2 delta's per interval (one on each side),
1721  // plus two sentinels
1722  const int profile_max_size = 2 * by_start_min_.size() + 2;
1723  profile_non_unique_time_.reserve(profile_max_size);
1724  profile_unique_time_.reserve(profile_max_size);
1725  }
1726 
1727  ~CumulativeTimeTable() override { gtl::STLDeleteElements(&by_start_min_); }
1728 
1729  void InitialPropagate() override {
1730  BuildProfile();
1731  PushTasks();
1732  // TODO(user): When a task has a fixed part, we could propagate
1733  // max_demand from its current location.
1734  }
1735 
1736  void Post() override {
1737  Demon* demon = MakeDelayedConstraintDemon0(
1738  solver(), this, &CumulativeTimeTable::InitialPropagate,
1739  "InitialPropagate");
1740  for (Task* const task : by_start_min_) {
1741  task->WhenAnything(demon);
1742  }
1743  capacity_->WhenRange(demon);
1744  }
1745 
1746  void Accept(ModelVisitor* const visitor) const override {
1747  LOG(FATAL) << "Should not be visited";
1748  }
1749 
1750  std::string DebugString() const override { return "CumulativeTimeTable"; }
1751 
1752  private:
1753  // Build the usage profile. Runs in O(n log n).
1754  void BuildProfile() {
1755  // Build profile with non unique time
1756  profile_non_unique_time_.clear();
1757  for (const Task* const task : by_start_min_) {
1758  const IntervalVar* const interval = task->interval;
1759  const int64_t start_max = interval->StartMax();
1760  const int64_t end_min = interval->EndMin();
1761  if (interval->MustBePerformed() && start_max < end_min) {
1762  const int64_t demand_min = task->DemandMin();
1763  if (demand_min > 0) {
1764  profile_non_unique_time_.emplace_back(start_max, +demand_min);
1765  profile_non_unique_time_.emplace_back(end_min, -demand_min);
1766  }
1767  }
1768  }
1769  // Sort
1770  std::sort(profile_non_unique_time_.begin(), profile_non_unique_time_.end(),
1771  TimeLessThan);
1772  // Build profile with unique times
1773  profile_unique_time_.clear();
1774  profile_unique_time_.emplace_back(std::numeric_limits<int64_t>::min(), 0);
1775  int64_t usage = 0;
1776  for (const ProfileDelta& step : profile_non_unique_time_) {
1777  if (step.time == profile_unique_time_.back().time) {
1778  profile_unique_time_.back().delta += step.delta;
1779  } else {
1780  profile_unique_time_.push_back(step);
1781  }
1782  // Update usage.
1783  usage += step.delta;
1784  }
1785  // Check final usage to be 0.
1786  DCHECK_EQ(0, usage);
1787  // Scan to find max usage.
1788  int64_t max_usage = 0;
1789  for (const ProfileDelta& step : profile_unique_time_) {
1790  usage += step.delta;
1791  if (usage > max_usage) {
1792  max_usage = usage;
1793  }
1794  }
1795  DCHECK_EQ(0, usage);
1796  capacity_->SetMin(max_usage);
1797  // Add a sentinel.
1798  profile_unique_time_.emplace_back(std::numeric_limits<int64_t>::max(), 0);
1799  }
1800 
1801  // Update the start min for all tasks. Runs in O(n^2) and Omega(n).
1802  void PushTasks() {
1803  std::sort(by_start_min_.begin(), by_start_min_.end(),
1804  StartMinLessThan<Task>);
1805  int64_t usage = 0;
1806  int profile_index = 0;
1807  for (const Task* const task : by_start_min_) {
1808  const IntervalVar* const interval = task->interval;
1809  if (interval->StartMin() == interval->StartMax() &&
1810  interval->EndMin() == interval->EndMax()) {
1811  continue;
1812  }
1813  while (interval->StartMin() > profile_unique_time_[profile_index].time) {
1814  DCHECK(profile_index < profile_unique_time_.size());
1815  ++profile_index;
1816  usage += profile_unique_time_[profile_index].delta;
1817  }
1818  PushTask(task, profile_index, usage);
1819  }
1820  }
1821 
1822  // Push the given task to new_start_min, defined as the smallest integer such
1823  // that the profile usage for all tasks, excluding the current one, does not
1824  // exceed capacity_ - task->demand on the interval
1825  // [new_start_min, new_start_min + task->interval->DurationMin() ).
1826  void PushTask(const Task* const task, int profile_index, int64_t usage) {
1827  // Init
1828  const IntervalVar* const interval = task->interval;
1829  const int64_t demand_min = task->DemandMin();
1830  if (demand_min == 0) { // Demand can be null, nothing to propagate.
1831  return;
1832  }
1833  const int64_t residual_capacity = CapSub(capacity_->Max(), demand_min);
1834  const int64_t duration = task->interval->DurationMin();
1835  const ProfileDelta& first_prof_delta = profile_unique_time_[profile_index];
1836 
1837  int64_t new_start_min = interval->StartMin();
1838 
1839  DCHECK_GE(first_prof_delta.time, interval->StartMin());
1840  // The check above is with a '>='. Let's first treat the '>' case
1841  if (first_prof_delta.time > interval->StartMin()) {
1842  // There was no profile delta at a time between interval->StartMin()
1843  // (included) and the current one.
1844  // As we don't delete delta's of 0 value, this means the current task
1845  // does not contribute to the usage before:
1846  DCHECK((interval->StartMax() >= first_prof_delta.time) ||
1847  (interval->StartMax() >= interval->EndMin()));
1848  // The 'usage' given in argument is valid at first_prof_delta.time. To
1849  // compute the usage at the start min, we need to remove the last delta.
1850  const int64_t usage_at_start_min = CapSub(usage, first_prof_delta.delta);
1851  if (usage_at_start_min > residual_capacity) {
1852  new_start_min = profile_unique_time_[profile_index].time;
1853  }
1854  }
1855 
1856  // Influence of current task
1857  const int64_t start_max = interval->StartMax();
1858  const int64_t end_min = interval->EndMin();
1859  ProfileDelta delta_start(start_max, 0);
1860  ProfileDelta delta_end(end_min, 0);
1861  if (interval->MustBePerformed() && start_max < end_min) {
1862  delta_start.delta = +demand_min;
1863  delta_end.delta = -demand_min;
1864  }
1865  while (profile_unique_time_[profile_index].time <
1866  CapAdd(duration, new_start_min)) {
1867  const ProfileDelta& profile_delta = profile_unique_time_[profile_index];
1868  DCHECK(profile_index < profile_unique_time_.size());
1869  // Compensate for current task
1870  if (profile_delta.time == delta_start.time) {
1871  usage -= delta_start.delta;
1872  }
1873  if (profile_delta.time == delta_end.time) {
1874  usage -= delta_end.delta;
1875  }
1876  // Increment time
1877  ++profile_index;
1878  DCHECK(profile_index < profile_unique_time_.size());
1879  // Does it fit?
1880  if (usage > residual_capacity) {
1881  new_start_min = profile_unique_time_[profile_index].time;
1882  }
1883  usage += profile_unique_time_[profile_index].delta;
1884  }
1885  task->interval->SetStartMin(new_start_min);
1886  }
1887 
1888  typedef std::vector<ProfileDelta> Profile;
1889 
1890  Profile profile_unique_time_;
1891  Profile profile_non_unique_time_;
1892  std::vector<Task*> by_start_min_;
1893  IntVar* const capacity_;
1894 
1895  DISALLOW_COPY_AND_ASSIGN(CumulativeTimeTable);
1896 };
1897 
1898 // Cumulative idempotent Time-Table.
1899 //
1900 // This propagator is based on Letort et al. 2012 add Gay et al. 2015.
1901 //
1902 // TODO(user): fill the description once the incremental aspect are
1903 // implemented.
1904 //
1905 // Worst case: O(n^2 log n) -- really unlikely in practice.
1906 // Best case: Omega(1).
1907 // Practical: Almost linear in the number of unfixed tasks.
1908 template <class Task>
1909 class TimeTableSync : public Constraint {
1910  public:
1911  TimeTableSync(Solver* const solver, const std::vector<Task*>& tasks,
1912  IntVar* const capacity)
1913  : Constraint(solver), tasks_(tasks), capacity_(capacity) {
1914  num_tasks_ = tasks_.size();
1915  gap_ = 0;
1916  prev_gap_ = 0;
1918  next_pos_ = std::numeric_limits<int64_t>::min();
1919  // Allocate vectors to contain no more than n_tasks.
1920  start_min_.reserve(num_tasks_);
1921  start_max_.reserve(num_tasks_);
1922  end_min_.reserve(num_tasks_);
1923  durations_.reserve(num_tasks_);
1924  demands_.reserve(num_tasks_);
1925  }
1926 
1927  ~TimeTableSync() override { gtl::STLDeleteElements(&tasks_); }
1928 
1929  void InitialPropagate() override {
1930  // Reset data structures.
1931  BuildEvents();
1932  while (!events_scp_.empty() && !events_ecp_.empty()) {
1933  // Move the sweep line.
1934  pos_ = NextEventTime();
1935  // Update the profile with compulsory part events.
1936  ProcessEventsScp();
1937  ProcessEventsEcp();
1938  // Update minimum capacity (may fail)
1939  capacity_->SetMin(capacity_->Max() - gap_);
1940  // Time to the next possible profile increase.
1941  next_pos_ = NextScpTime();
1942  // Consider new task to schedule.
1943  ProcessEventsPr();
1944  // Filter.
1945  FilterMin();
1946  }
1947  }
1948 
1949  void Post() override {
1950  Demon* demon = MakeDelayedConstraintDemon0(
1951  solver(), this, &TimeTableSync::InitialPropagate, "InitialPropagate");
1952  for (Task* const task : tasks_) {
1953  task->WhenAnything(demon);
1954  }
1955  capacity_->WhenRange(demon);
1956  }
1957 
1958  void Accept(ModelVisitor* const visitor) const override {
1959  LOG(FATAL) << "Should not be visited";
1960  }
1961 
1962  std::string DebugString() const override { return "TimeTableSync"; }
1963 
1964  private:
1965  // Task state.
1966  enum State { NONE, READY, CHECK, CONFLICT };
1967 
1968  inline int64_t NextScpTime() {
1969  return !events_scp_.empty() ? events_scp_.top().first
1971  }
1972 
1973  inline int64_t NextEventTime() {
1975  if (!events_pr_.empty()) {
1976  time = events_pr_.top().first;
1977  }
1978  if (!events_scp_.empty()) {
1979  int64_t t = events_scp_.top().first;
1980  time = t < time ? t : time;
1981  }
1982  if (!events_ecp_.empty()) {
1983  int64_t t = events_ecp_.top().first;
1984  time = t < time ? t : time;
1985  }
1986  return time;
1987  }
1988 
1989  void ProcessEventsScp() {
1990  while (!events_scp_.empty() && events_scp_.top().first == pos_) {
1991  const int64_t task_id = events_scp_.top().second;
1992  events_scp_.pop();
1993  const int64_t old_end_min = end_min_[task_id];
1994  if (states_[task_id] == State::CONFLICT) {
1995  // Update cached values.
1996  const int64_t new_end_min = pos_ + durations_[task_id];
1997  start_min_[task_id] = pos_;
1998  end_min_[task_id] = new_end_min;
1999  // Filter the domain
2000  tasks_[task_id]->interval->SetStartMin(pos_);
2001  }
2002  // The task is scheduled.
2003  states_[task_id] = State::READY;
2004  // Update the profile if the task has a compulsory part.
2005  if (pos_ < end_min_[task_id]) {
2006  gap_ -= demands_[task_id];
2007  if (old_end_min <= pos_) {
2008  events_ecp_.push(kv(end_min_[task_id], task_id));
2009  }
2010  }
2011  }
2012  }
2013 
2014  void ProcessEventsEcp() {
2015  while (!events_ecp_.empty() && events_ecp_.top().first == pos_) {
2016  const int64_t task_id = events_ecp_.top().second;
2017  events_ecp_.pop();
2018  // Update the event if it is not up to date.
2019  if (pos_ < end_min_[task_id]) {
2020  events_ecp_.push(kv(end_min_[task_id], task_id));
2021  } else {
2022  gap_ += demands_[task_id];
2023  }
2024  }
2025  }
2026 
2027  void ProcessEventsPr() {
2028  while (!events_pr_.empty() && events_pr_.top().first == pos_) {
2029  const int64_t task_id = events_pr_.top().second;
2030  events_pr_.pop();
2031  // The task is in conflict with the current profile.
2032  if (demands_[task_id] > gap_) {
2033  states_[task_id] = State::CONFLICT;
2034  conflict_.push(kv(demands_[task_id], task_id));
2035  continue;
2036  }
2037  // The task is not in conflict for the moment.
2038  if (next_pos_ < end_min_[task_id]) {
2039  states_[task_id] = State::CHECK;
2040  check_.push(kv(demands_[task_id], task_id));
2041  continue;
2042  }
2043  // The task is not in conflict and can be scheduled.
2044  states_[task_id] = State::READY;
2045  }
2046  }
2047 
2048  void FilterMin() {
2049  // The profile exceeds the capacity.
2050  capacity_->SetMin(capacity_->Max() - gap_);
2051  // The profile has increased.
2052  if (gap_ < prev_gap_) {
2053  // Reconsider the task in check state.
2054  while (!check_.empty() && demands_[check_.top().second] > gap_) {
2055  const int64_t task_id = check_.top().second;
2056  check_.pop();
2057  if (states_[task_id] == State::CHECK && pos_ < end_min_[task_id]) {
2058  states_[task_id] = State::CONFLICT;
2059  conflict_.push(kv(demands_[task_id], task_id));
2060  continue;
2061  }
2062  states_[task_id] = State::READY;
2063  }
2064  prev_gap_ = gap_;
2065  }
2066  // The profile has decreased.
2067  if (gap_ > prev_gap_) {
2068  // Reconsider the tasks in conflict.
2069  while (!conflict_.empty() && demands_[conflict_.top().second] <= gap_) {
2070  const int64_t task_id = conflict_.top().second;
2071  conflict_.pop();
2072  if (states_[task_id] != State::CONFLICT) {
2073  continue;
2074  }
2075  const int64_t old_end_min = end_min_[task_id];
2076  // Update the cache.
2077  start_min_[task_id] = pos_;
2078  end_min_[task_id] = pos_ + durations_[task_id];
2079  // Filter the domain.
2080  tasks_[task_id]->interval->SetStartMin(pos_); // should not fail.
2081  // The task still have to be checked.
2082  if (next_pos_ < end_min_[task_id]) {
2083  states_[task_id] = State::CHECK;
2084  check_.push(kv(demands_[task_id], task_id));
2085  } else {
2086  states_[task_id] = State::READY;
2087  }
2088  // Update possible compulsory part.
2089  const int64_t start_max = start_max_[task_id];
2090  if (start_max >= old_end_min && start_max < end_min_[task_id]) {
2091  events_ecp_.push(kv(end_min_[task_id], task_id));
2092  }
2093  }
2094  }
2095  prev_gap_ = gap_;
2096  }
2097 
2098  void BuildEvents() {
2099  // Reset the sweep line.
2101  next_pos_ = std::numeric_limits<int64_t>::min();
2102  gap_ = capacity_->Max();
2103  prev_gap_ = capacity_->Max();
2104  // Reset dynamic states.
2105  conflict_ = min_heap();
2106  check_ = max_heap();
2107  // Reset profile events.
2108  events_pr_ = min_heap();
2109  events_scp_ = min_heap();
2110  events_ecp_ = min_heap();
2111  // Reset cache.
2112  start_min_.clear();
2113  start_max_.clear();
2114  end_min_.clear();
2115  durations_.clear();
2116  demands_.clear();
2117  states_.clear();
2118  // Build events.
2119  for (int i = 0; i < num_tasks_; i++) {
2120  const int64_t s_min = tasks_[i]->interval->StartMin();
2121  const int64_t s_max = tasks_[i]->interval->StartMax();
2122  const int64_t e_min = tasks_[i]->interval->EndMin();
2123  // Cache the values.
2124  start_min_.push_back(s_min);
2125  start_max_.push_back(s_max);
2126  end_min_.push_back(e_min);
2127  durations_.push_back(tasks_[i]->interval->DurationMin());
2128  demands_.push_back(tasks_[i]->DemandMin());
2129  // Reset task state.
2130  states_.push_back(State::NONE);
2131  // Start compulsory part event.
2132  events_scp_.push(kv(s_max, i));
2133  // Pruning event only if the start time of the task is not fixed.
2134  if (s_min != s_max) {
2135  events_pr_.push(kv(s_min, i));
2136  }
2137  // End of compulsory part only if the task has a compulsory part.
2138  if (s_max < e_min) {
2139  events_ecp_.push(kv(e_min, i));
2140  }
2141  }
2142  }
2143 
2144  int64_t num_tasks_;
2145  std::vector<Task*> tasks_;
2146  IntVar* const capacity_;
2147 
2148  std::vector<int64_t> start_min_;
2149  std::vector<int64_t> start_max_;
2150  std::vector<int64_t> end_min_;
2151  std::vector<int64_t> end_max_;
2152  std::vector<int64_t> durations_;
2153  std::vector<int64_t> demands_;
2154 
2155  // Pair key value.
2156  typedef std::pair<int64_t, int64_t> kv;
2157  typedef std::priority_queue<kv, std::vector<kv>, std::greater<kv>> min_heap;
2158  typedef std::priority_queue<kv, std::vector<kv>, std::less<kv>> max_heap;
2159 
2160  // Profile events.
2161  min_heap events_pr_;
2162  min_heap events_scp_;
2163  min_heap events_ecp_;
2164 
2165  // Task state.
2166  std::vector<State> states_;
2167  min_heap conflict_;
2168  max_heap check_;
2169 
2170  // Sweep line state.
2171  int64_t pos_;
2172  int64_t next_pos_;
2173  int64_t gap_;
2174  int64_t prev_gap_;
2175 };
2176 
2177 class CumulativeConstraint : public Constraint {
2178  public:
2179  CumulativeConstraint(Solver* const s,
2180  const std::vector<IntervalVar*>& intervals,
2181  const std::vector<int64_t>& demands,
2182  IntVar* const capacity, const std::string& name)
2183  : Constraint(s),
2184  capacity_(capacity),
2185  intervals_(intervals),
2186  demands_(demands) {
2187  tasks_.reserve(intervals.size());
2188  for (int i = 0; i < intervals.size(); ++i) {
2189  tasks_.push_back(CumulativeTask(intervals[i], demands[i]));
2190  }
2191  }
2192 
2193  void Post() override {
2194  // For the cumulative constraint, there are many propagators, and they
2195  // don't dominate each other. So the strongest propagation is obtained
2196  // by posting a bunch of different propagators.
2197  const ConstraintSolverParameters& params = solver()->const_parameters();
2198  if (params.use_cumulative_time_table()) {
2199  if (params.use_cumulative_time_table_sync()) {
2200  PostOneSidedConstraint(false, false, true);
2201  PostOneSidedConstraint(true, false, true);
2202  } else {
2203  PostOneSidedConstraint(false, false, false);
2204  PostOneSidedConstraint(true, false, false);
2205  }
2206  }
2207  if (params.use_cumulative_edge_finder()) {
2208  PostOneSidedConstraint(false, true, false);
2209  PostOneSidedConstraint(true, true, false);
2210  }
2211  if (params.use_sequence_high_demand_tasks()) {
2212  PostHighDemandSequenceConstraint();
2213  }
2214  if (params.use_all_possible_disjunctions()) {
2215  PostAllDisjunctions();
2216  }
2217  }
2218 
2219  void InitialPropagate() override {
2220  // Nothing to do: this constraint delegates all the work to other classes
2221  }
2222 
2223  void Accept(ModelVisitor* const visitor) const override {
2224  // TODO(user): Build arrays on demand?
2225  visitor->BeginVisitConstraint(ModelVisitor::kCumulative, this);
2226  visitor->VisitIntervalArrayArgument(ModelVisitor::kIntervalsArgument,
2227  intervals_);
2228  visitor->VisitIntegerArrayArgument(ModelVisitor::kDemandsArgument,
2229  demands_);
2230  visitor->VisitIntegerExpressionArgument(ModelVisitor::kCapacityArgument,
2231  capacity_);
2232  visitor->EndVisitConstraint(ModelVisitor::kCumulative, this);
2233  }
2234 
2235  std::string DebugString() const override {
2236  return absl::StrFormat("CumulativeConstraint([%s], %s)",
2237  JoinDebugString(tasks_, ", "),
2238  capacity_->DebugString());
2239  }
2240 
2241  private:
2242  // Post temporal disjunctions for tasks that cannot overlap.
2243  void PostAllDisjunctions() {
2244  for (int i = 0; i < intervals_.size(); ++i) {
2245  IntervalVar* const interval_i = intervals_[i];
2246  if (interval_i->MayBePerformed()) {
2247  for (int j = i + 1; j < intervals_.size(); ++j) {
2248  IntervalVar* const interval_j = intervals_[j];
2249  if (interval_j->MayBePerformed()) {
2250  if (CapAdd(tasks_[i].demand, tasks_[j].demand) > capacity_->Max()) {
2251  Constraint* const constraint =
2252  solver()->MakeTemporalDisjunction(interval_i, interval_j);
2253  solver()->AddConstraint(constraint);
2254  }
2255  }
2256  }
2257  }
2258  }
2259  }
2260 
2261  // Post a Sequence constraint for tasks that requires strictly more than half
2262  // of the resource
2263  void PostHighDemandSequenceConstraint() {
2264  Constraint* constraint = nullptr;
2265  { // Need a block to avoid memory leaks in case the AddConstraint fails
2266  std::vector<IntervalVar*> high_demand_intervals;
2267  high_demand_intervals.reserve(intervals_.size());
2268  for (int i = 0; i < demands_.size(); ++i) {
2269  const int64_t demand = tasks_[i].demand;
2270  // Consider two tasks with demand d1 and d2 such that
2271  // d1 * 2 > capacity_ and d2 * 2 > capacity_.
2272  // Then d1 + d2 = 1/2 (d1 * 2 + d2 * 2)
2273  // > 1/2 (capacity_ + capacity_)
2274  // > capacity_.
2275  // Therefore these two tasks cannot overlap.
2276  if (demand * 2 > capacity_->Max() &&
2277  tasks_[i].interval->MayBePerformed()) {
2278  high_demand_intervals.push_back(tasks_[i].interval);
2279  }
2280  }
2281  if (high_demand_intervals.size() >= 2) {
2282  // If there are less than 2 such intervals, the constraint would do
2283  // nothing
2284  std::string seq_name = absl::StrCat(name(), "-HighDemandSequence");
2285  constraint = solver()->MakeDisjunctiveConstraint(high_demand_intervals,
2286  seq_name);
2287  }
2288  }
2289  if (constraint != nullptr) {
2290  solver()->AddConstraint(constraint);
2291  }
2292  }
2293 
2294  // Populate the given vector with useful tasks, meaning the ones on which
2295  // some propagation can be done
2296  void PopulateVectorUsefulTasks(
2297  bool mirror, std::vector<CumulativeTask*>* const useful_tasks) {
2298  DCHECK(useful_tasks->empty());
2299  for (int i = 0; i < tasks_.size(); ++i) {
2300  const CumulativeTask& original_task = tasks_[i];
2301  IntervalVar* const interval = original_task.interval;
2302  // Check if exceed capacity
2303  if (original_task.demand > capacity_->Max()) {
2304  interval->SetPerformed(false);
2305  }
2306  // Add to the useful_task vector if it may be performed and that it
2307  // actually consumes some of the resource.
2308  if (interval->MayBePerformed() && original_task.demand > 0) {
2309  Solver* const s = solver();
2310  IntervalVar* const original_interval = original_task.interval;
2311  IntervalVar* const interval =
2312  mirror ? s->MakeMirrorInterval(original_interval)
2313  : original_interval;
2314  IntervalVar* const relaxed_max = s->MakeIntervalRelaxedMax(interval);
2315  useful_tasks->push_back(
2316  new CumulativeTask(relaxed_max, original_task.demand));
2317  }
2318  }
2319  }
2320 
2321  // Makes and return an edge-finder or a time table, or nullptr if it is not
2322  // necessary.
2323  Constraint* MakeOneSidedConstraint(bool mirror, bool edge_finder,
2324  bool tt_sync) {
2325  std::vector<CumulativeTask*> useful_tasks;
2326  PopulateVectorUsefulTasks(mirror, &useful_tasks);
2327  if (useful_tasks.empty()) {
2328  return nullptr;
2329  } else {
2330  Solver* const s = solver();
2331  if (edge_finder) {
2332  const ConstraintSolverParameters& params = solver()->const_parameters();
2333  return useful_tasks.size() < params.max_edge_finder_size()
2334  ? s->RevAlloc(new EdgeFinder<CumulativeTask>(s, useful_tasks,
2335  capacity_))
2336  : nullptr;
2337  }
2338  if (tt_sync) {
2339  return s->RevAlloc(
2340  new TimeTableSync<CumulativeTask>(s, useful_tasks, capacity_));
2341  }
2342  return s->RevAlloc(
2343  new CumulativeTimeTable<CumulativeTask>(s, useful_tasks, capacity_));
2344  }
2345  }
2346 
2347  // Post a straight or mirrored edge-finder, if needed
2348  void PostOneSidedConstraint(bool mirror, bool edge_finder, bool tt_sync) {
2349  Constraint* const constraint =
2350  MakeOneSidedConstraint(mirror, edge_finder, tt_sync);
2351  if (constraint != nullptr) {
2352  solver()->AddConstraint(constraint);
2353  }
2354  }
2355 
2356  // Capacity of the cumulative resource
2357  IntVar* const capacity_;
2358 
2359  // The tasks that share the cumulative resource
2360  std::vector<CumulativeTask> tasks_;
2361 
2362  // Array of intervals for the visitor.
2363  const std::vector<IntervalVar*> intervals_;
2364  // Array of demands for the visitor.
2365  const std::vector<int64_t> demands_;
2366 
2367  DISALLOW_COPY_AND_ASSIGN(CumulativeConstraint);
2368 };
2369 
2370 class VariableDemandCumulativeConstraint : public Constraint {
2371  public:
2372  VariableDemandCumulativeConstraint(Solver* const s,
2373  const std::vector<IntervalVar*>& intervals,
2374  const std::vector<IntVar*>& demands,
2375  IntVar* const capacity,
2376  const std::string& name)
2377  : Constraint(s),
2378  capacity_(capacity),
2379  intervals_(intervals),
2380  demands_(demands) {
2381  tasks_.reserve(intervals.size());
2382  for (int i = 0; i < intervals.size(); ++i) {
2383  tasks_.push_back(VariableCumulativeTask(intervals[i], demands[i]));
2384  }
2385  }
2386 
2387  void Post() override {
2388  // For the cumulative constraint, there are many propagators, and they
2389  // don't dominate each other. So the strongest propagation is obtained
2390  // by posting a bunch of different propagators.
2391  const ConstraintSolverParameters& params = solver()->const_parameters();
2392  if (params.use_cumulative_time_table()) {
2393  PostOneSidedConstraint(false, false, false);
2394  PostOneSidedConstraint(true, false, false);
2395  }
2396  if (params.use_cumulative_edge_finder()) {
2397  PostOneSidedConstraint(false, true, false);
2398  PostOneSidedConstraint(true, true, false);
2399  }
2400  if (params.use_sequence_high_demand_tasks()) {
2401  PostHighDemandSequenceConstraint();
2402  }
2403  if (params.use_all_possible_disjunctions()) {
2404  PostAllDisjunctions();
2405  }
2406  }
2407 
2408  void InitialPropagate() override {
2409  // Nothing to do: this constraint delegates all the work to other classes
2410  }
2411 
2412  void Accept(ModelVisitor* const visitor) const override {
2413  // TODO(user): Build arrays on demand?
2414  visitor->BeginVisitConstraint(ModelVisitor::kCumulative, this);
2415  visitor->VisitIntervalArrayArgument(ModelVisitor::kIntervalsArgument,
2416  intervals_);
2417  visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kDemandsArgument,
2418  demands_);
2419  visitor->VisitIntegerExpressionArgument(ModelVisitor::kCapacityArgument,
2420  capacity_);
2421  visitor->EndVisitConstraint(ModelVisitor::kCumulative, this);
2422  }
2423 
2424  std::string DebugString() const override {
2425  return absl::StrFormat("VariableDemandCumulativeConstraint([%s], %s)",
2426  JoinDebugString(tasks_, ", "),
2427  capacity_->DebugString());
2428  }
2429 
2430  private:
2431  // Post temporal disjunctions for tasks that cannot overlap.
2432  void PostAllDisjunctions() {
2433  for (int i = 0; i < intervals_.size(); ++i) {
2434  IntervalVar* const interval_i = intervals_[i];
2435  if (interval_i->MayBePerformed()) {
2436  for (int j = i + 1; j < intervals_.size(); ++j) {
2437  IntervalVar* const interval_j = intervals_[j];
2438  if (interval_j->MayBePerformed()) {
2439  if (CapAdd(tasks_[i].demand->Min(), tasks_[j].demand->Min()) >
2440  capacity_->Max()) {
2441  Constraint* const constraint =
2442  solver()->MakeTemporalDisjunction(interval_i, interval_j);
2443  solver()->AddConstraint(constraint);
2444  }
2445  }
2446  }
2447  }
2448  }
2449  }
2450 
2451  // Post a Sequence constraint for tasks that requires strictly more than half
2452  // of the resource
2453  void PostHighDemandSequenceConstraint() {
2454  Constraint* constraint = nullptr;
2455  { // Need a block to avoid memory leaks in case the AddConstraint fails
2456  std::vector<IntervalVar*> high_demand_intervals;
2457  high_demand_intervals.reserve(intervals_.size());
2458  for (int i = 0; i < demands_.size(); ++i) {
2459  const int64_t demand = tasks_[i].demand->Min();
2460  // Consider two tasks with demand d1 and d2 such that
2461  // d1 * 2 > capacity_ and d2 * 2 > capacity_.
2462  // Then d1 + d2 = 1/2 (d1 * 2 + d2 * 2)
2463  // > 1/2 (capacity_ + capacity_)
2464  // > capacity_.
2465  // Therefore these two tasks cannot overlap.
2466  if (demand * 2 > capacity_->Max() &&
2467  tasks_[i].interval->MayBePerformed()) {
2468  high_demand_intervals.push_back(tasks_[i].interval);
2469  }
2470  }
2471  if (high_demand_intervals.size() >= 2) {
2472  // If there are less than 2 such intervals, the constraint would do
2473  // nothing
2474  const std::string seq_name =
2475  absl::StrCat(name(), "-HighDemandSequence");
2476  constraint = solver()->MakeStrictDisjunctiveConstraint(
2477  high_demand_intervals, seq_name);
2478  }
2479  }
2480  if (constraint != nullptr) {
2481  solver()->AddConstraint(constraint);
2482  }
2483  }
2484 
2485  // Populates the given vector with useful tasks, meaning the ones on which
2486  // some propagation can be done
2487  void PopulateVectorUsefulTasks(
2488  bool mirror, std::vector<VariableCumulativeTask*>* const useful_tasks) {
2489  DCHECK(useful_tasks->empty());
2490  for (int i = 0; i < tasks_.size(); ++i) {
2491  const VariableCumulativeTask& original_task = tasks_[i];
2492  IntervalVar* const interval = original_task.interval;
2493  // Check if exceed capacity
2494  if (original_task.demand->Min() > capacity_->Max()) {
2495  interval->SetPerformed(false);
2496  }
2497  // Add to the useful_task vector if it may be performed and that it
2498  // may actually consume some of the resource.
2499  if (interval->MayBePerformed() && original_task.demand->Max() > 0) {
2500  Solver* const s = solver();
2501  IntervalVar* const original_interval = original_task.interval;
2502  IntervalVar* const interval =
2503  mirror ? s->MakeMirrorInterval(original_interval)
2504  : original_interval;
2505  IntervalVar* const relaxed_max = s->MakeIntervalRelaxedMax(interval);
2506  useful_tasks->push_back(
2507  new VariableCumulativeTask(relaxed_max, original_task.demand));
2508  }
2509  }
2510  }
2511 
2512  // Makes and returns an edge-finder or a time table, or nullptr if it is not
2513  // necessary.
2514  Constraint* MakeOneSidedConstraint(bool mirror, bool edge_finder,
2515  bool tt_sync) {
2516  std::vector<VariableCumulativeTask*> useful_tasks;
2517  PopulateVectorUsefulTasks(mirror, &useful_tasks);
2518  if (useful_tasks.empty()) {
2519  return nullptr;
2520  } else {
2521  Solver* const s = solver();
2522  if (edge_finder) {
2523  return s->RevAlloc(
2524  new EdgeFinder<VariableCumulativeTask>(s, useful_tasks, capacity_));
2525  }
2526  if (tt_sync) {
2527  return s->RevAlloc(new TimeTableSync<VariableCumulativeTask>(
2528  s, useful_tasks, capacity_));
2529  }
2530  return s->RevAlloc(new CumulativeTimeTable<VariableCumulativeTask>(
2531  s, useful_tasks, capacity_));
2532  }
2533  }
2534 
2535  // Post a straight or mirrored edge-finder, if needed
2536  void PostOneSidedConstraint(bool mirror, bool edge_finder, bool tt_sync) {
2537  Constraint* const constraint =
2538  MakeOneSidedConstraint(mirror, edge_finder, tt_sync);
2539  if (constraint != nullptr) {
2540  solver()->AddConstraint(constraint);
2541  }
2542  }
2543 
2544  // Capacity of the cumulative resource
2545  IntVar* const capacity_;
2546 
2547  // The tasks that share the cumulative resource
2548  std::vector<VariableCumulativeTask> tasks_;
2549 
2550  // Array of intervals for the visitor.
2551  const std::vector<IntervalVar*> intervals_;
2552  // Array of demands for the visitor.
2553  const std::vector<IntVar*> demands_;
2554 
2555  DISALLOW_COPY_AND_ASSIGN(VariableDemandCumulativeConstraint);
2556 };
2557 } // namespace
2558 
2559 // Sequence Constraint
2560 
2561 // ----- Public class -----
2562 
2563 DisjunctiveConstraint::DisjunctiveConstraint(
2564  Solver* const s, const std::vector<IntervalVar*>& intervals,
2565  const std::string& name)
2566  : Constraint(s), intervals_(intervals) {
2567  if (!name.empty()) {
2568  set_name(name);
2569  }
2570  transition_time_ = [](int64_t x, int64_t y) { return 0; };
2571 }
2572 
2574 
2576  std::function<int64_t(int64_t, int64_t)> transition_time) {
2577  if (transition_time != nullptr) {
2578  transition_time_ = transition_time;
2579  } else {
2580  transition_time_ = [](int64_t x, int64_t y) { return 0; };
2581  }
2582 }
2583 
2584 // ---------- Factory methods ----------
2585 
2587  const std::vector<IntervalVar*>& intervals, const std::string& name) {
2588  return RevAlloc(new FullDisjunctiveConstraint(this, intervals, name, false));
2589 }
2590 
2592  const std::vector<IntervalVar*>& intervals, const std::string& name) {
2593  return RevAlloc(new FullDisjunctiveConstraint(this, intervals, name, true));
2594 }
2595 
2596 // Demands are constant
2597 
2598 Constraint* Solver::MakeCumulative(const std::vector<IntervalVar*>& intervals,
2599  const std::vector<int64_t>& demands,
2600  int64_t capacity, const std::string& name) {
2601  CHECK_EQ(intervals.size(), demands.size());
2602  for (int i = 0; i < intervals.size(); ++i) {
2603  CHECK_GE(demands[i], 0);
2604  }
2605  if (capacity == 1 && AreAllOnes(demands)) {
2606  return MakeDisjunctiveConstraint(intervals, name);
2607  }
2608  return RevAlloc(new CumulativeConstraint(this, intervals, demands,
2610 }
2611 
2612 Constraint* Solver::MakeCumulative(const std::vector<IntervalVar*>& intervals,
2613  const std::vector<int>& demands,
2614  int64_t capacity, const std::string& name) {
2615  return MakeCumulative(intervals, ToInt64Vector(demands), capacity, name);
2616 }
2617 
2618 Constraint* Solver::MakeCumulative(const std::vector<IntervalVar*>& intervals,
2619  const std::vector<int64_t>& demands,
2620  IntVar* const capacity,
2621  const std::string& name) {
2622  CHECK_EQ(intervals.size(), demands.size());
2623  for (int i = 0; i < intervals.size(); ++i) {
2624  CHECK_GE(demands[i], 0);
2625  }
2626  return RevAlloc(
2627  new CumulativeConstraint(this, intervals, demands, capacity, name));
2628 }
2629 
2630 Constraint* Solver::MakeCumulative(const std::vector<IntervalVar*>& intervals,
2631  const std::vector<int>& demands,
2632  IntVar* const capacity,
2633  const std::string& name) {
2634  return MakeCumulative(intervals, ToInt64Vector(demands), capacity, name);
2635 }
2636 
2637 // Demands are variable
2638 
2639 Constraint* Solver::MakeCumulative(const std::vector<IntervalVar*>& intervals,
2640  const std::vector<IntVar*>& demands,
2641  int64_t capacity, const std::string& name) {
2642  CHECK_EQ(intervals.size(), demands.size());
2643  for (int i = 0; i < intervals.size(); ++i) {
2644  CHECK_GE(demands[i]->Min(), 0);
2645  }
2646  if (AreAllBound(demands)) {
2647  std::vector<int64_t> fixed_demands(demands.size());
2648  for (int i = 0; i < demands.size(); ++i) {
2649  fixed_demands[i] = demands[i]->Value();
2650  }
2651  return MakeCumulative(intervals, fixed_demands, capacity, name);
2652  }
2653  return RevAlloc(new VariableDemandCumulativeConstraint(
2654  this, intervals, demands, MakeIntConst(capacity), name));
2655 }
2656 
2657 Constraint* Solver::MakeCumulative(const std::vector<IntervalVar*>& intervals,
2658  const std::vector<IntVar*>& demands,
2659  IntVar* const capacity,
2660  const std::string& name) {
2661  CHECK_EQ(intervals.size(), demands.size());
2662  for (int i = 0; i < intervals.size(); ++i) {
2663  CHECK_GE(demands[i]->Min(), 0);
2664  }
2665  if (AreAllBound(demands)) {
2666  std::vector<int64_t> fixed_demands(demands.size());
2667  for (int i = 0; i < demands.size(); ++i) {
2668  fixed_demands[i] = demands[i]->Value();
2669  }
2670  return MakeCumulative(intervals, fixed_demands, capacity, name);
2671  }
2672  return RevAlloc(new VariableDemandCumulativeConstraint(
2673  this, intervals, demands, capacity, name));
2674 }
2675 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
int right_child
A constraint is the main modeling object.
void SetTransitionTime(Solver::IndexEvaluator2 transition_time)
Add a transition time between intervals.
Definition: resource.cc:2575
The class IntVar is a subset of IntExpr.
static IntegralType CeilOfRatio(IntegralType numerator, IntegralType denominator)
Definition: mathutil.h:39
virtual std::string name() const
Object naming.
DisjunctiveConstraint * MakeStrictDisjunctiveConstraint(const std::vector< IntervalVar * > &intervals, const std::string &name)
This constraint forces all interval vars into an non-overlapping sequence.
Definition: resource.cc:2591
DisjunctiveConstraint * MakeDisjunctiveConstraint(const std::vector< IntervalVar * > &intervals, const std::string &name)
This constraint forces all interval vars into an non-overlapping sequence.
Definition: resource.cc:2586
Constraint * MakeCumulative(const std::vector< IntervalVar * > &intervals, const std::vector< int64_t > &demands, int64_t capacity, const std::string &name)
This constraint forces that, for any integer t, the sum of the demands corresponding to an interval c...
Definition: resource.cc:2598
T * RevAlloc(T *object)
Registers the given object as being reversible.
IntVar * MakeIntConst(int64_t val, const std::string &name)
IntConst will create a constant expression.
const std::string name
IntVar * var
Definition: expr_array.cc:1874
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: macros.h:29
const Collection::value_type::second_type FindPtrOrNull(const Collection &collection, const typename Collection::value_type::first_type &key)
Definition: map_util.h:89
void STLDeleteValues(T *v)
Definition: stl_util.h:382
void STLDeleteElements(T *container)
Definition: stl_util.h:372
double Distance(const VectorXd &vector1, const VectorXd &vector2, const Sharder &sharder)
Definition: sharder.cc:259
IntType CeilOfRatio(IntType numerator, IntType denominator)
Definition: sat/util.h:428
Collection of objects used to extend the Constraint Solver library.
int64_t CapAdd(int64_t x, int64_t y)
int64_t CapSub(int64_t x, int64_t y)
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
int64_t CapProd(int64_t x, int64_t y)
std::vector< int64_t > ToInt64Vector(const std::vector< int > &input)
Definition: utilities.cc:829
bool AreAllOnes(const std::vector< T > &values)
bool AreAllBound(const std::vector< IntVar * > &vars)
std::string JoinDebugString(const std::vector< T > &v, const std::string &separator)
Definition: string_array.h:38
static const int kNone
Definition: resource.cc:236
int64_t demand
Definition: resource.cc:126
int64_t residual_energetic_end_min
Definition: resource.cc:1246
int argmax_energy_opt
Definition: resource.cc:365
int64_t energetic_end_min
Definition: resource.cc:358
int64_t energy
Definition: resource.cc:355
int64_t energetic_end_min_opt
Definition: resource.cc:369
int64_t total_processing
Definition: resource.cc:200
int index
Definition: resource.cc:102
int64_t total_ect
Definition: resource.cc:201
static const int64_t kNotInitialized
Definition: resource.cc:1255
int64_t energy_opt
Definition: resource.cc:361
int argmax_energetic_end_min_opt
Definition: resource.cc:373
static const int64_t kNotAvailable
Definition: resource.cc:1302
int64_t time
Definition: resource.cc:1694
int64_t delta
Definition: resource.cc:1695
IntervalVar * interval
Definition: resource.cc:101
int64_t capacity
Rev< int64_t > start_max
Rev< int > performed
Rev< int64_t > end_min
int64_t start
#define VLOG(verboselevel)
Definition: vlog.h:39