Skip to content

Commit 3aaff5b

Browse files
committed
[CP-SAT] more work on 2d packing
1 parent dba2281 commit 3aaff5b

File tree

5 files changed

+54
-32
lines changed

5 files changed

+54
-32
lines changed

ortools/sat/2d_rectangle_presolve.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ bool PresolveFixed2dRectangles(
5959
}
6060

6161
const int original_num_boxes = fixed_boxes->size();
62+
63+
// The greedy algorithm is really fast. Run it first since it might greatly
64+
// reduce the size of large trivial instances.
65+
std::vector<Rectangle> empty_vec;
66+
if (ReduceNumberofBoxesGreedy(fixed_boxes, &empty_vec)) {
67+
changed = true;
68+
}
69+
6270
IntegerValue min_x_size = std::numeric_limits<IntegerValue>::max();
6371
IntegerValue min_y_size = std::numeric_limits<IntegerValue>::max();
6472

ortools/sat/cp_model_presolve.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3883,6 +3883,21 @@ bool CpModelPresolver::PropagateDomainsInLinear(int ct_index,
38833883
}
38843884
if (fixed) {
38853885
context_->UpdateRuleStats("linear: tightened into equality");
3886+
// Compute a new `var` hint so that the lhs of `ct` is equal to `rhs`.
3887+
int64_t var_hint = rhs.FixedValue();
3888+
bool var_hint_is_valid = true;
3889+
for (int j = 0; j < num_vars; ++j) {
3890+
if (j == i) continue;
3891+
const int term_var = ct->linear().vars(j);
3892+
if (!context_->VarHasSolutionHint(term_var)) {
3893+
var_hint_is_valid = false;
3894+
break;
3895+
}
3896+
var_hint -= context_->SolutionHint(term_var) * ct->linear().coeffs(j);
3897+
}
3898+
if (var_hint_is_valid) {
3899+
context_->UpdateRefSolutionHint(var, var_hint / var_coeff);
3900+
}
38863901
FillDomainInProto(rhs, ct->mutable_linear());
38873902
negated_rhs = rhs.Negation();
38883903

ortools/sat/diffn_util.cc

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2015,38 +2015,36 @@ absl::optional<std::pair<int, int>> FindOneIntersectionIfPresent(
20152015
return a.x_min < b.x_min;
20162016
}));
20172017

2018-
// Current y-coordinate intervals that are intersecting the sweep line.
2019-
// Note that the interval_set only contains disjoint intervals.
2020-
struct Interval {
2021-
int index;
2018+
// Set of box intersection the sweep line. We only store y_min, other
2019+
// coordinates can be accessed via rectangles[index].coordinate.
2020+
struct Element {
2021+
mutable int index;
20222022
IntegerValue y_min;
2023-
IntegerValue y_max;
2024-
2025-
// IMPORTANT: For correctness, we need later insert to be first!
2026-
bool operator<(const Interval& other) const {
2027-
if (y_min == other.y_min) return index > other.index;
2028-
return y_min < other.y_min;
2029-
}
2030-
2031-
std::string to_string() const {
2032-
return absl::StrCat("[", y_min.value(), ",", y_max.value(), "](", index,
2033-
")");
2034-
}
2023+
bool operator<(const Element& other) const { return y_min < other.y_min; }
20352024
};
2036-
2037-
// TODO(user): Use fixed binary tree instead, it should be faster.
2038-
// We just need insert/erase/previous/next API.
2039-
std::set<Interval> interval_set;
2025+
std::set<Element> interval_set;
20402026

20412027
for (int i = 0; i < rectangles.size(); ++i) {
20422028
const IntegerValue x = rectangles[i].x_min;
2029+
const IntegerValue y_min = rectangles[i].y_min;
2030+
const IntegerValue y_max = rectangles[i].y_max;
2031+
2032+
// TODO(user): We can handle that, but it require some changes below.
2033+
DCHECK_LE(y_min, y_max);
20432034

2044-
// Try to add the y part of this rectangle to the set, if there is an
2045-
// intersection, lazily remove it if its x_max is already passed, otherwise
2046-
// report the intersection.
2047-
const Interval to_insert = {i, rectangles[i].y_min, rectangles[i].y_max};
2048-
auto [it, inserted] = interval_set.insert(to_insert);
2049-
DCHECK(inserted);
2035+
// Try to add this rectangle to the set, if there is an intersection, lazily
2036+
// remove it if its x_max is already passed, otherwise report the
2037+
// intersection.
2038+
auto [it, inserted] = interval_set.insert({i, y_min});
2039+
if (!inserted) {
2040+
if (rectangles[it->index].x_max <= x) {
2041+
// We just replace if the rectangle at position i is stale.
2042+
it->index = i;
2043+
} else {
2044+
// Intersection.
2045+
return {{it->index, i}};
2046+
}
2047+
}
20502048

20512049
// Note that the intersection is either before 'it', or just after it.
20522050
if (it != interval_set.begin()) {
@@ -2057,8 +2055,9 @@ absl::optional<std::pair<int, int>> FindOneIntersectionIfPresent(
20572055
if (rectangles[it_before->index].x_max <= x) {
20582056
interval_set.erase(it_before);
20592057
} else {
2060-
DCHECK_LE(it_before->y_min, to_insert.y_min);
2061-
if (it_before->y_max > to_insert.y_min) {
2058+
DCHECK_LE(it_before->y_min, y_min);
2059+
const IntegerValue y_max_before = rectangles[it_before->index].y_max;
2060+
if (y_max_before > y_min) {
20622061
// Intersection.
20632062
return {{it_before->index, i}};
20642063
}
@@ -2073,8 +2072,8 @@ absl::optional<std::pair<int, int>> FindOneIntersectionIfPresent(
20732072
continue;
20742073
}
20752074

2076-
DCHECK_LE(to_insert.y_min, it->y_min);
2077-
if (to_insert.y_max > it->y_min) {
2075+
DCHECK_LE(y_min, it->y_min);
2076+
if (y_max > it->y_min) {
20782077
// Intersection.
20792078
return {{it->index, i}};
20802079
}

ortools/sat/routing_cuts.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ void ExtractAllSubsetsFromForest(absl::Span<const int> parent,
516516
}
517517

518518
std::vector<int> ComputeGomoryHuTree(
519-
int num_nodes, const std::vector<ArcWithLpValue>& relevant_arcs) {
519+
int num_nodes, absl::Span<const ArcWithLpValue> relevant_arcs) {
520520
// Initialize the graph. Note that we use only arcs with a relevant lp
521521
// value, so this should be small in practice.
522522
SimpleMaxFlow max_flow;

ortools/sat/routing_cuts.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ void SymmetrizeArcs(std::vector<ArcWithLpValue>* arcs);
108108
// Pairs Network Flow Analysis", Dan Gusfield, 1990,
109109
// https://ranger.uta.edu/~weems/NOTES5311/LAB/LAB2SPR21/gusfield.huGomory.pdf
110110
std::vector<int> ComputeGomoryHuTree(
111-
int num_nodes, const std::vector<ArcWithLpValue>& relevant_arcs);
111+
int num_nodes, absl::Span<const ArcWithLpValue> relevant_arcs);
112112

113113
// Cut generator for the circuit constraint, where in any feasible solution, the
114114
// arcs that are present (variable at 1) must form a circuit through all the

0 commit comments

Comments
 (0)