18 #include "absl/container/flat_hash_map.h"
19 #include "absl/strings/str_join.h"
37 void AddIsEqualToMinOf(IntegerVariable min_var,
38 const std::vector<AffineExpression>& exprs,
40 std::vector<LinearExpression> converted;
41 for (
const AffineExpression& affine : exprs) {
43 e.offset = affine.constant;
45 e.vars.push_back(affine.var);
46 e.coeffs.push_back(affine.coeff);
48 converted.push_back(e);
50 LinearExpression target;
51 target.vars.push_back(min_var);
52 target.coeffs.push_back(IntegerValue(1));
56 void AddIsEqualToMaxOf(IntegerVariable max_var,
57 const std::vector<AffineExpression>& exprs,
59 std::vector<LinearExpression> converted;
60 for (
const AffineExpression& affine : exprs) {
62 e.offset = affine.constant;
64 e.vars.push_back(affine.var);
65 e.coeffs.push_back(affine.coeff);
69 LinearExpression target;
71 target.coeffs.push_back(IntegerValue(1));
82 std::vector<AffineExpression> sizes;
83 for (
int box = 0; box < y->
NumTasks(); ++box) {
86 sizes.push_back(y->
Sizes()[box]);
89 const IntegerVariable min_start_var =
91 AddIsEqualToMinOf(min_start_var, y->
Starts(),
model);
93 const IntegerVariable max_end_var =
95 AddIsEqualToMaxOf(max_end_var, y->
Ends(),
model);
100 const std::vector<int64> coeffs = {-
capacity.coeff.value(), -1, 1};
103 coeffs,
capacity.constant.value()));
114 IntegerValue FindCanonicalValue(IntegerValue lb, IntegerValue ub) {
115 if (lb == ub)
return lb;
116 if (lb <= 0 && ub > 0)
return IntegerValue(0);
117 if (lb < 0 && ub <= 0) {
118 return -FindCanonicalValue(-ub, -lb);
122 IntegerValue candidate = ub;
123 for (
int o = 0; o < 62; ++o) {
125 const IntegerValue masked_ub(ub.value() & ~mask);
126 if (masked_ub >= lb) {
127 candidate = masked_ub;
135 void SplitDisjointBoxes(
const SchedulingConstraintHelper& x,
136 absl::Span<int> boxes,
137 std::vector<absl::Span<int>>* result) {
139 std::sort(boxes.begin(), boxes.end(),
140 [&x](
int a,
int b) { return x.StartMin(a) < x.StartMin(b); });
141 int current_start = 0;
142 std::size_t current_length = 1;
143 IntegerValue current_max_end = x.EndMax(boxes[0]);
145 for (
int b = 1;
b < boxes.size(); ++
b) {
146 const int box = boxes[
b];
147 if (x.StartMin(box) < current_max_end) {
150 current_max_end =
std::max(current_max_end, x.EndMax(box));
152 if (current_length > 1) {
153 result->emplace_back(&boxes[current_start], current_length);
157 current_max_end = x.EndMax(box);
162 if (current_length > 1) {
163 result->emplace_back(&boxes[current_start], current_length);
169 #define RETURN_IF_FALSE(f) \
170 if (!(f)) return false;
176 const int num_boxes = x_.
NumTasks();
180 active_boxes_.clear();
181 cached_areas_.resize(num_boxes);
182 cached_dimensions_.resize(num_boxes);
183 for (
int box = 0; box < num_boxes; ++box) {
185 if (cached_areas_[box] == 0)
continue;
188 Dimension& dimension = cached_dimensions_[box];
190 dimension.x_max = x_.
EndMax(box);
192 dimension.y_max = y_.
EndMax(box);
194 active_boxes_.push_back(box);
196 if (active_boxes_.size() <= 1)
return true;
198 SplitDisjointBoxes(x_, absl::MakeSpan(active_boxes_), &x_split_);
199 for (absl::Span<int> x_boxes : x_split_) {
200 SplitDisjointBoxes(y_, x_boxes, &y_split_);
201 for (absl::Span<int> y_boxes : y_split_) {
202 IntegerValue total_sum_of_areas(0);
203 for (
const int box : y_boxes) {
204 total_sum_of_areas += cached_areas_[box];
206 for (
const int box : y_boxes) {
208 FailWhenEnergyIsTooLarge(box, y_boxes, total_sum_of_areas));
218 const int id = watcher->
Register(
this);
226 void NonOverlappingRectanglesEnergyPropagator::SortBoxesIntoNeighbors(
227 int box, absl::Span<const int> local_boxes,
228 IntegerValue total_sum_of_areas) {
229 const Dimension& box_dim = cached_dimensions_[box];
232 for (
const int other_box : local_boxes) {
233 if (other_box == box)
continue;
234 const Dimension& other_dim = cached_dimensions_[other_box];
235 const IntegerValue span_x =
std::max(box_dim.x_max, other_dim.x_max) -
236 std::min(box_dim.x_min, other_dim.x_min);
237 const IntegerValue span_y =
std::max(box_dim.y_max, other_dim.y_max) -
238 std::min(box_dim.y_min, other_dim.y_min);
239 const IntegerValue bounding_area = span_x * span_y;
240 if (bounding_area < total_sum_of_areas) {
241 neighbors_.push_back({other_box, bounding_area});
244 std::sort(neighbors_.begin(), neighbors_.end());
247 bool NonOverlappingRectanglesEnergyPropagator::FailWhenEnergyIsTooLarge(
248 int box, absl::Span<const int> local_boxes,
249 IntegerValue total_sum_of_areas) {
250 SortBoxesIntoNeighbors(box, local_boxes, total_sum_of_areas);
252 Dimension area = cached_dimensions_[box];
253 IntegerValue sum_of_areas = cached_areas_[box];
255 const auto add_box_energy_in_rectangle_reason = [&](
int b) {
262 for (
int i = 0; i < neighbors_.size(); ++i) {
263 const int other_box = neighbors_[i].box;
264 CHECK_GT(cached_areas_[other_box], 0);
267 area.TakeUnionWith(cached_dimensions_[other_box]);
270 sum_of_areas += cached_areas_[other_box];
271 const IntegerValue bounding_area =
272 (area.x_max - area.x_min) * (area.y_max - area.y_min);
273 if (bounding_area >= total_sum_of_areas) {
278 if (sum_of_areas > bounding_area) {
281 add_box_energy_in_rectangle_reason(box);
282 for (
int j = 0; j <= i; ++j) {
283 add_box_energy_in_rectangle_reason(neighbors_[j].box);
301 x_(x->NumTasks(),
model),
302 y_(y->NumTasks(),
model),
305 overload_checker_(&x_),
306 forward_detectable_precedences_(true, &x_),
307 backward_detectable_precedences_(false, &x_),
308 forward_not_last_(true, &x_),
309 backward_not_last_(false, &x_),
310 forward_edge_finding_(true, &x_),
311 backward_edge_finding_(false, &x_) {}
317 int fast_priority,
int slow_priority) {
318 fast_id_ = watcher_->
Register(
this);
323 const int slow_id = watcher_->
Register(
this);
329 bool NonOverlappingRectanglesDisjunctivePropagator::
330 FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
333 std::function<
bool()> inner_propagate) {
335 active_boxes_.clear();
336 events_time_.clear();
337 for (
int box = 0; box < x.
NumTasks(); ++box) {
346 active_boxes_.push_back(box);
351 if (active_boxes_.size() < 2)
return true;
355 events_overlapping_boxes_.resize(events_time_.size());
356 for (
int i = 0; i < events_time_.size(); ++i) {
357 events_overlapping_boxes_[i].clear();
359 for (
const int box : active_boxes_) {
363 for (
int i = 0; i < events_time_.size(); ++i) {
364 const IntegerValue t = events_time_[i];
367 events_overlapping_boxes_[i].push_back(box);
379 for (std::vector<int>& overlapping_boxes : events_overlapping_boxes_) {
380 if (overlapping_boxes.size() < 2) {
384 const std::vector<int>& previous_overlapping_boxes =
385 events_overlapping_boxes_[new_size - 1];
393 if (std::includes(overlapping_boxes.begin(), overlapping_boxes.end(),
394 previous_overlapping_boxes.begin(),
395 previous_overlapping_boxes.end())) {
400 std::swap(events_overlapping_boxes_[new_size], overlapping_boxes);
406 boxes_to_propagate_.clear();
407 reduced_overlapping_boxes_.clear();
408 for (
int i = 0; i < new_size; ++i) {
409 SplitDisjointBoxes(x, absl::MakeSpan(events_overlapping_boxes_[i]),
411 for (absl::Span<int> sub_boxes : disjoint_boxes_) {
415 const auto& insertion = reduced_overlapping_boxes_.insert(sub_boxes);
416 if (insertion.second) boxes_to_propagate_.push_back(sub_boxes);
422 for (
const absl::Span<const int> boxes : boxes_to_propagate_) {
429 for (
int i = 0; i < y_.
NumTasks(); ++i) {
443 const IntegerValue line_to_use_for_reason = FindCanonicalValue(lb, ub);
458 std::function<bool()> inner_propagate;
460 inner_propagate = [
this]() {
474 inner_propagate = [
this]() {
475 if (x_.
NumTasks() <= 2)
return true;
485 global_x_, global_y_, inner_propagate));
489 global_y_, global_x_, inner_propagate));
496 bool NonOverlappingRectanglesDisjunctivePropagator::PropagateTwoBoxes() {
501 const auto left_box_before_right_box = [
this](
int left,
int right) {
503 const IntegerValue left_end_min = x_.
EndMin(left);
504 if (left_end_min > x_.
StartMin(right)) {
512 const IntegerValue right_start_max = x_.
StartMax(right);
513 if (right_start_max < x_.
EndMax(left)) {
531 return left_box_before_right_box(0, 1);
534 return left_box_before_right_box(1, 0);
542 #undef RETURN_IF_FALSE