71 absl::Span<const glop::ColIndex> cols,
72 absl::Span<const IntegerValue> coeffs,
73 IntegerValue lb, IntegerValue ub) {
74 const int num_terms = cols.size();
75 if (num_terms > kMaxInputConstraintSize)
return;
77 double activity = 0.0;
78 IntegerValue magnitude(0);
81 for (
int i = 0;
i < num_terms; ++
i) {
82 const int col = cols[
i].value();
84 magnitude = std::max(magnitude,
IntTypeAbs(coeffs[
i]));
87 if ((coeffs[
i].
value() & 1) == 0)
continue;
90 if (shifted_lp_values_[
col] > 1e-2) {
95 rhs_adjust ^= bound_parity_[
col];
101 if (magnitude > kMaxInputConstraintMagnitude)
return;
102 if (binary_row.
cols.empty())
return;
110 const double tighteness_threshold = 1e-2;
111 if (
ToDouble(ub) - activity < tighteness_threshold) {
114 binary_row.
rhs_parity = (ub.value() & 1) ^ rhs_adjust;
117 if (activity -
ToDouble(lb) < tighteness_threshold) {
120 binary_row.
rhs_parity = (lb.value() & 1) ^ rhs_adjust;
152 int eliminated_row) {
153 CHECK_LE(rows_[eliminated_row].slack, 1e-6);
154 CHECK(!rows_[eliminated_row].cols.empty());
157 tmp_marked_.resize(std::max(col_to_rows_.size(), rows_.size()));
158 DCHECK(std::all_of(tmp_marked_.begin(), tmp_marked_.end(),
159 [](
bool b) { return !b; }));
161 for (
const int other_row : col_to_rows_[eliminated_col]) {
162 if (other_row == eliminated_row)
continue;
163 col_to_rows_[eliminated_col][new_size++] = other_row;
168 rows_[other_row].rhs_parity ^= rows_[eliminated_row].rhs_parity;
169 rows_[other_row].slack += rows_[eliminated_row].slack;
173 auto& mutable_multipliers = rows_[other_row].multipliers;
174 mutable_multipliers.insert(mutable_multipliers.end(),
175 rows_[eliminated_row].multipliers.begin(),
176 rows_[eliminated_row].multipliers.end());
177 std::sort(mutable_multipliers.begin(), mutable_multipliers.end());
179 for (
const auto& entry : mutable_multipliers) {
180 if (new_size > 0 && entry == mutable_multipliers[new_size - 1]) {
184 mutable_multipliers[new_size++] = entry;
187 mutable_multipliers.resize(new_size);
190 col_to_rows_[eliminated_col].resize(new_size);
195 for (
const int other_col : rows_[eliminated_row].cols) {
196 if (other_col == eliminated_col)
continue;
198 &col_to_rows_[other_col]);
199 if (col_to_rows_[other_col].
size() == 1) {
200 CHECK_EQ(col_to_rows_[other_col][0], eliminated_row);
203 col_to_rows_[other_col].clear();
204 rows_[eliminated_row].slack += shifted_lp_values_[other_col];
207 rows_[eliminated_row].cols[new_size++] = other_col;
209 rows_[eliminated_row].cols.resize(new_size);
213 col_to_rows_[eliminated_col].clear();
214 rows_[eliminated_row].slack += shifted_lp_values_[eliminated_col];
219 std::vector<std::vector<std::pair<glop::RowIndex, IntegerValue>>> result;
222 const int num_cols = col_to_rows_.size();
223 for (
int singleton_col = 0; singleton_col < num_cols; ++singleton_col) {
224 if (col_to_rows_[singleton_col].
size() != 1)
continue;
226 const int row = col_to_rows_[singleton_col][0];
228 auto& mutable_cols = rows_[
row].cols;
229 for (
const int col : mutable_cols) {
230 if (
col == singleton_col)
continue;
231 mutable_cols[new_size++] =
col;
233 CHECK_LT(new_size, mutable_cols.size());
234 mutable_cols.resize(new_size);
235 col_to_rows_[singleton_col].clear();
236 rows_[
row].slack += shifted_lp_values_[singleton_col];
240 std::vector<int> to_process;
241 for (
int row = 0;
row < rows_.size(); ++
row) to_process.push_back(
row);
242 std::shuffle(to_process.begin(), to_process.end(), *random);
243 std::stable_sort(to_process.begin(), to_process.end(), [
this](
int a,
int b) {
244 return rows_[a].cols.size() < rows_[b].cols.size();
247 for (
const int row : to_process) {
248 if (rows_[
row].cols.empty())
continue;
249 if (rows_[
row].slack > 1e-6)
continue;
250 if (rows_[
row].multipliers.size() > kMaxAggregationSize)
continue;
253 int eliminated_col = -1;
254 double max_lp_value = 0.0;
255 for (
const int col : rows_[
row].cols) {
256 if (shifted_lp_values_[
col] > max_lp_value) {
257 max_lp_value = shifted_lp_values_[
col];
258 eliminated_col =
col;
261 if (eliminated_col == -1)
continue;
268 for (
const auto&
row : rows_) {
269 if (
row.cols.empty() &&
row.rhs_parity &&
row.slack < kSlackThreshold) {
270 result.push_back(
row.multipliers);
273 VLOG(2) <<
"#candidates: " << result.size() <<
" / " << rows_.size();