OR-Tools  8.1
sat/diffn.cc
Go to the documentation of this file.
1 // Copyright 2010-2018 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 
18 #include "absl/container/flat_hash_map.h"
19 #include "absl/strings/str_join.h"
21 #include "ortools/base/map_util.h"
22 #include "ortools/base/stl_util.h"
23 #include "ortools/sat/cumulative.h"
25 #include "ortools/sat/intervals.h"
26 #include "ortools/sat/sat_solver.h"
27 #include "ortools/sat/theta_tree.h"
28 #include "ortools/util/sort.h"
29 
30 namespace operations_research {
31 namespace sat {
32 
33 void AddCumulativeRelaxation(const std::vector<IntervalVariable>& x_intervals,
36  auto* integer_trail = model->GetOrCreate<IntegerTrail>();
37  std::vector<AffineExpression> sizes;
38 
39  int64 min_starts = kint64max;
40  int64 max_ends = kint64min;
41  for (int box = 0; box < y->NumTasks(); ++box) {
42  IntegerVariable s_var = y->SizeVars()[box];
43  if (s_var == kNoIntegerVariable || integer_trail->IsFixed(s_var)) {
44  sizes.push_back(AffineExpression(y->SizeMin(box)));
45  } else {
46  sizes.push_back(AffineExpression(s_var));
47  }
48  min_starts = std::min(min_starts, y->StartMin(box).value());
49  max_ends = std::max(max_ends, y->EndMax(box).value());
50  }
51 
52  const IntegerVariable min_start_var =
53  model->Add(NewIntegerVariable(min_starts, max_ends));
54  model->Add(IsEqualToMinOf(min_start_var, y->StartVars()));
55 
56  const IntegerVariable max_end_var =
57  model->Add(NewIntegerVariable(min_starts, max_ends));
58  model->Add(IsEqualToMaxOf(max_end_var, y->EndVars()));
59 
60  // (max_end - min_start) >= capacity.
62  model->Add(NewIntegerVariable(0, CapSub(max_ends, min_starts))));
63  const std::vector<int64> coeffs = {-capacity.coeff.value(), -1, 1};
64  model->Add(
65  WeightedSumGreaterOrEqual({capacity.var, min_start_var, max_end_var},
66  coeffs, capacity.constant.value()));
67 
68  model->Add(Cumulative(x_intervals, sizes, capacity, x));
69 }
70 
71 namespace {
72 
73 // We want for different propagation to reuse as much as possible the same
74 // line. The idea behind this is to compute the 'canonical' line to use
75 // when explaining that boxes overlap on the 'y_dim' dimension. We compute
76 // the multiple of the biggest power of two that is common to all boxes.
77 IntegerValue FindCanonicalValue(IntegerValue lb, IntegerValue ub) {
78  if (lb == ub) return lb;
79  if (lb <= 0 && ub > 0) return IntegerValue(0);
80  if (lb < 0 && ub <= 0) {
81  return -FindCanonicalValue(-ub, -lb);
82  }
83 
84  int64 mask = 0;
85  IntegerValue candidate = ub;
86  for (int o = 0; o < 62; ++o) {
87  mask = 2 * mask + 1;
88  const IntegerValue masked_ub(ub.value() & ~mask);
89  if (masked_ub >= lb) {
90  candidate = masked_ub;
91  } else {
92  break;
93  }
94  }
95  return candidate;
96 }
97 
98 void SplitDisjointBoxes(const SchedulingConstraintHelper& x,
99  absl::Span<int> boxes,
100  std::vector<absl::Span<int>>* result) {
101  result->clear();
102  std::sort(boxes.begin(), boxes.end(),
103  [&x](int a, int b) { return x.StartMin(a) < x.StartMin(b); });
104  int current_start = 0;
105  std::size_t current_length = 1;
106  IntegerValue current_max_end = x.EndMax(boxes[0]);
107 
108  for (int b = 1; b < boxes.size(); ++b) {
109  const int box = boxes[b];
110  if (x.StartMin(box) < current_max_end) {
111  // Merge.
112  current_length++;
113  current_max_end = std::max(current_max_end, x.EndMax(box));
114  } else {
115  if (current_length > 1) { // Ignore lists of size 1.
116  result->emplace_back(&boxes[current_start], current_length);
117  }
118  current_start = b;
119  current_length = 1;
120  current_max_end = x.EndMax(box);
121  }
122  }
123 
124  // Push last span.
125  if (current_length > 1) {
126  result->emplace_back(&boxes[current_start], current_length);
127  }
128 }
129 
130 } // namespace
131 
132 #define RETURN_IF_FALSE(f) \
133  if (!(f)) return false;
134 
137 
139  const int num_boxes = x_.NumTasks();
140  x_.SetTimeDirection(true);
141  y_.SetTimeDirection(true);
142 
143  active_boxes_.clear();
144  cached_areas_.resize(num_boxes);
145  cached_dimensions_.resize(num_boxes);
146  for (int box = 0; box < num_boxes; ++box) {
147  cached_areas_[box] = x_.SizeMin(box) * y_.SizeMin(box);
148  if (cached_areas_[box] == 0) continue;
149 
150  // TODO(user): Also consider shifted end max.
151  Dimension& dimension = cached_dimensions_[box];
152  dimension.x_min = x_.ShiftedStartMin(box);
153  dimension.x_max = x_.EndMax(box);
154  dimension.y_min = y_.ShiftedStartMin(box);
155  dimension.y_max = y_.EndMax(box);
156 
157  active_boxes_.push_back(box);
158  }
159  if (active_boxes_.size() <= 1) return true;
160 
161  SplitDisjointBoxes(x_, absl::MakeSpan(active_boxes_), &x_split_);
162  for (absl::Span<int> x_boxes : x_split_) {
163  SplitDisjointBoxes(y_, x_boxes, &y_split_);
164  for (absl::Span<int> y_boxes : y_split_) {
165  IntegerValue total_sum_of_areas(0);
166  for (const int box : y_boxes) {
167  total_sum_of_areas += cached_areas_[box];
168  }
169  for (const int box : y_boxes) {
171  FailWhenEnergyIsTooLarge(box, y_boxes, total_sum_of_areas));
172  }
173  }
174  }
175 
176  return true;
177 }
178 
180  GenericLiteralWatcher* watcher) {
181  const int id = watcher->Register(this);
182  x_.WatchAllTasks(id, watcher, /*watch_start_max=*/false,
183  /*watch_end_max=*/true);
184  y_.WatchAllTasks(id, watcher, /*watch_start_max=*/false,
185  /*watch_end_max=*/true);
186  return id;
187 }
188 
189 void NonOverlappingRectanglesEnergyPropagator::SortBoxesIntoNeighbors(
190  int box, absl::Span<const int> local_boxes,
191  IntegerValue total_sum_of_areas) {
192  const Dimension& box_dim = cached_dimensions_[box];
193 
194  neighbors_.clear();
195  for (const int other_box : local_boxes) {
196  if (other_box == box) continue;
197  const Dimension& other_dim = cached_dimensions_[other_box];
198  const IntegerValue span_x = std::max(box_dim.x_max, other_dim.x_max) -
199  std::min(box_dim.x_min, other_dim.x_min);
200  const IntegerValue span_y = std::max(box_dim.y_max, other_dim.y_max) -
201  std::min(box_dim.y_min, other_dim.y_min);
202  const IntegerValue bounding_area = span_x * span_y;
203  if (bounding_area < total_sum_of_areas) {
204  neighbors_.push_back({other_box, bounding_area});
205  }
206  }
207  std::sort(neighbors_.begin(), neighbors_.end());
208 }
209 
210 bool NonOverlappingRectanglesEnergyPropagator::FailWhenEnergyIsTooLarge(
211  int box, absl::Span<const int> local_boxes,
212  IntegerValue total_sum_of_areas) {
213  SortBoxesIntoNeighbors(box, local_boxes, total_sum_of_areas);
214 
215  Dimension area = cached_dimensions_[box];
216  IntegerValue sum_of_areas = cached_areas_[box];
217 
218  const auto add_box_energy_in_rectangle_reason = [&](int b) {
219  x_.AddEnergyAfterReason(b, x_.SizeMin(b), area.x_min);
220  x_.AddEndMaxReason(b, area.x_max);
221  y_.AddEnergyAfterReason(b, y_.SizeMin(b), area.y_min);
222  y_.AddEndMaxReason(b, area.y_max);
223  };
224 
225  for (int i = 0; i < neighbors_.size(); ++i) {
226  const int other_box = neighbors_[i].box;
227  CHECK_GT(cached_areas_[other_box], 0);
228 
229  // Update Bounding box.
230  area.TakeUnionWith(cached_dimensions_[other_box]);
231 
232  // Update sum of areas.
233  sum_of_areas += cached_areas_[other_box];
234  const IntegerValue bounding_area =
235  (area.x_max - area.x_min) * (area.y_max - area.y_min);
236  if (bounding_area >= total_sum_of_areas) {
237  // Nothing will be deduced. Exiting.
238  return true;
239  }
240 
241  if (sum_of_areas > bounding_area) {
242  x_.ClearReason();
243  y_.ClearReason();
244  add_box_energy_in_rectangle_reason(box);
245  for (int j = 0; j <= i; ++j) {
246  add_box_energy_in_rectangle_reason(neighbors_[j].box);
247  }
248  x_.ImportOtherReasons(y_);
249  return x_.ReportConflict();
250  }
251  }
252  return true;
253 }
254 
255 // Note that x_ and y_ must be initialized with enough intervals when passed
256 // to the disjunctive propagators.
261  Model* model)
262  : global_x_(*x),
263  global_y_(*y),
264  x_(x->NumTasks(), model),
265  y_(y->NumTasks(), model),
266  strict_(strict),
267  watcher_(model->GetOrCreate<GenericLiteralWatcher>()),
268  overload_checker_(&x_),
269  forward_detectable_precedences_(true, &x_),
270  backward_detectable_precedences_(false, &x_),
271  forward_not_last_(true, &x_),
272  backward_not_last_(false, &x_),
273  forward_edge_finding_(true, &x_),
274  backward_edge_finding_(false, &x_) {}
275 
278 
280  int fast_priority, int slow_priority) {
281  fast_id_ = watcher_->Register(this);
282  watcher_->SetPropagatorPriority(fast_id_, fast_priority);
283  global_x_.WatchAllTasks(fast_id_, watcher_);
284  global_y_.WatchAllTasks(fast_id_, watcher_);
285 
286  const int slow_id = watcher_->Register(this);
287  watcher_->SetPropagatorPriority(slow_id, slow_priority);
288  global_x_.WatchAllTasks(slow_id, watcher_);
289  global_y_.WatchAllTasks(slow_id, watcher_);
290 }
291 
292 bool NonOverlappingRectanglesDisjunctivePropagator::
293  FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
296  std::function<bool()> inner_propagate) {
297  // Compute relevant events (line in the y dimension).
298  active_boxes_.clear();
299  events_time_.clear();
300  for (int box = 0; box < x.NumTasks(); ++box) {
301  if (!strict_ && (x.SizeMin(box) == 0 || y.SizeMin(box) == 0)) {
302  continue;
303  }
304 
305  const IntegerValue start_max = y.StartMax(box);
306  const IntegerValue end_min = y.EndMin(box);
307  if (start_max < end_min) {
308  events_time_.push_back(start_max);
309  active_boxes_.push_back(box);
310  }
311  }
312 
313  // Less than 2 boxes, no propagation.
314  if (active_boxes_.size() < 2) return true;
315 
316  // Add boxes to the event lists they always overlap with.
317  gtl::STLSortAndRemoveDuplicates(&events_time_);
318  events_overlapping_boxes_.resize(events_time_.size());
319  for (int i = 0; i < events_time_.size(); ++i) {
320  events_overlapping_boxes_[i].clear();
321  }
322  for (const int box : active_boxes_) {
323  const IntegerValue start_max = y.StartMax(box);
324  const IntegerValue end_min = y.EndMin(box);
325 
326  for (int i = 0; i < events_time_.size(); ++i) {
327  const IntegerValue t = events_time_[i];
328  if (t < start_max) continue;
329  if (t >= end_min) break;
330  events_overlapping_boxes_[i].push_back(box);
331  }
332  }
333 
334  // Scan events chronologically to remove events where there is only one
335  // mandatory box, or dominated events lists.
336  //
337  // Optimization: We do not resize the events_overlapping_boxes_ vector so that
338  // we do not free/realloc the memory of the inner vector from one propagate to
339  // the next. This save a bit more than 1%.
340  int new_size = 0;
341  {
342  for (std::vector<int>& overlapping_boxes : events_overlapping_boxes_) {
343  if (overlapping_boxes.size() < 2) {
344  continue; // Remove current event.
345  }
346  if (new_size > 0) {
347  const std::vector<int>& previous_overlapping_boxes =
348  events_overlapping_boxes_[new_size - 1];
349 
350  // If the previous set of boxes is included in the current one, replace
351  // the old one by the new one.
352  //
353  // Note that because the events correspond to new boxes, there is no
354  // need to check for the other side (current set included in previous
355  // set).
356  if (std::includes(overlapping_boxes.begin(), overlapping_boxes.end(),
357  previous_overlapping_boxes.begin(),
358  previous_overlapping_boxes.end())) {
359  --new_size;
360  }
361  }
362 
363  std::swap(events_overlapping_boxes_[new_size], overlapping_boxes);
364  ++new_size;
365  }
366  }
367 
368  // Split lists of boxes into disjoint set of boxes (w.r.t. overlap).
369  boxes_to_propagate_.clear();
370  reduced_overlapping_boxes_.clear();
371  for (int i = 0; i < new_size; ++i) {
372  SplitDisjointBoxes(x, absl::MakeSpan(events_overlapping_boxes_[i]),
373  &disjoint_boxes_);
374  for (absl::Span<int> sub_boxes : disjoint_boxes_) {
375  // Boxes are sorted in a stable manner in the Split method.
376  // Note that we do not use reduced_overlapping_boxes_ directly so that
377  // the order of iteration is deterministic.
378  const auto& insertion = reduced_overlapping_boxes_.insert(sub_boxes);
379  if (insertion.second) boxes_to_propagate_.push_back(sub_boxes);
380  }
381  }
382 
383  // And finally propagate.
384  // TODO(user): Sorting of boxes seems influential on the performance. Test.
385  for (const absl::Span<const int> boxes : boxes_to_propagate_) {
386  x_.ResetFromSubset(x, boxes);
387  y_.ResetFromSubset(y, boxes);
388 
389  // Collect the common overlapping coordinates of all boxes.
390  IntegerValue lb(kint64min);
391  IntegerValue ub(kint64max);
392  for (int i = 0; i < y_.NumTasks(); ++i) {
393  lb = std::max(lb, y_.StartMax(i));
394  ub = std::min(ub, y_.EndMin(i) - 1);
395  }
396  CHECK_LE(lb, ub);
397 
398  // TODO(user): We should scan the integer trail to find the oldest
399  // non-empty common interval. Then we can pick the canonical value within
400  // it.
401 
402  // We want for different propagation to reuse as much as possible the same
403  // line. The idea behind this is to compute the 'canonical' line to use
404  // when explaining that boxes overlap on the 'y_dim' dimension. We compute
405  // the multiple of the biggest power of two that is common to all boxes.
406  const IntegerValue line_to_use_for_reason = FindCanonicalValue(lb, ub);
407 
408  // Setup x_dim for propagation.
409  x_.SetOtherHelper(&y_, line_to_use_for_reason);
410 
411  RETURN_IF_FALSE(inner_propagate());
412  }
413 
414  return true;
415 }
416 
418  global_x_.SetTimeDirection(true);
419  global_y_.SetTimeDirection(true);
420 
421  std::function<bool()> inner_propagate;
422  if (watcher_->GetCurrentId() == fast_id_) {
423  inner_propagate = [this]() {
424  if (x_.NumTasks() == 2) {
425  // In that case, we can use simpler algorithms.
426  // Note that this case happens frequently (~30% of all calls to this
427  // method according to our tests).
428  RETURN_IF_FALSE(PropagateTwoBoxes());
429  } else {
430  RETURN_IF_FALSE(overload_checker_.Propagate());
431  RETURN_IF_FALSE(forward_detectable_precedences_.Propagate());
432  RETURN_IF_FALSE(backward_detectable_precedences_.Propagate());
433  }
434  return true;
435  };
436  } else {
437  inner_propagate = [this]() {
438  if (x_.NumTasks() <= 2) return true;
439  RETURN_IF_FALSE(forward_not_last_.Propagate());
440  RETURN_IF_FALSE(backward_not_last_.Propagate());
441  RETURN_IF_FALSE(backward_edge_finding_.Propagate());
442  RETURN_IF_FALSE(forward_edge_finding_.Propagate());
443  return true;
444  };
445  }
446 
447  RETURN_IF_FALSE(FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
448  global_x_, global_y_, inner_propagate));
449 
450  // We can actually swap dimensions to propagate vertically.
451  RETURN_IF_FALSE(FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
452  global_y_, global_x_, inner_propagate));
453 
454  return true;
455 }
456 
457 // Specialized propagation on only two boxes that must intersect with the
458 // given y_line_for_reason.
459 bool NonOverlappingRectanglesDisjunctivePropagator::PropagateTwoBoxes() {
460  // For each direction and each order, we test if the boxes can be disjoint.
461  const int state =
462  (x_.EndMin(0) <= x_.StartMax(1)) + 2 * (x_.EndMin(1) <= x_.StartMax(0));
463 
464  const auto left_box_before_right_box = [this](int left, int right) {
465  // left box pushes right box.
466  const IntegerValue left_end_min = x_.EndMin(left);
467  if (left_end_min > x_.StartMin(right)) {
468  x_.ClearReason();
469  x_.AddReasonForBeingBefore(left, right);
470  x_.AddEndMinReason(left, left_end_min);
471  RETURN_IF_FALSE(x_.IncreaseStartMin(right, left_end_min));
472  }
473 
474  // right box pushes left box.
475  const IntegerValue right_start_max = x_.StartMax(right);
476  if (right_start_max < x_.EndMax(left)) {
477  x_.ClearReason();
478  x_.AddReasonForBeingBefore(left, right);
479  x_.AddStartMaxReason(right, right_start_max);
480  RETURN_IF_FALSE(x_.DecreaseEndMax(left, right_start_max));
481  }
482 
483  return true;
484  };
485 
486  switch (state) {
487  case 0: { // Conflict.
488  x_.ClearReason();
489  x_.AddReasonForBeingBefore(0, 1);
490  x_.AddReasonForBeingBefore(1, 0);
491  return x_.ReportConflict();
492  }
493  case 1: { // b1 is left of b2.
494  return left_box_before_right_box(0, 1);
495  }
496  case 2: { // b2 is left of b1.
497  return left_box_before_right_box(1, 0);
498  }
499  default: { // Nothing to deduce.
500  return true;
501  }
502  }
503 }
504 
505 #undef RETURN_IF_FALSE
506 } // namespace sat
507 } // namespace operations_research
operations_research::sat::GenericLiteralWatcher::Register
int Register(PropagatorInterface *propagator)
Definition: integer.cc:1922
operations_research::sat::SchedulingConstraintHelper::StartMin
IntegerValue StartMin(int t) const
Definition: intervals.h:374
min
int64 min
Definition: alldiff_cst.cc:138
operations_research::sat::AffineExpression
Definition: integer.h:205
map_util.h
operations_research::sat::IntegerTrail
Definition: integer.h:518
operations_research::CapSub
int64 CapSub(int64 x, int64 y)
Definition: saturated_arithmetic.h:154
operations_research::sat::kNoIntegerVariable
const IntegerVariable kNoIntegerVariable(-1)
RETURN_IF_FALSE
#define RETURN_IF_FALSE(f)
Definition: sat/diffn.cc:132
max
int64 max
Definition: alldiff_cst.cc:139
operations_research::sat::SchedulingConstraintHelper::ImportOtherReasons
void ImportOtherReasons(const SchedulingConstraintHelper &other_helper)
Definition: intervals.cc:394
operations_research::sat::SchedulingConstraintHelper::IncreaseStartMin
ABSL_MUST_USE_RESULT bool IncreaseStartMin(int t, IntegerValue new_min_start)
Definition: intervals.cc:311
operations_research::sat::AddCumulativeRelaxation
void AddCumulativeRelaxation(const std::vector< IntervalVariable > &x_intervals, SchedulingConstraintHelper *x, SchedulingConstraintHelper *y, Model *model)
Definition: sat/diffn.cc:33
operations_research::sat::SchedulingConstraintHelper::WatchAllTasks
void WatchAllTasks(int id, GenericLiteralWatcher *watcher, bool watch_start_max=true, bool watch_end_max=true) const
Definition: intervals.cc:360
operations_research::sat::SchedulingConstraintHelper::EndMin
IntegerValue EndMin(int t) const
Definition: intervals.h:382
operations_research::Dimension
Definition: pack.cc:34
disjunctive.h
operations_research::sat::SchedulingConstraintHelper::SetOtherHelper
void SetOtherHelper(SchedulingConstraintHelper *other_helper, IntegerValue event)
Definition: intervals.h:281
CHECK_GT
#define CHECK_GT(val1, val2)
Definition: base/logging.h:702
operations_research::sat::SchedulingConstraintHelper::SetTimeDirection
void SetTimeDirection(bool is_forward)
Definition: intervals.cc:143
operations_research
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
Definition: dense_doubly_linked_list.h:21
operations_research::sat::SchedulingConstraintHelper::AddEnergyAfterReason
void AddEnergyAfterReason(int t, IntegerValue energy_min, IntegerValue time)
Definition: intervals.h:504
kint64min
static const int64 kint64min
Definition: integral_types.h:60
operations_research::sat::SchedulingConstraintHelper::EndMax
IntegerValue EndMax(int t) const
Definition: intervals.h:386
int64
int64_t int64
Definition: integral_types.h:34
operations_research::sat::NonOverlappingRectanglesDisjunctivePropagator::NonOverlappingRectanglesDisjunctivePropagator
NonOverlappingRectanglesDisjunctivePropagator(bool strict, SchedulingConstraintHelper *x, SchedulingConstraintHelper *y, Model *model)
Definition: sat/diffn.cc:258
sat_solver.h
operations_research::sat::SchedulingConstraintHelper::ShiftedStartMin
IntegerValue ShiftedStartMin(int t) const
Definition: intervals.h:391
operations_research::sat::GenericLiteralWatcher
Definition: integer.h:1075
a
int64 a
Definition: constraint_solver/table.cc:42
operations_research::sat::WeightedSumGreaterOrEqual
std::function< void(Model *)> WeightedSumGreaterOrEqual(const std::vector< IntegerVariable > &vars, const VectorInt &coefficients, int64 lower_bound)
Definition: integer_expr.h:404
operations_research::sat::NonOverlappingRectanglesDisjunctivePropagator::~NonOverlappingRectanglesDisjunctivePropagator
~NonOverlappingRectanglesDisjunctivePropagator() override
Definition: sat/diffn.cc:277
operations_research::sat::SchedulingConstraintHelper::ClearReason
void ClearReason()
Definition: intervals.h:417
operations_research::sat::NewIntegerVariable
std::function< IntegerVariable(Model *)> NewIntegerVariable(int64 lb, int64 ub)
Definition: integer.h:1353
operations_research::sat::SchedulingConstraintHelper::ReportConflict
ABSL_MUST_USE_RESULT bool ReportConflict()
Definition: intervals.cc:355
operations_research::sat::GenericLiteralWatcher::SetPropagatorPriority
void SetPropagatorPriority(int id, int priority)
Definition: integer.cc:1945
operations_research::sat::SchedulingConstraintHelper
Definition: intervals.h:137
operations_research::sat::SchedulingConstraintHelper::StartMax
IntegerValue StartMax(int t) const
Definition: intervals.h:378
operations_research::sat::DisjunctiveEdgeFinding::Propagate
bool Propagate() final
Definition: disjunctive.cc:1150
intervals.h
operations_research::sat::DisjunctiveOverloadChecker::Propagate
bool Propagate() final
Definition: disjunctive.cc:458
gtl::STLSortAndRemoveDuplicates
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
Definition: stl_util.h:58
operations_research::sat::NonOverlappingRectanglesDisjunctivePropagator::Propagate
bool Propagate() final
Definition: sat/diffn.cc:417
operations_research::sat::NonOverlappingRectanglesEnergyPropagator::Propagate
bool Propagate() final
Definition: sat/diffn.cc:138
operations_research::sat::Cumulative
std::function< void(Model *)> Cumulative(const std::vector< IntervalVariable > &vars, const std::vector< AffineExpression > &demands, AffineExpression capacity, SchedulingConstraintHelper *helper)
Definition: cumulative.cc:35
operations_research::sat::SchedulingConstraintHelper::DecreaseEndMax
ABSL_MUST_USE_RESULT bool DecreaseEndMax(int t, IntegerValue new_max_end)
Definition: intervals.cc:317
operations_research::sat::Model
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:38
operations_research::sat::SchedulingConstraintHelper::NumTasks
int NumTasks() const
Definition: intervals.h:157
operations_research::sat::SchedulingConstraintHelper::SizeVars
const std::vector< IntegerVariable > & SizeVars() const
Definition: intervals.h:263
operations_research::sat::SchedulingConstraintHelper::AddReasonForBeingBefore
void AddReasonForBeingBefore(int before, int after)
Definition: intervals.cc:227
start_max
Rev< int64 > start_max
Definition: sched_constraints.cc:242
operations_research::sat::SchedulingConstraintHelper::AddStartMaxReason
void AddStartMaxReason(int t, IntegerValue upper_bound)
Definition: intervals.h:468
theta_tree.h
CHECK_LE
#define CHECK_LE(val1, val2)
Definition: base/logging.h:699
diffn.h
model
GRBmodel * model
Definition: gurobi_interface.cc:269
operations_research::sat::SchedulingConstraintHelper::ResetFromSubset
void ResetFromSubset(const SchedulingConstraintHelper &other, absl::Span< const int > tasks)
Definition: intervals.cc:97
sort.h
operations_research::sat::SchedulingConstraintHelper::EndVars
const std::vector< IntegerVariable > & EndVars() const
Definition: intervals.h:262
operations_research::sat::SchedulingConstraintHelper::SizeMin
IntegerValue SizeMin(int t) const
Definition: intervals.h:356
operations_research::sat::SchedulingConstraintHelper::StartVars
const std::vector< IntegerVariable > & StartVars() const
Definition: intervals.h:261
operations_research::sat::DisjunctiveDetectablePrecedences::Propagate
bool Propagate() final
Definition: disjunctive.cc:638
end_min
Rev< int64 > end_min
Definition: sched_constraints.cc:243
stl_util.h
iterator_adaptors.h
b
int64 b
Definition: constraint_solver/table.cc:43
operations_research::sat::IsEqualToMinOf
std::function< void(Model *)> IsEqualToMinOf(IntegerVariable min_var, const std::vector< IntegerVariable > &vars)
Definition: integer_expr.h:661
operations_research::sat::DisjunctiveNotLast::Propagate
bool Propagate() final
Definition: disjunctive.cc:970
operations_research::sat::SchedulingConstraintHelper::AddEndMinReason
void AddEndMinReason(int t, IntegerValue lower_bound)
Definition: intervals.h:476
capacity
int64 capacity
Definition: routing_flow.cc:129
operations_research::sat::IsEqualToMaxOf
std::function< void(Model *)> IsEqualToMaxOf(IntegerVariable max_var, const std::vector< IntegerVariable > &vars)
Definition: integer_expr.h:730
cumulative.h
operations_research::sat::NonOverlappingRectanglesEnergyPropagator::RegisterWith
int RegisterWith(GenericLiteralWatcher *watcher)
Definition: sat/diffn.cc:179
operations_research::sat::GenericLiteralWatcher::GetCurrentId
int GetCurrentId() const
Definition: integer.h:1165
operations_research::sat::SchedulingConstraintHelper::AddEndMaxReason
void AddEndMaxReason(int t, IntegerValue upper_bound)
Definition: intervals.h:496
operations_research::sat::NonOverlappingRectanglesEnergyPropagator::~NonOverlappingRectanglesEnergyPropagator
~NonOverlappingRectanglesEnergyPropagator() override
Definition: sat/diffn.cc:136
kint64max
static const int64 kint64max
Definition: integral_types.h:62
operations_research::sat::NonOverlappingRectanglesDisjunctivePropagator::Register
void Register(int fast_priority, int slow_priority)
Definition: sat/diffn.cc:279