Skip to content
Draft
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
7 changes: 5 additions & 2 deletions cpp/include/cuopt/mathematical_optimization/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#define CUOPT_BARRIER_STEP_SCALE "barrier_step_scale"
#define CUOPT_ELIMINATE_DENSE_COLUMNS "eliminate_dense_columns"
#define CUOPT_CUDSS_DETERMINISTIC "cudss_deterministic"
#define CUOPT_CUDSS_HYPER_ND_NLEVELS "cudss_hyper_nd_nlevels"
#define CUOPT_PRESOLVE "presolve"
#define CUOPT_MIP_PROBING "mip_probing"
#define CUOPT_DUAL_POSTSOLVE "dual_postsolve"
Expand Down Expand Up @@ -238,8 +239,10 @@
#define CUOPT_MIP_SCALING_ON 1
#define CUOPT_MIP_SCALING_NO_OBJECTIVE 2

#define CUOPT_BARRIER_ITERATIVE_REFINEMENT_OFF 0
#define CUOPT_BARRIER_ITERATIVE_REFINEMENT_ON 1
/* @brief Iterative refinement for barrier method */
#define CUOPT_BARRIER_IR_OFF 0
#define CUOPT_BARRIER_IR_GMRES 1
#define CUOPT_BARRIER_IR_FIXED_POINT 2

/* @brief Scalar problem attribute selectors
* Passed as cuopt_int_t; the valid set depends on the accessor's value type. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ class pdlp_solver_settings_t {
bool per_constraint_residual{false};
bool crossover{false};
bool cudss_deterministic{false};
i_t cudss_nd_nlevels{-1};
i_t folding{-1};
i_t augmented{-1};
i_t dualize{-1};
Expand All @@ -303,7 +304,8 @@ class pdlp_solver_settings_t {
i_t qcqp_ruiz_equilibration{-1};
bool eliminate_dense_columns{true};
pdlp_precision_t pdlp_precision{pdlp_precision_t::DefaultPrecision};
bool barrier_iterative_refinement{true};
// Iterative refinement for barrier method: 0: off, 1: gmres (default), 2: fixed_point
i_t barrier_iterative_refinement{barrier_iterative_refinement_t::GMRES};
i_t barrier_soc_threshold{100};
f_t barrier_step_scale{0.9};
bool save_best_primal_so_far{false};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,5 +142,19 @@ enum presolver_t : int {
PSLP = CUOPT_PRESOLVE_PSLP
};

/**
* @brief Enum representing the iterative refinement method used by the barrier
* solver after each solve.
*
* Off: Disable iterative refinement.
* GMRES: Use restarted GMRES (default).
* FixedPoint: Use a fixed-point residual-correction loop.
*/
enum barrier_iterative_refinement_t : int {
Off = CUOPT_BARRIER_IR_OFF,
GMRES = CUOPT_BARRIER_IR_GMRES,
FixedPoint = CUOPT_BARRIER_IR_FIXED_POINT
};

} // namespace mathematical_optimization
} // namespace cuopt
29 changes: 21 additions & 8 deletions cpp/src/barrier/barrier.cu
Original file line number Diff line number Diff line change
Expand Up @@ -2278,9 +2278,13 @@ int barrier_solver_t<i_t, f_t>::initial_point(iteration_data_t<i_t, f_t>& data)
}
} op(data);

