21#include "absl/base/log_severity.h"
22#include "absl/base/optimization.h"
23#include "absl/log/check.h"
24#include "absl/log/log.h"
25#include "absl/types/span.h"
39 bool x_is_forward_after_swap,
bool y_is_forward_after_swap,
41 if (axes_are_swapped_ != swap_x_and_y) {
42 std::swap(x_helper_, y_helper_);
43 std::swap(x_demands_helper_, y_demands_helper_);
44 axes_are_swapped_ = !axes_are_swapped_;
46 if (!x_helper_->SynchronizeAndSetTimeDirection(x_is_forward_after_swap))
48 if (!y_helper_->SynchronizeAndSetTimeDirection(y_is_forward_after_swap))
54 if (x_demands_helper_ ==
nullptr) {
55 x_demands_helper_ = std::make_unique<SchedulingDemandHelper>(
56 x_helper_->Sizes(), y_helper_.get(), model_);
58 return *x_demands_helper_;
62 if (y_demands_helper_ ==
nullptr) {
63 y_demands_helper_ = std::make_unique<SchedulingDemandHelper>(
64 y_helper_->Sizes(), x_helper_.get(), model_);
66 return *y_demands_helper_;
73 .bounding_area = {.x_min = x_helper_->StartMin(index),
74 .x_max = x_helper_->StartMax(index) +
75 x_helper_->SizeMin(index),
76 .y_min = y_helper_->StartMin(index),
77 .y_max = y_helper_->StartMax(index) +
78 y_helper_->SizeMin(index)},
79 .x_size = x_helper_->SizeMin(index),
80 .y_size = y_helper_->SizeMin(index)};
86 .x = {.start_min = x_helper_->StartMin(index),
87 .start_max = x_helper_->StartMax(index),
88 .end_min = x_helper_->EndMin(index),
89 .end_max = x_helper_->EndMax(index)},
90 .y = {.start_min = y_helper_->StartMin(index),
91 .start_max = y_helper_->StartMax(index),
92 .end_min = y_helper_->EndMin(index),
93 .end_max = y_helper_->EndMax(index)}};
97void ClearAndAddMandatoryOverlapReason(
int box1,
int box2,
109 DCHECK_NE(box1, box2);
111 std::vector<PairwiseRestriction> restrictions;
114 DCHECK_EQ(restrictions.size(), 1);
115 DCHECK(restrictions[0].type ==
118 ClearAndAddMandatoryOverlapReason(box1, box2, x_helper_.get());
119 ClearAndAddMandatoryOverlapReason(box1, box2, y_helper_.get());
120 x_helper_->ImportReasonsFromOther(*y_helper_);
121 return x_helper_->ReportConflict();
125 absl::Span<const RectangleInRange> ranges) {
126 if (ranges.size() == 2) {
129 x_helper_->ResetReason();
130 y_helper_->ResetReason();
131 for (
const auto& range : ranges) {
132 const int b = range.box_index;
134 x_helper_->AddStartMinReason(
b, range.bounding_area.x_min);
135 y_helper_->AddStartMinReason(
b, range.bounding_area.y_min);
137 x_helper_->AddStartMaxReason(
b, range.bounding_area.x_max - range.x_size);
138 y_helper_->AddStartMaxReason(
b, range.bounding_area.y_max - range.y_size);
140 x_helper_->AddSizeMinReason(
b);
141 y_helper_->AddSizeMinReason(
b);
143 x_helper_->AddPresenceReason(
b);
144 y_helper_->AddPresenceReason(
b);
146 x_helper_->ImportReasonsFromOther(*y_helper_);
147 return x_helper_->ReportConflict();
158bool LeftBoxBeforeRightBoxOnFirstDimension(
int left,
int right,
162 x->AddPresenceReason(left);
163 x->AddPresenceReason(right);
164 x->AddReasonForBeingBeforeAssumingNoOverlap(left, right);
166 ClearAndAddMandatoryOverlapReason(left, right, y);
168 x->ImportReasonsFromOther(*y);
169 return x->PushTaskOrderWhenPresent(left, right);
180 return LeftBoxBeforeRightBoxOnFirstDimension(
181 first, second, x_helper_.get(), y_helper_.get());
183 return LeftBoxBeforeRightBoxOnFirstDimension(
184 second, first, x_helper_.get(), y_helper_.get());
186 return LeftBoxBeforeRightBoxOnFirstDimension(
187 first, second, y_helper_.get(), x_helper_.get());
189 return LeftBoxBeforeRightBoxOnFirstDimension(
190 second, first, y_helper_.get(), x_helper_.get());
195void NoOverlap2DConstraintHelper::Reset(
196 absl::Span<const Rectangle> fixed_boxes,
197 absl::Span<const int> non_fixed_box_indexes) {
198 inprocessing_count_++;
199 std::vector<AffineExpression> x_starts;
200 std::vector<AffineExpression> x_ends;
201 std::vector<AffineExpression> x_sizes;
202 std::vector<LiteralIndex> x_reason_for_presence;
203 std::vector<AffineExpression> y_starts;
204 std::vector<AffineExpression> y_ends;
205 std::vector<AffineExpression> y_sizes;
206 std::vector<LiteralIndex> y_reason_for_presence;
208 auto add_non_fixed_box = [&](
int box_index) {
209 x_starts.push_back(x_helper_->Starts()[box_index]);
210 x_ends.push_back(x_helper_->Ends()[box_index]);
211 x_sizes.push_back(x_helper_->Sizes()[box_index]);
212 if (x_helper_->IsOptional(box_index)) {
213 x_reason_for_presence.push_back(x_helper_->PresenceLiteral(box_index));
218 y_starts.push_back(y_helper_->Starts()[box_index]);
219 y_ends.push_back(y_helper_->Ends()[box_index]);
220 y_sizes.push_back(y_helper_->Sizes()[box_index]);
221 if (y_helper_->IsOptional(box_index)) {
222 y_reason_for_presence.push_back(y_helper_->PresenceLiteral(box_index));
227 return x_starts.size() - 1;
230 auto add_fixed_box = [&](
const Rectangle& box) {
231 x_starts.push_back(AffineExpression(box.x_min));
232 x_ends.push_back(AffineExpression(box.x_max));
233 x_sizes.push_back(box.SizeX());
236 y_starts.push_back(AffineExpression(box.y_min));
237 y_ends.push_back(AffineExpression(box.y_max));
238 y_sizes.push_back(box.SizeY());
241 return x_starts.size() - 1;
244 std::vector<Rectangle> active_bounding_boxes;
245 std::vector<std::tuple<int, bool>> active_box_indexes;
246 int new_num_boxes = fixed_boxes.size() + non_fixed_box_indexes.size();
247 active_bounding_boxes.reserve(new_num_boxes);
248 active_box_indexes.reserve(new_num_boxes);
249 for (
int box : non_fixed_box_indexes) {
251 active_box_indexes.push_back({box,
false});
253 for (
int box = 0; box < fixed_boxes.size(); ++box) {
254 active_bounding_boxes.push_back(fixed_boxes[box]);
255 active_box_indexes.push_back({box,
true});
257 CompactVectorVector<int> components =
259 connected_components_.clear();
260 for (absl::Span<const int> component : components.AsVectorOfSpan()) {
261 if (component.size() < 2)
continue;
262 connected_components_.Add({});
263 for (
int idx : component) {
264 const auto [box_idx, is_fixed] = active_box_indexes[idx];
267 new_index = add_fixed_box(fixed_boxes[box_idx]);
269 new_index = add_non_fixed_box(box_idx);
271 connected_components_.AppendToLastVector(new_index);
274 const int old_num_boxes =
NumBoxes();
276 if (old_num_boxes != connected_components_.num_entries()) {
277 VLOG_EVERY_N_SEC(1, 1) <<
"Total boxes: "
278 << connected_components_.num_entries()
279 <<
" connected components: "
280 << connected_components_.size()
281 <<
" dropped single box components: "
283 connected_components_.num_entries();
285 VLOG_EVERY_N_SEC(1, 2) <<
"No_overlap_2d helper inprocessing: "
286 << connected_components_.size() <<
" components and "
287 << connected_components_.num_entries() <<
" boxes";
289 x_helper_ = std::make_unique<SchedulingConstraintHelper>(
290 std::move(x_starts), std::move(x_ends), std::move(x_sizes),
291 std::move(x_reason_for_presence), model_);
292 y_helper_ = std::make_unique<SchedulingConstraintHelper>(
293 std::move(y_starts), std::move(y_ends), std::move(y_sizes),
294 std::move(y_reason_for_presence), model_);
295 x_helper_->SetEnforcementId(enforcement_id_);
296 y_helper_->SetEnforcementId(enforcement_id_);
297 x_demands_helper_ =
nullptr;
298 y_demands_helper_ =
nullptr;
302 return enforcement_helper_.Status(enforcement_id_) ==
308 for (
const int id : propagators_watching_) {
309 watcher_->CallOnNextPropagate(
id);
311 if (!x_helper_->Propagate() || !y_helper_->Propagate())
return false;
313 if (x_helper_->CurrentDecisionLevel() == 0) {
314 ++level_zero_bound_change_idx_;
322 std::vector<Rectangle> fixed_boxes;
323 std::vector<int> non_fixed_box_indexes;
324 std::vector<RectangleInRange> non_fixed_boxes;
325 fixed_boxes.reserve(num_boxes);
326 non_fixed_box_indexes.reserve(num_boxes);
327 non_fixed_boxes.reserve(num_boxes);
328 bool has_zero_area_boxes =
false;
329 for (
int box_index = 0; box_index < num_boxes; ++box_index) {
330 if (x_helper_->IsAbsent(box_index) || y_helper_->IsAbsent(box_index)) {
333 if (x_helper_->SizeMin(box_index) == 0 ||
334 y_helper_->SizeMin(box_index) == 0) {
335 has_zero_area_boxes =
true;
338 non_fixed_boxes.push_back(
340 .x_size = x_helper_->SizeMin(box_index),
341 .y_size = y_helper_->SizeMin(box_index)});
342 non_fixed_box_indexes.push_back(box_index);
348 const int original_num_fixed_boxes = fixed_boxes.size();
349 if (!non_fixed_boxes.empty() && !has_zero_area_boxes) {
355 if (fixed_boxes.size() != original_num_fixed_boxes) {
356 VLOG_EVERY_N_SEC(1, 1) <<
"Num_boxes: " << num_boxes
357 <<
" fixed_before: " << original_num_fixed_boxes
358 <<
" fixed_after: " << fixed_boxes.size();
360 Reset(fixed_boxes, non_fixed_box_indexes);
367 absl::Span<const Literal> enforcement_literals) {
368 const int id = watcher->
Register(
this);
370 for (
int b = 0;
b < num_boxes; ++
b) {
371 if (x_helper_->IsOptional(
b)) {
374 if (y_helper_->IsOptional(
b)) {
386 enforcement_helper_.Register(enforcement_literals, watcher,
id);
387 x_helper_->SetEnforcementId(enforcement_id_);
388 y_helper_->SetEnforcementId(enforcement_id_);
void WatchLiteral(Literal l, int id, int watch_index=-1)
void SetPropagatorPriority(int id, int priority)
void WatchIntegerVariable(IntegerVariable i, int id, int watch_index=-1)
int Register(PropagatorInterface *propagator)
bool ReportConflictFromTwoBoxes(int box1, int box2)
void RegisterWith(GenericLiteralWatcher *watcher, absl::Span< const Literal > enforcement_literals)
SchedulingDemandHelper & y_demands_helper()
bool SynchronizeAndSetDirection(bool x_is_forward_after_swap=true, bool y_is_forward_after_swap=true, bool swap_x_and_y=false)
bool IsFixed(int index) const
bool ReportConflictFromInfeasibleBoxRanges(absl::Span< const RectangleInRange > ranges)
bool IsOptional(int index) const
bool Propagate() override
ItemWithVariableSize GetItemWithVariableSize(int index) const
Rectangle GetBoundingRectangle(int index) const
bool PropagateRelativePosition(int first, int second, PairwiseRestriction::PairwiseRestrictionType type)
SchedulingDemandHelper & x_demands_helper()
RectangleInRange GetItemRangeForSizeMin(int index) const
void AddPresenceReason(int t)
void AddReasonForBeingBeforeAssumingNoOverlap(int before, int after)
const LiteralIndex kNoLiteralIndex(-1)
CompactVectorVector< int > GetOverlappingRectangleComponents(absl::Span< const Rectangle > rectangles)
void AppendPairwiseRestrictions(absl::Span< const ItemWithVariableSize > items, std::vector< PairwiseRestriction > *result)
std::vector< std::pair< int, int > > FindPartialRectangleIntersections(absl::Span< const Rectangle > rectangles)
bool PresolveFixed2dRectangles(absl::Span< const RectangleInRange > non_fixed_boxes, std::vector< Rectangle > *fixed_boxes)