Recursive RINS#1482
Conversation
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
cb9557d to
aefe31a
Compare
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
…bmip (and restarted) problems. Papilo can now be applied to an user_problem_t inplace. Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
# Conflicts: # cpp/src/mip_heuristics/diversity/lns/rins.cu # cpp/src/mip_heuristics/diversity/recombiners/sub_mip.cuh
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
…e old warm start code. Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
…/root change diving procedure when the RINS neighbourhood is not large enough Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
…ation count for the root relaxation (it should reflect the number of simplex iterations). Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
…. this enable the use of diving heuristics for RINS. Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
…f the neighbourhood is too loose or it already found an improving solution. Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
cpp/src/mip_heuristics/presolve/third_party_presolve.cpp (1)
1300-1307: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win
get_coefflinear scan makes reduced-cost replay quadratic per row.When the
(row, col)key is absent fromcoeff_current(the common case),get_coeffscans the entire row inA. Callers iteratepover that same row and callget_coeff(row, A_indices[p])(Lines 1354-1357 and 1441-1443), so each row costsO(row_nnz²). SinceA_values[p]is already the coefficient forA_indices[p], only map-overridden entries need a lookup — pass the known value and consult the map only for overrides to keep the replay linear in nnz.♻️ Illustrative change at the call sites
- for (i_t p = A_offsets[i]; p < A_offsets[i + 1]; ++p) { - z[A_indices[p]] += y[i] * get_coeff(i, A_indices[p]); - } + for (i_t p = A_offsets[i]; p < A_offsets[i + 1]; ++p) { + const i_t col = A_indices[p]; + auto it = coeff_current.find(coeff_key(i, col)); + const f_t a = (it != coeff_current.end()) ? it->second : A_values[p]; + z[col] += y[i] * a; + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cpp/src/mip_heuristics/presolve/third_party_presolve.cpp` around lines 1300 - 1307, The get_coeff helper currently does a linear scan of A for every miss in coeff_current, which makes the reduced-cost replay quadratic when called inside the row iteration loops. Update the logic around get_coeff and its call sites in the replay path so the caller passes the already-known A_values[p] for A_indices[p], and only consult coeff_current for overridden entries instead of rescanning the row. Keep the fix localized to get_coeff and the loops that invoke it so the replay stays linear in nnz.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@cpp/src/mip_heuristics/presolve/third_party_presolve.cpp`:
- Around line 1300-1307: The get_coeff helper currently does a linear scan of A
for every miss in coeff_current, which makes the reduced-cost replay quadratic
when called inside the row iteration loops. Update the logic around get_coeff
and its call sites in the replay path so the caller passes the already-known
A_values[p] for A_indices[p], and only consult coeff_current for overridden
entries instead of rescanning the row. Keep the fix localized to get_coeff and
the loops that invoke it so the replay stays linear in nnz.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: abae84ad-32f0-4d30-9d20-25a91ec0603b
📒 Files selected for processing (8)
cpp/src/branch_and_bound/branch_and_bound.cppcpp/src/branch_and_bound/constants.hppcpp/src/branch_and_bound/pseudo_costs.hppcpp/src/branch_and_bound/worker.hppcpp/src/mip_heuristics/presolve/third_party_presolve.cppcpp/tests/dual_simplex/unit_tests/solve.cppcpp/tests/linear_programming/unit_tests/presolve_test.cucpp/tests/mip/presolve_test.cu
🚧 Files skipped from review as they are similar to previous changes (7)
- cpp/tests/dual_simplex/unit_tests/solve.cpp
- cpp/src/branch_and_bound/constants.hpp
- cpp/tests/mip/presolve_test.cu
- cpp/src/branch_and_bound/pseudo_costs.hpp
- cpp/tests/linear_programming/unit_tests/presolve_test.cu
- cpp/src/branch_and_bound/worker.hpp
- cpp/src/branch_and_bound/branch_and_bound.cpp
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
…ilo to my fork with the fix, revert when the PR is merged) Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
…han the main solve) Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
…reads for ex9 test Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
…let the degeneracy test to handle optimal as well Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
aliceb-nv
left a comment
There was a problem hiding this comment.
Thanks a lot for the hard work and amazing results Nicolas! Approving with a few nits; let's also get Chris' eyes on the dual simplex/B&B parts
| @@ -1645,6 +1698,12 @@ void branch_and_bound_t<i_t, f_t>::plunge_with(bfs_worker_t<i_t, f_t>* worker, | |||
| break; | |||
There was a problem hiding this comment.
Let's check with Chris that these logging changes are agreed upon
| // Free row (both sides infinite). | ||
| problem.row_sense[r] = 'L'; | ||
| problem.rhs[r] = std::numeric_limits<f_t>::infinity(); |
There was a problem hiding this comment.
Do we handle free rows properly in simplex?
There was a problem hiding this comment.
It is a good question. Let me check, although @chris-maes or @rg20 may answer better than me.
| FetchContent_Declare( | ||
| papilo | ||
| GIT_REPOSITORY "https://github.com/scipopt/papilo.git" | ||
| GIT_REPOSITORY "https://github.com/nguidotti/papilo.git" | ||
| # We would want to get the main branch. However, the main branch | ||
| # does not have some of the presolvers and settings that we need | ||
| # Mainly, probing and clique merging. | ||
| # This is the reason we are using the development branch | ||
| # from Oct 12, 2025. Once these changes are merged into the main branch, | ||
| #we can switch to the main branch. | ||
| GIT_TAG "741a2b9c8155b249d6df574d758b4d97d4417520" | ||
| GIT_TAG "0cfea20c5655249174dbd04f0fb7bd6b1f6e9a0c" |
There was a problem hiding this comment.
Why do we pin on your repo? Is it because of a required upstream fix? If so, we probably should wait until it is merged before merging the PR instead of depending on a personal repo (or at least, track that with an issue)
There was a problem hiding this comment.
Yeah, this is only temporary. I will wait for scipopt/papilo#89 to merged before merging this PR
| const f_t t1 = b - c * simplex_problem.lower[s]; | ||
| const f_t t2 = b - c * simplex_problem.upper[s]; |
There was a problem hiding this comment.
The following was flagged by an analysis agent, do you believe it's legit?
At presolve.cpp:748-754, for a row with b = +inf and a standard [0, inf) slack:
- t1 = b − c·l_s = inf − 0 = inf
- t2 = b − c·u_s = inf − inf = NaN
- std::min(t1, t2) and std::max(t1, t2) both discard the NaN operand and return inf, so lo == hi == +inf
- the lo == hi branch fires → row recovered as sense 'E' with rhs = +inf — a vacuous constraint has become an unsatisfiable one.
The same collapse happens NaN-free if the row carries an artificial with bounds [0,0] (t1 = t2 = inf). Downstream, build_papilo_problem sets lhs = rhs = +inf with only the rhs infinity flag (third_party_presolve.cpp:304-315), so Papilo sees a^T x >= +inf and declares the sub-MIP INFEASIBLE. solve_submip records it via save_infeasible and moves on — every RINS/sub-MIP on such an instance silently reports infeasible, disabling the whole heuristic with no assert firing even in debug builds.
There was a problem hiding this comment.
I do not think b can be inf here since
…her review comments. Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
… solution Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
|
Caution Review failedAn error occurred during the review process. Please try again later. Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR adds Sub-MIP/RINS branch-and-bound support, PaPILO-backed presolve crush/uncrush paths, an inverse simplex-to-user-problem conversion, simplex-iteration accounting updates, and related test and dataset changes. ChangesSub-MIP/RINS and Presolve Crush Support
Estimated code review effort: 5 (Critical) | ~120 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ 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 |
…tion. Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
…re calling cpu fj Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
This PR implements the recursive RINS heuristics similar to HiGHS. More specifically, it applies a dive-like procedure to create a RINS sub-MIP, presolved it with Papilo and then passes to the cut-and-branch procedure. It also launch a CPU FJ worker over the sub-MIP that runs in parallel to cut-and-branch.
Since the current implementation, does not have an unified problem representation, this PR also adds:
lp_problem_t(standard form) touser_problem_t(range form).user_problem_tinstead ofoptimization_problem_t.Additionally, the number of worker per diving heuristic is no longer tied to the total number of workers, which allows the solver to use all diving heuristics in low thread counts (we rotate between the different heuristics for each diving worker launch).
Results
MIPLIB2017, 10min, GH200
Checklist