Skip to content

Comments

Add a dual aggregation presolver for binary variables with a single lock#901

Open
aliceb-nv wants to merge 487 commits intoNVIDIA:mainfrom
aliceb-nv:setppc-presolve
Open

Add a dual aggregation presolver for binary variables with a single lock#901
aliceb-nv wants to merge 487 commits intoNVIDIA:mainfrom
aliceb-nv:setppc-presolve

Conversation

@aliceb-nv
Copy link
Contributor

@aliceb-nv aliceb-nv commented Feb 23, 2026

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 = y can 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-787933 at the root, thus adding +1 optimal in 10min runs.

Description

Issue

Checklist

  • I am familiar with the Contributing Guidelines.
  • Testing
    • New or existing tests cover these changes
    • Added tests
    • Created an issue to follow-up
    • NA
  • Documentation
    • The documentation is up to date with these changes
    • Added new documentation
    • NA

Summary by CodeRabbit

Release Notes

  • New Features

    • Added a new presolve optimization algorithm for integral column problems.
  • Tests

    • Introduced new test case validating the presolve optimization method.
    • Expanded test dataset with an additional benchmark problem instance.
  • Chores

    • Updated build configuration to support the new optimization module.

@aliceb-nv aliceb-nv added this to the 26.04 milestone Feb 23, 2026
@aliceb-nv aliceb-nv requested a review from a team as a code owner February 23, 2026 20:02
@aliceb-nv aliceb-nv added the non-breaking Introduces a non-breaking change label Feb 23, 2026
@aliceb-nv aliceb-nv requested review from a team as code owners February 23, 2026 20:02
@aliceb-nv aliceb-nv added the improvement Improves an existing functionality label Feb 23, 2026
@copy-pr-bot
Copy link

copy-pr-bot bot commented Feb 23, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@aliceb-nv
Copy link
Contributor Author

/ok to test 7761da8

@coderabbitai
Copy link

coderabbitai bot commented Feb 23, 2026

📝 Walkthrough

Walkthrough

This 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

Cohort / File(s) Summary
Single-Lock Dual Aggregation Implementation
cpp/src/mip_heuristics/presolve/single_lock_dual_aggregation.hpp, cpp/src/mip_heuristics/presolve/single_lock_dual_aggregation.cpp
Introduces new presolver template class with header definition (+56 lines) and full algorithm implementation (+359 lines). Algorithm performs constraint scanning for lock occurrences, candidate filtering for binary/implied-integral variables, mini-probing for implication detection, and substitution-based reductions with time-limit checks.
Presolve Integration
cpp/src/mip_heuristics/presolve/third_party_presolve.cpp
Registers SingleLockDualAggregation as an additional MIP-category presolve method alongside existing methods; includes new header and updates method instantiation logic.
Build Configuration
cpp/src/mip_heuristics/CMakeLists.txt
Adds new source file presolve/single_lock_dual_aggregation.cpp to MIP_LP_NECESSARY_FILES build target.
Tests and Dataset
cpp/tests/mip/termination_test.cu, datasets/mip/download_miplib_test_dataset.sh
Adds new test case slda_presolve_optimal validating presolver behavior on neos-787933.mps instance; registers new test instance in dataset download script.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title precisely describes the main change: adding a dual aggregation presolver specifically for binary variables with a single lock.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between d54b193 and 7761da8.

📒 Files selected for processing (6)
  • cpp/src/mip_heuristics/CMakeLists.txt
  • cpp/src/mip_heuristics/presolve/single_lock_dual_aggregation.cpp
  • cpp/src/mip_heuristics/presolve/single_lock_dual_aggregation.hpp
  • cpp/src/mip_heuristics/presolve/third_party_presolve.cpp
  • cpp/tests/mip/termination_test.cu
  • datasets/mip/download_miplib_test_dataset.sh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Improves an existing functionality non-breaking Introduces a non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants