139 if (!helper_.IsEnforced())
return true;
140 if (!helper_.SynchronizeAndSetDirection(
141 x_is_forward_after_swap_, y_is_forward_after_swap_, swap_x_and_y_)) {
147 PopulateActiveBoxRanges();
159 for (
int i = 0;
i < num_active_ranges;
i++) {
173 potential_x_positions_.clear();
174 potential_y_positions_.clear();
177 potential_x_positions_.push_back(mandatory_region.
x_max);
178 potential_y_positions_.push_back(mandatory_region.
y_max);
184 std::vector<std::pair<int, std::optional<IntegerValue>>> found_propagations;
199 bool placed_at_x_min =
false;
202 potential_y_positions_.begin();
203 for (
int j = y_start; j < potential_y_positions_.size(); ++j) {
209 placed_at_x_min =
true;
212 .y_min = potential_y_positions_[j],
213 .y_max = potential_y_positions_[j] + box.
y_size};
218 if (placed_at_x_min)
continue;
225 std::optional<IntegerValue> new_x_min = std::nullopt;
226 for (
int j = 0; j < potential_x_positions_.size(); ++j) {
234 new_x_min = potential_x_positions_[j];
237 for (
int k = y_start; k < potential_y_positions_.size(); ++k) {
238 const IntegerValue potential_y_position = potential_y_positions_[k];
242 if (CanPlace(
i, {potential_x_positions_[j], potential_y_position})) {
245 new_x_min = potential_x_positions_[j];
249 if (new_x_min.has_value()) {
253 found_propagations.push_back({
i, new_x_min});
260 int box_index, IntegerValue new_x_min) {
276 potential_y_positions_.begin();
277 conflicts_per_x_and_y_.clear();
279 &conflicts_per_x_and_y_));
280 for (
int j = y_start; j < potential_y_positions_.size(); ++j) {
285 CHECK(!CanPlace(box_index,
287 &conflicts_per_x_and_y_));
289 for (
int j = 0; j < potential_x_positions_.size(); ++j) {
293 if (potential_x_positions_[j] >= new_x_min) {
296 CHECK(!CanPlace(box_index,
298 &conflicts_per_x_and_y_));
299 for (
int k = y_start; k < potential_y_positions_.size(); ++k) {
300 const IntegerValue potential_y_position = potential_y_positions_[k];
304 CHECK(!CanPlace(box_index,
305 {potential_x_positions_[j], potential_y_position},
306 &conflicts_per_x_and_y_));
314 std::vector<std::vector<int>> conflicting_position_per_box(
316 for (
int i = 0;
i < conflicts_per_x_and_y_.size(); ++
i) {
317 DCHECK(!conflicts_per_x_and_y_[
i].empty());
318 for (
const int j : conflicts_per_x_and_y_[
i]) {
319 conflicting_position_per_box[j].push_back(
i);
323 for (
const auto& conflicts : conflicting_position_per_box) {
324 if (conflicts.empty())
continue;
326 for (
const int i : conflicts) {
336 GuidedLocalSearch search(&inv);
337 CHECK(search.SetMaxIterations(100).NextSolution());
343 std::vector<int> boxes_participating_in_propagation;
344 boxes_participating_in_propagation.reserve(model.
num_subsets() + 1);
345 boxes_participating_in_propagation.push_back(box_index);
346 for (
int i = 0;
i < conflicting_position_per_box.size(); ++
i) {
347 const auto& conflicts = conflicting_position_per_box[
i];
348 if (conflicts.empty())
continue;
350 boxes_participating_in_propagation.push_back(
i);
354 VLOG_EVERY_N_SEC(3, 2) <<
"Found no_overlap_2d constraint propagation with "
355 << boxes_participating_in_propagation.size() <<
"/"
364 return boxes_participating_in_propagation;
368 const std::vector<std::pair<
int, std::optional<IntegerValue>>>&
369 found_propagations) {
370 for (
const auto& [box_index, new_x_min] : found_propagations) {
372 helper_.ResetReason();
374 const std::vector<int> minimum_problem_with_propagator =
376 box_index, new_x_min.has_value()
379 for (
const int j : minimum_problem_with_propagator) {
391 if (j != box_index || !new_x_min.has_value()) {
394 helper_.AddLeftMaxReason(
397 helper_.AddBottomMaxReason(
400 helper_.AddSizeMinReason(
b);
401 helper_.AddPresenceReason(
b);
403 if (new_x_min.has_value()) {
405 if (!helper_.IncreaseLeftMin(box_index, *new_x_min)) {
410 return helper_.ReportConflict();