34#include "absl/algorithm/container.h"
35#include "absl/container/btree_set.h"
36#include "absl/container/flat_hash_map.h"
37#include "absl/container/flat_hash_set.h"
38#include "absl/container/inlined_vector.h"
39#include "absl/log/check.h"
40#include "absl/log/log.h"
41#include "absl/log/vlog_is_on.h"
42#include "absl/random/bit_gen_ref.h"
43#include "absl/types/span.h"
66 if (intersect.
SizeX() == 0) {
77 absl::InlinedVector<Rectangle, 4> result;
80 result.push_back({.x_min =
x_min,
81 .x_max = intersect.
x_min,
87 result.push_back({.x_min = intersect.
x_max,
94 result.push_back({.x_min = intersect.
x_min,
95 .x_max = intersect.
x_max,
97 .y_max = intersect.
y_min});
101 result.push_back({.x_min = intersect.
x_min,
102 .x_max = intersect.
x_max,
103 .y_min = intersect.
y_max,
111 absl::Span<const Rectangle> rectangles) {
112 if (rectangles.empty())
return {};
114 std::vector<std::pair<int, int>> intersections =
116 const int num_intersections = intersections.size();
117 intersections.reserve(num_intersections * 2 + 1);
118 for (
int i = 0;
i < num_intersections; ++
i) {
119 intersections.push_back({intersections[
i].second, intersections[
i].first});
128 for (
int i = 0;
i < components.size(); ++
i) {
129 absl::Span<const int> component = components[
i];
131 for (
const int r : component) {
132 result.AppendToLastVector(r);
143 IntegerValue total_energy(0);
144 for (
const int b : boxes) {
145 const IntegerValue x_min = x->ShiftedStartMin(
b);
146 const IntegerValue x_max = x->ShiftedEndMax(
b);
147 if (x_min < bounding_box.x_min || x_max > bounding_box.x_max)
continue;
150 if (y_min < bounding_box.y_min || y_max > bounding_box.y_max)
continue;
152 x->AddEnergyMinInIntervalReason(
b, bounding_box.x_min, bounding_box.x_max);
155 x->AddPresenceReason(
b);
158 total_energy += x->SizeMin(
b) * y->
SizeMin(
b);
162 if (total_energy > bounding_box.Area())
break;
165 CHECK_GT(total_energy, bounding_box.Area());
166 x->ImportReasonsFromOther(*y);
167 return x->ReportConflict();
171 absl::Span<const IntegerValue> energies,
172 absl::Span<const int> boxes,
175 std::vector<IntegerValue> x_starts;
176 std::vector<TaskTime> boxes_by_increasing_x_max;
177 for (
const int b : boxes) {
178 x_starts.push_back(rectangles[
b].x_min);
179 boxes_by_increasing_x_max.push_back({
b, rectangles[
b].x_max});
182 std::sort(boxes_by_increasing_x_max.begin(), boxes_by_increasing_x_max.end());
184 std::vector<IntegerValue> y_starts;
185 std::vector<IntegerValue> energy_sum;
186 std::vector<TaskTime> boxes_by_increasing_y_max;
188 std::vector<std::vector<int>> stripes(x_starts.size());
189 for (
int i = 0;
i < boxes_by_increasing_x_max.size(); ++
i) {
190 const int b = boxes_by_increasing_x_max[
i].task_index;
191 const IntegerValue x_min = rectangles[
b].x_min;
192 const IntegerValue x_max = rectangles[
b].x_max;
193 for (
int j = 0; j < x_starts.size(); ++j) {
194 if (x_starts[j] > x_min)
break;
195 stripes[j].push_back(
b);
200 boxes_by_increasing_y_max.clear();
201 for (
const int b : stripes[j]) {
202 y_starts.push_back(rectangles[
b].y_min);
203 boxes_by_increasing_y_max.push_back({
b, rectangles[
b].y_max});
206 std::sort(boxes_by_increasing_y_max.begin(),
207 boxes_by_increasing_y_max.end());
209 const IntegerValue x_size = x_max - x_starts[j];
210 energy_sum.assign(y_starts.size(), IntegerValue(0));
211 for (
int i = 0;
i < boxes_by_increasing_y_max.size(); ++
i) {
212 const int b = boxes_by_increasing_y_max[
i].task_index;
213 const IntegerValue y_min = rectangles[
b].y_min;
214 const IntegerValue y_max = rectangles[
b].y_max;
215 for (
int j = 0; j < y_starts.size(); ++j) {
216 if (y_starts[j] > y_min)
break;
217 energy_sum[j] += energies[
b];
218 if (energy_sum[j] > x_size * (y_max - y_starts[j])) {
219 if (conflict !=
nullptr) {
220 *conflict = rectangles[
b];
221 for (
int k = 0; k <
i; ++k) {
222 const int task_index = boxes_by_increasing_y_max[k].task_index;
223 if (rectangles[task_index].y_min >= y_starts[j]) {
238 absl::Span<const Rectangle> rectangles,
239 absl::Span<const IntegerValue> rectangle_energies,
240 IntegerValue* x_threshold, IntegerValue* y_threshold,
247 std::vector<IntegerValue> starts;
248 std::vector<TaskTime> task_by_increasing_x_max;
249 for (
const int t : local_boxes) {
250 const IntegerValue x_min =
251 transpose ? rectangles[t].y_min : rectangles[t].x_min;
252 const IntegerValue x_max =
253 transpose ? rectangles[t].y_max : rectangles[t].x_max;
254 starts.push_back(x_min);
255 task_by_increasing_x_max.push_back({t, x_max});
261 std::sort(task_by_increasing_x_max.begin(), task_by_increasing_x_max.end());
265 IntegerValue max_conflict_height(0);
268 absl::flat_hash_set<std::pair<IntegerValue, IntegerValue>> stripes;
271 std::vector<IntegerValue> energies(starts.size(), IntegerValue(0));
274 std::vector<IntegerValue> energy_at_max_y(starts.size(), IntegerValue(0));
275 std::vector<IntegerValue> energy_at_min_y(starts.size(), IntegerValue(0));
282 const IntegerValue threshold = transpose ? *y_threshold : *x_threshold;
283 for (
int i = 0;
i < task_by_increasing_x_max.size(); ++
i) {
284 const int t = task_by_increasing_x_max[
i].task_index;
286 const IntegerValue energy = rectangle_energies[t];
287 IntegerValue x_min = rectangles[t].x_min;
288 IntegerValue x_max = rectangles[t].x_max;
289 IntegerValue y_min = rectangles[t].y_min;
290 IntegerValue y_max = rectangles[t].y_max;
292 std::swap(x_min, y_min);
293 std::swap(x_max, y_max);
297 while (first_j + 1 < starts.size() && x_max - starts[first_j] > threshold) {
300 for (
int j = first_j; starts[j] <= x_min; ++j) {
301 const IntegerValue old_energy_at_max = energy_at_max_y[j];
302 const IntegerValue old_energy_at_min = energy_at_min_y[j];
304 energies[j] += energy;
306 const bool is_disjoint = y_min >= y_maxs[j] || y_max <= y_mins[j];
308 if (y_min <= y_mins[j]) {
309 if (y_min < y_mins[j]) {
311 energy_at_min_y[j] = energy;
313 energy_at_min_y[j] += energy;
317 if (y_max >= y_maxs[j]) {
318 if (y_max > y_maxs[j]) {
320 energy_at_max_y[j] = energy;
322 energy_at_max_y[j] += energy;
329 if (is_disjoint)
continue;
331 const IntegerValue width = x_max - starts[j];
332 IntegerValue conflict_height =
CeilRatio(energies[j], width) - 1;
333 if (y_max - y_min > conflict_height)
continue;
334 if (conflict_height >= y_maxs[j] - y_mins[j]) {
336 if (conflict !=
nullptr) {
337 *conflict = rectangles[t];
338 for (
int k = 0; k <
i; ++k) {
339 const int task_index = task_by_increasing_x_max[k].task_index;
340 const IntegerValue task_x_min = transpose
341 ? rectangles[task_index].y_min
342 : rectangles[task_index].x_min;
343 if (task_x_min < starts[j])
continue;
352 IntegerValue can_remove = std::min(old_energy_at_min, old_energy_at_max);
353 if (old_energy_at_min < old_energy_at_max) {
354 if (y_maxs[j] - y_min >=
355 CeilRatio(energies[j] - old_energy_at_min, width)) {
358 can_remove = old_energy_at_max;
360 }
else if (old_energy_at_max < old_energy_at_min) {
361 if (y_max - y_mins[j] >=
362 CeilRatio(energies[j] - old_energy_at_max, width)) {
363 can_remove = old_energy_at_min;
366 conflict_height =
CeilRatio(energies[j] - can_remove, width) - 1;
370 if (y_max - y_min > conflict_height)
continue;
372 if (VLOG_IS_ON(2)) stripes.insert({starts[j], x_max});
373 max_conflict_height = std::max(max_conflict_height, conflict_height);
377 VLOG(2) <<
" num_starts: " << starts.size() - 1 <<
"/" << local_boxes.size()
378 <<
" conflict_height: " << max_conflict_height
379 <<
" num_stripes:" << stripes.size() <<
" (<= " << threshold <<
")";
382 *x_threshold = std::min(*x_threshold, max_conflict_height);
384 *y_threshold = std::min(*y_threshold, max_conflict_height);
390 absl::Span<const Rectangle> cached_rectangles, absl::Span<int> boxes,
391 IntegerValue threshold_x, IntegerValue threshold_y,
392 absl::BitGenRef random) {
394 for (
const int b : boxes) {
396 if (dim.
x_max - dim.
x_min > threshold_x)
continue;
397 if (dim.
y_max - dim.
y_min > threshold_y)
continue;
398 boxes[new_size++] =
b;
400 if (new_size == 0)
return {};
401 std::shuffle(&boxes[0], &boxes[0] + new_size, random);
402 return {&boxes[0], new_size};
406 absl::Span<const Rectangle> cached_rectangles,
407 absl::Span<const IntegerValue> energies, absl::Span<int> boxes) {
409 std::sort(boxes.begin(), boxes.end(), [cached_rectangles](
int a,
int b) {
410 return cached_rectangles[a].Area() < cached_rectangles[b].Area();
413 IntegerValue total_energy(0);
414 for (
const int box : boxes) total_energy += energies[box];
418 int new_size = boxes.size();
419 while (new_size > 0 &&
420 cached_rectangles[boxes[new_size - 1]].Area() >= total_energy) {
422 total_energy -= energies[boxes[new_size]];
424 return boxes.subspan(0, new_size);
428 CompactVectorVector<int>* result,
429 absl::Span<const int> order) {
431 DCHECK(std::is_sorted(intervals.begin(), intervals.end(),
439 const int size = intervals.size();
440 for (
int end_index = 0; end_index < size;) {
441 const IntegerValue time = intervals[end_index].start;
446 if (min_end_in_set <= time) {
448 if (start_index + 1 < end_index) {
450 for (
int i = start_index;
i < end_index; ++
i) {
451 result->AppendToLastVector(intervals[
i].index);
457 int new_start = end_index;
458 for (
int i = end_index; --
i >= start_index;) {
459 if (intervals[
i].
end > time) {
460 min_end_in_set = std::min(min_end_in_set, intervals[
i].
end);
461 intervals[--new_start] = intervals[
i];
464 start_index = new_start;
469 const int old_end = end_index;
470 while (end_index < size && intervals[end_index].start == time) {
471 min_end_in_set = std::min(min_end_in_set, intervals[end_index].
end);
477 if (!order.empty() && end_index > old_end) {
478 std::sort(intervals.data() + old_end, intervals.data() + end_index,
480 return order[a.index] < order[b.index];
483 intervals.data() + start_index, intervals.data() + old_end,
484 intervals.data() + end_index,
486 return order[a.index] < order[b.index];
492 if (start_index + 1 < size) {
494 for (
int i = start_index;
i < size; ++
i) {
495 result->AppendToLastVector(intervals[
i].index);
501 std::vector<IndexedInterval>* intervals,
502 std::vector<std::vector<int>>* components) {
504 if (intervals->empty())
return;
505 if (intervals->size() == 1) {
506 components->push_back({intervals->front().index});
517 std::sort(intervals->begin(), intervals->end(),
520 IntegerValue end_max_so_far = (*intervals)[0].end;
521 components->push_back({(*intervals)[0].index});
522 for (
int i = 1;
i < intervals->size(); ++
i) {
524 if (interval.
start >= end_max_so_far) {
525 components->push_back({interval.
index});
527 components->back().push_back(interval.
index);
529 end_max_so_far = std::max(end_max_so_far, interval.
end);
534 std::vector<IndexedInterval>* intervals) {
535 std::vector<int> articulation_points;
536 if (intervals->size() < 3)
return articulation_points;
539 DCHECK_LT(interval.start, interval.end);
543 std::sort(intervals->begin(), intervals->end(),
544 IndexedInterval::ComparatorByStart());
546 IntegerValue end_max_so_far = (*intervals)[0].end;
547 int index_of_max = 0;
549 for (
int i = 1;
i < intervals->size(); ++
i) {
550 const IndexedInterval& interval = (*intervals)[
i];
551 if (interval.start >= end_max_so_far) {
553 end_max_so_far = interval.end;
562 if (articulation_points.empty() ||
563 articulation_points.back() != index_of_max) {
564 articulation_points.push_back(index_of_max);
568 if (interval.end > end_max_so_far) {
569 prev_end_max = end_max_so_far;
570 end_max_so_far = interval.end;
572 }
else if (interval.end > prev_end_max) {
573 prev_end_max = interval.end;
577 for (
int& index : articulation_points) index = (*intervals)[index].index;
578 return articulation_points;
582bool IsZeroOrPowerOfTwo(
int value) {
return (value & (value - 1)) == 0; }
586 std::vector<PairwiseRestriction>* result) {
589 (item1.x.end_min <= item2.x.start_max) +
591 2 * (item2.x.end_min <= item1.x.start_max) +
593 4 * (item1.y.end_min <= item2.y.start_max) +
595 8 * (item2.y.end_min <= item1.y.start_max);
597 if (!IsZeroOrPowerOfTwo(state)) {
609 if (item1.x.end_min > item2.x.start_min ||
610 item2.x.start_max < item1.x.end_max) {
618 if (item2.x.end_min > item1.x.start_min ||
619 item1.x.start_max < item2.x.end_max) {
627 if (item1.y.end_min > item2.y.start_min ||
628 item2.y.start_max < item1.y.end_max) {
635 if (item2.y.end_min > item1.y.start_min ||
636 item1.y.start_max < item2.y.end_max) {
645 {.first_index = item1.index, .second_index = item2.index, .type = type});
650 std::vector<PairwiseRestriction>* result) {
651 for (
int i1 = 0; i1 + 1 < items.size(); ++i1) {
652 for (
int i2 = i1 + 1; i2 < items.size(); ++i2) {
653 AppendPairwiseRestriction(items[i1], items[i2], result);
659 absl::Span<const ItemWithVariableSize> items,
660 absl::Span<const ItemWithVariableSize> other_items,
661 std::vector<PairwiseRestriction>* result) {
662 for (
int i1 = 0; i1 < items.size(); ++i1) {
663 for (
int i2 = 0; i2 < other_items.size(); ++i2) {
664 AppendPairwiseRestriction(items[i1], other_items[i2], result);
671 num_rectangles_added_ = 0;
675 IntegerValue y_min, IntegerValue y_max) {
676 DCHECK_LE(x_min, x_max);
677 if (x_min == x_max)
return;
680 StartRectangleEvent(num_rectangles_added_, x_min, y_min, y_max));
681 events_.push_back(EndRectangleEvent(num_rectangles_added_, x_max));
682 ++num_rectangles_added_;
687 IntegerValue y_height) {
688 DCHECK_LE(x_min, x_max);
689 if (x_min == x_max)
return;
691 events_.push_back(ChangeMandatoryProfileEvent(x_min, y_height));
692 events_.push_back(ChangeMandatoryProfileEvent(x_max, -y_height));
696 std::vector<CapacityProfile::Rectangle>* result) {
697 std::sort(events_.begin(), events_.end());
700 IntegerValue mandatory_capacity(0);
706 for (
int i = 0;
i < events_.size();) {
707 const IntegerValue current_time = events_[
i].time;
708 for (;
i < events_.size(); ++
i) {
709 const Event&
event = events_[
i];
710 if (event.time != current_time)
break;
712 switch (events_[
i].type) {
713 case START_RECTANGLE: {
714 min_pq.Add({
event.index, -
event.y_min});
715 max_pq.Add({
event.index,
event.y_max});
718 case END_RECTANGLE: {
719 min_pq.Remove(event.index);
720 max_pq.Remove(event.index);
723 case CHANGE_MANDATORY_PROFILE: {
724 mandatory_capacity +=
event.y_min;
730 DCHECK(!max_pq.IsEmpty() || mandatory_capacity == 0);
731 const IntegerValue new_height =
734 : max_pq.Top().value + min_pq.Top().value - mandatory_capacity;
735 if (new_height != result->back().height) {
736 result->push_back({current_time, new_height});
741IntegerValue CapacityProfile::GetBoundingArea() {
742 std::sort(events_.begin(), events_.end());
746 IntegerValue area(0);
748 IntegerValue previous_height(0);
750 for (
int i = 0;
i < events_.size();) {
751 const IntegerValue current_time = events_[
i].time;
752 for (;
i < events_.size(); ++
i) {
753 const Event&
event = events_[
i];
754 if (event.time != current_time)
break;
756 switch (event.type) {
757 case START_RECTANGLE: {
758 min_pq.Add({
event.index, -
event.y_min});
759 max_pq.Add({
event.index,
event.y_max});
762 case END_RECTANGLE: {
763 min_pq.Remove(event.index);
764 max_pq.Remove(event.index);
767 case CHANGE_MANDATORY_PROFILE: {
772 const IntegerValue new_height =
773 max_pq.IsEmpty() ? IntegerValue(0)
774 : max_pq.Top().value + min_pq.Top().value;
775 if (previous_height != 0) {
776 area += previous_height * (current_time - previous_time);
778 previous_time = current_time;
779 previous_height = new_height;
785 IntegerValue range_max, IntegerValue size,
786 IntegerValue interval_min,
787 IntegerValue interval_max) {
790 const IntegerValue overlap_on_left =
791 std::min(range_min + size, interval_max) -
792 std::max(range_min, interval_min);
796 const IntegerValue overlap_on_right =
797 std::min(range_max, interval_max) -
798 std::max(range_max - size, interval_min);
800 return std::max(IntegerValue(0), std::min(overlap_on_left, overlap_on_right));
803ProbingRectangle::ProbingRectangle(
804 const std::vector<RectangleInRange>& intervals)
805 : intervals_(intervals) {
807 if (intervals_.empty()) {
810 interval_points_sorted_by_x_.reserve(intervals_.size() * 4 + 2);
811 interval_points_sorted_by_y_.reserve(intervals_.size() * 4 + 2);
813 Rectangle bounding_box = {.x_min = std::numeric_limits<IntegerValue>::max(),
814 .x_max = std::numeric_limits<IntegerValue>::min(),
815 .y_min = std::numeric_limits<IntegerValue>::max(),
816 .y_max = std::numeric_limits<IntegerValue>::min()};
818 for (
int i = 0;
i < intervals_.size(); ++
i) {
832 interval_points_sorted_by_x_.push_back(
834 interval_points_sorted_by_x_.push_back(
839 interval_points_sorted_by_y_.push_back(
841 interval_points_sorted_by_y_.push_back(
846 full_energy_ = minimum_energy_;
849 interval_points_sorted_by_x_.push_back({bounding_box.x_min - 1, -1});
850 interval_points_sorted_by_x_.push_back({bounding_box.x_max + 1, -1});
851 interval_points_sorted_by_y_.push_back({bounding_box.y_min - 1, -1});
852 interval_points_sorted_by_y_.push_back({bounding_box.y_max + 1, -1});
854 auto comparator = [](
const IntervalPoint& a,
const IntervalPoint&
b) {
855 return std::tie(a.value, a.index) < std::tie(
b.value,
b.index);
860 grouped_intervals_sorted_by_x_.reserve(interval_points_sorted_by_x_.size());
861 grouped_intervals_sorted_by_y_.reserve(interval_points_sorted_by_y_.size());
863 while (
i < interval_points_sorted_by_x_.size()) {
865 while (
i < interval_points_sorted_by_x_.size() &&
866 interval_points_sorted_by_x_[
i].value ==
867 interval_points_sorted_by_x_[idx_begin].value) {
870 grouped_intervals_sorted_by_x_.push_back(
871 {interval_points_sorted_by_x_[idx_begin].value,
872 absl::Span<IntervalPoint>(interval_points_sorted_by_x_)
873 .subspan(idx_begin,
i - idx_begin)});
877 while (
i < interval_points_sorted_by_y_.size()) {
879 while (
i < interval_points_sorted_by_y_.size() &&
880 interval_points_sorted_by_y_[
i].value ==
881 interval_points_sorted_by_y_[idx_begin].value) {
884 grouped_intervals_sorted_by_y_.push_back(
885 {interval_points_sorted_by_y_[idx_begin].value,
886 absl::Span<IntervalPoint>(interval_points_sorted_by_y_)
887 .subspan(idx_begin,
i - idx_begin)});
894 indexes_[Edge::LEFT] = 0;
895 indexes_[
Edge::RIGHT] = grouped_intervals_sorted_by_x_.size() - 1;
897 indexes_[
Edge::TOP] = grouped_intervals_sorted_by_y_.size() - 1;
900 next_indexes_[
Edge::RIGHT] = grouped_intervals_sorted_by_x_.size() - 2;
902 next_indexes_[
Edge::TOP] = grouped_intervals_sorted_by_y_.size() - 2;
904 minimum_energy_ = full_energy_;
905 ranges_touching_both_boundaries_[0].clear();
906 ranges_touching_both_boundaries_[1].clear();
908 for (
int i = 0;
i < 4; ++
i) {
909 corner_count_[
i] = 0;
910 intersect_length_[
i] = 0;
911 cached_delta_energy_[
i] = 0;
916 Shrink(Edge::BOTTOM);
921Rectangle ProbingRectangle::GetCurrentRectangle()
const {
923 .x_min = grouped_intervals_sorted_by_x_[indexes_[
Edge::LEFT]].coordinate,
924 .x_max = grouped_intervals_sorted_by_x_[indexes_[
Edge::RIGHT]].coordinate,
926 grouped_intervals_sorted_by_y_[indexes_[
Edge::BOTTOM]].coordinate,
927 .y_max = grouped_intervals_sorted_by_y_[indexes_[
Edge::TOP]].coordinate};
937bool CanConsumeEnergy(
const Rectangle& rectangle,
938 const RectangleInRange& item) {
939 return (rectangle.x_max > item.bounding_area.x_max - item.x_size) &&
940 (rectangle.y_max > item.bounding_area.y_max - item.y_size) &&
941 (rectangle.x_min < item.bounding_area.x_min + item.x_size) &&
942 (rectangle.y_min < item.bounding_area.y_min + item.y_size);
945std::array<bool, 4> GetPossibleEdgeIntersection(
const Rectangle& rectangle,
946 const RectangleInRange& range) {
947 std::array<bool, 4> result;
948 using Edge = ProbingRectangle::Edge;
949 result[Edge::LEFT] = rectangle.x_min >= range.bounding_area.x_min;
950 result[Edge::BOTTOM] = rectangle.y_min >= range.bounding_area.y_min;
951 result[Edge::RIGHT] = rectangle.x_max <= range.bounding_area.x_max;
952 result[Edge::TOP] = rectangle.y_max <= range.bounding_area.y_max;
960void ProbingRectangle::ValidateInvariants()
const {
961 const Rectangle current_rectangle = GetCurrentRectangle();
963 IntegerValue intersect_length[4] = {0, 0, 0, 0};
964 IntegerValue corner_count[4] = {0, 0, 0, 0};
965 IntegerValue energy = 0;
966 CHECK_LE(next_indexes_[Edge::LEFT], indexes_[Edge::RIGHT]);
967 CHECK_LE(next_indexes_[Edge::BOTTOM], indexes_[Edge::TOP]);
968 CHECK_GE(next_indexes_[Edge::TOP], indexes_[Edge::BOTTOM]);
969 CHECK_GE(next_indexes_[Edge::RIGHT], indexes_[Edge::LEFT]);
971 for (
int interval_idx = 0; interval_idx < intervals_.size(); interval_idx++) {
972 const RectangleInRange& range = intervals_[interval_idx];
974 const Rectangle min_intersect =
975 range.GetMinimumIntersection(current_rectangle);
976 CHECK_LE(min_intersect.SizeX(), range.x_size);
977 CHECK_LE(min_intersect.SizeY(), range.y_size);
978 energy += min_intersect.Area();
980 std::array<bool, 4> touching_boundary = {
false,
false,
false,
false};
981 CHECK_EQ(CanConsumeEnergy(current_rectangle, range) &&
982 current_rectangle.Area() != 0,
983 range.GetMinimumIntersectionArea(current_rectangle) != 0);
984 if (CanConsumeEnergy(current_rectangle, range)) {
985 touching_boundary = GetPossibleEdgeIntersection(current_rectangle, range);
989 touching_boundary[Edge::LEFT] && touching_boundary[Edge::RIGHT],
990 ranges_touching_both_boundaries_[Direction::LEFT_AND_RIGHT].contains(
993 touching_boundary[Edge::TOP] && touching_boundary[Edge::BOTTOM],
994 ranges_touching_both_boundaries_[Direction::TOP_AND_BOTTOM].contains(
997 if (touching_boundary[Edge::LEFT] && !touching_boundary[Edge::RIGHT]) {
999 range.bounding_area.y_min, range.bounding_area.y_max, range.y_size,
1000 current_rectangle.y_min, current_rectangle.y_max);
1003 if (touching_boundary[Edge::RIGHT] && !touching_boundary[Edge::LEFT]) {
1005 range.bounding_area.y_min, range.bounding_area.y_max, range.y_size,
1006 current_rectangle.y_min, current_rectangle.y_max);
1009 if (touching_boundary[Edge::TOP] && !touching_boundary[Edge::BOTTOM]) {
1011 range.bounding_area.x_min, range.bounding_area.x_max, range.x_size,
1012 current_rectangle.x_min, current_rectangle.x_max);
1015 if (touching_boundary[Edge::BOTTOM] && !touching_boundary[Edge::TOP]) {
1017 range.bounding_area.x_min, range.bounding_area.x_max, range.x_size,
1018 current_rectangle.x_min, current_rectangle.x_max);
1021 if ((touching_boundary[Edge::LEFT] && touching_boundary[Edge::RIGHT]) ||
1022 (touching_boundary[Edge::TOP] && touching_boundary[Edge::BOTTOM])) {
1027 if (touching_boundary[Edge::BOTTOM] && touching_boundary[Edge::LEFT]) {
1028 corner_count[RectangleInRange::Corner::BOTTOM_LEFT]++;
1030 if (touching_boundary[Edge::BOTTOM] && touching_boundary[Edge::RIGHT]) {
1031 corner_count[RectangleInRange::Corner::BOTTOM_RIGHT]++;
1033 if (touching_boundary[Edge::TOP] && touching_boundary[Edge::LEFT]) {
1034 corner_count[RectangleInRange::Corner::TOP_LEFT]++;
1036 if (touching_boundary[Edge::TOP] && touching_boundary[Edge::RIGHT]) {
1037 corner_count[RectangleInRange::Corner::TOP_RIGHT]++;
1041 CHECK_EQ(energy, minimum_energy_);
1042 for (
int i = 0;
i < 4;
i++) {
1043 CHECK_EQ(intersect_length[i], intersect_length_[i]);
1044 CHECK_EQ(corner_count[i], corner_count_[i]);
1051 using Edge = ProbingRectangle::Edge;
1052 using Direction = ProbingRectangle::Direction;
1053 using Corner = RectangleInRange::Corner;
1057 struct OrthogonalInfo {
1059 Corner adjacent_corner;
1062 Direction shrink_direction;
1063 Direction orthogonal_shrink_direction;
1065 OrthogonalInfo orthogonal_edges[2];
1068struct EdgeInfoHolder {
1069 using Edge = ProbingRectangle::Edge;
1070 using Direction = ProbingRectangle::Direction;
1071 using Corner = RectangleInRange::Corner;
1073 static constexpr EdgeInfo kLeft = {
1074 .opposite_edge = Edge::RIGHT,
1075 .shrink_direction = Direction::LEFT_AND_RIGHT,
1076 .orthogonal_shrink_direction = Direction::TOP_AND_BOTTOM,
1077 .orthogonal_edges = {
1078 {.edge = Edge::BOTTOM, .adjacent_corner = Corner::BOTTOM_LEFT},
1079 {.edge = Edge::TOP, .adjacent_corner = Corner::TOP_LEFT}}};
1081 static constexpr EdgeInfo kRight = {
1082 .opposite_edge = Edge::LEFT,
1083 .shrink_direction = Direction::LEFT_AND_RIGHT,
1084 .orthogonal_shrink_direction = Direction::TOP_AND_BOTTOM,
1085 .orthogonal_edges = {
1086 {.edge = Edge::BOTTOM, .adjacent_corner = Corner::BOTTOM_RIGHT},
1087 {.edge = Edge::TOP, .adjacent_corner = Corner::TOP_RIGHT}}};
1088 static constexpr EdgeInfo kBottom = {
1089 .opposite_edge = Edge::TOP,
1090 .shrink_direction = Direction::TOP_AND_BOTTOM,
1091 .orthogonal_shrink_direction = Direction::LEFT_AND_RIGHT,
1092 .orthogonal_edges = {
1093 {.edge = Edge::LEFT, .adjacent_corner = Corner::BOTTOM_LEFT},
1094 {.edge = Edge::RIGHT, .adjacent_corner = Corner::BOTTOM_RIGHT}}};
1095 static constexpr EdgeInfo kTop = {
1096 .opposite_edge = Edge::BOTTOM,
1097 .shrink_direction = Direction::TOP_AND_BOTTOM,
1098 .orthogonal_shrink_direction = Direction::LEFT_AND_RIGHT,
1099 .orthogonal_edges = {
1100 {.edge = Edge::LEFT, .adjacent_corner = Corner::TOP_LEFT},
1101 {.edge = Edge::RIGHT, .adjacent_corner = Corner::TOP_RIGHT}}};
1104constexpr const EdgeInfo& GetEdgeInfo(ProbingRectangle::Edge edge) {
1105 using Edge = ProbingRectangle::Edge;
1108 return EdgeInfoHolder::kLeft;
1110 return EdgeInfoHolder::kRight;
1112 return EdgeInfoHolder::kBottom;
1114 return EdgeInfoHolder::kTop;
1116 LOG(FATAL) <<
"Invalid edge: " <<
static_cast<int>(edge);
1119IntegerValue GetSmallest1DIntersection(ProbingRectangle::Direction direction,
1120 const RectangleInRange& range,
1121 const Rectangle& rectangle) {
1122 switch (direction) {
1123 case ProbingRectangle::Direction::LEFT_AND_RIGHT:
1125 range.bounding_area.x_max, range.x_size,
1126 rectangle.x_min, rectangle.x_max);
1127 case ProbingRectangle::Direction::TOP_AND_BOTTOM:
1129 range.bounding_area.y_max, range.y_size,
1130 rectangle.y_min, rectangle.y_max);
1132 LOG(FATAL) <<
"Invalid direction: " <<
static_cast<int>(direction);
1137template <ProbingRectangle::Edge edge>
1138void ProbingRectangle::ShrinkImpl() {
1139 constexpr EdgeInfo e = GetEdgeInfo(edge);
1141 bool update_next_index[4] = {
false,
false,
false,
false};
1142 update_next_index[edge] =
true;
1144 IntegerValue step_1d_size;
1145 minimum_energy_ -= GetShrinkDeltaEnergy(edge);
1146 const std::vector<PointsForCoordinate>& sorted_intervals =
1147 e.shrink_direction == Direction::LEFT_AND_RIGHT
1148 ? grouped_intervals_sorted_by_x_
1149 : grouped_intervals_sorted_by_y_;
1151 const Rectangle prev_rectangle = GetCurrentRectangle();
1152 indexes_[edge] = next_indexes_[edge];
1153 const Rectangle current_rectangle = GetCurrentRectangle();
1157 step_1d_size = current_rectangle.x_min - prev_rectangle.x_min;
1158 next_indexes_[edge] =
1159 std::min(indexes_[edge] + 1, indexes_[e.opposite_edge]);
1160 next_indexes_[e.opposite_edge] =
1161 std::max(indexes_[edge], next_indexes_[e.opposite_edge]);
1164 step_1d_size = current_rectangle.y_min - prev_rectangle.y_min;
1165 next_indexes_[edge] =
1166 std::min(indexes_[edge] + 1, indexes_[e.opposite_edge]);
1167 next_indexes_[e.opposite_edge] =
1168 std::max(indexes_[edge], next_indexes_[e.opposite_edge]);
1171 step_1d_size = prev_rectangle.x_max - current_rectangle.x_max;
1172 next_indexes_[edge] =
1173 std::max(indexes_[edge] - 1, indexes_[e.opposite_edge]);
1174 next_indexes_[e.opposite_edge] =
1175 std::min(indexes_[edge], next_indexes_[e.opposite_edge]);
1178 step_1d_size = prev_rectangle.y_max - current_rectangle.y_max;
1179 next_indexes_[edge] =
1180 std::max(indexes_[edge] - 1, indexes_[e.opposite_edge]);
1181 next_indexes_[e.opposite_edge] =
1182 std::min(indexes_[edge], next_indexes_[e.opposite_edge]);
1186 absl::Span<ProbingRectangle::IntervalPoint> items_touching_coordinate =
1187 sorted_intervals[indexes_[edge]].items_touching_coordinate;
1189 IntegerValue delta_corner_count[4] = {0, 0, 0, 0};
1190 for (
const auto& item : items_touching_coordinate) {
1191 const RectangleInRange& range = intervals_[item.index];
1192 if (!CanConsumeEnergy(prev_rectangle, range)) {
1197 const std::array<bool, 4> touching_boundary_before =
1198 GetPossibleEdgeIntersection(prev_rectangle, range);
1199 const std::array<bool, 4> touching_boundary_after =
1200 CanConsumeEnergy(current_rectangle, range)
1201 ? GetPossibleEdgeIntersection(current_rectangle, range)
1202 : std::array<bool, 4>({
false,
false,
false,
false});
1204 bool remove_corner[4] = {
false,
false,
false,
false};
1205 auto erase_item = [
this, &prev_rectangle, &range, &touching_boundary_before,
1206 &remove_corner](Edge edge_to_erase) {
1207 const EdgeInfo& erase_info = GetEdgeInfo(edge_to_erase);
1208 intersect_length_[edge_to_erase] -= GetSmallest1DIntersection(
1209 erase_info.orthogonal_shrink_direction, range, prev_rectangle);
1211 if (touching_boundary_before[erase_info.orthogonal_edges[0].edge] &&
1212 touching_boundary_before[erase_info.orthogonal_edges[1].edge]) {
1216 for (
const auto [orthogonal_edge, corner] : erase_info.orthogonal_edges) {
1217 if (touching_boundary_before[orthogonal_edge]) {
1218 remove_corner[corner] =
true;
1223 if (touching_boundary_after[edge] && !touching_boundary_before[edge]) {
1224 if (touching_boundary_before[e.opposite_edge]) {
1225 ranges_touching_both_boundaries_[e.shrink_direction].insert(item.index);
1226 erase_item(e.opposite_edge);
1229 intersect_length_[edge] += GetSmallest1DIntersection(
1230 e.orthogonal_shrink_direction, range, prev_rectangle);
1232 if (!touching_boundary_before[e.orthogonal_edges[0].edge] ||
1233 !touching_boundary_before[e.orthogonal_edges[1].edge]) {
1234 for (
const auto [orthogonal_edge, corner] : e.orthogonal_edges) {
1235 if (touching_boundary_before[orthogonal_edge]) {
1236 delta_corner_count[corner]++;
1243 for (
int i = 0;
i < 4;
i++) {
1244 const Edge edge_to_update = (Edge)i;
1245 const EdgeInfo& info = GetEdgeInfo(edge_to_update);
1246 const bool remove_edge = touching_boundary_before[edge_to_update] &&
1247 !touching_boundary_after[edge_to_update];
1252 update_next_index[edge_to_update] =
true;
1254 if (touching_boundary_before[info.opposite_edge]) {
1255 ranges_touching_both_boundaries_[info.shrink_direction].erase(
1258 erase_item(edge_to_update);
1262 for (
int i = 0;
i < 4;
i++) {
1263 corner_count_[
i] -= remove_corner[
i];
1268 for (
const int idx : ranges_touching_both_boundaries_[e.shrink_direction]) {
1269 const RectangleInRange& range = intervals_[idx];
1270 const std::array<bool, 2> touching_corner =
1271 (e.shrink_direction == Direction::LEFT_AND_RIGHT)
1272 ? std::array<bool, 2>(
1273 {current_rectangle.y_min >= range.bounding_area.y_min,
1274 current_rectangle.y_max <= range.bounding_area.y_max})
1275 : std::array<bool, 2>(
1276 {current_rectangle.x_min >= range.bounding_area.x_min,
1277 current_rectangle.x_max <= range.bounding_area.x_max});
1278 if (touching_corner[0] == touching_corner[1]) {
1285 const IntegerValue incr =
1286 GetSmallest1DIntersection(e.shrink_direction, range, prev_rectangle) -
1287 GetSmallest1DIntersection(e.shrink_direction, range, current_rectangle);
1288 for (
int i = 0;
i < 2;
i++) {
1289 if (touching_corner[i]) {
1290 intersect_length_[e.orthogonal_edges[
i].edge] -= incr;
1295 for (
const auto [orthogonal_edge, corner] : e.orthogonal_edges) {
1296 intersect_length_[orthogonal_edge] -= corner_count_[corner] * step_1d_size;
1299 for (
int i = 0;
i < 4;
i++) {
1300 corner_count_[
i] += delta_corner_count[
i];
1303 auto points_consume_energy =
1305 ¤t_rectangle](absl::Span<ProbingRectangle::IntervalPoint> points) {
1306 for (
const auto& item : points) {
1307 const RectangleInRange& range = intervals_[item.index];
1308 if (CanConsumeEnergy(current_rectangle, range)) {
1314 if (update_next_index[Edge::LEFT]) {
1315 for (; next_indexes_[Edge::LEFT] < indexes_[Edge::RIGHT];
1316 ++next_indexes_[Edge::LEFT]) {
1317 if (points_consume_energy(
1318 grouped_intervals_sorted_by_x_[next_indexes_[Edge::LEFT]]
1319 .items_touching_coordinate)) {
1324 if (update_next_index[Edge::BOTTOM]) {
1325 for (; next_indexes_[Edge::BOTTOM] < indexes_[Edge::TOP];
1326 ++next_indexes_[Edge::BOTTOM]) {
1327 if (points_consume_energy(
1328 grouped_intervals_sorted_by_y_[next_indexes_[Edge::BOTTOM]]
1329 .items_touching_coordinate)) {
1334 if (update_next_index[Edge::RIGHT]) {
1335 for (; next_indexes_[Edge::RIGHT] > indexes_[Edge::LEFT];
1336 --next_indexes_[Edge::RIGHT]) {
1337 if (points_consume_energy(
1338 grouped_intervals_sorted_by_x_[next_indexes_[Edge::RIGHT]]
1339 .items_touching_coordinate)) {
1344 if (update_next_index[Edge::TOP]) {
1345 for (; next_indexes_[Edge::TOP] > indexes_[Edge::BOTTOM];
1346 --next_indexes_[Edge::TOP]) {
1347 if (points_consume_energy(
1348 grouped_intervals_sorted_by_y_[next_indexes_[Edge::TOP]]
1349 .items_touching_coordinate)) {
1355 probe_area_ = current_rectangle.Area();
1356 CacheShrinkDeltaEnergy(0);
1357 CacheShrinkDeltaEnergy(1);
1360void ProbingRectangle::Shrink(Edge edge) {
1363 ShrinkImpl<Edge::LEFT>();
1366 ShrinkImpl<Edge::BOTTOM>();
1369 ShrinkImpl<Edge::RIGHT>();
1372 ShrinkImpl<Edge::TOP>();
1377IntegerValue ProbingRectangle::GetShrinkDeltaArea(Edge edge)
const {
1378 const Rectangle current_rectangle = GetCurrentRectangle();
1379 const std::vector<PointsForCoordinate>& sorted_intervals =
1381 ? grouped_intervals_sorted_by_x_
1382 : grouped_intervals_sorted_by_y_;
1383 const IntegerValue coordinate =
1384 sorted_intervals[next_indexes_[edge]].coordinate;
1387 return (coordinate - current_rectangle.x_min) * current_rectangle.SizeY();
1389 return (coordinate - current_rectangle.y_min) * current_rectangle.SizeX();
1391 return (current_rectangle.x_max - coordinate) * current_rectangle.SizeY();
1393 return (current_rectangle.y_max - coordinate) * current_rectangle.SizeX();
1395 LOG(FATAL) <<
"Invalid edge: " <<
static_cast<int>(edge);
1398void ProbingRectangle::CacheShrinkDeltaEnergy(
int dimension) {
1399 const Rectangle current_rectangle = GetCurrentRectangle();
1400 Rectangle next_rectangle_up = current_rectangle;
1401 Rectangle next_rectangle_down = current_rectangle;
1402 IntegerValue step_1d_size_up, step_1d_size_down;
1403 IntegerValue units_crossed_up, units_crossed_down;
1404 IntegerValue* delta_energy_up_ptr;
1405 IntegerValue* delta_energy_down_ptr;
1407 if (dimension == 0) {
1409 if (!CanShrink(Edge::LEFT)) {
1410 cached_delta_energy_[Edge::LEFT] = 0;
1411 cached_delta_energy_[Edge::RIGHT] = 0;
1415 next_rectangle_up.x_min =
1416 grouped_intervals_sorted_by_x_[next_indexes_[Edge::LEFT]].coordinate;
1417 next_rectangle_down.x_max =
1418 grouped_intervals_sorted_by_x_[next_indexes_[Edge::RIGHT]].coordinate;
1420 step_1d_size_up = next_rectangle_up.x_min - current_rectangle.x_min;
1421 step_1d_size_down = current_rectangle.x_max - next_rectangle_down.x_max;
1422 units_crossed_up = intersect_length_[Edge::LEFT];
1423 units_crossed_down = intersect_length_[Edge::RIGHT];
1424 delta_energy_up_ptr = &cached_delta_energy_[Edge::LEFT];
1425 delta_energy_down_ptr = &cached_delta_energy_[Edge::RIGHT];
1427 if (!CanShrink(Edge::TOP)) {
1428 cached_delta_energy_[Edge::BOTTOM] = 0;
1429 cached_delta_energy_[Edge::TOP] = 0;
1433 next_rectangle_up.y_min =
1434 grouped_intervals_sorted_by_y_[next_indexes_[Edge::BOTTOM]].coordinate;
1435 next_rectangle_down.y_max =
1436 grouped_intervals_sorted_by_y_[next_indexes_[Edge::TOP]].coordinate;
1438 step_1d_size_up = next_rectangle_up.y_min - current_rectangle.y_min;
1439 step_1d_size_down = current_rectangle.y_max - next_rectangle_down.y_max;
1440 units_crossed_up = intersect_length_[Edge::BOTTOM];
1441 units_crossed_down = intersect_length_[Edge::TOP];
1442 delta_energy_up_ptr = &cached_delta_energy_[Edge::BOTTOM];
1443 delta_energy_down_ptr = &cached_delta_energy_[Edge::TOP];
1445 IntegerValue delta_energy_up = 0;
1446 IntegerValue delta_energy_down = 0;
1449 for (
const int idx : ranges_touching_both_boundaries_[dimension]) {
1450 const RectangleInRange& range = intervals_[idx];
1452 range.bounding_area.x_min, range.bounding_area.x_max, range.x_size,
1453 current_rectangle.x_min, current_rectangle.x_max);
1455 range.bounding_area.y_min, range.bounding_area.y_max, range.y_size,
1456 current_rectangle.y_min, current_rectangle.y_max);
1457 const IntegerValue curr = curr_x * curr_y;
1458 delta_energy_up += curr;
1459 delta_energy_down += curr;
1461 if (dimension == 0) {
1463 range.bounding_area.x_min, range.bounding_area.x_max, range.x_size,
1464 next_rectangle_up.x_min, next_rectangle_up.x_max);
1466 range.bounding_area.x_min, range.bounding_area.x_max, range.x_size,
1467 next_rectangle_down.x_min, next_rectangle_down.x_max);
1469 delta_energy_up -= curr_y * up_x;
1470 delta_energy_down -= curr_y * down_x;
1473 range.bounding_area.y_min, range.bounding_area.y_max, range.y_size,
1474 next_rectangle_up.y_min, next_rectangle_up.y_max);
1476 range.bounding_area.y_min, range.bounding_area.y_max, range.y_size,
1477 next_rectangle_down.y_min, next_rectangle_down.y_max);
1479 delta_energy_up -= curr_x * up_y;
1480 delta_energy_down -= curr_x * down_y;
1483 delta_energy_up += units_crossed_up * step_1d_size_up;
1484 delta_energy_down += units_crossed_down * step_1d_size_down;
1485 *delta_energy_up_ptr = delta_energy_up;
1486 *delta_energy_down_ptr = delta_energy_down;
1489bool ProbingRectangle::CanShrink(Edge edge)
const {
1498 LOG(FATAL) <<
"Invalid edge: " <<
static_cast<int>(edge);
1502std::vector<double> GetExpTable() {
1503 std::vector<double> table(101);
1504 for (
int i = 0; i <= 100; ++i) {
1505 table[i] = std::exp(-(i - 50) / 5.0);
1513 const std::vector<RectangleInRange>& intervals, absl::BitGenRef random,
1514 double temperature,
double candidate_energy_usage_factor) {
1518 static const std::vector<double>* cached_probabilities =
1519 new std::vector<double>(GetExpTable());
1521 const double inv_temp = 1.0 / temperature;
1522 absl::InlinedVector<ProbingRectangle::Edge, 4> candidates;
1523 absl::InlinedVector<IntegerValue, 4> energy_deltas;
1524 absl::InlinedVector<double, 4> weights;
1528 if (min_energy > rect_area) {
1530 }
else if (min_energy.value() >
1531 candidate_energy_usage_factor * rect_area.value()) {
1534 if (min_energy == 0) {
1538 energy_deltas.clear();
1540 for (
int border_idx = 0; border_idx < 4; ++border_idx) {
1546 candidates.push_back(border);
1549 energy_deltas.push_back(delta_energy - delta_area);
1551 const IntegerValue min_energy_delta =
1552 *std::min_element(energy_deltas.begin(), energy_deltas.end());
1554 for (
const IntegerValue delta_slack : energy_deltas) {
1555 const int64_t table_lookup =
1556 std::max((int64_t)0,
1557 std::min((int64_t)((delta_slack - min_energy_delta).value() *
1561 weights.push_back((*cached_probabilities)[table_lookup]);
1572std::string RenderDot(std::optional<Rectangle> bb,
1573 absl::Span<const Rectangle>
solution,
1574 std::string_view extra_dot_payload) {
1575 const std::vector<std::string> colors = {
"#0000ff80",
"#ee00ee80",
1576 "#ff000080",
"#eeee0080",
1577 "#00ff0080",
"#00eeee80"};
1578 std::stringstream ss;
1579 ss <<
"digraph {\n";
1580 ss <<
" graph [ bgcolor=lightgray ]\n";
1581 ss <<
" node [style=filled shape=box]\n";
1582 if (bb.has_value()) {
1583 ss <<
" bb [fillcolor=\"grey\" pos=\"" << 2 * bb->x_min + bb->SizeX()
1584 <<
"," << 2 * bb->y_min + bb->SizeY() <<
"!\" width=" << 2 * bb->SizeX()
1585 <<
" height=" << 2 * bb->SizeY() <<
"]\n";
1588 ss <<
" " <<
i <<
" [fillcolor=\"" << colors[
i % colors.size()]
1591 <<
"!\" width=" << 2 *
solution[
i].SizeX()
1592 <<
" height=" << 2 *
solution[
i].SizeY() <<
"]\n";
1594 ss << extra_dot_payload;
1599std::vector<Rectangle> FindEmptySpaces(
1600 const Rectangle& bounding_box, std::vector<Rectangle> ocupied_rectangles) {
1602 std::sort(ocupied_rectangles.begin(), ocupied_rectangles.end(),
1604 return std::tuple(a.x_min, -a.x_max, a.y_min) <
1605 std::tuple(b.x_min, -b.x_max, b.y_min);
1610std::vector<Rectangle> PavedRegionDifference(
1611 std::vector<Rectangle> original_region,
1612 absl::Span<const Rectangle> area_to_remove) {
1613 std::vector<Rectangle> new_area_to_cover;
1614 new_area_to_cover.reserve(original_region.size());
1615 for (
const Rectangle& rectangle : area_to_remove) {
1616 new_area_to_cover.clear();
1617 for (
const Rectangle& r : original_region) {
1618 const auto& new_rectangles = r.RegionDifference(rectangle);
1619 new_area_to_cover.insert(new_area_to_cover.end(), new_rectangles.begin(),
1620 new_rectangles.end());
1622 original_region.swap(new_area_to_cover);
1623 if (original_region.empty())
break;
1625 return original_region;
1634struct BinaryTreeNode {
1665 void RecomputeConnectedComponents(TreeNodeIndex idx) {
1667 if (node.occupying_box_index != -1) {
1668 node.connected_components_descendants = {
1669 union_find.FindRoot(node.occupying_box_index)};
1672 node.connected_components_descendants.clear();
1673 if (tree.IsLeaf(idx))
return;
1674 for (
const TreeNodeIndex child_idx :
1675 {tree.LeftChild(idx), tree.RightChild(idx)}) {
1679 tree_nodes[child_idx].connected_components_descendants) {
1680 node.connected_components_descendants.insert(union_find.FindRoot(c));
1688 void RemoveNodeIfXMaxLowerOrEqual(TreeNodeIndex idx,
int x_threshold) {
1689 BinaryTreeNode& node = tree_nodes[idx];
1690 if (node.occupying_box_index == -1) {
1694 if (node.occupying_box_x_max > x_threshold) {
1698 node.occupying_box_index = -1;
1699 RecomputeConnectedComponents(idx);
1702 void UpdateChildrenIntersecting(TreeNodeIndex idx,
int sweep_line_x_pos,
1703 int component_index,
1704 std::vector<int>* new_connections) {
1705 if (
tree.IsLeaf(idx))
return;
1706 for (
const TreeNodeIndex child_idx :
1707 {
tree.LeftChild(idx),
tree.RightChild(idx)}) {
1710 if (child_node.occupying_box_index != -1) {
1711 if (
union_find.AddEdge(child_node.occupying_box_index,
1713 new_connections->push_back(child_node.occupying_box_index);
1719 const bool had_different_component =
1720 absl::c_any_of(child_node.connected_components_descendants,
1721 [
this, component_index](
const int c) {
1722 return !union_find.Connected(c, component_index);
1726 child_node.connected_components_descendants = {component_index};
1736 if (had_different_component) {
1743 bool UpdateParents(TreeNodeIndex node,
int sweep_line_x_pos,
1744 int component_index, std::vector<int>* new_connections) {
1745 if (node ==
tree.Root())
return false;
1746 for (TreeNodeIndex parent =
tree.Parent(node); parent !=
tree.Root();
1747 parent =
tree.Parent(parent)) {
1750 if (parent_value.occupying_box_index != -1) {
1751 if (
union_find.AddEdge(parent_value.occupying_box_index,
1753 new_connections->push_back(parent_value.occupying_box_index);
1757 parent_value.connected_components_descendants.insert(component_index);
1766 void AddInterval(TreeNodeIndex idx,
int sweep_line_x_pos,
int box_index,
1767 int x_max, std::vector<int>* new_connections) {
1769 int cur_box_component =
union_find.FindRoot(box_index);
1771 if (node.occupying_box_index == -1) {
1772 node.connected_components_descendants = {box_index};
1773 node.occupying_box_index = box_index;
1774 node.occupying_box_x_max = x_max;
1775 const bool had_occupied_parent = UpdateParents(
1776 idx, sweep_line_x_pos, cur_box_component, new_connections);
1779 if (!had_occupied_parent) {
1780 UpdateChildrenIntersecting(idx, sweep_line_x_pos, cur_box_component,
1785 if (union_find.AddEdge(node.occupying_box_index, cur_box_component)) {
1786 new_connections->push_back(node.occupying_box_index);
1787 cur_box_component = union_find.FindRoot(cur_box_component);
1789 node.connected_components_descendants = {cur_box_component};
1790 if (node.occupying_box_x_max < x_max) {
1792 node.occupying_box_index = box_index;
1793 node.occupying_box_x_max = x_max;
1798 FixedShapeBinaryTree tree;
1799 util_intops::StrongVector<TreeNodeIndex, BinaryTreeNode> tree_nodes;
1814 absl::Span<const Rectangle32> rectangles, int32_t
y_max) {
1820 DCHECK(std::is_sorted(rectangles.begin(), rectangles.end(),
1822 return a.x_min < b.x_min;
1827 std::vector<TreeNodeIndex> interval_pieces;
1828 std::vector<int> new_connections;
1829 std::vector<std::pair<int, int>> arcs;
1830 for (
int rectangle_index = 0; rectangle_index < rectangles.size();
1831 ++rectangle_index) {
1832 DCHECK_LT(rectangles[rectangle_index].x_min,
1833 rectangles[rectangle_index].x_max);
1834 DCHECK_LT(rectangles[rectangle_index].y_min,
1835 rectangles[rectangle_index].y_max);
1836 const int sweep_line_x_pos = rectangles[rectangle_index].x_min;
1837 const Rectangle32& r = rectangles[rectangle_index];
1838 interval_pieces.clear();
1839 interval_tree.tree.PartitionIntervalIntoNodes(
1840 LeafIndex(r.
y_min), LeafIndex(r.
y_max - 1), &interval_pieces);
1841 new_connections.clear();
1842 for (
const TreeNodeIndex& node : interval_pieces) {
1843 interval_tree.AddInterval(node, sweep_line_x_pos, rectangle_index,
1844 r.
x_max, &new_connections);
1846 for (
const int new_connection : new_connections) {
1847 arcs.push_back({rectangles[new_connection].index, r.
index});
1854struct PostProcessedResult {
1855 std::vector<Rectangle32> rectangles_sorted_by_x_min;
1856 std::pair<int32_t, int32_t> bounding_box;
1859PostProcessedResult ConvertToRectangle32WithNonZeroSizes(
1860 absl::Span<const Rectangle> rectangles) {
1909 if (rectangles.empty())
return {};
1916 std::vector<std::tuple<IntegerValue, Event, int>> x_events;
1917 std::vector<std::tuple<IntegerValue, Event, int>> y_events;
1918 x_events.reserve(rectangles.size() * 2);
1919 y_events.reserve(rectangles.size() * 2);
1920 for (
int i = 0;
i < rectangles.size(); ++
i) {
1921 const Rectangle& r = rectangles[
i];
1922 DCHECK_GE(r.SizeX(), 0);
1923 DCHECK_GE(r.SizeY(), 0);
1924 if (r.SizeX() == 0) {
1925 x_events.push_back({r.x_min, Event::kPoint,
i});
1927 x_events.push_back({r.x_min, Event::kBegin,
i});
1928 x_events.push_back({r.x_max, Event::kEnd,
i});
1930 if (r.SizeY() == 0) {
1931 y_events.push_back({r.y_min, Event::kPoint,
i});
1933 y_events.push_back({r.y_min, Event::kBegin,
i});
1934 y_events.push_back({r.y_max, Event::kEnd,
i});
1937 std::sort(y_events.begin(), y_events.end());
1939 std::vector<Rectangle32> rectangles32;
1940 rectangles32.resize(rectangles.size());
1941 IntegerValue prev_y = 0;
1942 Event prev_event = Event::kEnd;
1944 for (
const auto [y, event, index] : y_events) {
1945 if ((prev_event != event && prev_event != Event::kEnd) || prev_y != y ||
1946 event == Event::kPoint || cur_index == -1) {
1952 rectangles32[index].y_min = cur_index;
1953 rectangles32[index].index = index;
1956 rectangles32[index].y_max = cur_index;
1959 rectangles32[index].y_min = cur_index;
1960 rectangles32[index].y_max = cur_index + 1;
1961 rectangles32[index].index = index;
1967 const int max_y_index = cur_index + 1;
1971 std::sort(x_events.begin(), x_events.end());
1972 IntegerValue prev_x = 0;
1973 prev_event = Event::kEnd;
1975 for (
const auto [x, event, index] : x_events) {
1976 if ((prev_event != event && prev_event != Event::kEnd) || prev_x != x ||
1977 event == Event::kPoint || cur_index == -1) {
1983 rectangles32[index].x_min = cur_index;
1986 rectangles32[index].x_max = cur_index;
1989 rectangles32[index].x_min = cur_index;
1990 rectangles32[index].x_max = cur_index + 1;
1996 const int max_x_index = cur_index + 1;
1998 std::vector<Rectangle32> sorted_rectangles32;
1999 sorted_rectangles32.reserve(rectangles.size());
2000 for (
const auto [x, event, index] : x_events) {
2001 if (event == Event::kBegin || event == Event::kPoint) {
2002 sorted_rectangles32.push_back(rectangles32[index]);
2006 return {sorted_rectangles32, {max_x_index, max_y_index}};
2008template <
typename RectangleT>
2009std::optional<std::pair<int, int>> FindOneIntersectionIfPresentImpl(
2010 absl::Span<const RectangleT> rectangles) {
2011 using CoordinateType = std::decay_t<
decltype(RectangleT::x_min)>;
2012 DCHECK(absl::c_is_sorted(rectangles,
2013 [](
const RectangleT& a,
const RectangleT& b) {
2014 return a.x_min <
b.x_min;
2021 CoordinateType y_min;
2022 bool operator<(
const Element& other)
const {
return y_min < other.y_min; }
2027 absl::btree_set<Element> interval_set;
2029 for (
int i = 0;
i < rectangles.size(); ++
i) {
2030 const CoordinateType
x = rectangles[
i].x_min;
2031 const CoordinateType y_min = rectangles[
i].y_min;
2032 const CoordinateType y_max = rectangles[
i].y_max;
2035 DCHECK_LE(y_min, y_max);
2040 auto [it, inserted] = interval_set.insert({
i, y_min});
2042 if (rectangles[it->index].x_max <= x) {
2047 return {{it->index,
i}};
2052 if (it != interval_set.begin()) {
2053 auto it_before = it;
2057 if (rectangles[it_before->index].x_max <= x) {
2060 it = interval_set.erase(it_before);
2062 DCHECK_LE(it_before->y_min, y_min);
2063 const CoordinateType y_max_before =
2064 rectangles[it_before->index].y_max;
2065 if (y_max_before > y_min) {
2067 return {{it_before->index,
i}};
2076 while (it != interval_set.end()) {
2078 if (rectangles[it->index].x_max <= x) {
2079 it = interval_set.erase(it);
2083 DCHECK_LE(y_min, it->y_min);
2084 if (y_max > it->y_min) {
2086 return {{it->index,
i}};
2098 absl::Span<const Rectangle> rectangles) {
2099 auto postprocessed = ConvertToRectangle32WithNonZeroSizes(rectangles);
2101 postprocessed.rectangles_sorted_by_x_min,
2102 postprocessed.bounding_box.second);
2105std::optional<std::pair<int, int>> FindOneIntersectionIfPresent(
2106 absl::Span<const Rectangle> rectangles) {
2107 return FindOneIntersectionIfPresentImpl(rectangles);
2110std::optional<std::pair<int, int>> FindOneIntersectionIfPresentWithZeroArea(
2111 absl::Span<const Rectangle> rectangles) {
2112 auto postprocessed = ConvertToRectangle32WithNonZeroSizes(rectangles);
2113 std::optional<std::pair<int, int>> result = FindOneIntersectionIfPresentImpl(
2114 absl::MakeConstSpan(postprocessed.rectangles_sorted_by_x_min));
2115 if (!result.has_value())
return {};
2116 return {{postprocessed.rectangles_sorted_by_x_min[result->first].index,
2117 postprocessed.rectangles_sorted_by_x_min[result->second].index}};
void AddMandatoryConsumption(IntegerValue x_min, IntegerValue x_max, IntegerValue y_height)
void AddRectangle(IntegerValue x_min, IntegerValue x_max, IntegerValue y_min, IntegerValue y_max)
void BuildResidualCapacityProfile(std::vector< Rectangle > *result)
void ResetFromPairs(const Collection &pairs, int minimum_num_nodes=0)
IntegerValue GetShrinkDeltaEnergy(Edge edge) const
IntegerValue GetCurrentRectangleArea() const
IntegerValue GetMinimumEnergy() const
IntegerValue GetShrinkDeltaArea(Edge edge) const
Rectangle GetCurrentRectangle() const
bool CanShrink(Edge edge) const
void AddPresenceReason(int t)
IntegerValue ShiftedEndMax(int t) const
IntegerValue ShiftedStartMin(int t) const
IntegerValue SizeMin(int t) const
void AddEnergyMinInIntervalReason(int t, IntegerValue min, IntegerValue max)
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
void STLClearObject(T *obj)
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
IntegerValue CeilRatio(IntegerValue dividend, IntegerValue positive_divisor)
CompactVectorVector< int > GetOverlappingRectangleComponents(absl::Span< const Rectangle > rectangles)
absl::Span< int > FilterBoxesAndRandomize(absl::Span< const 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, absl::Span< const Rectangle > rectangles, absl::Span< const IntegerValue > rectangle_energies, IntegerValue *x_threshold, IntegerValue *y_threshold, Rectangle *conflict)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
absl::Span< int > FilterBoxesThatAreTooLarge(absl::Span< const Rectangle > cached_rectangles, absl::Span< const IntegerValue > energies, absl::Span< int > boxes)
std::vector< int > GetIntervalArticulationPoints(std::vector< IndexedInterval > *intervals)
void AppendPairwiseRestrictions(absl::Span< const ItemWithVariableSize > items, std::vector< PairwiseRestriction > *result)
void ConstructOverlappingSets(absl::Span< IndexedInterval > intervals, CompactVectorVector< int > *result, absl::Span< const int > order)
int WeightedPick(absl::Span< const double > input, absl::BitGenRef random)
bool ReportEnergyConflict(Rectangle bounding_box, absl::Span< const int > boxes, SchedulingConstraintHelper *x, SchedulingConstraintHelper *y)
std::vector< std::pair< int, int > > FindPartialRectangleIntersectionsImpl(absl::Span< const Rectangle32 > rectangles, int32_t y_max)
FindRectanglesResult FindRectanglesWithEnergyConflictMC(const std::vector< RectangleInRange > &intervals, absl::BitGenRef random, double temperature, double candidate_energy_usage_factor)
std::vector< Rectangle > PavedRegionDifference(std::vector< Rectangle > original_region, absl::Span< const Rectangle > area_to_remove)
bool BoxesAreInEnergyConflict(absl::Span< const Rectangle > rectangles, absl::Span< const IntegerValue > energies, absl::Span< const int > boxes, Rectangle *conflict)
std::vector< std::pair< int, int > > FindPartialRectangleIntersections(absl::Span< const Rectangle > rectangles)
IntegerValue Smallest1DIntersection(IntegerValue range_min, IntegerValue range_max, IntegerValue size, IntegerValue interval_min, IntegerValue interval_max)
void GetOverlappingIntervalComponents(std::vector< IndexedInterval > *intervals, std::vector< std::vector< int > > *components)
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
ClosedInterval::Iterator end(ClosedInterval interval)
void FindStronglyConnectedComponents(NodeIndex num_nodes, const Graph &graph, SccOutput *components)
absl::flat_hash_set< int > connected_components_descendants
std::vector< Rectangle > conflicts
std::vector< Rectangle > candidates
void GrowToInclude(const Rectangle &other)
absl::InlinedVector< Rectangle, 4 > RegionDifference(const Rectangle &other) const
IntegerValue SizeX() const
bool IsDisjoint(const Rectangle &other) const
Rectangle Intersect(const Rectangle &other) const
DenseConnectedComponentsFinder union_find
void RemoveNodeIfXMaxLowerOrEqual(TreeNodeIndex idx, int x_threshold)
void UpdateChildrenIntersecting(TreeNodeIndex idx, int sweep_line_x_pos, int component_index, std::vector< int > *new_connections)
FixedShapeBinaryTree tree
util_intops::StrongVector< TreeNodeIndex, BinaryTreeNode > tree_nodes