Skip to content

Recursive RINS#1482

Open
nguidotti wants to merge 73 commits into
NVIDIA:mainfrom
nguidotti:recursive-submip
Open

Recursive RINS#1482
nguidotti wants to merge 73 commits into
NVIDIA:mainfrom
nguidotti:recursive-submip

Conversation

@nguidotti

@nguidotti nguidotti commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

This PR implements the recursive RINS heuristics. 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:

  • A routine for converting a lp_problem_t (standard form) to user_problem_t (range form).
  • Allow Papilo to be applied to an user_problem_t instead of optimization_problem_t.
  • Adds an upper bound callback for retrieving the upper bound of the main solver (since it may change if another worker find a better incumbent).

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

================================================================================
 main-2026-07-03 (1) vs recursive-submip (2)
================================================================================

------------------------------------------------------------------------------------------------------------------------------
|                                        |       Run 1        |       Run 2        |     Abs. Diff.     |   Rel. Diff. (%)   |
------------------------------------------------------------------------------------------------------------------------------
| Imported                                                 240                  240                   +0                 --- |
| Feasible                                                 227                  228                   +1                 --- |
| Optimal                                                   86                   91                   +5                 --- |
| Solutions with <0.1% primal gap                          138                  151                  +13                 --- |
| Nodes explored (mean)                              1.326e+07            1.296e+07           -3.057e+05               -2.31 |
| Nodes explored (shifted geomean)                   1.262e+04            1.239e+04                 -230               -1.82 |
| Relative MIP gap (mean)                               0.2777               0.2726             -0.00512               -1.84 |
| Relative MIP gap (shifted geomean)                   0.09089              0.08901            -0.001883               -2.07 |
| Solve time (mean)                                      422.6                435.4               +12.79               +3.03 |
| Solve time (shifted geomean)                           196.9                226.6               +29.66               +15.1 |
| Primal gap (mean)                                      9.969                 9.29               -0.679               -6.81 |
| Primal gap (shifted geomean)                          0.4584               0.3491              -0.1093               -23.8 |
| Primal integral (mean)                                 25.02                22.97               -2.051                -8.2 |
| Primal integral (shifted geomean)                      2.849                2.421              -0.4275                 -15 |
------------------------------------------------------------------------------------------------------------------------------


----------------------------------------------------------------------
|             Name             |     status 1     |     status 2     |
----------------------------------------------------------------------
| neos-1171737                           feasible            optimal |
| radiationm40-10-02                     feasible            optimal |
| rail01                                  timeout           feasible |
| ran14x18-disj-8                        feasible            optimal |
| triptim1                               feasible            optimal |
| unitcal_7                              feasible            optimal |
----------------------------------------------------------------------

@nguidotti nguidotti added this to the 26.08 milestone Jun 26, 2026
@nguidotti nguidotti added non-breaking Introduces a non-breaking change improvement Improves an existing functionality mip labels Jun 26, 2026
@copy-pr-bot

copy-pr-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown

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>
nguidotti added 23 commits June 29, 2026 12:56
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>
Comment thread cpp/src/branch_and_bound/branch_and_bound.cpp Outdated
Comment thread cpp/src/branch_and_bound/branch_and_bound.cpp Outdated
Comment thread cpp/src/branch_and_bound/branch_and_bound.cpp Outdated
Comment thread cpp/src/branch_and_bound/branch_and_bound.cpp Outdated
Comment thread cpp/src/branch_and_bound/branch_and_bound.cpp Outdated
Comment thread cpp/src/branch_and_bound/branch_and_bound.cpp Outdated
Comment thread cpp/src/branch_and_bound/branch_and_bound.cpp Outdated
Comment thread cpp/src/branch_and_bound/branch_and_bound.cpp Outdated
Comment thread cpp/src/branch_and_bound/branch_and_bound.cpp Outdated
Comment thread cpp/src/branch_and_bound/branch_and_bound.cpp
Comment thread cpp/src/branch_and_bound/branch_and_bound.cpp Outdated

@chris-maes chris-maes left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I only made it through branch_and_bound.cpp. I need to finish the review later.

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>
Comment thread cpp/src/branch_and_bound/branch_and_bound.cpp Outdated
Comment thread cpp/src/branch_and_bound/branch_and_bound.cpp Outdated
Comment thread cpp/src/branch_and_bound/constants.hpp Outdated
std::vector<omp_mutex_t> pseudo_cost_mutex_down;

omp_atomic_t<int64_t> strong_branching_lp_iter = 0;
bool has_initial_pseudocost = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: member variables should end with and underscore has_initial_pseudocost_

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The other variables do not have the underscore. Do you want me to rename them all?

Comment thread cpp/src/dual_simplex/presolve.cpp Outdated
Comment thread cpp/src/mip_heuristics/presolve/third_party_presolve.cpp Outdated
Comment thread cpp/src/mip_heuristics/presolve/third_party_presolve.cpp
Comment thread cpp/src/mip_heuristics/presolve/third_party_presolve.cpp Outdated
"reduced problem must match crush output dimension");
for (size_t j = 0; j < reduced_primal.size(); ++j) {
reduced_primal[j] =
std::clamp(reduced_primal[j], reduced_problem.lower[j], reduced_problem.upper[j]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

But couldn't clamping cause us to loose feasibility for the lb <= A*x <= ub constraints?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@aliceb-nv for viz. This is just the duplicate of the other crush function (since I need to apply for an user_problem_t instead of optimization_problem_t)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It can. That's the price to pay 😅 Dual reductions inherently cut off part of the polytope. If papilo performed some, we can mostly only hope that canonicalization back into the polytope is possible. Sometimes it may not be (e.g. papilo used DualFix to safely tighten the bounds of some variables because it proved it won't cut off any optimal solution, and then it may decide to do propagation on this.... But, afaik, this is just an inherent risk that cannot practically be avoided)

Comment thread cpp/src/mip_heuristics/presolve/third_party_presolve.hpp
Comment thread cpp/src/mip_heuristics/feasibility_jump/fj_cpu_worker.cuh Outdated
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Signed-off-by: Nicolas L. Guidotti <nguidotti@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEA] Recursive RINS

5 participants