Skip to content
Open

RENS #1719

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions cpp/include/cuopt/mathematical_optimization/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
#define CUOPT_MIP_STRONG_CHVATAL_GOMORY_CUTS "mip_strong_chvatal_gomory_cuts"
#define CUOPT_MIP_REDUCED_COST_STRENGTHENING "mip_reduced_cost_strengthening"
#define CUOPT_MIP_RINS "mip_rins"
#define CUOPT_MIP_RENS "mip_rens"
#define CUOPT_MIP_OBJECTIVE_STEP "mip_objective_step"
#define CUOPT_MIP_CUT_CHANGE_THRESHOLD "mip_cut_change_threshold"
#define CUOPT_MIP_CUT_MIN_ORTHOGONALITY "mip_cut_min_orthogonality"
Expand Down Expand Up @@ -136,14 +137,15 @@
#define CUOPT_MIP_HYPER_DIVING_SHOW_TYPE "mip_hyper_diving_show_type"

/* @brief Recursive sub-MIP (RINS) hyper-parameters */
#define CUOPT_MIP_HYPER_SUBMIP_BASE_TARGET_FIXRATE "mip_hyper_submip_base_target_fixrate"
#define CUOPT_MIP_HYPER_SUBMIP_MIN_FIXRATE "mip_hyper_submip_min_fixrate"
#define CUOPT_MIP_HYPER_SUBMIP_MIN_FIXRATE_CAP "mip_hyper_submip_min_fixrate_cap"
#define CUOPT_MIP_HYPER_SUBMIP_TARGET_MIP_GAP "mip_hyper_submip_target_mip_gap"
#define CUOPT_MIP_HYPER_SUBMIP_NODE_LIMIT_BASE "mip_hyper_submip_node_limit_base"
#define CUOPT_MIP_HYPER_SUBMIP_MAX_LEVEL "mip_hyper_submip_max_level"
#define CUOPT_MIP_HYPER_SUBMIP_ITERATION_LIMIT_RATIO "mip_hyper_submip_iteration_limit_ratio"
#define CUOPT_MIP_HYPER_SUBMIP_ENABLE_CPUFJ "mip_hyper_submip_enable_cpufj"
#define CUOPT_MIP_HYPER_SUBMIP_BASE_TARGET_FIXRATE "mip_hyper_submip_base_target_fixrate"
#define CUOPT_MIP_HYPER_SUBMIP_MIN_FIXRATE "mip_hyper_submip_min_fixrate"
#define CUOPT_MIP_HYPER_SUBMIP_MIN_FIXRATE_CAP "mip_hyper_submip_min_fixrate_cap"
#define CUOPT_MIP_HYPER_SUBMIP_TARGET_MIP_GAP "mip_hyper_submip_target_mip_gap"
#define CUOPT_MIP_HYPER_SUBMIP_NODE_LIMIT_OFFSET "mip_hyper_submip_node_limit_offset"
#define CUOPT_MIP_HYPER_SUBMIP_ITERATION_LIMIT_OFFSET "mip_hyper_submip_iteration_limit_offset"
#define CUOPT_MIP_HYPER_SUBMIP_MAX_LEVEL "mip_hyper_submip_max_level"
#define CUOPT_MIP_HYPER_SUBMIP_ITERATION_LIMIT_RATIO "mip_hyper_submip_iteration_limit_ratio"
#define CUOPT_MIP_HYPER_SUBMIP_ENABLE_CPUFJ "mip_hyper_submip_enable_cpufj"

