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>
| policy.graphviz(search_tree, node_ptr, "lower bound", leaf_obj); | ||
| policy.update_pseudo_costs(node_ptr, leaf_obj); | ||
| node_ptr->lower_bound = leaf_obj; | ||
| // If the objective is integral or must move in steps than |
There was a problem hiding this comment.
We should get in the habit of keeping refactors like this separate from functional changing PR. It's easier to review PRs that keep the two separate. Refactors should have no functionality changes.
There was a problem hiding this comment.
I needed to move this logic to a separated function to avoid code duplication: it is applied in both the tree_update() and rins()
| bool stop = halt_callback_(user_obj, user_lower); | ||
| if (stop) { | ||
| node_concurrent_halt_ = 1; | ||
| solver_status_ = mip_status_t::HALT; |
There was a problem hiding this comment.
When is HALT triggerred?
There was a problem hiding this comment.
Add a comment above
| break; | ||
| } | ||
|
|
||
| dual_status_t lp_status = solve_node_lp(&node, rins_worker, rins_stats, log); |
There was a problem hiding this comment.
Is this solving the root node of the sub-MIP? If so a comment would be helpful to guide the reader.
| scope_guard cpufj_guard([&]() { root_fj_cpu_worker.stop(); }); | ||
| root_fj_cpu_worker.improvement_callback = | ||
| [this](f_t obj, const std::vector<f_t>& assignment, double work_units) { | ||
| std::vector<f_t> user_assignment; |
There was a problem hiding this comment.
Is this just a refactor? Or are there functional changes here?
There was a problem hiding this comment.
Just refactor. We are using the CPU FJ in a few places now, so I move all the logic to a single method set_solution_from_cpu_fj
| // original-space in the mip_solver_context_t), but does NOT imply incumbent_.has_incumbent. | ||
| omp_atomic_t<f_t> upper_bound_; | ||
|
|
||
| // Callback for halting the solver. This passes the current upper and lower bound of the solver |
There was a problem hiding this comment.
Under what conditions is the solver halted?
There was a problem hiding this comment.
Add a description
| std::atomic<int> root_concurrent_halt_{0}; | ||
| std::atomic<int> node_concurrent_halt_{0}; | ||
| bool is_root_solution_set{false}; | ||
| bool root_warm_start_{false}; |
There was a problem hiding this comment.
We should be careful about the use of the word "warm start" in MIP. What is meant here? That an initial integer feasible solution is available? If so, we usually call that a "MIP start".
There was a problem hiding this comment.
renamed the variable
| // Feb. 07, 2019, _arXiv_: arXiv:1902.02615. doi: | ||
| // [10.48550/arXiv.1902.02615](https://doi.org/10.48550/arXiv.1902.02615). | ||
| enum search_strategy_t : int { | ||
| enum worker_type_t : int { |
There was a problem hiding this comment.
Since I added the HEURISTICS and SUBMIP, search_strategy_t seems a little bit off
| // minimize c^T x | ||
| // subject to A x = b | ||
| // l <= x <= u | ||
| // and express it as a user_problem in range (row-bounded) form |
There was a problem hiding this comment.
Is it necessary to convert the problem into ranged form? Can't you give Papilo the problem above. That is, Papilo should not require ranges. You can just set the l_row = u_row = b.
|
|
||
| // LP/MIP only: no quadratic objective and no second-order cones. | ||
| user_problem.cone_var_start = 0; | ||
| user_problem.second_order_cone_dims.clear(); |
There was a problem hiding this comment.
Don't you need to set the quadratic objective terms to zero?
|
|
||
| namespace cuopt::mathematical_optimization::simplex { | ||
|
|
||
| struct submip_settings_t { |
There was a problem hiding this comment.
Are all these settings necessary? Which ones are you considering exposing to the user?
| // or -1 to draw from the global cuopt::seed_generator (the historical behavior). | ||
| // In deterministic mode the caller MUST pass an explicit seed, otherwise the underlying | ||
| // seed_generator::get_seed() racing with concurrent callers breaks reproducibility. | ||
| void from_simplex_lp(const simplex::lp_problem_t<i_t, f_t>& problem, |
There was a problem hiding this comment.
It's a bit strange to construct a fj_cpu_worker_t from_simplex_lp. Maybe this function could have a better name.
| const std::vector<char>& row_sense = problem.row_sense; | ||
| const std::vector<f_t>& rhs = problem.rhs; | ||
|
|
||
| // Range rows carry an extra width and are listed separately; mark them so the row-bound |
There was a problem hiding this comment.
My hunch is that this is not necessary. Just pass the linear_program_t representation directly to Papilo.
| case papilo::PostsolveStatus::kOk: CUOPT_LOG_DEBUG("Post-solve status: succeeded"); break; | ||
| case papilo::PostsolveStatus::kFailed: | ||
| CUOPT_LOG_INFO( | ||
| CUOPT_LOG_DEBUG( |
There was a problem hiding this comment.
Ideally logging changes like this are done as a separate PR. Not mixed in with large functional changes.
There was a problem hiding this comment.
I silence this log line since the sub-MIP was constantly triggering the kFailed line, which polluted the logs. Let me re-enable and see if this is still the case after the latest changes.
chris-maes
left a comment
There was a problem hiding this comment.
One of the biggest concerns is the switching between Ax = b, l <= x <= u, and lb <= Ax <= ub. My hunch is that this is unnecessary and just adds overhead. Could you try giving Papilo the form b <= A*x <= b, l <= x <= u and see if it accepts that. If so, you can eliminate a lot of complexity from the code.
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