27 const std::vector<Rectangle>& rectangles,
28 absl::Span<int> active_rectangles) {
29 if (active_rectangles.empty())
return {};
31 std::vector<absl::Span<int>> result;
32 const int size = active_rectangles.size();
33 for (
int start = 0; start < size;) {
36 for (
int i = start; i < end; i++) {
37 for (
int j = end; j < size; ++j) {
38 if (!rectangles[active_rectangles[i]].IsDisjoint(
39 rectangles[active_rectangles[j]])) {
40 std::swap(active_rectangles[end++], active_rectangles[j]);
44 if (end > start + 1) {
45 result.push_back(active_rectangles.subspan(start, end - start));
57 IntegerValue total_energy(0);
58 for (
const int b : boxes) {
61 if (x_min < bounding_box.x_min || x_max > bounding_box.
x_max)
continue;
64 if (y_min < bounding_box.y_min || y_max > bounding_box.
y_max)
continue;
76 if (total_energy > bounding_box.
Area())
break;
85 const std::vector<IntegerValue>& energies,
86 absl::Span<const int> boxes,
89 std::vector<IntegerValue> x_starts;
90 std::vector<TaskTime> boxes_by_increasing_x_max;
91 for (
const int b : boxes) {
92 x_starts.push_back(rectangles[
b].x_min);
93 boxes_by_increasing_x_max.push_back({
b, rectangles[
b].x_max});
96 std::sort(boxes_by_increasing_x_max.begin(), boxes_by_increasing_x_max.end());
98 std::vector<IntegerValue> y_starts;
99 std::vector<IntegerValue> energy_sum;
100 std::vector<TaskTime> boxes_by_increasing_y_max;
102 std::vector<std::vector<int>> stripes(x_starts.size());
103 for (
int i = 0; i < boxes_by_increasing_x_max.size(); ++i) {
104 const int b = boxes_by_increasing_x_max[i].task_index;
105 const IntegerValue x_min = rectangles[
b].x_min;
106 const IntegerValue x_max = rectangles[
b].x_max;
107 for (
int j = 0; j < x_starts.size(); ++j) {
108 if (x_starts[j] > x_min)
break;
109 stripes[j].push_back(
b);
114 boxes_by_increasing_y_max.clear();
115 for (
const int b : stripes[j]) {
116 y_starts.push_back(rectangles[
b].y_min);
117 boxes_by_increasing_y_max.push_back({
b, rectangles[
b].y_max});
120 std::sort(boxes_by_increasing_y_max.begin(),
121 boxes_by_increasing_y_max.end());
123 const IntegerValue x_size = x_max - x_starts[j];
124 energy_sum.assign(y_starts.size(), IntegerValue(0));
125 for (
int i = 0; i < boxes_by_increasing_y_max.size(); ++i) {
126 const int b = boxes_by_increasing_y_max[i].task_index;
127 const IntegerValue y_min = rectangles[
b].y_min;
128 const IntegerValue y_max = rectangles[
b].y_max;
129 for (
int j = 0; j < y_starts.size(); ++j) {
130 if (y_starts[j] > y_min)
break;
131 energy_sum[j] += energies[
b];
132 if (energy_sum[j] > x_size * (y_max - y_starts[j])) {
133 if (conflict !=
nullptr) {
134 *conflict = rectangles[
b];
135 for (
int k = 0; k < i; ++k) {
136 const int task_index = boxes_by_increasing_y_max[k].task_index;
137 if (rectangles[task_index].y_min >= y_starts[j]) {
152 const std::vector<Rectangle>& rectangles,
153 const std::vector<IntegerValue>& rectangle_energies,
154 IntegerValue* x_threshold, IntegerValue* y_threshold,
161 std::vector<IntegerValue> starts;
162 std::vector<TaskTime> task_by_increasing_x_max;
163 for (
const int t : local_boxes) {
164 const IntegerValue x_min =
165 transpose ? rectangles[t].y_min : rectangles[t].x_min;
166 const IntegerValue x_max =
167 transpose ? rectangles[t].y_max : rectangles[t].x_max;
168 starts.push_back(x_min);
169 task_by_increasing_x_max.push_back({t, x_max});
175 std::sort(task_by_increasing_x_max.begin(), task_by_increasing_x_max.end());
179 IntegerValue max_conflict_height(0);
182 absl::flat_hash_set<std::pair<IntegerValue, IntegerValue>> stripes;
185 std::vector<IntegerValue> energies(starts.size(), IntegerValue(0));
188 std::vector<IntegerValue> energy_at_max_y(starts.size(), IntegerValue(0));
189 std::vector<IntegerValue> energy_at_min_y(starts.size(), IntegerValue(0));
196 const IntegerValue threshold = transpose ? *y_threshold : *x_threshold;
197 for (
int i = 0; i < task_by_increasing_x_max.size(); ++i) {
198 const int t = task_by_increasing_x_max[i].task_index;
200 const IntegerValue
energy = rectangle_energies[t];
201 IntegerValue x_min = rectangles[t].x_min;
202 IntegerValue x_max = rectangles[t].x_max;
203 IntegerValue y_min = rectangles[t].y_min;
204 IntegerValue y_max = rectangles[t].y_max;
211 while (first_j + 1 < starts.size() && x_max - starts[first_j] > threshold) {
214 for (
int j = first_j; starts[j] <= x_min; ++j) {
215 const IntegerValue old_energy_at_max = energy_at_max_y[j];
216 const IntegerValue old_energy_at_min = energy_at_min_y[j];
220 const bool is_disjoint = y_min >= y_maxs[j] || y_max <= y_mins[j];
222 if (y_min <= y_mins[j]) {
223 if (y_min < y_mins[j]) {
225 energy_at_min_y[j] =
energy;
227 energy_at_min_y[j] +=
energy;
231 if (y_max >= y_maxs[j]) {
232 if (y_max > y_maxs[j]) {
234 energy_at_max_y[j] =
energy;
236 energy_at_max_y[j] +=
energy;
243 if (is_disjoint)
continue;
245 const IntegerValue width = x_max - starts[j];
246 IntegerValue conflict_height =
CeilRatio(energies[j], width) - 1;
247 if (y_max - y_min > conflict_height)
continue;
248 if (conflict_height >= y_maxs[j] - y_mins[j]) {
250 if (conflict !=
nullptr) {
251 *conflict = rectangles[t];
252 for (
int k = 0; k < i; ++k) {
253 const int task_index = task_by_increasing_x_max[k].task_index;
254 const IntegerValue task_x_min = transpose
255 ? rectangles[task_index].
y_min
256 : rectangles[task_index].x_min;
257 if (task_x_min < starts[j])
continue;
266 IntegerValue can_remove =
std::min(old_energy_at_min, old_energy_at_max);
267 if (old_energy_at_min < old_energy_at_max) {
268 if (y_maxs[j] - y_min >=
269 CeilRatio(energies[j] - old_energy_at_min, width)) {
272 can_remove = old_energy_at_max;
274 }
else if (old_energy_at_max < old_energy_at_min) {
275 if (y_max - y_mins[j] >=
276 CeilRatio(energies[j] - old_energy_at_max, width)) {
277 can_remove = old_energy_at_min;
280 conflict_height =
CeilRatio(energies[j] - can_remove, width) - 1;
284 if (y_max - y_min > conflict_height)
continue;
286 if (
VLOG_IS_ON(2)) stripes.insert({starts[j], x_max});
287 max_conflict_height =
std::max(max_conflict_height, conflict_height);
291 VLOG(2) <<
" num_starts: " << starts.size() - 1 <<
"/" << local_boxes.size()
292 <<
" conflict_height: " << max_conflict_height
293 <<
" num_stripes:" << stripes.size() <<
" (<= " << threshold <<
")";
296 *x_threshold =
std::min(*x_threshold, max_conflict_height);
298 *y_threshold =
std::min(*y_threshold, max_conflict_height);
304 const std::vector<Rectangle>& cached_rectangles, absl::Span<int> boxes,
305 IntegerValue threshold_x, IntegerValue threshold_y,
306 absl::BitGenRef random) {
308 for (
const int b : boxes) {
310 if (dim.
x_max - dim.
x_min > threshold_x)
continue;
311 if (dim.
y_max - dim.
y_min > threshold_y)
continue;
312 boxes[new_size++] =
b;
314 if (new_size == 0)
return {};
315 std::shuffle(&boxes[0], &boxes[0] + new_size, random);
316 return {&boxes[0], new_size};
320 const std::vector<Rectangle>& cached_rectangles,
321 const std::vector<IntegerValue>& energies, absl::Span<int> boxes) {
323 std::sort(boxes.begin(), boxes.end(), [&cached_rectangles](
int a,
int b) {
324 return cached_rectangles[a].Area() < cached_rectangles[b].Area();
327 IntegerValue total_energy(0);
328 for (
const int box : boxes) total_energy += energies[box];
332 int new_size = boxes.size();
333 while (new_size > 0 &&
334 cached_rectangles[boxes[new_size - 1]].Area() >= total_energy) {
336 total_energy -= energies[boxes[new_size]];
338 return boxes.subspan(0, new_size);
347 std::vector<IndexedInterval>* intervals,
348 std::vector<std::vector<int>>* result) {
350 if (already_sorted) {
351 DCHECK(std::is_sorted(intervals->begin(), intervals->end(),
354 std::sort(intervals->begin(), intervals->end(),
359 const int size = intervals->size();
365 for (
int end_index = 0; end_index < size;) {
366 const IntegerValue
time = (*intervals)[end_index].start;
371 if (min_end_in_set <=
time) {
372 result->push_back({});
374 for (
int i = start_index; i < end_index; ++i) {
375 result->back().push_back((*intervals)[i].
index);
376 if ((*intervals)[i].end <=
time) {
377 std::swap((*intervals)[start_index++], (*intervals)[i]);
379 min_end_in_set =
std::min(min_end_in_set, (*intervals)[i].end);
384 if (result->back().size() == 1) result->pop_back();
389 min_end_in_set =
std::min(min_end_in_set, (*intervals)[end_index].end);
391 }
while (end_index < size && (*intervals)[end_index].start ==
time);
396 std::vector<IndexedInterval>* intervals,
397 std::vector<std::vector<int>>* components) {
399 if (intervals->empty())
return;
400 if (intervals->size() == 1) {
401 components->push_back({intervals->front().
index});
412 std::sort(intervals->begin(), intervals->end(),
415 IntegerValue end_max_so_far = (*intervals)[0].end;
416 components->push_back({(*intervals)[0].index});
417 for (
int i = 1; i < intervals->size(); ++i) {
419 if (
interval.start >= end_max_so_far) {
429 std::vector<IndexedInterval>* intervals) {
430 std::vector<int> articulation_points;
431 if (intervals->size() < 3)
return articulation_points;
438 std::sort(intervals->begin(), intervals->end(),
441 IntegerValue end_max_so_far = (*intervals)[0].end;
442 int index_of_max = 0;
444 for (
int i = 1; i < intervals->size(); ++i) {
446 if (
interval.start >= end_max_so_far) {
457 if (articulation_points.empty() ||
458 articulation_points.back() != index_of_max) {
459 articulation_points.push_back(index_of_max);
463 if (
interval.end > end_max_so_far) {
464 prev_end_max = end_max_so_far;
467 }
else if (
interval.end > prev_end_max) {
472 for (
int&
index : articulation_points)
index = (*intervals)[
index].index;
473 return articulation_points;
#define CHECK_GT(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
#define VLOG(verboselevel)
int index() const
Returns the index of the interval constraint in the model.
IntegerValue ShiftedStartMin(int t) const
void AddPresenceReason(int t)
IntegerValue ShiftedEndMax(int t) const
ABSL_MUST_USE_RESULT bool ReportConflict()
void ImportOtherReasons(const SchedulingConstraintHelper &other_helper)
void AddEnergyMinInIntervalReason(int t, IntegerValue min, IntegerValue max)
IntegerValue SizeMin(int t) const
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
void swap(IdMap< K, V > &a, IdMap< K, V > &b)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
std::ostream & operator<<(std::ostream &os, const BoolVar &var)
void GetOverlappingIntervalComponents(std::vector< IndexedInterval > *intervals, std::vector< std::vector< int > > *components)
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
std::vector< int > GetIntervalArticulationPoints(std::vector< IndexedInterval > *intervals)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
std::vector< absl::Span< int > > GetOverlappingRectangleComponents(const std::vector< Rectangle > &rectangles, absl::Span< int > active_rectangles)
absl::Span< int > FilterBoxesAndRandomize(const std::vector< Rectangle > &cached_rectangles, absl::Span< int > boxes, IntegerValue threshold_x, IntegerValue threshold_y, absl::BitGenRef random)
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)
bool ReportEnergyConflict(Rectangle bounding_box, absl::Span< const int > boxes, SchedulingConstraintHelper *x, SchedulingConstraintHelper *y)
void ConstructOverlappingSets(bool already_sorted, std::vector< IndexedInterval > *intervals, std::vector< std::vector< int > > *result)
bool BoxesAreInEnergyConflict(const std::vector< Rectangle > &rectangles, const std::vector< IntegerValue > &energies, absl::Span< const int > boxes, Rectangle *conflict)
absl::Span< int > FilterBoxesThatAreTooLarge(const std::vector< Rectangle > &cached_rectangles, const std::vector< IntegerValue > &energies, absl::Span< int > boxes)
Collection of objects used to extend the Constraint Solver library.
IntegerValue Area() const
void TakeUnionWith(const Rectangle &other)
bool IsDisjoint(const Rectangle &other) const
#define VLOG_IS_ON(verboselevel)