/* @brief QCQP (barrier) scaling hyper-parameters */
#define CUOPT_QCQP_HYPER_RUIZ_EQUILIBRATION "qcqp_hyper_ruiz_equilibration"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
*/
template <typename i_t, typename f_t>
struct mip_submip_hyper_params_t {
// Enable or disable (recursive) RINS: -1 automatic, 0 disabled, 1 enabled
// Enable or disable (recursive) RINS/RENS: -1 automatic, 0 disabled, 1 enabled
i_t rins = -1;
i_t rens = -1;

// Base for calculating the target fix rate for the neighbourhood. Actual target value is
// determined automatically according to the success and infeasible rate.
Expand All @@ -29,7 +30,10 @@ struct mip_submip_hyper_params_t {
f_t target_mip_gap = 0.01;

// The base node limit for the sub-MIP
i_t node_limit_base = 200;
i_t node_limit_offset = 200;

// The base iteration limit for the sub-MIP
i_t iteration_limit_offset = 10000;

// The current level in the recursion. This is an internal parameter and will set automatically.
i_t level = 0;
Expand Down
378 changes: 230 additions & 148 deletions cpp/src/branch_and_bound/branch_and_bound.cpp

Large diffs are not rendered by default.

20 changes: 11 additions & 9 deletions cpp/src/branch_and_bound/branch_and_bound.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,9 @@ class branch_and_bound_t {
diving_worker_pool_t<i_t, f_t> diving_worker_pool_;

// Worker pool dedicated to recursive RINS
diving_worker_pool_t<i_t, f_t> rins_worker_pool_;
diving_worker_pool_t<i_t, f_t> submip_worker_pool_;
submip_stats_t rins_stats_;
submip_stats_t rens_stats_;

// Global status of the solver.
omp_atomic_t<mip_status_t> solver_status_;
Expand Down Expand Up @@ -369,27 +370,28 @@ class branch_and_bound_t {
void dive_with(diving_worker_t<i_t, f_t>* worker, i_t backtrack_limit);

// Launch a new RINS worker
bool launch_rins_worker(const std::vector<f_t>& sol);
bool launch_submip_worker(const std::vector<f_t>& sol);
void set_solution_from_submip(const simplex::lp_problem_t<i_t, f_t>& lp,
const std::vector<f_t>& solution,
const third_party_presolve_t<i_t, f_t>& presolver,
f_t fixrate);
submip_stats_t& submip_stats,
f_t fixrate,
std::string_view log_prefix);

// Solve the RINS sub-MIP
void solve_submip(diving_worker_t<i_t, f_t>* worker,
const std::vector<f_t>& current_incumbent,
const std::vector<simplex::variable_type_t>& var_type,
submip_stats_t& submip_stats,
i_t num_var_fixed,
i_t num_integers,
i_t submip_level,
std::string_view log_prefix,
bool is_root_heuristic);

// Creates and solves the RINS sub-MIP
void rins(diving_worker_t<i_t, f_t>* worker,
const std::vector<f_t>& current_incumbent,
const std::vector<simplex::variable_type_t>& var_types,
bool is_root_heuristic);
void recursive_submip(diving_worker_t<i_t, f_t>* worker,
const std::vector<f_t>& current_incumbent,
const std::vector<simplex::variable_type_t>& var_types,
bool is_root_heuristic);

void launch_root_heuristics(const simplex::lp_problem_t<i_t, f_t>& lp,
const std::vector<f_t>& sol,
Expand Down
4 changes: 4 additions & 0 deletions cpp/src/branch_and_bound/constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ enum class heuristics_origin_t {
// [3] E. Danna, E. Rothberg, and C. L. Pape, “Exploring relaxation induced neighborhoods to
// improve MIP solutions,” Math. Program., vol. 102, no. 1, pp. 71–90, Jan. 2005,
// doi: 10.1007/s10107-004-0518-7.
// [4] T. Berthold, “RENS: The optimal rounding,” Math. Prog. Comp., vol. 6, no. 1,
// pp. 33–54, Mar. 2014, doi: 10.1007/s12532-013-0060-9.
enum class search_strategy_t : int {
BEST_FIRST = 0, // Best-First + Plunging.
PSEUDOCOST_DIVING = 1, // Pseudocost diving [1, Section 9.2.5]
Expand All @@ -34,6 +36,7 @@ enum class search_strategy_t : int {
FARKAS_DIVING = 5, // Farkas Diving (see [2])
VECTOR_LENGTH_DIVING = 6, // Vector Length Diving [1, Section 9.2.6]
RINS = 7, // RINS (see [3])
RENS = 8 // RENS (see [1, Section 9.1.1], [4])
};

enum class branch_direction_t { NONE = -1, DOWN = 0, UP = 1 };
Expand All @@ -49,6 +52,7 @@ inline const char* search_strategy_to_string(search_strategy_t search_strategy)
case search_strategy_t::FARKAS_DIVING: return "FARKAS_DIVING";
case search_strategy_t::VECTOR_LENGTH_DIVING: return "VECTOR_LENGTH_DIVING";
case search_strategy_t::RINS: return "RINS";
case search_strategy_t::RENS: return "RENS";
}

return "UNKNOWN";
Expand Down
6 changes: 4 additions & 2 deletions cpp/src/math_optimization/solver_settings.cu
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ solver_settings_t<i_t, f_t>::solver_settings_t() : pdlp_settings(), mip_settings
{CUOPT_MIP_STRONG_CHVATAL_GOMORY_CUTS, &mip_settings.strong_chvatal_gomory_cuts, -1, 1, -1},
{CUOPT_MIP_REDUCED_COST_STRENGTHENING, &mip_settings.reduced_cost_strengthening, -1, std::numeric_limits<i_t>::max(), -1},
{CUOPT_MIP_RINS, &mip_settings.submip_params.rins, -1, 1, -1},
{CUOPT_MIP_RENS, &mip_settings.submip_params.rens, -1, 1, -1},
{CUOPT_MIP_OBJECTIVE_STEP, &mip_settings.objective_step, 0, 1, 1},
{CUOPT_NUM_GPUS, &pdlp_settings.num_gpus, -1, 72, 1},
{CUOPT_NUM_GPUS, &mip_settings.num_gpus, -1, 72, 1},
Expand Down Expand Up @@ -185,8 +186,9 @@ solver_settings_t<i_t, f_t>::solver_settings_t() : pdlp_settings(), mip_settings
{CUOPT_MIP_HYPER_DIVING_NODE_LIMIT, &mip_settings.diving_params.node_limit, 0, std::numeric_limits<i_t>::max(), 500, "maximum nodes explored per dive"},
{CUOPT_MIP_HYPER_DIVING_BACKTRACK_LIMIT, &mip_settings.diving_params.backtrack_limit, 0, std::numeric_limits<int16_t>::max(), 5, "maximum backtracking allowed per dive"},
// Recursive sub-MIP (RINS) hyper-parameters (hidden from default --help: name contains "hyper_")
{CUOPT_MIP_HYPER_SUBMIP_NODE_LIMIT_BASE, &mip_settings.submip_params.node_limit_base, 0, std::numeric_limits<i_t>::max(), 200, "base node limit for the sub-MIP"},
{CUOPT_MIP_HYPER_SUBMIP_MAX_LEVEL, &mip_settings.submip_params.max_level, 0, std::numeric_limits<i_t>::max(), 10, "maximum sub-MIP recursion level"},
{CUOPT_MIP_HYPER_SUBMIP_NODE_LIMIT_OFFSET, &mip_settings.submip_params.node_limit_offset, 0, std::numeric_limits<i_t>::max(), 200, "base node limit for the sub-MIP"},
{CUOPT_MIP_HYPER_SUBMIP_ITERATION_LIMIT_OFFSET, &mip_settings.submip_params.iteration_limit_offset, 0, std::numeric_limits<i_t>::max(), 10000, "base sub-MIP simplex-iteration limit for root heuristics"},
{CUOPT_MIP_HYPER_SUBMIP_MAX_LEVEL, &mip_settings.submip_params.max_level, 0, std::numeric_limits<i_t>::max(), 10, "maximum sub-MIP recursion level"},
// QCQP (barrier) scaling hyper-parameter
{CUOPT_QCQP_HYPER_RUIZ_EQUILIBRATION, &pdlp_settings.qcqp_ruiz_equilibration, -1, 1, -1, "Ruiz equilibration for QCQP barrier scaling: -1 automatic (row/column imbalance heuristic), 0 disabled, 1 enabled"},
};
Expand Down
1 change: 1 addition & 0 deletions cpp/src/mip_heuristics/diversity/recombiners/sub_mip.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class sub_mip_recombiner_t : public recombiner_t<i_t, f_t> {
branch_and_bound_settings.zero_half_cuts = 0;
branch_and_bound_settings.inside_submip = 1;
branch_and_bound_settings.submip_settings.rins = 0;
branch_and_bound_settings.submip_settings.rens = 0;
branch_and_bound_settings.strong_branching_simplex_iteration_limit = 200;
branch_and_bound_settings.solution_callback = [this](std::vector<f_t>& solution,
f_t objective) {
Expand Down
5 changes: 3 additions & 2 deletions cpp/src/mip_heuristics/root_heuristics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ struct root_heuristics_t {
const simplex::simplex_solver_settings_t<i_t, f_t>& settings,
f_t root_obj,
const std::vector<simplex::variable_status_t>& root_vstatus,
const std::vector<f_t>& sol)
const std::vector<f_t>& sol,
search_strategy_t type)
{
submip_worker_ =
std::make_unique<diving_worker_t<i_t, f_t>>(id, lp, Arow_, var_types_, settings);
Expand All @@ -51,7 +52,7 @@ struct root_heuristics_t {
submip_worker_->leaf_solution.x = sol;
submip_worker_->recompute_bounds = false;
submip_worker_->recompute_basis = true;
submip_worker_->search_strategy = search_strategy_t::RINS;
submip_worker_->search_strategy = type;
submip_worker_->set_active();

return submip_worker_.get();
Expand Down