if (settings.barrier_iterative_refinement) {
if (settings.barrier_iterative_refinement != barrier_iterative_refinement_t::Off) {
const f_t ir_tol = data.has_sparse_cones() ? f_t(1e-12) : f_t(1e-8);
iterative_refinement<i_t, f_t, op_t>(op, rhs, soln, ir_tol);

const i_t internal_method =
(settings.barrier_iterative_refinement == barrier_iterative_refinement_t::FixedPoint) ? 0
: 1;
iterative_refinement<i_t, f_t, op_t>(op, rhs, soln, ir_tol, internal_method);
}

for (i_t k = 0; k < lp.num_cols; k++) {
Expand Down Expand Up @@ -2903,11 +2907,15 @@ i_t barrier_solver_t<i_t, f_t>::gpu_compute_search_direction(iteration_data_t<i_
data_.chol->solve(b, x);
}
} op(data);
if (settings.barrier_iterative_refinement) {
if (settings.barrier_iterative_refinement != barrier_iterative_refinement_t::Off) {
raft::common::nvtx::range fun_scope("Barrier: iterative_refinement");
const f_t ir_tol = data.has_sparse_cones() ? f_t(1e-12) : f_t(1e-8);
const f_t ir_tol = data.has_sparse_cones() ? f_t(1e-12) : f_t(1e-8);

const i_t internal_method =
(settings.barrier_iterative_refinement == barrier_iterative_refinement_t::FixedPoint) ? 0
: 1;
const f_t solve_err = iterative_refinement<i_t, f_t, op_t>(
op, data.d_augmented_rhs_, data.d_augmented_soln_, ir_tol);
op, data.d_augmented_rhs_, data.d_augmented_soln_, ir_tol, internal_method);
if (solve_err > 1e-1) {
settings.log.printf("|| Aug (dx, dy) - aug_rhs || %e after IR\n", solve_err);
}
Expand Down Expand Up @@ -2977,7 +2985,8 @@ i_t barrier_solver_t<i_t, f_t>::gpu_compute_search_direction(iteration_data_t<i_
// GMRES can handle large, potentially ill-conditioned systems better than simple Richardson
// or classical iterative refinement, at the potential cost of higher computational work and
// memory. This is only used on the pure Schur-complement (n_dense_columns == 0).
if (settings.barrier_iterative_refinement && data.n_dense_columns == 0) {
if (settings.barrier_iterative_refinement != barrier_iterative_refinement_t::Off &&
data.n_dense_columns == 0) {
struct adat_op_t {
adat_op_t(iteration_data_t<i_t, f_t>& data) : data_(data) {}
iteration_data_t<i_t, f_t>& data_;
Expand All @@ -2993,8 +3002,12 @@ i_t barrier_solver_t<i_t, f_t>::gpu_compute_search_direction(iteration_data_t<i_
data_.gpu_solve_adat(b, x);
}
} adat_op(data);
const f_t adat_solve_err =
iterative_refinement<i_t, f_t, adat_op_t>(adat_op, data.d_h_, data.d_dy_);

const i_t internal_method =
(settings.barrier_iterative_refinement == barrier_iterative_refinement_t::FixedPoint) ? 0
: 1;
const f_t adat_solve_err = iterative_refinement<i_t, f_t, adat_op_t>(
adat_op, data.d_h_, data.d_dy_, f_t(1e-8), internal_method);
if (adat_solve_err > 1e-1) {
settings.log.printf("||ADAT*dy - h|| %e after IR\n", adat_solve_err);
}
Expand Down
26 changes: 12 additions & 14 deletions cpp/src/barrier/iterative_refinement.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ struct subtract_scaled_op {
};

template <typename i_t, typename f_t, typename T>
f_t iterative_refinement_simple(T& op,
const rmm::device_uvector<f_t>& b,
rmm::device_uvector<f_t>& x,
f_t tol = 1e-8)
f_t iterative_refinement_fixed_point(T& op,
const rmm::device_uvector<f_t>& b,
rmm::device_uvector<f_t>& x,
f_t tol = 1e-8)
Comment thread
yuwenchen95 marked this conversation as resolved.
{
rmm::device_uvector<f_t> x_sav(x, x.stream());

Expand Down Expand Up @@ -362,16 +362,15 @@ f_t iterative_refinement_gmres(T& op,
}

template <typename i_t, typename f_t, typename T>
f_t iterative_refinement(T& op,
const dense_vector_t<i_t, f_t>& b,
dense_vector_t<i_t, f_t>& x,
f_t tol = 1e-8)
f_t iterative_refinement(
T& op, const dense_vector_t<i_t, f_t>& b, dense_vector_t<i_t, f_t>& x, f_t tol, i_t method)
{
rmm::device_uvector<f_t> d_b(b.size(), op.data_.handle_ptr->get_stream());
raft::copy(d_b.data(), b.data(), b.size(), op.data_.handle_ptr->get_stream());
rmm::device_uvector<f_t> d_x(x.size(), op.data_.handle_ptr->get_stream());
raft::copy(d_x.data(), x.data(), x.size(), op.data_.handle_ptr->get_stream());
auto err = iterative_refinement_gmres<i_t, f_t, T>(op, d_b, d_x, tol);
auto err = (method == 0) ? iterative_refinement_fixed_point<i_t, f_t, T>(op, d_b, d_x, tol)
: iterative_refinement_gmres<i_t, f_t, T>(op, d_b, d_x, tol);

raft::copy(x.data(), d_x.data(), x.size(), op.data_.handle_ptr->get_stream());

Expand All @@ -380,12 +379,11 @@ f_t iterative_refinement(T& op,
}

template <typename i_t, typename f_t, typename T>
f_t iterative_refinement(T& op,
const rmm::device_uvector<f_t>& b,
rmm::device_uvector<f_t>& x,
f_t tol = 1e-8)
f_t iterative_refinement(
T& op, const rmm::device_uvector<f_t>& b, rmm::device_uvector<f_t>& x, f_t tol, i_t method)
{
return iterative_refinement_gmres<i_t, f_t, T>(op, b, x, tol);
return (method == 0) ? iterative_refinement_fixed_point<i_t, f_t, T>(op, b, x, tol)
: iterative_refinement_gmres<i_t, f_t, T>(op, b, x, tol);
}

} // namespace cuopt::mathematical_optimization::barrier
10 changes: 10 additions & 0 deletions cpp/src/barrier/sparse_cholesky.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,16 @@ class sparse_cholesky_cudss_t : public sparse_cholesky_base_t<i_t, f_t> {
status,
"cudssConfigSet for deterministic mode");
}

if (settings_.cudss_nd_nlevels >= 0) {
settings_.log.printf("cuDSS ND levels : %d\n", settings_.cudss_nd_nlevels);
int32_t nd_nlevels = settings_.cudss_nd_nlevels;
CUDSS_CALL_AND_CHECK_EXIT(
cudssConfigSet(solverConfig, CUDSS_CONFIG_ND_NLEVELS, &nd_nlevels, sizeof(int32_t)),
status,
"cudssConfigSet for nd nlevels");
}

#endif

#if USE_ITERATIVE_REFINEMENT
Expand Down
13 changes: 8 additions & 5 deletions cpp/src/dual_simplex/simplex_solver_settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <cuopt/mathematical_optimization/mip/diving_hyper_params.hpp>
#include <cuopt/mathematical_optimization/mip/submip_hyper_params.hpp>
#include <cuopt/mathematical_optimization/utilities/internals.hpp>

#include <dual_simplex/logger.hpp>
#include <math_optimization/types.hpp>
Expand Down Expand Up @@ -66,10 +67,11 @@ struct simplex_solver_settings_t {
print_presolve_stats(true),
barrier_presolve(false),
cudss_deterministic(false),
cudss_nd_nlevels(-1),
deterministic(false),
barrier(false),
eliminate_dense_columns(true),
barrier_iterative_refinement(true),
barrier_iterative_refinement(barrier_iterative_refinement_t::GMRES),
barrier_step_scale(0.9),
barrier_soc_threshold(100),
num_gpus(1),
Expand Down Expand Up @@ -161,12 +163,13 @@ struct simplex_solver_settings_t {
bool print_presolve_stats; // true to print presolve stats
bool barrier_presolve; // true to use barrier presolve
bool cudss_deterministic; // true to use cuDSS deterministic mode, false for non-deterministic
i_t cudss_nd_nlevels; // -1 automatic/unset, else METIS nested-dissection depth for cuDSS
bool barrier; // true to use barrier method, false to use dual simplex method
bool deterministic; // true to use B&B deterministic mode, false to use non-deterministic mode
bool eliminate_dense_columns; // true to eliminate dense columns from A*D*A^T
bool barrier_iterative_refinement; // true to use iterative refinement for barrier method
f_t barrier_step_scale; // step scale for barrier method
i_t barrier_soc_threshold; // SOC dimension above which rank-2 sparse scaling is used
bool eliminate_dense_columns; // true to eliminate dense columns from A*D*A^T
i_t barrier_iterative_refinement; // 0: off, 1: gmres (default), 2: fixed_point
f_t barrier_step_scale; // step scale for barrier method
i_t barrier_soc_threshold; // SOC dimension above which rank-2 sparse scaling is used
int num_gpus; // Number of GPUs to use (maximum of 2 gpus are supported at the moment)
i_t folding; // -1 automatic, 0 don't fold, 1 fold
i_t augmented; // -1 automatic, 0 to solve with ADAT, 1 to solve with augmented system
Expand Down
28 changes: 15 additions & 13 deletions cpp/src/grpc/codegen/field_registry.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -496,8 +496,7 @@ pdlp_settings:
- dual_postsolve:
# C++ default is `true`; using proto3 `optional` so that a client that
# omits this field gets the solver default rather than the proto3 zero
# (`false`). See also the matching `optional` markers on
# `barrier_iterative_refinement` (pdlp) and `probing` (mip).
# (`false`). See also the matching `optional` marker on `probing` (mip).
field_num: 17
type: bool
optional: true
Expand Down Expand Up @@ -539,15 +538,6 @@ pdlp_settings:
field_num: 27
type: bool
optional: true
- barrier_iterative_refinement:
# Whether the barrier method runs iterative refinement after each solve
# (see cpp/src/barrier/barrier.cu). C++ default is `true`. Declared as
# proto3 `optional` so that a client which omits this field preserves
# the solver default; without `optional`, the proto3 wire zero (`false`)
# would silently overwrite the C++ default.
field_num: 31
type: bool
optional: true
- barrier_step_scale:
# Step scale used by the barrier method primal/dual updates. Local-solve
# binding restricts the range to [0.5, 0.9999] with default 0.9; see
Expand All @@ -559,6 +549,19 @@ pdlp_settings:
field_num: 33
type: int32
optional: true
- cudss_nd_nlevels:
field_num: 34
type: int32
optional: true
# field_num 35-37 previously used by cudss_hybrid_mode/cudss_hybrid_execute_mode/
# cudss_host_nthreads, removed — do not reuse these numbers.
# field_num 31 previously held `barrier_iterative_refinement` as a bool; that field
# was retired and the name reused below (field_num 38) for the merged int method,
# so the exposed parameter name is unchanged even though the wire field_num moved.
- barrier_iterative_refinement:
field_num: 38
type: int32
optional: true
- save_best_primal_so_far:
field_num: 28
type: bool
Expand Down Expand Up @@ -726,8 +729,7 @@ mip_settings:
# C++ default is `true`; declared as proto3 `optional` so that a client
# which omits this field preserves the solver default. Without
# `optional`, the proto3 wire zero (`false`) would silently overwrite
# the C++ default. See also `dual_postsolve` and
# `barrier_iterative_refinement` in pdlp_settings.
# the C++ default. See also `dual_postsolve` in pdlp_settings.
field_num: 29
type: bool
optional: true
Expand Down
3 changes: 2 additions & 1 deletion cpp/src/grpc/codegen/generated/cuopt_remote_data.proto
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,10 @@ message PDLPSolverSettings {
bool save_best_primal_so_far = 28;
bool first_primal_feasible = 29;
optional int32 pdlp_precision = 30;
optional bool barrier_iterative_refinement = 31;
optional double barrier_step_scale = 32;
optional int32 postsolve_info = 33;
optional int32 cudss_nd_nlevels = 34;
optional int32 barrier_iterative_refinement = 38;
PDLPWarmStartData warm_start_data = 50;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@
pb_settings->set_ordering(settings.ordering);
pb_settings->set_barrier_dual_initial_point(settings.barrier_dual_initial_point);
pb_settings->set_eliminate_dense_columns(settings.eliminate_dense_columns);
pb_settings->set_barrier_iterative_refinement(settings.barrier_iterative_refinement);
pb_settings->set_barrier_step_scale(settings.barrier_step_scale);
pb_settings->set_postsolve_info(settings.postsolve_info);
pb_settings->set_cudss_nd_nlevels(settings.cudss_nd_nlevels);

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.

are these auto generated?

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.

I think so when I added these new parameters.

pb_settings->set_barrier_iterative_refinement(settings.barrier_iterative_refinement);
pb_settings->set_save_best_primal_so_far(settings.save_best_primal_so_far);
pb_settings->set_first_primal_feasible(settings.first_primal_feasible);
pb_settings->set_pdlp_precision(static_cast<int32_t>(settings.pdlp_precision));
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,18 @@
if (pb_settings.has_eliminate_dense_columns()) {
settings.eliminate_dense_columns = pb_settings.eliminate_dense_columns();
}
if (pb_settings.has_barrier_iterative_refinement()) {
settings.barrier_iterative_refinement = pb_settings.barrier_iterative_refinement();
}
if (pb_settings.has_barrier_step_scale()) {
settings.barrier_step_scale = pb_settings.barrier_step_scale();
}
if (pb_settings.has_postsolve_info()) {
settings.postsolve_info = pb_settings.postsolve_info();
}
if (pb_settings.has_cudss_nd_nlevels()) {
settings.cudss_nd_nlevels = pb_settings.cudss_nd_nlevels();
}
if (pb_settings.has_barrier_iterative_refinement()) {
settings.barrier_iterative_refinement = pb_settings.barrier_iterative_refinement();
}
settings.save_best_primal_so_far = pb_settings.save_best_primal_so_far();
settings.first_primal_feasible = pb_settings.first_primal_feasible();
if (pb_settings.has_pdlp_precision()) {
Expand Down
4 changes: 3 additions & 1 deletion cpp/src/math_optimization/solver_settings.cu
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ solver_settings_t<i_t, f_t>::solver_settings_t() : pdlp_settings(), mip_settings
{CUOPT_FOLDING, &pdlp_settings.folding, -1, 1, -1},
{CUOPT_DUALIZE, &pdlp_settings.dualize, -1, 1, -1},
{CUOPT_ORDERING, &pdlp_settings.ordering, -1, 1, -1},
{CUOPT_BARRIER_ITERATIVE_REFINEMENT, &pdlp_settings.barrier_iterative_refinement, CUOPT_BARRIER_IR_OFF, CUOPT_BARRIER_IR_FIXED_POINT, CUOPT_BARRIER_IR_GMRES},
{CUOPT_BARRIER_DUAL_INITIAL_POINT, &pdlp_settings.barrier_dual_initial_point, -1, 1, -1},
{CUOPT_POSTSOLVE_INFO, &pdlp_settings.postsolve_info, -1, 1, -1},
{CUOPT_MIP_CUT_PASSES, &mip_settings.max_cut_passes, -1, std::numeric_limits<i_t>::max(), 10},
Expand Down Expand Up @@ -190,6 +191,8 @@ solver_settings_t<i_t, f_t>::solver_settings_t() : pdlp_settings(), mip_settings
{CUOPT_BARRIER_PRESOLVE_BOUND_FREE_VARIABLES, &pdlp_settings.barrier_presolve_bound_free_variables, -1, 1, -1, "Bound free variables during barrier presolve: -1 automatic (current default behavior), 0 disabled, 1 enabled"},
// 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"},
// cuDSS (barrier) reordering hyper-parameter
{CUOPT_CUDSS_HYPER_ND_NLEVELS, &pdlp_settings.cudss_nd_nlevels, -1, std::numeric_limits<i_t>::max(), -1, "METIS nested-dissection depth for cuDSS: -1 unset (cuDSS default), else explicit depth"},
};

// Bool parameters
Expand All @@ -206,7 +209,6 @@ solver_settings_t<i_t, f_t>::solver_settings_t() : pdlp_settings(), mip_settings
{CUOPT_ELIMINATE_DENSE_COLUMNS, &pdlp_settings.eliminate_dense_columns, true},
{CUOPT_CUDSS_DETERMINISTIC, &pdlp_settings.cudss_deterministic, false},
{CUOPT_DUAL_POSTSOLVE, &pdlp_settings.dual_postsolve, true},
{CUOPT_BARRIER_ITERATIVE_REFINEMENT, &pdlp_settings.barrier_iterative_refinement, true},
{CUOPT_MIP_PROBING, &mip_settings.probing, true},
{CUOPT_USE_DISTRIBUTED_PDLP, &pdlp_settings.use_distributed_pdlp, false},
// Diving heuristic hyper-parameters (hidden from default --help: name contains "hyper_")
Expand Down
Loading