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>
| worker->leaf_problem, var_types_, settings_, submip_problem); | ||
|
|
||
| third_party_presolve_t<i_t, f_t> presolver; | ||
| f_t presolve_time_limit = std::min(0.1 * submip_settings.time_limit, 60.0); |
There was a problem hiding this comment.
Note: presolve based on time limit introduce non-determinism into the solve.
There was a problem hiding this comment.
I do not think Papilo supports or uses work limit
There was a problem hiding this comment.
Have we tested if Papilo needs this scaled-down time limit here? On a restarted problem it may be able to reach the fixed point quickly. If not, then the expensive Probing pass has a separate work unit that can be tuned - I assume it's also possible to set a limit on the number of rounds.
There was a problem hiding this comment.
I copy the settings from the regular presolve pass. Honestly, I would not spend too much effort for this since I hope we can replace the presolve + cut-and-branch for the submip for a call to the entire solver stack (with maybe some parts turn off) when we have the unified problem object
There was a problem hiding this comment.
I'd rather not introduce sources of nondeterminism in new PRs please :( We'll need a way to run a determinsitic "light" papilo presolve pass at some point regardless
There was a problem hiding this comment.
The recursive RINS is disable for the deterministic mode. In any case, we have the same problem when calling the Papilo in the regular solve, right?
There was a problem hiding this comment.
When and for which node the recursive RINS triggers is quite non-deterministic, too.
There was a problem hiding this comment.
We don't have this issue when running Papilo at the root because we disable the time limit there in determinsitic mode. Papilo terminates on its own, with some caps on the Probing work limits
There was a problem hiding this comment.
Okay,, let's track that recursive RINS is strictly non-determinsitic with an issue. That's something I'll have to address later
There was a problem hiding this comment.
Created here: #1579. If the solver is deterministic and we can call the solver stack directly, then we probably only need to do is make the triggering logic deterministic.
|
|
||
| // We need to do this dance of uncrush methods since we are working on the presolved space on | ||
| // the augmented space (structural + slack + cuts), while the `set_solution_from_heuristics` | ||
| // expects a solution on the user space. So we go from presolved space -> augmented space -> |
There was a problem hiding this comment.
What is the augmented space? Just with the addition of slack variables. Note that slack variables are always placed at the end, and so the conversion from the problem with slacks to without slacks is trivial, you just drop variables at the end.
There was a problem hiding this comment.
We start with a range form, user_problem_t with lp_problem_t with
For the submip, we need to convert the augmented problem back to range form. However, this is a direct conversion (set the range rows as equality and all slacks and cuts are preserved) so the user_problem_t will have the dimensions user_problem_t which the routine set_solution_from_heuristic expects. For this reason, we need to first uncrush the solution from the presolved space of the augmented system via Papilo, then uncrush the results again to the original user_problem_t. Note that this is recursive (a sub-mip 2 levels deep will need to do 2 conversion which is done by going up the solver stack).
We will have a similar issue with restarts unless we accumulate the reductions into a single Papilo object that was created in the beginning
| submip_bnb.set_halt_callback(halt_callback_); | ||
| } else { | ||
| // This should only be called by the main solver. | ||
| submip_bnb.set_halt_callback([this](f_t, f_t submip_lower_bound) { |
There was a problem hiding this comment.
Is a callback necessary here? I think you might be able to simplify things by just having a variable cutoff that can be set to the upper bound by the main solve. Or better yet, why not just have the submip have a pointer to the upper bound variable of the main solve. That way every time the main solve updates the upper bound, the submip can see it.
There was a problem hiding this comment.
This was originally what I did (having a pointer to the upper bound of the main solve). The current approach is more flexible, though. This allows not only to stop due to the cutoff but also if the solver status changes (e.g., let say the solver reaches the node/time limit and stops, then this callback can signal all the sub-MIP solves to stop immediately)
| } | ||
|
|
||
| fj_cpu_worker_t<i_t, f_t> submip_fj_cpu_worker; | ||
| scope_guard cpufj_guard([&]() { submip_fj_cpu_worker.stop(); }); |
There was a problem hiding this comment.
What is going on here? Could you add some comment to explain?
There was a problem hiding this comment.
Added comment:
// Launch a CPU FJ worker on the presolved sub-MIP with a fixed budget (in terms of work units)
// to run in parallel with the cut-and-branch algorithm with the goal of finding a quick feasible
// solution for the sub-MIP problem. The CPU FJ uses the current incumbent (crushed into the
// presolved space) as initial guess. The worker is automatically stop when we go out of the
// scope.
chris-maes
left a comment
There was a problem hiding this comment.
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>
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:
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