Add a dual aggregation presolver for binary variables with a single lock#901
Add a dual aggregation presolver for binary variables with a single lock#901aliceb-nv wants to merge 487 commits intoNVIDIA:mainfrom
Conversation
|
/ok to test 7761da8 |
📝 WalkthroughWalkthroughThis PR introduces a new Single-Lock Dual Aggregation presolver module for MIP optimization. It adds a template-based presolver class with implementation and header files, integrates it into the presolve pipeline, updates the build configuration, and includes a test case with a new test dataset instance. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@cpp/src/mip_heuristics/presolve/single_lock_dual_aggregation.cpp`:
- Around line 71-75: The row classification logic incorrectly makes the 'R'
branch unreachable, so rows with both bounds infinite are misclassified; update
the test building row_dir in single_lock_dual_aggregation.cpp (the variables
row_flags, papilo::RowFlag::kLhsInf, kRhsInf and the row_dir assignment) to
explicitly check for both-infinite first (lhs_inf && rhs_inf -> 'R'), then
both-finite -> 'E', then lhs_inf -> 'L', else rhs_inf -> 'G', and keep the
subsequent if (row_dir == 'R') continue; unchanged.
In `@cpp/src/mip_heuristics/presolve/single_lock_dual_aggregation.hpp`:
- Around line 42-53: The helper is_binary_or_implied currently uses exact
equality for bounds which can miss implied binaries; change its signature to
accept a tolerance (e.g., add a double tol parameter) and use epsilon
comparisons against 0 and 1 (e.g., check lower_bounds[col] within tol of 0 and
upper_bounds[col] within tol of 1) instead of ==; update all call sites in the
.cpp to pass the model tolerance (use num.getFeasTol() where available) so the
binary/implied check is robust to small numerical inaccuracies.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
cpp/src/mip_heuristics/CMakeLists.txtcpp/src/mip_heuristics/presolve/single_lock_dual_aggregation.cppcpp/src/mip_heuristics/presolve/single_lock_dual_aggregation.hppcpp/src/mip_heuristics/presolve/third_party_presolve.cppcpp/tests/mip/termination_test.cudatasets/mip/download_miplib_test_dataset.sh
This PR adds a dual aggregation pass to Papilo to recognize cases where a binary variable$x$ has only a single lock preventing it from reaching its objective-favorable bound. When found, the pass attempts to substitute $x$ with a master binary variable $y$ present in the locking row.
This new pass attempts to perform a substitution of$x$ with another binary variable y in the row that locks $x$ .
For this, a probing is performed to try to prove that y = 0 => x = 0. We do this by showing x=1 AND y=0 violates the single locking row's activity bounds.
We also prove that y = 1 => x = 1 by showing that the constraint is always satisfied when y = 1, and the objective is not worsened by setting x to 1.
If these two clauses are true, the subsitution
x = ycan be safely performed.We also handle the reverse case of a single down-lock.
This pass runs in O(nnz) time.
With these changes, we solve
neos-787933at the root, thus adding +1 optimal in 10min runs.Description
Issue
Checklist
Summary by CodeRabbit
Release Notes
New Features
Tests
Chores