OR-Tools  9.6
diffn_util.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 #include "ortools/sat/diffn_util.h"
15 
16 #include <stddef.h>
17 
18 #include <algorithm>
19 #include <ostream>
20 #include <utility>
21 #include <vector>
22 
23 #include "absl/container/flat_hash_set.h"
24 #include "absl/random/bit_gen_ref.h"
25 #include "absl/types/span.h"
26 #include "ortools/base/logging.h"
27 #include "ortools/base/stl_util.h"
28 #include "ortools/sat/integer.h"
29 #include "ortools/sat/intervals.h"
32 
33 namespace operations_research {
34 namespace sat {
35 
36 bool Rectangle::IsDisjoint(const Rectangle& other) const {
37  return x_min >= other.x_max || other.x_min >= x_max || y_min >= other.y_max ||
38  other.y_min >= y_max;
39 }
40 
41 std::vector<absl::Span<int>> GetOverlappingRectangleComponents(
42  const std::vector<Rectangle>& rectangles,
43  absl::Span<int> active_rectangles) {
44  if (active_rectangles.empty()) return {};
45 
46  std::vector<absl::Span<int>> result;
47  const int size = active_rectangles.size();
48  for (int start = 0; start < size;) {
49  // Find the component of active_rectangles[start].
50  int end = start + 1;
51  for (int i = start; i < end; i++) {
52  for (int j = end; j < size; ++j) {
53  if (!rectangles[active_rectangles[i]].IsDisjoint(
54  rectangles[active_rectangles[j]])) {
55  std::swap(active_rectangles[end++], active_rectangles[j]);
56  }
57  }
58  }
59  if (end > start + 1) {
60  result.push_back(active_rectangles.subspan(start, end - start));
61  }
62  start = end;
63  }
64  return result;
65 }
66 
67 bool ReportEnergyConflict(Rectangle bounding_box, absl::Span<const int> boxes,
70  x->ClearReason();
71  y->ClearReason();
72  IntegerValue total_energy(0);
73  for (const int b : boxes) {
74  const IntegerValue x_min = x->ShiftedStartMin(b);
75  const IntegerValue x_max = x->ShiftedEndMax(b);
76  if (x_min < bounding_box.x_min || x_max > bounding_box.x_max) continue;
77  const IntegerValue y_min = y->ShiftedStartMin(b);
78  const IntegerValue y_max = y->ShiftedEndMax(b);
79  if (y_min < bounding_box.y_min || y_max > bounding_box.y_max) continue;
80 
81  x->AddEnergyMinInIntervalReason(b, bounding_box.x_min, bounding_box.x_max);
82  y->AddEnergyMinInIntervalReason(b, bounding_box.y_min, bounding_box.y_max);
83 
84  x->AddPresenceReason(b);
85  y->AddPresenceReason(b);
86 
87  total_energy += x->SizeMin(b) * y->SizeMin(b);
88 
89  // We abort early if a subset of boxes is enough.
90  // TODO(user): Also relax the box if possible.
91  if (total_energy > bounding_box.Area()) break;
92  }
93 
94  CHECK_GT(total_energy, bounding_box.Area());
95  x->ImportOtherReasons(*y);
96  return x->ReportConflict();
97 }
98 
99 bool BoxesAreInEnergyConflict(const std::vector<Rectangle>& rectangles,
100  const std::vector<IntegerValue>& energies,
101  absl::Span<const int> boxes,
102  Rectangle* conflict) {
103  // First consider all relevant intervals along the x axis.
104  std::vector<IntegerValue> x_starts;
105  std::vector<TaskTime> boxes_by_increasing_x_max;
106  for (const int b : boxes) {
107  x_starts.push_back(rectangles[b].x_min);
108  boxes_by_increasing_x_max.push_back({b, rectangles[b].x_max});
109  }
111  std::sort(boxes_by_increasing_x_max.begin(), boxes_by_increasing_x_max.end());
112 
113  std::vector<IntegerValue> y_starts;
114  std::vector<IntegerValue> energy_sum;
115  std::vector<TaskTime> boxes_by_increasing_y_max;
116 
117  std::vector<std::vector<int>> stripes(x_starts.size());
118  for (int i = 0; i < boxes_by_increasing_x_max.size(); ++i) {
119  const int b = boxes_by_increasing_x_max[i].task_index;
120  const IntegerValue x_min = rectangles[b].x_min;
121  const IntegerValue x_max = rectangles[b].x_max;
122  for (int j = 0; j < x_starts.size(); ++j) {
123  if (x_starts[j] > x_min) break;
124  stripes[j].push_back(b);
125 
126  // Redo the same on the y coordinate for the current x interval
127  // which is [starts[j], x_max].
128  y_starts.clear();
129  boxes_by_increasing_y_max.clear();
130  for (const int b : stripes[j]) {
131  y_starts.push_back(rectangles[b].y_min);
132  boxes_by_increasing_y_max.push_back({b, rectangles[b].y_max});
133  }
135  std::sort(boxes_by_increasing_y_max.begin(),
136  boxes_by_increasing_y_max.end());
137 
138  const IntegerValue x_size = x_max - x_starts[j];
139  energy_sum.assign(y_starts.size(), IntegerValue(0));
140  for (int i = 0; i < boxes_by_increasing_y_max.size(); ++i) {
141  const int b = boxes_by_increasing_y_max[i].task_index;
142  const IntegerValue y_min = rectangles[b].y_min;
143  const IntegerValue y_max = rectangles[b].y_max;
144  for (int j = 0; j < y_starts.size(); ++j) {
145  if (y_starts[j] > y_min) break;
146  energy_sum[j] += energies[b];
147  if (energy_sum[j] > x_size * (y_max - y_starts[j])) {
148  if (conflict != nullptr) {
149  *conflict = rectangles[b];
150  for (int k = 0; k < i; ++k) {
151  const int task_index = boxes_by_increasing_y_max[k].task_index;
152  if (rectangles[task_index].y_min >= y_starts[j]) {
153  conflict->TakeUnionWith(rectangles[task_index]);
154  }
155  }
156  }
157  return true;
158  }
159  }
160  }
161  }
162  }
163  return false;
164 }
165 
166 bool AnalyzeIntervals(bool transpose, absl::Span<const int> local_boxes,
167  const std::vector<Rectangle>& rectangles,
168  const std::vector<IntegerValue>& rectangle_energies,
169  IntegerValue* x_threshold, IntegerValue* y_threshold,
170  Rectangle* conflict) {
171  // First, we compute the possible x_min values (removing duplicates).
172  // We also sort the relevant tasks by their x_max.
173  //
174  // TODO(user): If the number of unique x_max is smaller than the number of
175  // unique x_min, it is better to do it the other way around.
176  std::vector<IntegerValue> starts;
177  std::vector<TaskTime> task_by_increasing_x_max;
178  for (const int t : local_boxes) {
179  const IntegerValue x_min =
180  transpose ? rectangles[t].y_min : rectangles[t].x_min;
181  const IntegerValue x_max =
182  transpose ? rectangles[t].y_max : rectangles[t].x_max;
183  starts.push_back(x_min);
184  task_by_increasing_x_max.push_back({t, x_max});
185  }
187 
188  // Note that for the same end_max, the order change our heuristic to
189  // evaluate the max_conflict_height.
190  std::sort(task_by_increasing_x_max.begin(), task_by_increasing_x_max.end());
191 
192  // The maximum y dimension of a bounding area for which there is a potential
193  // conflict.
194  IntegerValue max_conflict_height(0);
195 
196  // This is currently only used for logging.
197  absl::flat_hash_set<std::pair<IntegerValue, IntegerValue>> stripes;
198 
199  // All quantities at index j correspond to the interval [starts[j], x_max].
200  std::vector<IntegerValue> energies(starts.size(), IntegerValue(0));
201  std::vector<IntegerValue> y_mins(starts.size(), kMaxIntegerValue);
202  std::vector<IntegerValue> y_maxs(starts.size(), -kMaxIntegerValue);
203  std::vector<IntegerValue> energy_at_max_y(starts.size(), IntegerValue(0));
204  std::vector<IntegerValue> energy_at_min_y(starts.size(), IntegerValue(0));
205 
206  // Sentinel.
207  starts.push_back(kMaxIntegerValue);
208 
209  // Iterate over all boxes by increasing x_max values.
210  int first_j = 0;
211  const IntegerValue threshold = transpose ? *y_threshold : *x_threshold;
212  for (int i = 0; i < task_by_increasing_x_max.size(); ++i) {
213  const int t = task_by_increasing_x_max[i].task_index;
214 
215  const IntegerValue energy = rectangle_energies[t];
216  IntegerValue x_min = rectangles[t].x_min;
217  IntegerValue x_max = rectangles[t].x_max;
218  IntegerValue y_min = rectangles[t].y_min;
219  IntegerValue y_max = rectangles[t].y_max;
220  if (transpose) {
221  std::swap(x_min, y_min);
222  std::swap(x_max, y_max);
223  }
224 
225  // Add this box contribution to all the [starts[j], x_max] intervals.
226  while (first_j + 1 < starts.size() && x_max - starts[first_j] > threshold) {
227  ++first_j;
228  }
229  for (int j = first_j; starts[j] <= x_min; ++j) {
230  const IntegerValue old_energy_at_max = energy_at_max_y[j];
231  const IntegerValue old_energy_at_min = energy_at_min_y[j];
232 
233  energies[j] += energy;
234 
235  const bool is_disjoint = y_min >= y_maxs[j] || y_max <= y_mins[j];
236 
237  if (y_min <= y_mins[j]) {
238  if (y_min < y_mins[j]) {
239  y_mins[j] = y_min;
240  energy_at_min_y[j] = energy;
241  } else {
242  energy_at_min_y[j] += energy;
243  }
244  }
245 
246  if (y_max >= y_maxs[j]) {
247  if (y_max > y_maxs[j]) {
248  y_maxs[j] = y_max;
249  energy_at_max_y[j] = energy;
250  } else {
251  energy_at_max_y[j] += energy;
252  }
253  }
254 
255  // If the new box is disjoint in y from the ones added so far, there
256  // cannot be a new conflict involving this box, so we skip until we add
257  // new boxes.
258  if (is_disjoint) continue;
259 
260  const IntegerValue width = x_max - starts[j];
261  IntegerValue conflict_height = CeilRatio(energies[j], width) - 1;
262  if (y_max - y_min > conflict_height) continue;
263  if (conflict_height >= y_maxs[j] - y_mins[j]) {
264  // We have a conflict.
265  if (conflict != nullptr) {
266  *conflict = rectangles[t];
267  for (int k = 0; k < i; ++k) {
268  const int task_index = task_by_increasing_x_max[k].task_index;
269  const IntegerValue task_x_min = transpose
270  ? rectangles[task_index].y_min
271  : rectangles[task_index].x_min;
272  if (task_x_min < starts[j]) continue;
273  conflict->TakeUnionWith(rectangles[task_index]);
274  }
275  }
276  return false;
277  }
278 
279  // Because we currently do not have a conflict involving the new box, the
280  // only way to have one is to remove enough energy to reduce the y domain.
281  IntegerValue can_remove = std::min(old_energy_at_min, old_energy_at_max);
282  if (old_energy_at_min < old_energy_at_max) {
283  if (y_maxs[j] - y_min >=
284  CeilRatio(energies[j] - old_energy_at_min, width)) {
285  // In this case, we need to remove at least old_energy_at_max to have
286  // a conflict.
287  can_remove = old_energy_at_max;
288  }
289  } else if (old_energy_at_max < old_energy_at_min) {
290  if (y_max - y_mins[j] >=
291  CeilRatio(energies[j] - old_energy_at_max, width)) {
292  can_remove = old_energy_at_min;
293  }
294  }
295  conflict_height = CeilRatio(energies[j] - can_remove, width) - 1;
296 
297  // If the new box height is above the conflict_height, do not count
298  // it now. We only need to consider conflict involving the new box.
299  if (y_max - y_min > conflict_height) continue;
300 
301  if (VLOG_IS_ON(2)) stripes.insert({starts[j], x_max});
302  max_conflict_height = std::max(max_conflict_height, conflict_height);
303  }
304  }
305 
306  VLOG(2) << " num_starts: " << starts.size() - 1 << "/" << local_boxes.size()
307  << " conflict_height: " << max_conflict_height
308  << " num_stripes:" << stripes.size() << " (<= " << threshold << ")";
309 
310  if (transpose) {
311  *x_threshold = std::min(*x_threshold, max_conflict_height);
312  } else {
313  *y_threshold = std::min(*y_threshold, max_conflict_height);
314  }
315  return true;
316 }
317 
318 absl::Span<int> FilterBoxesAndRandomize(
319  const std::vector<Rectangle>& cached_rectangles, absl::Span<int> boxes,
320  IntegerValue threshold_x, IntegerValue threshold_y,
321  absl::BitGenRef random) {
322  size_t new_size = 0;
323  for (const int b : boxes) {
324  const Rectangle& dim = cached_rectangles[b];
325  if (dim.x_max - dim.x_min > threshold_x) continue;
326  if (dim.y_max - dim.y_min > threshold_y) continue;
327  boxes[new_size++] = b;
328  }
329  if (new_size == 0) return {};
330  std::shuffle(&boxes[0], &boxes[0] + new_size, random);
331  return {&boxes[0], new_size};
332 }
333 
335  const std::vector<Rectangle>& cached_rectangles,
336  const std::vector<IntegerValue>& energies, absl::Span<int> boxes) {
337  // Sort the boxes by increasing area.
338  std::sort(boxes.begin(), boxes.end(), [&cached_rectangles](int a, int b) {
339  return cached_rectangles[a].Area() < cached_rectangles[b].Area();
340  });
341 
342  IntegerValue total_energy(0);
343  for (const int box : boxes) total_energy += energies[box];
344 
345  // Remove all the large boxes until we have one with area smaller than the
346  // energy of the boxes below.
347  int new_size = boxes.size();
348  while (new_size > 0 &&
349  cached_rectangles[boxes[new_size - 1]].Area() >= total_energy) {
350  --new_size;
351  total_energy -= energies[boxes[new_size]];
352  }
353  return boxes.subspan(0, new_size);
354 }
355 
356 std::ostream& operator<<(std::ostream& out, const IndexedInterval& interval) {
357  return out << "[" << interval.start << ".." << interval.end << " (#"
358  << interval.index << ")]";
359 }
360 
361 void ConstructOverlappingSets(bool already_sorted,
362  std::vector<IndexedInterval>* intervals,
363  std::vector<std::vector<int>>* result) {
364  result->clear();
365  if (already_sorted) {
366  DCHECK(std::is_sorted(intervals->begin(), intervals->end(),
368  } else {
369  std::sort(intervals->begin(), intervals->end(),
371  }
372  IntegerValue min_end_in_set = kMaxIntegerValue;
373  intervals->push_back({-1, kMaxIntegerValue, kMaxIntegerValue}); // Sentinel.
374  const int size = intervals->size();
375 
376  // We do a line sweep. The "current" subset crossing the "line" at
377  // (time, time + 1) will be in (*intervals)[start_index, end_index) at the end
378  // of the loop block.
379  int start_index = 0;
380  for (int end_index = 0; end_index < size;) {
381  const IntegerValue time = (*intervals)[end_index].start;
382 
383  // First, if there is some deletion, we will push the "old" set to the
384  // result before updating it. Otherwise, we will have a superset later, so
385  // we just continue for now.
386  if (min_end_in_set <= time) {
387  result->push_back({});
388  min_end_in_set = kMaxIntegerValue;
389  for (int i = start_index; i < end_index; ++i) {
390  result->back().push_back((*intervals)[i].index);
391  if ((*intervals)[i].end <= time) {
392  std::swap((*intervals)[start_index++], (*intervals)[i]);
393  } else {
394  min_end_in_set = std::min(min_end_in_set, (*intervals)[i].end);
395  }
396  }
397 
398  // Do not output subset of size one.
399  if (result->back().size() == 1) result->pop_back();
400  }
401 
402  // Add all the new intervals starting exactly at "time".
403  do {
404  min_end_in_set = std::min(min_end_in_set, (*intervals)[end_index].end);
405  ++end_index;
406  } while (end_index < size && (*intervals)[end_index].start == time);
407  }
408 }
409 
411  std::vector<IndexedInterval>* intervals,
412  std::vector<std::vector<int>>* components) {
413  components->clear();
414  if (intervals->empty()) return;
415  if (intervals->size() == 1) {
416  components->push_back({intervals->front().index});
417  return;
418  }
419 
420  // For correctness, ComparatorByStart is enough, but in unit tests we want to
421  // verify this function against another implementation, and fully defined
422  // sorting with tie-breaking makes that much easier.
423  // If that becomes a performance bottleneck:
424  // - One may want to sort the list outside of this function, and simply
425  // have this function DCHECK that it's sorted by start.
426  // - One may use stable_sort() with ComparatorByStart().
427  std::sort(intervals->begin(), intervals->end(),
429 
430  IntegerValue end_max_so_far = (*intervals)[0].end;
431  components->push_back({(*intervals)[0].index});
432  for (int i = 1; i < intervals->size(); ++i) {
433  const IndexedInterval& interval = (*intervals)[i];
434  if (interval.start >= end_max_so_far) {
435  components->push_back({interval.index});
436  } else {
437  components->back().push_back(interval.index);
438  }
439  end_max_so_far = std::max(end_max_so_far, interval.end);
440  }
441 }
442 
444  std::vector<IndexedInterval>* intervals) {
445  std::vector<int> articulation_points;
446  if (intervals->size() < 3) return articulation_points; // Empty.
447  if (DEBUG_MODE) {
448  for (const IndexedInterval& interval : *intervals) {
449  DCHECK_LT(interval.start, interval.end);
450  }
451  }
452 
453  std::sort(intervals->begin(), intervals->end(),
455 
456  IntegerValue end_max_so_far = (*intervals)[0].end;
457  int index_of_max = 0;
458  IntegerValue prev_end_max = kMinIntegerValue; // Initialized as a sentinel.
459  for (int i = 1; i < intervals->size(); ++i) {
460  const IndexedInterval& interval = (*intervals)[i];
461  if (interval.start >= end_max_so_far) {
462  // New connected component.
463  end_max_so_far = interval.end;
464  index_of_max = i;
465  prev_end_max = kMinIntegerValue;
466  continue;
467  }
468  // Still the same connected component. Was the previous "max" an
469  // articulation point ?
470  if (prev_end_max != kMinIntegerValue && interval.start >= prev_end_max) {
471  // We might be re-inserting the same articulation point: guard against it.
472  if (articulation_points.empty() ||
473  articulation_points.back() != index_of_max) {
474  articulation_points.push_back(index_of_max);
475  }
476  }
477  // Update the max end.
478  if (interval.end > end_max_so_far) {
479  prev_end_max = end_max_so_far;
480  end_max_so_far = interval.end;
481  index_of_max = i;
482  } else if (interval.end > prev_end_max) {
483  prev_end_max = interval.end;
484  }
485  }
486  // Convert articulation point indices to IndexedInterval.index.
487  for (int& index : articulation_points) index = (*intervals)[index].index;
488  return articulation_points;
489 }
490 
492  events_.clear();
493  num_rectangles_added_ = 0;
494 }
495 
496 void CapacityProfile::AddRectangle(IntegerValue x_min, IntegerValue x_max,
497  IntegerValue y_min, IntegerValue y_max) {
498  DCHECK_LE(x_min, x_max);
499  if (x_min == x_max) return;
500 
501  events_.push_back(
502  StartRectangleEvent(num_rectangles_added_, x_min, y_min, y_max));
503  events_.push_back(EndRectangleEvent(num_rectangles_added_, x_max));
504  ++num_rectangles_added_;
505 }
506 
508  IntegerValue x_max,
509  IntegerValue y_height) {
510  DCHECK_LE(x_min, x_max);
511  if (x_min == x_max) return;
512 
513  events_.push_back(ChangeMandatoryProfileEvent(x_min, y_height));
514  events_.push_back(ChangeMandatoryProfileEvent(x_max, -y_height));
515 }
516 
518  std::vector<CapacityProfile::Rectangle>* result) {
519  std::sort(events_.begin(), events_.end());
520  IntegerPriorityQueue<QueueElement> min_pq(num_rectangles_added_);
521  IntegerPriorityQueue<QueueElement> max_pq(num_rectangles_added_);
522  IntegerValue mandatory_capacity(0);
523 
524  result->clear();
525 
526  result->push_back({kMinIntegerValue, IntegerValue(0)});
527 
528  for (int i = 0; i < events_.size();) {
529  const IntegerValue current_time = events_[i].time;
530  for (; i < events_.size(); ++i) {
531  const Event& event = events_[i];
532  if (event.time != current_time) break;
533 
534  switch (events_[i].type) {
535  case START_RECTANGLE: {
536  min_pq.Add({event.index, -event.y_min});
537  max_pq.Add({event.index, event.y_max});
538  break;
539  }
540  case END_RECTANGLE: {
541  min_pq.Remove(event.index);
542  max_pq.Remove(event.index);
543  break;
544  }
545  case CHANGE_MANDATORY_PROFILE: {
546  mandatory_capacity += event.y_min;
547  break;
548  }
549  }
550  }
551 
552  DCHECK(!max_pq.IsEmpty() || mandatory_capacity == 0);
553  const IntegerValue new_height =
554  max_pq.IsEmpty()
555  ? IntegerValue(0)
556  : max_pq.Top().value + min_pq.Top().value - mandatory_capacity;
557  if (new_height != result->back().height) {
558  result->push_back({current_time, new_height});
559  }
560  }
561 }
562 
564  std::sort(events_.begin(), events_.end());
565  IntegerPriorityQueue<QueueElement> min_pq(num_rectangles_added_);
566  IntegerPriorityQueue<QueueElement> max_pq(num_rectangles_added_);
567 
568  IntegerValue area(0);
569  IntegerValue previous_time = kMinIntegerValue;
570  IntegerValue previous_height(0);
571 
572  for (int i = 0; i < events_.size();) {
573  const IntegerValue current_time = events_[i].time;
574  for (; i < events_.size(); ++i) {
575  const Event& event = events_[i];
576  if (event.time != current_time) break;
577 
578  switch (event.type) {
579  case START_RECTANGLE: {
580  min_pq.Add({event.index, -event.y_min});
581  max_pq.Add({event.index, event.y_max});
582  break;
583  }
584  case END_RECTANGLE: {
585  min_pq.Remove(event.index);
586  max_pq.Remove(event.index);
587  break;
588  }
589  case CHANGE_MANDATORY_PROFILE: {
590  break;
591  }
592  }
593  }
594  const IntegerValue new_height =
595  max_pq.IsEmpty() ? IntegerValue(0)
596  : max_pq.Top().value + min_pq.Top().value;
597  if (previous_height != 0) {
598  area += previous_height * (current_time - previous_time);
599  }
600  previous_time = current_time;
601  previous_height = new_height;
602  }
603  return area;
604 }
605 
606 } // namespace sat
607 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
void AddMandatoryConsumption(IntegerValue x_min, IntegerValue x_max, IntegerValue y_height)
Definition: diffn_util.cc:507
void AddRectangle(IntegerValue x_min, IntegerValue x_max, IntegerValue y_min, IntegerValue y_max)
Definition: diffn_util.cc:496
void BuildResidualCapacityProfile(std::vector< Rectangle > *result)
Definition: diffn_util.cc:517
int index() const
Returns the index of the interval constraint in the model.
Definition: cp_model.h:492
void ImportOtherReasons(const SchedulingConstraintHelper &other_helper)
Definition: intervals.cc:622
void AddEnergyMinInIntervalReason(int t, IntegerValue min, IntegerValue max)
Definition: intervals.h:761
int64_t b
int64_t a
int index
const bool DEBUG_MODE
Definition: macros.h:24
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
Definition: stl_util.h:58
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
Definition: id_map.h:269
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
std::ostream & operator<<(std::ostream &os, const BoolVar &var)
Definition: cp_model.cc:88
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
Definition: integer.h:89
std::vector< int > GetIntervalArticulationPoints(std::vector< IndexedInterval > *intervals)
Definition: diffn_util.cc:443
void GetOverlappingIntervalComponents(std::vector< IndexedInterval > *intervals, std::vector< std::vector< int >> *components)
Definition: diffn_util.cc:410
std::vector< absl::Span< int > > GetOverlappingRectangleComponents(const std::vector< Rectangle > &rectangles, absl::Span< int > active_rectangles)
Definition: diffn_util.cc:41
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:318
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
void ConstructOverlappingSets(bool already_sorted, std::vector< IndexedInterval > *intervals, std::vector< std::vector< int >> *result)
Definition: diffn_util.cc:361
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:166
bool ReportEnergyConflict(Rectangle bounding_box, absl::Span< const int > boxes, SchedulingConstraintHelper *x, SchedulingConstraintHelper *y)
Definition: diffn_util.cc:67
bool BoxesAreInEnergyConflict(const std::vector< Rectangle > &rectangles, const std::vector< IntegerValue > &energies, absl::Span< const int > boxes, Rectangle *conflict)
Definition: diffn_util.cc:99
absl::Span< int > FilterBoxesThatAreTooLarge(const std::vector< Rectangle > &cached_rectangles, const std::vector< IntegerValue > &energies, absl::Span< int > boxes)
Definition: diffn_util.cc:334
Collection of objects used to extend the Constraint Solver library.
int64_t energy
Definition: resource.cc:355
int64_t time
Definition: resource.cc:1694
IntervalVar * interval
Definition: resource.cc:101
std::optional< int64_t > end
int64_t start
const int width
Definition: statistics.cc:37
#define VLOG(verboselevel)
Definition: vlog.h:39
#define VLOG_IS_ON(verboselevel)
Definition: vlog_is_on.h:47