OR-Tools  9.1
sat/diffn.cc
Go to the documentation of this file.
1 // Copyright 2010-2021 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #include "ortools/sat/diffn.h"
15 
16 #include <algorithm>
17 #include <cstdint>
18 #include <limits>
19 
20 #include "absl/container/flat_hash_map.h"
21 #include "absl/strings/str_join.h"
23 #include "ortools/base/map_util.h"
24 #include "ortools/base/stl_util.h"
25 #include "ortools/sat/cumulative.h"
26 #include "ortools/sat/diffn_util.h"
28 #include "ortools/sat/intervals.h"
29 #include "ortools/sat/sat_solver.h"
30 #include "ortools/sat/theta_tree.h"
31 #include "ortools/util/sort.h"
32 
33 namespace operations_research {
34 namespace sat {
35 
36 namespace {
37 
38 // TODO(user): Use the faster variable only version if all expressions reduce
39 // to a single variable?
40 void AddIsEqualToMinOf(IntegerVariable min_var,
41  const std::vector<AffineExpression>& exprs,
42  Model* model) {
43  std::vector<LinearExpression> converted;
44  for (const AffineExpression& affine : exprs) {
45  LinearExpression e;
46  e.offset = affine.constant;
47  if (affine.var != kNoIntegerVariable) {
48  e.vars.push_back(affine.var);
49  e.coeffs.push_back(affine.coeff);
50  }
51  converted.push_back(e);
52  }
53  LinearExpression target;
54  target.vars.push_back(min_var);
55  target.coeffs.push_back(IntegerValue(1));
56  model->Add(IsEqualToMinOf(target, converted));
57 }
58 
59 void AddIsEqualToMaxOf(IntegerVariable max_var,
60  const std::vector<AffineExpression>& exprs,
61  Model* model) {
62  std::vector<LinearExpression> converted;
63  for (const AffineExpression& affine : exprs) {
64  LinearExpression e;
65  e.offset = affine.constant;
66  if (affine.var != kNoIntegerVariable) {
67  e.vars.push_back(affine.var);
68  e.coeffs.push_back(affine.coeff);
69  }
70  converted.push_back(NegationOf(e));
71  }
72  LinearExpression target;
73  target.vars.push_back(NegationOf(max_var));
74  target.coeffs.push_back(IntegerValue(1));
75  model->Add(IsEqualToMinOf(target, converted));
76 }
77 
78 } // namespace
79 
80 void AddCumulativeRelaxation(const std::vector<IntervalVariable>& x_intervals,
83  int64_t min_starts = std::numeric_limits<int64_t>::max();
84  int64_t max_ends = std::numeric_limits<int64_t>::min();
85  std::vector<AffineExpression> sizes;
86  for (int box = 0; box < y->NumTasks(); ++box) {
87  min_starts = std::min(min_starts, y->StartMin(box).value());
88  max_ends = std::max(max_ends, y->EndMax(box).value());
89  sizes.push_back(y->Sizes()[box]);
90  }
91 
92  const IntegerVariable min_start_var =
93  model->Add(NewIntegerVariable(min_starts, max_ends));
94  AddIsEqualToMinOf(min_start_var, y->Starts(), model);
95 
96  const IntegerVariable max_end_var =
97  model->Add(NewIntegerVariable(min_starts, max_ends));
98  AddIsEqualToMaxOf(max_end_var, y->Ends(), model);
99 
100  // (max_end - min_start) >= capacity.
102  model->Add(NewIntegerVariable(0, CapSub(max_ends, min_starts))));
103  const std::vector<int64_t> coeffs = {-capacity.coeff.value(), -1, 1};
104  model->Add(
105  WeightedSumGreaterOrEqual({capacity.var, min_start_var, max_end_var},
106  coeffs, capacity.constant.value()));
107 
108  model->Add(Cumulative(x_intervals, sizes, capacity, x));
109 }
110 
111 #define RETURN_IF_FALSE(f) \
112  if (!(f)) return false;
113 
116 
118  const int num_boxes = x_.NumTasks();
119  if (!x_.SynchronizeAndSetTimeDirection(true)) return false;
120  if (!y_.SynchronizeAndSetTimeDirection(true)) return false;
121 
122  active_boxes_.clear();
123  cached_energies_.resize(num_boxes);
124  cached_rectangles_.resize(num_boxes);
125  for (int box = 0; box < num_boxes; ++box) {
126  cached_energies_[box] = x_.SizeMin(box) * y_.SizeMin(box);
127  if (cached_energies_[box] == 0) continue;
128  if (!x_.IsPresent(box) || !y_.IsPresent(box)) continue;
129 
130  // The code needs the size min to be larger or equal to the mandatory part
131  // for it to works correctly. This is always enforced by the helper.
132  DCHECK_GE(x_.SizeMin(box), x_.EndMin(box) - x_.StartMax(box));
133  DCHECK_GE(y_.SizeMin(box), y_.EndMin(box) - y_.StartMax(box));
134 
135  Rectangle& rectangle = cached_rectangles_[box];
136  rectangle.x_min = x_.ShiftedStartMin(box);
137  rectangle.x_max = x_.ShiftedEndMax(box);
138  rectangle.y_min = y_.ShiftedStartMin(box);
139  rectangle.y_max = y_.ShiftedEndMax(box);
140 
141  active_boxes_.push_back(box);
142  }
143 
144  absl::Span<int> initial_boxes = FilterBoxesThatAreTooLarge(
145  cached_rectangles_, cached_energies_, absl::MakeSpan(active_boxes_));
146  if (initial_boxes.size() <= 1) return true;
147 
148  Rectangle conflicting_rectangle;
149  std::vector<absl::Span<int>> components =
150  GetOverlappingRectangleComponents(cached_rectangles_, initial_boxes);
151  for (absl::Span<int> boxes : components) {
152  // Computes the size on x and y past which there is no point doing any
153  // energetic reasonning. We do a few iterations since as we filter one size,
154  // we can potentially filter more on the transposed dimension.
155  threshold_x_ = kMaxIntegerValue;
156  threshold_y_ = kMaxIntegerValue;
157  for (int i = 0; i < 3; ++i) {
158  if (!AnalyzeIntervals(/*transpose=*/i == 1, boxes, cached_rectangles_,
159  cached_energies_, &threshold_x_, &threshold_y_,
160  &conflicting_rectangle)) {
161  return ReportEnergyConflict(conflicting_rectangle, boxes, &x_, &y_);
162  }
163  boxes = FilterBoxesAndRandomize(cached_rectangles_, boxes, threshold_x_,
164  threshold_y_, *random_);
165  if (boxes.size() <= 1) break;
166  }
167  if (boxes.size() <= 1) continue;
168 
169  // Now that we removed boxes with a large domain, resplit everything.
170  const std::vector<absl::Span<int>> local_components =
171  GetOverlappingRectangleComponents(cached_rectangles_, boxes);
172  for (absl::Span<int> local_boxes : local_components) {
173  IntegerValue total_sum_of_areas(0);
174  for (const int box : local_boxes) {
175  total_sum_of_areas += cached_energies_[box];
176  }
177  for (const int box : local_boxes) {
179  FailWhenEnergyIsTooLarge(box, local_boxes, total_sum_of_areas));
180  }
181  }
182  }
183 
184  return true;
185 }
186 
188  GenericLiteralWatcher* watcher) {
189  const int id = watcher->Register(this);
190  x_.WatchAllTasks(id, watcher, /*watch_start_max=*/true,
191  /*watch_end_max=*/true);
192  y_.WatchAllTasks(id, watcher, /*watch_start_max=*/true,
193  /*watch_end_max=*/true);
194  return id;
195 }
196 
197 void NonOverlappingRectanglesEnergyPropagator::SortBoxesIntoNeighbors(
198  int box, absl::Span<const int> local_boxes,
199  IntegerValue total_sum_of_areas) {
200  const Rectangle& box_dim = cached_rectangles_[box];
201 
202  neighbors_.clear();
203  for (const int other_box : local_boxes) {
204  if (other_box == box) continue;
205  const Rectangle& other_dim = cached_rectangles_[other_box];
206  const IntegerValue span_x = std::max(box_dim.x_max, other_dim.x_max) -
207  std::min(box_dim.x_min, other_dim.x_min);
208  if (span_x > threshold_x_) continue;
209  const IntegerValue span_y = std::max(box_dim.y_max, other_dim.y_max) -
210  std::min(box_dim.y_min, other_dim.y_min);
211  if (span_y > threshold_y_) continue;
212  const IntegerValue bounding_area = span_x * span_y;
213  if (bounding_area < total_sum_of_areas) {
214  neighbors_.push_back({other_box, bounding_area});
215  }
216  }
217  std::sort(neighbors_.begin(), neighbors_.end());
218 }
219 
220 bool NonOverlappingRectanglesEnergyPropagator::FailWhenEnergyIsTooLarge(
221  int box, absl::Span<const int> local_boxes,
222  IntegerValue total_sum_of_areas) {
223  SortBoxesIntoNeighbors(box, local_boxes, total_sum_of_areas);
224 
225  Rectangle area = cached_rectangles_[box];
226  IntegerValue sum_of_areas = cached_energies_[box];
227 
228  const auto add_box_energy_in_rectangle_reason = [&](int b) {
229  x_.AddEnergyMinInIntervalReason(b, area.x_min, area.x_max);
230  y_.AddEnergyMinInIntervalReason(b, area.y_min, area.y_max);
231  };
232 
233  for (int i = 0; i < neighbors_.size(); ++i) {
234  const int other_box = neighbors_[i].box;
235  CHECK_GT(cached_energies_[other_box], 0);
236 
237  // Update Bounding box.
238  area.TakeUnionWith(cached_rectangles_[other_box]);
239  if (area.x_max - area.x_min > threshold_x_) break;
240  if (area.y_max - area.y_min > threshold_y_) break;
241 
242  // Update sum of areas.
243  sum_of_areas += cached_energies_[other_box];
244  const IntegerValue bounding_area =
245  (area.x_max - area.x_min) * (area.y_max - area.y_min);
246  if (bounding_area >= total_sum_of_areas) {
247  // Nothing will be deduced. Exiting.
248  return true;
249  }
250 
251  if (sum_of_areas > bounding_area) {
252  x_.ClearReason();
253  y_.ClearReason();
254  add_box_energy_in_rectangle_reason(box);
255  for (int j = 0; j <= i; ++j) {
256  add_box_energy_in_rectangle_reason(neighbors_[j].box);
257  }
258  x_.ImportOtherReasons(y_);
259  return x_.ReportConflict();
260  }
261  }
262  return true;
263 }
264 
265 namespace {
266 
267 // We want for different propagation to reuse as much as possible the same
268 // line. The idea behind this is to compute the 'canonical' line to use
269 // when explaining that boxes overlap on the 'y_dim' dimension. We compute
270 // the multiple of the biggest power of two that is common to all boxes.
271 IntegerValue FindCanonicalValue(IntegerValue lb, IntegerValue ub) {
272  if (lb == ub) return lb;
273  if (lb <= 0 && ub > 0) return IntegerValue(0);
274  if (lb < 0 && ub <= 0) {
275  return -FindCanonicalValue(-ub, -lb);
276  }
277 
278  int64_t mask = 0;
279  IntegerValue candidate = ub;
280  for (int o = 0; o < 62; ++o) {
281  mask = 2 * mask + 1;
282  const IntegerValue masked_ub(ub.value() & ~mask);
283  if (masked_ub >= lb) {
284  candidate = masked_ub;
285  } else {
286  break;
287  }
288  }
289  return candidate;
290 }
291 
292 void SplitDisjointBoxes(const SchedulingConstraintHelper& x,
293  absl::Span<int> boxes,
294  std::vector<absl::Span<int>>* result) {
295  result->clear();
296  std::sort(boxes.begin(), boxes.end(), [&x](int a, int b) {
297  return x.ShiftedStartMin(a) < x.ShiftedStartMin(b);
298  });
299  int current_start = 0;
300  std::size_t current_length = 1;
301  IntegerValue current_max_end = x.EndMax(boxes[0]);
302 
303  for (int b = 1; b < boxes.size(); ++b) {
304  const int box = boxes[b];
305  if (x.ShiftedStartMin(box) < current_max_end) {
306  // Merge.
307  current_length++;
308  current_max_end = std::max(current_max_end, x.EndMax(box));
309  } else {
310  if (current_length > 1) { // Ignore lists of size 1.
311  result->emplace_back(&boxes[current_start], current_length);
312  }
313  current_start = b;
314  current_length = 1;
315  current_max_end = x.EndMax(box);
316  }
317  }
318 
319  // Push last span.
320  if (current_length > 1) {
321  result->emplace_back(&boxes[current_start], current_length);
322  }
323 }
324 
325 } // namespace
326 
327 // Note that x_ and y_ must be initialized with enough intervals when passed
328 // to the disjunctive propagators.
333  Model* model)
334  : global_x_(*x),
335  global_y_(*y),
336  x_(x->NumTasks(), model),
337  strict_(strict),
338  watcher_(model->GetOrCreate<GenericLiteralWatcher>()),
339  overload_checker_(&x_),
340  forward_detectable_precedences_(true, &x_),
341  backward_detectable_precedences_(false, &x_),
342  forward_not_last_(true, &x_),
343  backward_not_last_(false, &x_),
344  forward_edge_finding_(true, &x_),
345  backward_edge_finding_(false, &x_) {}
346 
349 
351  int fast_priority, int slow_priority) {
352  fast_id_ = watcher_->Register(this);
353  watcher_->SetPropagatorPriority(fast_id_, fast_priority);
354  global_x_.WatchAllTasks(fast_id_, watcher_);
355  global_y_.WatchAllTasks(fast_id_, watcher_);
356 
357  // This propagator is the one making sure our propagation is complete, so
358  // we do need to make sure it is called again if it modified some bounds.
360 
361  const int slow_id = watcher_->Register(this);
362  watcher_->SetPropagatorPriority(slow_id, slow_priority);
363  global_x_.WatchAllTasks(slow_id, watcher_);
364  global_y_.WatchAllTasks(slow_id, watcher_);
365 }
366 
367 bool NonOverlappingRectanglesDisjunctivePropagator::
368  FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
370  std::function<bool()> inner_propagate) {
371  // Note that since we only push bounds on x, we cache the value for y just
372  // once.
373  if (!y->SynchronizeAndSetTimeDirection(true)) return false;
374 
375  // Compute relevant boxes, the one with a mandatory part of y. Because we will
376  // need to sort it this way, we consider them by increasing start max.
377  indexed_intervals_.clear();
378  const std::vector<TaskTime>& temp = y->TaskByDecreasingStartMax();
379  for (int i = temp.size(); --i >= 0;) {
380  const int box = temp[i].task_index;
381  if (!strict_ && (x.SizeMin(box) == 0 || y->SizeMin(box) == 0)) continue;
382 
383  // Ignore a box if its x interval and its y interval are not present at
384  // the same time.
385  if (!x.IsPresent(box) || !y->IsPresent(box)) continue;
386 
387  const IntegerValue start_max = temp[i].time;
388  const IntegerValue end_min = y->EndMin(box);
389  if (start_max < end_min) {
390  indexed_intervals_.push_back({box, start_max, end_min});
391  }
392  }
393 
394  // Less than 2 boxes, no propagation.
395  if (indexed_intervals_.size() < 2) return true;
396  ConstructOverlappingSets(/*already_sorted=*/true, &indexed_intervals_,
397  &events_overlapping_boxes_);
398 
399  // Split lists of boxes into disjoint set of boxes (w.r.t. overlap).
400  boxes_to_propagate_.clear();
401  reduced_overlapping_boxes_.clear();
402  for (int i = 0; i < events_overlapping_boxes_.size(); ++i) {
403  SplitDisjointBoxes(x, absl::MakeSpan(events_overlapping_boxes_[i]),
404  &disjoint_boxes_);
405  for (absl::Span<int> sub_boxes : disjoint_boxes_) {
406  // Boxes are sorted in a stable manner in the Split method.
407  // Note that we do not use reduced_overlapping_boxes_ directly so that
408  // the order of iteration is deterministic.
409  const auto& insertion = reduced_overlapping_boxes_.insert(sub_boxes);
410  if (insertion.second) boxes_to_propagate_.push_back(sub_boxes);
411  }
412  }
413 
414  // And finally propagate.
415  //
416  // TODO(user): Sorting of boxes seems influential on the performance. Test.
417  for (const absl::Span<const int> boxes : boxes_to_propagate_) {
418  x_.ClearOtherHelper();
419  if (!x_.ResetFromSubset(x, boxes)) return false;
420 
421  // Collect the common overlapping coordinates of all boxes.
422  IntegerValue lb(std::numeric_limits<int64_t>::min());
423  IntegerValue ub(std::numeric_limits<int64_t>::max());
424  for (const int b : boxes) {
425  lb = std::max(lb, y->StartMax(b));
426  ub = std::min(ub, y->EndMin(b) - 1);
427  }
428  CHECK_LE(lb, ub);
429 
430  // TODO(user): We should scan the integer trail to find the oldest
431  // non-empty common interval. Then we can pick the canonical value within
432  // it.
433 
434  // We want for different propagation to reuse as much as possible the same
435  // line. The idea behind this is to compute the 'canonical' line to use
436  // when explaining that boxes overlap on the 'y_dim' dimension. We compute
437  // the multiple of the biggest power of two that is common to all boxes.
438  const IntegerValue line_to_use_for_reason = FindCanonicalValue(lb, ub);
439 
440  // Setup x_dim for propagation.
441  x_.SetOtherHelper(y, boxes, line_to_use_for_reason);
442 
443  RETURN_IF_FALSE(inner_propagate());
444  }
445 
446  return true;
447 }
448 
450  global_x_.SetTimeDirection(true);
451  global_y_.SetTimeDirection(true);
452 
453  std::function<bool()> inner_propagate;
454  if (watcher_->GetCurrentId() == fast_id_) {
455  inner_propagate = [this]() {
456  if (x_.NumTasks() == 2) {
457  // In that case, we can use simpler algorithms.
458  // Note that this case happens frequently (~30% of all calls to this
459  // method according to our tests).
460  RETURN_IF_FALSE(PropagateTwoBoxes());
461  } else {
462  RETURN_IF_FALSE(overload_checker_.Propagate());
463  RETURN_IF_FALSE(forward_detectable_precedences_.Propagate());
464  RETURN_IF_FALSE(backward_detectable_precedences_.Propagate());
465  }
466  return true;
467  };
468  } else {
469  inner_propagate = [this]() {
470  if (x_.NumTasks() <= 2) return true;
471  RETURN_IF_FALSE(forward_not_last_.Propagate());
472  RETURN_IF_FALSE(backward_not_last_.Propagate());
473  RETURN_IF_FALSE(backward_edge_finding_.Propagate());
474  RETURN_IF_FALSE(forward_edge_finding_.Propagate());
475  return true;
476  };
477  }
478 
479  RETURN_IF_FALSE(FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
480  global_x_, &global_y_, inner_propagate));
481 
482  // We can actually swap dimensions to propagate vertically.
483  RETURN_IF_FALSE(FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
484  global_y_, &global_x_, inner_propagate));
485 
486  // If two boxes must overlap but do not have a mandatory line/column that
487  // crosses both of them, then the code above do not see it. So we manually
488  // propagate this case.
489  //
490  // TODO(user): Since we are at it, do more propagation even if no conflict?
491  // This rarely propagate, so disabled for now. Investigate if it is worth
492  // it.
493  if (/*DISABLES CODE*/ (false) && watcher_->GetCurrentId() == fast_id_) {
494  const int num_boxes = global_x_.NumTasks();
495  for (int box1 = 0; box1 < num_boxes; ++box1) {
496  if (!global_x_.IsPresent(box1)) continue;
497  for (int box2 = box1 + 1; box2 < num_boxes; ++box2) {
498  if (!global_x_.IsPresent(box2)) continue;
499  if (global_x_.EndMin(box1) <= global_x_.StartMax(box2)) continue;
500  if (global_x_.EndMin(box2) <= global_x_.StartMax(box1)) continue;
501  if (global_y_.EndMin(box1) <= global_y_.StartMax(box2)) continue;
502  if (global_y_.EndMin(box2) <= global_y_.StartMax(box1)) continue;
503 
504  // X and Y must overlap. This is a conflict.
505  global_x_.ClearReason();
506  global_x_.AddPresenceReason(box1);
507  global_x_.AddPresenceReason(box2);
508  global_x_.AddReasonForBeingBefore(box1, box2);
509  global_x_.AddReasonForBeingBefore(box2, box1);
510  global_y_.ClearReason();
511  global_y_.AddReasonForBeingBefore(box1, box2);
512  global_y_.AddReasonForBeingBefore(box2, box1);
513  global_x_.ImportOtherReasons(global_y_);
514  return global_x_.ReportConflict();
515  }
516  }
517  }
518 
519  return true;
520 }
521 
522 // Specialized propagation on only two boxes that must intersect with the
523 // given y_line_for_reason.
524 bool NonOverlappingRectanglesDisjunctivePropagator::PropagateTwoBoxes() {
525  // For each direction and each order, we test if the boxes can be disjoint.
526  const int state =
527  (x_.EndMin(0) <= x_.StartMax(1)) + 2 * (x_.EndMin(1) <= x_.StartMax(0));
528 
529  const auto left_box_before_right_box = [this](int left, int right) {
530  // left box pushes right box.
531  const IntegerValue left_end_min = x_.EndMin(left);
532  if (left_end_min > x_.StartMin(right)) {
533  x_.ClearReason();
534  x_.AddReasonForBeingBefore(left, right);
535  x_.AddEndMinReason(left, left_end_min);
536  RETURN_IF_FALSE(x_.IncreaseStartMin(right, left_end_min));
537  }
538 
539  // right box pushes left box.
540  const IntegerValue right_start_max = x_.StartMax(right);
541  if (right_start_max < x_.EndMax(left)) {
542  x_.ClearReason();
543  x_.AddReasonForBeingBefore(left, right);
544  x_.AddStartMaxReason(right, right_start_max);
545  RETURN_IF_FALSE(x_.DecreaseEndMax(left, right_start_max));
546  }
547 
548  return true;
549  };
550 
551  switch (state) {
552  case 0: { // Conflict.
553  x_.ClearReason();
554  x_.AddReasonForBeingBefore(0, 1);
555  x_.AddReasonForBeingBefore(1, 0);
556  return x_.ReportConflict();
557  }
558  case 1: { // b1 is left of b2.
559  return left_box_before_right_box(0, 1);
560  }
561  case 2: { // b2 is left of b1.
562  return left_box_before_right_box(1, 0);
563  }
564  default: { // Nothing to deduce.
565  return true;
566  }
567  }
568 }
569 
570 #undef RETURN_IF_FALSE
571 } // namespace sat
572 } // namespace operations_research
int64_t CapSub(int64_t x, int64_t y)
int64_t min
Definition: alldiff_cst.cc:139
ABSL_MUST_USE_RESULT bool SynchronizeAndSetTimeDirection(bool is_forward)
Definition: intervals.cc:295
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:38
#define CHECK_GT(val1, val2)
Definition: base/logging.h:703
absl::Span< int > FilterBoxesAndRandomize(const std::vector< Rectangle > &cached_rectangles, absl::Span< int > boxes, IntegerValue threshold_x, IntegerValue threshold_y, absl::BitGenRef random)
Definition: diffn_util.cc:300
void SetOtherHelper(SchedulingConstraintHelper *other_helper, absl::Span< const int > map_to_other_helper, IntegerValue event)
Definition: intervals.h:355
void AddReasonForBeingBefore(int before, int after)
Definition: intervals.cc:382
GRBmodel * model
void WatchAllTasks(int id, GenericLiteralWatcher *watcher, bool watch_start_max=true, bool watch_end_max=true) const
Definition: intervals.cc:508
void ImportOtherReasons(const SchedulingConstraintHelper &other_helper)
Definition: intervals.cc:541
ABSL_MUST_USE_RESULT bool IncreaseStartMin(int t, IntegerValue new_start_min)
Definition: intervals.cc:453
void AddStartMaxReason(int t, IntegerValue upper_bound)
Definition: intervals.h:568
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
void AddCumulativeRelaxation(const std::vector< IntervalVariable > &x_intervals, SchedulingConstraintHelper *x, SchedulingConstraintHelper *y, Model *model)
Definition: sat/diffn.cc:80
void AddEndMinReason(int t, IntegerValue lower_bound)
Definition: intervals.h:575
int64_t b
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64_t lb, int64_t ub)
Definition: integer.h:1483
int64_t max
Definition: alldiff_cst.cc:140
std::function< void(Model *)> IsEqualToMinOf(IntegerVariable min_var, const std::vector< IntegerVariable > &vars)
Definition: integer_expr.h:675
Rev< int64_t > start_max
ABSL_MUST_USE_RESULT bool DecreaseEndMax(int t, IntegerValue new_end_max)
Definition: intervals.cc:462
#define CHECK_LE(val1, val2)
Definition: base/logging.h:700
Rev< int64_t > end_min
void AddEnergyMinInIntervalReason(int t, IntegerValue min, IntegerValue max)
Definition: intervals.h:600
void SetPropagatorPriority(int id, int priority)
Definition: integer.cc:2019
int64_t capacity
void ConstructOverlappingSets(bool already_sorted, std::vector< IndexedInterval > *intervals, std::vector< std::vector< int >> *result)
Definition: diffn_util.cc:343
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:890
std::vector< absl::Span< int > > GetOverlappingRectangleComponents(const std::vector< Rectangle > &rectangles, absl::Span< int > active_rectangles)
Definition: diffn_util.cc:26
bool AnalyzeIntervals(bool transpose, absl::Span< const int > local_boxes, const std::vector< Rectangle > &rectangles, const std::vector< IntegerValue > &rectangle_energies, IntegerValue *x_threshold, IntegerValue *y_threshold, Rectangle *conflict)
Definition: diffn_util.cc:148
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Definition: integer.cc:29
const std::vector< AffineExpression > & Ends() const
Definition: intervals.h:337
#define RETURN_IF_FALSE(f)
Definition: sat/diffn.cc:111
bool ReportEnergyConflict(Rectangle bounding_box, absl::Span< const int > boxes, SchedulingConstraintHelper *x, SchedulingConstraintHelper *y)
Definition: diffn_util.cc:52
const std::vector< AffineExpression > & Starts() const
Definition: intervals.h:336
int Register(PropagatorInterface *propagator)
Definition: integer.cc:1996
NonOverlappingRectanglesDisjunctivePropagator(bool strict, SchedulingConstraintHelper *x, SchedulingConstraintHelper *y, Model *model)
Definition: sat/diffn.cc:330
Collection of objects used to extend the Constraint Solver library.
const IntegerVariable kNoIntegerVariable(-1)
absl::Span< int > FilterBoxesThatAreTooLarge(const std::vector< Rectangle > &cached_rectangles, const std::vector< IntegerValue > &energies, absl::Span< int > boxes)
Definition: diffn_util.cc:316
std::function< void(Model *)> WeightedSumGreaterOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64_t lower_bound)
Definition: integer_expr.h:407
ABSL_MUST_USE_RESULT bool ResetFromSubset(const SchedulingConstraintHelper &other, absl::Span< const int > tasks)
Definition: intervals.cc:218
const std::vector< TaskTime > & TaskByDecreasingStartMax()
Definition: intervals.cc:337
std::function< void(Model *)> Cumulative(const std::vector< IntervalVariable > &vars, const std::vector< AffineExpression > &demands, AffineExpression capacity, SchedulingConstraintHelper *helper=nullptr)
Definition: cumulative.h:45
const std::vector< AffineExpression > & Sizes() const
Definition: intervals.h:338
int64_t a