From 278d02a191c4466bae3c09efcc708f3e4365c4eb Mon Sep 17 00:00:00 2001 From: yuwenchen95 Date: Tue, 14 Jul 2026 07:42:07 -0700 Subject: [PATCH 1/9] Extend Sedumi initialization to LP/QP Signed-off-by: yuwenchen95 --- cpp/src/barrier/barrier.cu | 56 +++++++++++-------- .../dual_simplex/simplex_solver_settings.hpp | 3 +- cpp/src/math_optimization/solver_settings.cu | 2 +- .../cuopt_server/tests/test_lp.py | 2 +- .../linear_programming/data_definition.py | 3 +- 5 files changed, 38 insertions(+), 28 deletions(-) diff --git a/cpp/src/barrier/barrier.cu b/cpp/src/barrier/barrier.cu index 784f6c0901..e55abddce3 100644 --- a/cpp/src/barrier/barrier.cu +++ b/cpp/src/barrier/barrier.cu @@ -2155,41 +2155,49 @@ int barrier_solver_t::initial_point(iteration_data_t& data) const bool use_augmented = data.use_augmented; const bool has_direct_free_linear = data.n_direct_free_linear > 0; - // SOCP: data-dependent initial point following SeDuMi (Sturm, 1999). - // mu = sqrt((1 + ||b||_inf) * (1 + ||c||_inf)) - // primal and dual: x = mu * e_K, z = mu * e_K + const i_t init_strategy = data.has_cones() ? 2 : settings.barrier_dual_initial_point; + + // Option 2: Sturm/SeDuMi-style mu-based primal+dual initial point. + // mu = sqrt((1 + ||b||_inf) * (1 + ||c||_inf)); x = z = mu * e_K. // where e_K is the identity of the symmetric cone: // LP block: e = 1, SOC block: e = (sqrt(2), 0, ..., 0) - if (data.has_cones()) { - const i_t cs = data.cone_start(); - const f_t norm_b = vector_norm_inf(lp.rhs); - const f_t norm_c = vector_norm_inf(lp.objective); - const f_t mu = std::sqrt((1.0 + norm_b) * (1.0 + norm_c)); - const f_t sqrt2 = std::sqrt(2.0); - const f_t x_soc = mu * sqrt2; - const f_t z_soc = mu * sqrt2; - // Linear orthant - for (i_t j = 0; j < cs; ++j) { + // Full primal+dual point; no factorization/solve (main loop factorizes later). + if (init_strategy == 2) { + const f_t norm_b = vector_norm_inf(lp.rhs); + const f_t norm_c = vector_norm_inf(lp.objective); + const f_t mu = std::sqrt((1.0 + norm_b) * (1.0 + norm_c)); + const f_t sqrt2 = std::sqrt(2.0); + const i_t linear_end = data.linear_xz_size(lp.num_cols); + + // Linear orthant: x = z = mu * e, with e = 1 + for (i_t j = 0; j < linear_end; ++j) { data.x[j] = mu; data.z[j] = mu; } if (has_direct_free_linear) { for (i_t j : presolve_info.direct_free_variables) { - if (j < cs) { data.z[j] = 0.0; } + if (j < linear_end) { data.z[j] = 0.0; } } } - // SOC blocks - i_t off = 0; - for (size_t k = 0; k < lp.second_order_cone_dims.size(); k++) { - i_t q_k = lp.second_order_cone_dims[k]; - data.x[cs + off] = x_soc; - data.z[cs + off] = z_soc; - for (i_t j = 1; j < q_k; ++j) { - data.x[cs + off + j] = 0.0; - data.z[cs + off + j] = 0.0; + + // SOC blocks: x = z = mu * e, with e = (sqrt(2), 0, ..., 0) + if (data.has_cones()) { + const i_t cs = data.cone_start(); + const f_t x_soc = mu * sqrt2; + const f_t z_soc = mu * sqrt2; + i_t off = 0; + for (size_t k = 0; k < lp.second_order_cone_dims.size(); k++) { + i_t q_k = lp.second_order_cone_dims[k]; + data.x[cs + off] = x_soc; + data.z[cs + off] = z_soc; + for (i_t j = 1; j < q_k; ++j) { + data.x[cs + off + j] = 0.0; + data.z[cs + off + j] = 0.0; + } + off += q_k; } - off += q_k; } + data.y.set_scalar(0.0); if (data.n_upper_bounds > 0) { data.w.set_scalar(mu); diff --git a/cpp/src/dual_simplex/simplex_solver_settings.hpp b/cpp/src/dual_simplex/simplex_solver_settings.hpp index d5834f323f..fe8c5474e3 100644 --- a/cpp/src/dual_simplex/simplex_solver_settings.hpp +++ b/cpp/src/dual_simplex/simplex_solver_settings.hpp @@ -164,7 +164,8 @@ struct simplex_solver_settings_t { i_t dualize; // -1 automatic, 0 to not dualize, 1 to dualize i_t ordering; // -1 automatic, 0 to use nested dissection, 1 to use AMD i_t barrier_dual_initial_point; // -1 automatic, 0 to use Lustig, Marsten, and Shanno initial - // point, 1 to use initial point form dual least squares problem + // point, 1 to use initial point form dual least squares problem, + // 2 to use Sturm/SeDuMi mu-based primal+dual point bool check_Q; // true to check if Q is positive semidefinite bool crossover; // true to do crossover, false to not i_t refactor_frequency; // number of basis updates before refactorization diff --git a/cpp/src/math_optimization/solver_settings.cu b/cpp/src/math_optimization/solver_settings.cu index 8bfd7cd8ba..816414c893 100644 --- a/cpp/src/math_optimization/solver_settings.cu +++ b/cpp/src/math_optimization/solver_settings.cu @@ -131,7 +131,7 @@ solver_settings_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_DUAL_INITIAL_POINT, &pdlp_settings.barrier_dual_initial_point, -1, 1, -1}, + {CUOPT_BARRIER_DUAL_INITIAL_POINT, &pdlp_settings.barrier_dual_initial_point, -1, 2, -1}, {CUOPT_MIP_CUT_PASSES, &mip_settings.max_cut_passes, -1, std::numeric_limits::max(), 10}, {CUOPT_MIP_MIXED_INTEGER_ROUNDING_CUTS, &mip_settings.mir_cuts, -1, 1, -1}, {CUOPT_MIP_MIXED_INTEGER_GOMORY_CUTS, &mip_settings.mixed_integer_gomory_cuts, -1, 1, -1}, diff --git a/python/cuopt_server/cuopt_server/tests/test_lp.py b/python/cuopt_server/cuopt_server/tests/test_lp.py index e3a683f8de..8ea85b60ab 100644 --- a/python/cuopt_server/cuopt_server/tests/test_lp.py +++ b/python/cuopt_server/cuopt_server/tests/test_lp.py @@ -180,7 +180,7 @@ def test_barrier_solver_options( - cudss_deterministic: True for deterministic, False for nondeterministic - barrier_dual_initial_point: (-1) automatic, (0) Lustig-Marsten-Shanno, - (1) dual least squares + (1) dual least squares, (2) Sturm/SeDuMi mu-based primal+dual """ data = get_std_data_for_lp() diff --git a/python/cuopt_server/cuopt_server/utils/linear_programming/data_definition.py b/python/cuopt_server/cuopt_server/utils/linear_programming/data_definition.py index 6cd8f7828a..75998a347a 100644 --- a/python/cuopt_server/cuopt_server/utils/linear_programming/data_definition.py +++ b/python/cuopt_server/cuopt_server/utils/linear_programming/data_definition.py @@ -501,7 +501,8 @@ class SolverConfig(BaseModel): description="Set the type of dual initial point to use for the barrier" "solver. -1 for automatic, 0 to use Lustig, Marsten, and Shanno" "initial point, 1 to use initial point from a dual least squares" - "problem", + "problem, 2 to use Sturm/SeDuMi mu-based primal+dual" + "point", ) eliminate_dense_columns: Optional[bool] = Field( default=True, From 8e29f927a73e64046bfc38693e6b4a3f78365eaf Mon Sep 17 00:00:00 2001 From: yuwenchen95 Date: Wed, 15 Jul 2026 09:58:14 -0700 Subject: [PATCH 2/9] Extend dual initial point strategies for socp Signed-off-by: yuwenchen95 --- cpp/src/barrier/barrier.cu | 144 ++++++++++++++++++++++++------------- 1 file changed, 96 insertions(+), 48 deletions(-) diff --git a/cpp/src/barrier/barrier.cu b/cpp/src/barrier/barrier.cu index e55abddce3..bae7e258ca 100644 --- a/cpp/src/barrier/barrier.cu +++ b/cpp/src/barrier/barrier.cu @@ -94,6 +94,39 @@ bool validate_barrier_cone_layout(const lp_problem_t& problem, return true; } +// Push entries into interior of nonnegative orthant and SOC. +template +static void ensure_initial_point_interior(dense_vector_t& values, + f_t epsilon_adjust, + const std::vector& linear_mask, + i_t linear_end, + const std::vector& cone_dims) +{ + f_t min_linear = inf; + for (i_t j = 0; j < linear_end; ++j) { + if (linear_mask[j]) { min_linear = std::min(min_linear, values[j]); } + } + if (min_linear <= epsilon_adjust) { + const f_t delta = -min_linear + epsilon_adjust; + for (i_t j = 0; j < linear_end; ++j) { + if (linear_mask[j]) { values[j] += delta; } + } + } + + i_t off = 0; + for (i_t q_k : cone_dims) { + const i_t base = linear_end + off; + f_t tail_sq = 0.0; + for (i_t j = 1; j < q_k; ++j) { + const f_t t = values[base + j]; + tail_sq += t * t; + } + const f_t tail_norm = std::sqrt(tail_sq); + if (values[base] <= tail_norm + epsilon_adjust) { values[base] = tail_norm + epsilon_adjust; } + off += q_k; + } +} + template [[maybe_unused]] static void pairwise_multiply( f_t* a, f_t* b, f_t* out, int size, rmm::cuda_stream_view stream) @@ -239,7 +272,6 @@ class iteration_data_t { complementarity_residual_norm_save(inf), diag(lp.num_cols), inv_diag(lp.num_cols), - inv_sqrt_diag(lp.num_cols), AD(lp.num_cols, lp.num_rows, 0), AT(lp.num_rows, lp.num_cols, 0), ADAT(lp.num_rows, lp.num_rows, 0), @@ -540,12 +572,9 @@ class iteration_data_t { } inv_diag.set_scalar(1.0); - if (use_augmented) { diag.multiply_scalar(-1.0); } if (n_upper_bounds > 0 || (has_Q && !use_augmented)) { diag.inverse(inv_diag); } // TMP diag and inv_diag should directly created and filled on the GPU raft::copy(d_inv_diag.data(), inv_diag.data(), inv_diag.size(), stream_view_); - inv_sqrt_diag.set_scalar(1.0); - if (n_upper_bounds > 0 || (has_Q && !use_augmented)) { inv_diag.sqrt(inv_sqrt_diag); } } if (settings.concurrent_halt != nullptr && *settings.concurrent_halt == 1) { return; } @@ -1912,7 +1941,6 @@ class iteration_data_t { dense_vector_t diag; pinned_dense_vector_t inv_diag; - dense_vector_t inv_sqrt_diag; rmm::device_uvector d_original_A_values; @@ -2237,15 +2265,18 @@ int barrier_solver_t::initial_point(iteration_data_t& data) dense_vector_t DinvFu(lp.num_cols); // DinvFu = Dinv * Fu data.inv_diag.pairwise_product(Fu, DinvFu); dense_vector_t q(lp.num_rows); + const i_t aug_base = lp.num_cols + lp.num_rows; + const i_t aug_size = use_augmented ? std::max(aug_base, data.device_augmented.n) : aug_base; if (use_augmented) { - dense_vector_t rhs(lp.num_cols + lp.num_rows); + dense_vector_t rhs(aug_size); + rhs.set_scalar(0.0); for (i_t k = 0; k < lp.num_cols; k++) { rhs[k] = -Fu[k]; } for (i_t k = 0; k < lp.num_rows; k++) { rhs[lp.num_cols + k] = rhs_x[k]; } - dense_vector_t soln(lp.num_cols + lp.num_rows); + dense_vector_t soln(aug_size); i_t solve_status = data.chol->solve(rhs, soln); struct op_t { op_t(iteration_data_t& data) : data_(data) {} @@ -2263,7 +2294,11 @@ int barrier_solver_t::initial_point(iteration_data_t& data) } } op(data); - if (settings.barrier_iterative_refinement) { + // Initial-point IR is LP/QP-only. Cone problems and direct-free linear vars are excluded. + if (settings.barrier_iterative_refinement && !data.has_cones() && + data.n_direct_free_linear == 0) { + raft::copy( + data.d_diag_.data(), data.diag.data(), data.diag.size(), data.handle_ptr->get_stream()); iterative_refinement(op, rhs, soln); } @@ -2317,27 +2352,19 @@ int barrier_solver_t::initial_point(iteration_data_t& data) } } - // Verify A*x = b - dense_vector_t init_primal_residual(lp.num_rows); - init_primal_residual = lp.rhs; - data.cusparse_view_.spmv(1.0, data.x, -1.0, init_primal_residual); - data.handle_ptr->get_stream().synchronize(); -#ifdef PRINT_INFO - settings.log.printf("||b - A * x||: %.16e\n", vector_norm2(init_primal_residual)); -#endif - - if (data.n_upper_bounds > 0) { - dense_vector_t init_bound_residual(data.n_upper_bounds); - for (i_t k = 0; k < data.n_upper_bounds; k++) { - i_t j = data.upper_bounds[k]; - init_bound_residual[k] = lp.upper[j] - data.w[k] - data.x[j]; - } -#ifdef PRINT_INFO - settings.log.printf("|| u - w - x||: %e\n", vector_norm2(init_bound_residual)); -#endif - } - float64_t epsilon_adjust = 10.0; + // Push entries into interior of nonnegative orthant and SOC. + const bool has_soc = data.has_cones(); + const i_t linear_end = has_soc ? data.cone_start() : lp.num_cols; + auto ensure_interior = [&](dense_vector_t& values, + const std::vector& linear_mask) { + if (has_soc) { + ensure_initial_point_interior( + values, epsilon_adjust, linear_mask, linear_end, lp.second_order_cone_dims); + } else { + values.ensure_positive(epsilon_adjust, linear_mask); + } + }; if (settings.barrier_dual_initial_point == -1 || settings.barrier_dual_initial_point == 0) { // Use the dual starting point suggested by the paper @@ -2388,12 +2415,12 @@ int barrier_solver_t::initial_point(iteration_data_t& data) } } } else if (use_augmented) { - dense_vector_t dual_rhs(lp.num_cols + lp.num_rows); + dense_vector_t dual_rhs(aug_size); dual_rhs.set_scalar(0.0); for (i_t k = 0; k < lp.num_cols; k++) { dual_rhs[k] = data.c[k]; } - dense_vector_t py(lp.num_cols + lp.num_rows); + dense_vector_t py(aug_size); data.chol->solve(dual_rhs, py); for (i_t k = 0; k < lp.num_cols; k++) { data.z[k] = py[k]; @@ -2407,7 +2434,6 @@ int barrier_solver_t::initial_point(iteration_data_t& data) data.v.multiply_scalar(-1.0); data.v.ensure_positive(epsilon_adjust); - data.z.ensure_positive(epsilon_adjust, nonnegative_z); } else { // First compute rhs = A*Dinv*c dense_vector_t rhs(lp.num_rows); @@ -2431,24 +2457,8 @@ int barrier_solver_t::initial_point(iteration_data_t& data) data.gather_upper_bounds(data.z, data.v); data.v.multiply_scalar(-1.0); data.v.ensure_positive(epsilon_adjust); - data.z.ensure_positive(epsilon_adjust, nonnegative_z); } - // Verify A'*y + z - E*v - Q*x = c - dense_vector_t init_dual_residual(lp.num_cols); - data.z.pairwise_subtract(data.c, init_dual_residual); - if (data.Q.n > 0) { matrix_vector_multiply(data.Q, -1.0, data.x, 1.0, init_dual_residual); } - data.cusparse_view_.transpose_spmv(1.0, data.y, 1.0, init_dual_residual); - if (data.n_upper_bounds > 0) { - for (i_t k = 0; k < data.n_upper_bounds; k++) { - i_t j = data.upper_bounds[k]; - init_dual_residual[j] -= data.v[k]; - } - } -#ifdef PRINT_INFO - settings.log.printf("||A^T y + z - E*v - Q*x - c ||: %e\n", - vector_norm2(init_dual_residual)); -#endif // Make sure (w, x, v, z) > 0. Skip free variables being handled directly. data.w.ensure_positive(epsilon_adjust); std::vector nonnegative_variables(data.x.size(), 1); @@ -2457,7 +2467,8 @@ int barrier_solver_t::initial_point(iteration_data_t& data) nonnegative_variables[j] = 0; } } - data.x.ensure_positive(epsilon_adjust, nonnegative_variables); + ensure_interior(data.z, nonnegative_z); + ensure_interior(data.x, nonnegative_variables); // Direct free variables: reduced cost z = 0 (no complementarity condition). if (has_direct_free_linear) { for (i_t j : presolve_info.direct_free_variables) { @@ -2468,6 +2479,43 @@ int barrier_solver_t::initial_point(iteration_data_t& data) settings.log.printf("min v %e min z %e\n", data.v.minimum(), data.z.minimum()); #endif + // Residual checks below reflect the final initial point, after positivity shifts. + // Verify A*x = b + dense_vector_t init_primal_residual(lp.num_rows); + init_primal_residual = lp.rhs; + data.cusparse_view_.spmv(1.0, data.x, -1.0, init_primal_residual); + data.handle_ptr->get_stream().synchronize(); +#ifdef PRINT_INFO + settings.log.printf("||b - A * x||: %.16e\n", vector_norm2(init_primal_residual)); +#endif + + if (data.n_upper_bounds > 0) { + dense_vector_t init_bound_residual(data.n_upper_bounds); + for (i_t k = 0; k < data.n_upper_bounds; k++) { + i_t j = data.upper_bounds[k]; + init_bound_residual[k] = lp.upper[j] - data.w[k] - data.x[j]; + } +#ifdef PRINT_INFO + settings.log.printf("|| u - w - x||: %e\n", vector_norm2(init_bound_residual)); +#endif + } + + // Verify A'*y + z - E*v - Q*x = c + dense_vector_t init_dual_residual(lp.num_cols); + data.z.pairwise_subtract(data.c, init_dual_residual); + if (data.Q.n > 0) { matrix_vector_multiply(data.Q, -1.0, data.x, 1.0, init_dual_residual); } + data.cusparse_view_.transpose_spmv(1.0, data.y, 1.0, init_dual_residual); + if (data.n_upper_bounds > 0) { + for (i_t k = 0; k < data.n_upper_bounds; k++) { + i_t j = data.upper_bounds[k]; + init_dual_residual[j] -= data.v[k]; + } + } +#ifdef PRINT_INFO + settings.log.printf("||A^T y + z - E*v - Q*x - c ||: %e\n", + vector_norm2(init_dual_residual)); +#endif + return 0; } From d39ddefa3986a4e3361665fbb048e3d4151c218d Mon Sep 17 00:00:00 2001 From: yuwenchen95 Date: Thu, 16 Jul 2026 11:37:56 -0700 Subject: [PATCH 3/9] Use ENUM for initial point strategies Signed-off-by: yuwenchen95 --- .../cuopt/mathematical_optimization/constants.h | 5 +++++ .../utilities/internals.hpp | 15 +++++++++++++++ cpp/src/barrier/barrier.cu | 16 ++++++++++++---- cpp/src/dual_simplex/simplex_solver_settings.hpp | 4 +--- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/cpp/include/cuopt/mathematical_optimization/constants.h b/cpp/include/cuopt/mathematical_optimization/constants.h index 5e720a645e..8d896d38e9 100644 --- a/cpp/include/cuopt/mathematical_optimization/constants.h +++ b/cpp/include/cuopt/mathematical_optimization/constants.h @@ -183,6 +183,11 @@ #define CUOPT_METHOD_BARRIER 3 #define CUOPT_METHOD_UNSET 4 +#define CUOPT_BARRIER_DUAL_INITIAL_POINT_AUTOMATIC -1 +#define CUOPT_BARRIER_DUAL_INITIAL_POINT_LUSTIG_MARSTEN_SHANNO 0 +#define CUOPT_BARRIER_DUAL_INITIAL_POINT_DUAL_LEAST_SQUARES 1 +#define CUOPT_BARRIER_DUAL_INITIAL_POINT_SEDUMI_MU 2 + /* @brief PDLP precision mode constants */ #define CUOPT_PDLP_DEFAULT_PRECISION -1 #define CUOPT_PDLP_SINGLE_PRECISION 0 diff --git a/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp b/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp index aaec8ef842..f5602b0ff0 100644 --- a/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp +++ b/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp @@ -142,5 +142,20 @@ enum presolver_t : int { PSLP = CUOPT_PRESOLVE_PSLP }; +/** + * @brief Barrier primal-dual initial-point strategy. + * + * Automatic: use Lustig-Marsten-Shanno for LP/QP; Sturm/SeDuMi mu-based point for conic problems. + * LustigMarstenShanno: Mehrotra-style dual start (Lustig, Marsten, Shanno, SIAM J. Optim. 1992). + * DualLeastSquares: solve augmented or ADAT dual least-squares system. + * SedumiMu: Sturm/SeDuMi mu-based primal+dual point (no factorization). + */ +enum barrier_dual_initial_point_t : int { + Automatic = CUOPT_BARRIER_DUAL_INITIAL_POINT_AUTOMATIC, + LustigMarstenShanno = CUOPT_BARRIER_DUAL_INITIAL_POINT_LUSTIG_MARSTEN_SHANNO, + DualLeastSquares = CUOPT_BARRIER_DUAL_INITIAL_POINT_DUAL_LEAST_SQUARES, + SedumiMu = CUOPT_BARRIER_DUAL_INITIAL_POINT_SEDUMI_MU +}; + } // namespace mathematical_optimization } // namespace cuopt diff --git a/cpp/src/barrier/barrier.cu b/cpp/src/barrier/barrier.cu index bae7e258ca..563292206c 100644 --- a/cpp/src/barrier/barrier.cu +++ b/cpp/src/barrier/barrier.cu @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -2183,14 +2184,20 @@ int barrier_solver_t::initial_point(iteration_data_t& data) const bool use_augmented = data.use_augmented; const bool has_direct_free_linear = data.n_direct_free_linear > 0; - const i_t init_strategy = data.has_cones() ? 2 : settings.barrier_dual_initial_point; + const barrier_dual_initial_point_t input_strategy = + static_cast(settings.barrier_dual_initial_point); - // Option 2: Sturm/SeDuMi-style mu-based primal+dual initial point. + const barrier_dual_initial_point_t init_strategy = + (data.has_cones() && input_strategy == barrier_dual_initial_point_t::Automatic) + ? barrier_dual_initial_point_t::SedumiMu + : input_strategy; + + // SedumiMu: Sturm/SeDuMi-style mu-based primal+dual initial point. // mu = sqrt((1 + ||b||_inf) * (1 + ||c||_inf)); x = z = mu * e_K. // where e_K is the identity of the symmetric cone: // LP block: e = 1, SOC block: e = (sqrt(2), 0, ..., 0) // Full primal+dual point; no factorization/solve (main loop factorizes later). - if (init_strategy == 2) { + if (init_strategy == barrier_dual_initial_point_t::SedumiMu) { const f_t norm_b = vector_norm_inf(lp.rhs); const f_t norm_c = vector_norm_inf(lp.objective); const f_t mu = std::sqrt((1.0 + norm_b) * (1.0 + norm_c)); @@ -2366,7 +2373,8 @@ int barrier_solver_t::initial_point(iteration_data_t& data) } }; - if (settings.barrier_dual_initial_point == -1 || settings.barrier_dual_initial_point == 0) { + if (init_strategy == barrier_dual_initial_point_t::Automatic || + init_strategy == barrier_dual_initial_point_t::LustigMarstenShanno) { // Use the dual starting point suggested by the paper // On Implementing Mehrotra’s Predictor–Corrector Interior-Point Method for Linear Programming // Irvin J. Lustig, Roy E. Marsten, and David F. Shanno diff --git a/cpp/src/dual_simplex/simplex_solver_settings.hpp b/cpp/src/dual_simplex/simplex_solver_settings.hpp index fe8c5474e3..821ba462ef 100644 --- a/cpp/src/dual_simplex/simplex_solver_settings.hpp +++ b/cpp/src/dual_simplex/simplex_solver_settings.hpp @@ -163,9 +163,7 @@ struct simplex_solver_settings_t { i_t augmented; // -1 automatic, 0 to solve with ADAT, 1 to solve with augmented system i_t dualize; // -1 automatic, 0 to not dualize, 1 to dualize i_t ordering; // -1 automatic, 0 to use nested dissection, 1 to use AMD - i_t barrier_dual_initial_point; // -1 automatic, 0 to use Lustig, Marsten, and Shanno initial - // point, 1 to use initial point form dual least squares problem, - // 2 to use Sturm/SeDuMi mu-based primal+dual point + i_t barrier_dual_initial_point; // barrier_dual_initial_point_t; see internals.hpp bool check_Q; // true to check if Q is positive semidefinite bool crossover; // true to do crossover, false to not i_t refactor_frequency; // number of basis updates before refactorization From 4f5e8fde594797eb40c5719624af412b9fb28665 Mon Sep 17 00:00:00 2001 From: YUWEN Chen Date: Thu, 23 Jul 2026 07:42:59 -0700 Subject: [PATCH 4/9] restore residual check in initialization and clean up code related to initial point Signed-off-by: YUWEN Chen --- .../utilities/internals.hpp | 15 ---- cpp/src/barrier/barrier.cu | 74 +++++++++---------- cpp/src/barrier/barrier.hpp | 16 ++++ .../dual_simplex/simplex_solver_settings.hpp | 3 +- 4 files changed, 54 insertions(+), 54 deletions(-) diff --git a/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp b/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp index f5602b0ff0..aaec8ef842 100644 --- a/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp +++ b/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp @@ -142,20 +142,5 @@ enum presolver_t : int { PSLP = CUOPT_PRESOLVE_PSLP }; -/** - * @brief Barrier primal-dual initial-point strategy. - * - * Automatic: use Lustig-Marsten-Shanno for LP/QP; Sturm/SeDuMi mu-based point for conic problems. - * LustigMarstenShanno: Mehrotra-style dual start (Lustig, Marsten, Shanno, SIAM J. Optim. 1992). - * DualLeastSquares: solve augmented or ADAT dual least-squares system. - * SedumiMu: Sturm/SeDuMi mu-based primal+dual point (no factorization). - */ -enum barrier_dual_initial_point_t : int { - Automatic = CUOPT_BARRIER_DUAL_INITIAL_POINT_AUTOMATIC, - LustigMarstenShanno = CUOPT_BARRIER_DUAL_INITIAL_POINT_LUSTIG_MARSTEN_SHANNO, - DualLeastSquares = CUOPT_BARRIER_DUAL_INITIAL_POINT_DUAL_LEAST_SQUARES, - SedumiMu = CUOPT_BARRIER_DUAL_INITIAL_POINT_SEDUMI_MU -}; - } // namespace mathematical_optimization } // namespace cuopt diff --git a/cpp/src/barrier/barrier.cu b/cpp/src/barrier/barrier.cu index 563292206c..e7af2a294b 100644 --- a/cpp/src/barrier/barrier.cu +++ b/cpp/src/barrier/barrier.cu @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -2359,6 +2358,26 @@ int barrier_solver_t::initial_point(iteration_data_t& data) } } + // Verify A*x = b + dense_vector_t init_primal_residual(lp.num_rows); + init_primal_residual = lp.rhs; + data.cusparse_view_.spmv(1.0, data.x, -1.0, init_primal_residual); + data.handle_ptr->get_stream().synchronize(); +#ifdef PRINT_INFO + settings.log.printf("||b - A * x||: %.16e\n", vector_norm2(init_primal_residual)); +#endif + + if (data.n_upper_bounds > 0) { + dense_vector_t init_bound_residual(data.n_upper_bounds); + for (i_t k = 0; k < data.n_upper_bounds; k++) { + i_t j = data.upper_bounds[k]; + init_bound_residual[k] = lp.upper[j] - data.w[k] - data.x[j]; + } +#ifdef PRINT_INFO + settings.log.printf("|| u - w - x||: %e\n", vector_norm2(init_bound_residual)); +#endif + } + float64_t epsilon_adjust = 10.0; // Push entries into interior of nonnegative orthant and SOC. const bool has_soc = data.has_cones(); @@ -2467,6 +2486,22 @@ int barrier_solver_t::initial_point(iteration_data_t& data) data.v.ensure_positive(epsilon_adjust); } + // Verify A'*y + z - E*v - Q*x = c + dense_vector_t init_dual_residual(lp.num_cols); + data.z.pairwise_subtract(data.c, init_dual_residual); + if (data.Q.n > 0) { matrix_vector_multiply(data.Q, -1.0, data.x, 1.0, init_dual_residual); } + data.cusparse_view_.transpose_spmv(1.0, data.y, 1.0, init_dual_residual); + if (data.n_upper_bounds > 0) { + for (i_t k = 0; k < data.n_upper_bounds; k++) { + i_t j = data.upper_bounds[k]; + init_dual_residual[j] -= data.v[k]; + } + } +#ifdef PRINT_INFO + settings.log.printf("||A^T y + z - E*v - Q*x - c ||: %e\n", + vector_norm2(init_dual_residual)); +#endif + // Make sure (w, x, v, z) > 0. Skip free variables being handled directly. data.w.ensure_positive(epsilon_adjust); std::vector nonnegative_variables(data.x.size(), 1); @@ -2487,43 +2522,6 @@ int barrier_solver_t::initial_point(iteration_data_t& data) settings.log.printf("min v %e min z %e\n", data.v.minimum(), data.z.minimum()); #endif - // Residual checks below reflect the final initial point, after positivity shifts. - // Verify A*x = b - dense_vector_t init_primal_residual(lp.num_rows); - init_primal_residual = lp.rhs; - data.cusparse_view_.spmv(1.0, data.x, -1.0, init_primal_residual); - data.handle_ptr->get_stream().synchronize(); -#ifdef PRINT_INFO - settings.log.printf("||b - A * x||: %.16e\n", vector_norm2(init_primal_residual)); -#endif - - if (data.n_upper_bounds > 0) { - dense_vector_t init_bound_residual(data.n_upper_bounds); - for (i_t k = 0; k < data.n_upper_bounds; k++) { - i_t j = data.upper_bounds[k]; - init_bound_residual[k] = lp.upper[j] - data.w[k] - data.x[j]; - } -#ifdef PRINT_INFO - settings.log.printf("|| u - w - x||: %e\n", vector_norm2(init_bound_residual)); -#endif - } - - // Verify A'*y + z - E*v - Q*x = c - dense_vector_t init_dual_residual(lp.num_cols); - data.z.pairwise_subtract(data.c, init_dual_residual); - if (data.Q.n > 0) { matrix_vector_multiply(data.Q, -1.0, data.x, 1.0, init_dual_residual); } - data.cusparse_view_.transpose_spmv(1.0, data.y, 1.0, init_dual_residual); - if (data.n_upper_bounds > 0) { - for (i_t k = 0; k < data.n_upper_bounds; k++) { - i_t j = data.upper_bounds[k]; - init_dual_residual[j] -= data.v[k]; - } - } -#ifdef PRINT_INFO - settings.log.printf("||A^T y + z - E*v - Q*x - c ||: %e\n", - vector_norm2(init_dual_residual)); -#endif - return 0; } diff --git a/cpp/src/barrier/barrier.hpp b/cpp/src/barrier/barrier.hpp index 07094a54a5..57e691be71 100644 --- a/cpp/src/barrier/barrier.hpp +++ b/cpp/src/barrier/barrier.hpp @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -18,6 +19,21 @@ #include namespace cuopt::mathematical_optimization::barrier { +/** + * @brief Barrier primal-dual initial-point strategy. + * + * Automatic: use Lustig-Marsten-Shanno for LP/QP; Sturm/SeDuMi mu-based point for conic problems. + * LustigMarstenShanno: Mehrotra-style dual start (Lustig, Marsten, Shanno, SIAM J. Optim. 1992). + * DualLeastSquares: solve augmented or ADAT dual least-squares system. + * SedumiMu: Sturm/SeDuMi mu-based primal+dual point (no factorization). + */ +enum barrier_dual_initial_point_t : int { + Automatic = CUOPT_BARRIER_DUAL_INITIAL_POINT_AUTOMATIC, + LustigMarstenShanno = CUOPT_BARRIER_DUAL_INITIAL_POINT_LUSTIG_MARSTEN_SHANNO, + DualLeastSquares = CUOPT_BARRIER_DUAL_INITIAL_POINT_DUAL_LEAST_SQUARES, + SedumiMu = CUOPT_BARRIER_DUAL_INITIAL_POINT_SEDUMI_MU +}; + /** Validates SOC layout on an simplex::lp_problem_t before barrier presolve/solve. */ template bool validate_barrier_cone_layout(const simplex::lp_problem_t& problem, diff --git a/cpp/src/dual_simplex/simplex_solver_settings.hpp b/cpp/src/dual_simplex/simplex_solver_settings.hpp index ca2fc53e0a..646397513e 100644 --- a/cpp/src/dual_simplex/simplex_solver_settings.hpp +++ b/cpp/src/dual_simplex/simplex_solver_settings.hpp @@ -167,7 +167,8 @@ struct simplex_solver_settings_t { i_t augmented; // -1 automatic, 0 to solve with ADAT, 1 to solve with augmented system i_t dualize; // -1 automatic, 0 to not dualize, 1 to dualize i_t ordering; // -1 automatic, 0 to use nested dissection, 1 to use AMD - i_t barrier_dual_initial_point; // barrier_dual_initial_point_t; see internals.hpp + i_t barrier_dual_initial_point; // -1 automatic, 0 Lustig-Marsten-Shanno, + // 1 dual least squares, 2 SeDuMi mu-based bool check_Q; // true to check if Q is positive semidefinite bool crossover; // true to do crossover, false to not i_t refactor_frequency; // number of basis updates before refactorization From ffc457c30cd38b30c31e59d342ac5faf38cfb76f Mon Sep 17 00:00:00 2001 From: yuwenchen95 Date: Tue, 11 Aug 2026 07:28:00 -0700 Subject: [PATCH 5/9] Unify initial positive push for cone constraints Signed-off-by: yuwenchen95 --- cpp/src/barrier/barrier.cu | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/cpp/src/barrier/barrier.cu b/cpp/src/barrier/barrier.cu index 59826ac5ec..f7eaf52525 100644 --- a/cpp/src/barrier/barrier.cu +++ b/cpp/src/barrier/barrier.cu @@ -105,17 +105,12 @@ static void ensure_initial_point_interior(dense_vector_t& values, i_t linear_end, const std::vector& cone_dims) { - f_t min_linear = inf; - for (i_t j = 0; j < linear_end; ++j) { - if (linear_mask[j]) { min_linear = std::min(min_linear, values[j]); } - } - if (min_linear <= epsilon_adjust) { - const f_t delta = -min_linear + epsilon_adjust; - for (i_t j = 0; j < linear_end; ++j) { - if (linear_mask[j]) { values[j] += delta; } - } - } + // Linear shift + std::vector linear_only_mask(values.size(), 0); + std::copy(linear_mask.begin(), linear_mask.begin() + linear_end, linear_only_mask.begin()); + values.ensure_positive(epsilon_adjust, linear_only_mask); + // Cone shift i_t off = 0; for (i_t q_k : cone_dims) { const i_t base = linear_end + off; @@ -2405,12 +2400,8 @@ int barrier_solver_t::initial_point(iteration_data_t& data) const i_t linear_end = has_soc ? data.cone_start() : lp.num_cols; auto ensure_interior = [&](dense_vector_t& values, const std::vector& linear_mask) { - if (has_soc) { - ensure_initial_point_interior( - values, epsilon_adjust, linear_mask, linear_end, lp.second_order_cone_dims); - } else { - values.ensure_positive(epsilon_adjust, linear_mask); - } + ensure_initial_point_interior( + values, epsilon_adjust, linear_mask, linear_end, lp.second_order_cone_dims); }; if (init_strategy == barrier_dual_initial_point_t::Automatic || From 225421fa05916c229c2c2f3b91c0b2c3735ac362 Mon Sep 17 00:00:00 2001 From: yuwenchen95 Date: Wed, 12 Aug 2026 06:12:20 -0700 Subject: [PATCH 6/9] make initial-point safeguard a hyperparameter Signed-off-by: yuwenchen95 --- .../mathematical_optimization/constants.h | 3 +- .../pdlp/solver_settings.hpp | 3 ++ cpp/src/barrier/barrier.cu | 2 +- .../dual_simplex/simplex_solver_settings.hpp | 3 ++ cpp/src/math_optimization/solver_settings.cu | 2 + cpp/src/pdlp/solve.cu | 38 ++++++++++--------- 6 files changed, 31 insertions(+), 20 deletions(-) diff --git a/cpp/include/cuopt/mathematical_optimization/constants.h b/cpp/include/cuopt/mathematical_optimization/constants.h index f4281e781b..84068fbeac 100644 --- a/cpp/include/cuopt/mathematical_optimization/constants.h +++ b/cpp/include/cuopt/mathematical_optimization/constants.h @@ -145,7 +145,8 @@ #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" +#define CUOPT_QCQP_HYPER_RUIZ_EQUILIBRATION "qcqp_hyper_ruiz_equilibration" +#define CUOPT_BARRIER_HYPER_INITIAL_POINT_SAFEGUARD "barrier_hyper_initial_point_safeguard" /* @brief MIP determinism mode constants */ #define CUOPT_MODE_OPPORTUNISTIC 0 diff --git a/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp b/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp index ffcf3fad7a..2af9213e1b 100644 --- a/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp +++ b/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp @@ -300,6 +300,9 @@ class pdlp_solver_settings_t { // imbalance heuristic), 0 disabled, 1 enabled. Distinct from PDLP's own Ruiz // scaling in pdlp_hyper_params_t. i_t qcqp_ruiz_equilibration{-1}; + // Margin used to push the barrier method's initial iterate into the interior of the + // nonnegative orthant / SOC (values are shifted to be at least this far from the boundary). + f_t barrier_hyper_initial_point_safeguard{10.0}; bool eliminate_dense_columns{true}; pdlp_precision_t pdlp_precision{pdlp_precision_t::DefaultPrecision}; bool barrier_iterative_refinement{true}; diff --git a/cpp/src/barrier/barrier.cu b/cpp/src/barrier/barrier.cu index f7eaf52525..11ae3e50c6 100644 --- a/cpp/src/barrier/barrier.cu +++ b/cpp/src/barrier/barrier.cu @@ -2394,7 +2394,7 @@ int barrier_solver_t::initial_point(iteration_data_t& data) #endif } - float64_t epsilon_adjust = 10.0; + const f_t epsilon_adjust = settings.barrier_hyper_initial_point_safeguard; // Push entries into interior of nonnegative orthant and SOC. const bool has_soc = data.has_cones(); const i_t linear_end = has_soc ? data.cone_start() : lp.num_cols; diff --git a/cpp/src/dual_simplex/simplex_solver_settings.hpp b/cpp/src/dual_simplex/simplex_solver_settings.hpp index 2de4ea9744..3961667380 100644 --- a/cpp/src/dual_simplex/simplex_solver_settings.hpp +++ b/cpp/src/dual_simplex/simplex_solver_settings.hpp @@ -80,6 +80,7 @@ struct simplex_solver_settings_t { barrier_dual_initial_point(-1), postsolve_info(-1), qcqp_ruiz_equilibration(-1), + barrier_hyper_initial_point_safeguard(10.0), check_Q(false), crossover(false), refactor_frequency(100), @@ -175,6 +176,8 @@ struct simplex_solver_settings_t { // 1 dual least squares, 2 SeDuMi mu-based i_t postsolve_info; // -1 automatic (disabled), 0 disabled, 1 enabled i_t qcqp_ruiz_equilibration; // -1 automatic (imbalance heuristic), 0 disabled, 1 enabled + f_t barrier_hyper_initial_point_safeguard; // margin pushing the barrier initial iterate into + // the interior of the nonnegative orthant / SOC bool check_Q; // true to check if Q is positive semidefinite bool crossover; // true to do crossover, false to not i_t refactor_frequency; // number of basis updates before refactorization diff --git a/cpp/src/math_optimization/solver_settings.cu b/cpp/src/math_optimization/solver_settings.cu index 550f64a87f..72b8d97def 100644 --- a/cpp/src/math_optimization/solver_settings.cu +++ b/cpp/src/math_optimization/solver_settings.cu @@ -124,6 +124,8 @@ solver_settings_t::solver_settings_t() : pdlp_settings(), mip_settings {CUOPT_MIP_HYPER_SUBMIP_MIN_FIXRATE_CAP, &mip_settings.submip_params.min_fixrate_cap, f_t(0.0), f_t(1.0), f_t(0.1), "hard cap on the minimum fix rate for solving a sub-MIP"}, {CUOPT_MIP_HYPER_SUBMIP_TARGET_MIP_GAP, &mip_settings.submip_params.target_mip_gap, f_t(0.0), f_t(1.0), f_t(0.01), "MIP gap target for the sub-MIP"}, {CUOPT_MIP_HYPER_SUBMIP_ITERATION_LIMIT_RATIO, &mip_settings.submip_params.iteration_limit_ratio, f_t(0.0), f_t(1.0), f_t(0.8), "sub-MIP simplex-iteration limit as a factor of parent B&B iterations"}, + // QCQP (barrier) hyper-parameter (hidden from default --help: name contains "hyper_") + {CUOPT_BARRIER_HYPER_INITIAL_POINT_SAFEGUARD, &pdlp_settings.barrier_hyper_initial_point_safeguard, f_t(0.0), std::numeric_limits::infinity(), f_t(10.0), "margin pushing the barrier initial iterate into the interior of the nonnegative orthant / SOC"}, }; // Int parameters diff --git a/cpp/src/pdlp/solve.cu b/cpp/src/pdlp/solve.cu index 9e54bb1a11..396725ad80 100644 --- a/cpp/src/pdlp/solve.cu +++ b/cpp/src/pdlp/solve.cu @@ -498,24 +498,26 @@ std::tuple, simplex::lp_status_t, f_t, f_t, f_t f_t norm_rhs = vector_norm2(user_problem.rhs); simplex::simplex_solver_settings_t barrier_settings; - barrier_settings.num_gpus = settings.num_gpus; - barrier_settings.time_limit = settings.time_limit; - barrier_settings.iteration_limit = settings.iteration_limit; - barrier_settings.concurrent_halt = settings.concurrent_halt; - barrier_settings.folding = settings.folding; - barrier_settings.augmented = settings.augmented; - barrier_settings.dualize = settings.dualize; - barrier_settings.ordering = settings.ordering; - barrier_settings.barrier_dual_initial_point = settings.barrier_dual_initial_point; - barrier_settings.postsolve_info = settings.postsolve_info; - barrier_settings.barrier = true; - barrier_settings.barrier_presolve = true; - barrier_settings.crossover = settings.crossover; - barrier_settings.eliminate_dense_columns = settings.eliminate_dense_columns; - barrier_settings.barrier_iterative_refinement = settings.barrier_iterative_refinement; - barrier_settings.barrier_soc_threshold = settings.barrier_soc_threshold; - barrier_settings.barrier_step_scale = settings.barrier_step_scale; - barrier_settings.qcqp_ruiz_equilibration = settings.qcqp_ruiz_equilibration; + barrier_settings.num_gpus = settings.num_gpus; + barrier_settings.time_limit = settings.time_limit; + barrier_settings.iteration_limit = settings.iteration_limit; + barrier_settings.concurrent_halt = settings.concurrent_halt; + barrier_settings.folding = settings.folding; + barrier_settings.augmented = settings.augmented; + barrier_settings.dualize = settings.dualize; + barrier_settings.ordering = settings.ordering; + barrier_settings.barrier_dual_initial_point = settings.barrier_dual_initial_point; + barrier_settings.postsolve_info = settings.postsolve_info; + barrier_settings.barrier = true; + barrier_settings.barrier_presolve = true; + barrier_settings.crossover = settings.crossover; + barrier_settings.eliminate_dense_columns = settings.eliminate_dense_columns; + barrier_settings.barrier_iterative_refinement = settings.barrier_iterative_refinement; + barrier_settings.barrier_soc_threshold = settings.barrier_soc_threshold; + barrier_settings.barrier_step_scale = settings.barrier_step_scale; + barrier_settings.qcqp_ruiz_equilibration = settings.qcqp_ruiz_equilibration; + barrier_settings.barrier_hyper_initial_point_safeguard = + settings.barrier_hyper_initial_point_safeguard; barrier_settings.cudss_deterministic = settings.cudss_deterministic; barrier_settings.barrier_relaxed_feasibility_tol = settings.tolerances.relative_primal_tolerance; barrier_settings.barrier_relaxed_optimality_tol = settings.tolerances.relative_dual_tolerance; From 40789ae66259e00045a4333f2725958c93778d7b Mon Sep 17 00:00:00 2001 From: yuwenchen95 Date: Mon, 17 Aug 2026 05:45:46 -0700 Subject: [PATCH 7/9] Make safeguard as a regular parameter Signed-off-by: yuwenchen95 --- cpp/include/cuopt/mathematical_optimization/constants.h | 6 ++++-- .../mathematical_optimization/pdlp/solver_settings.hpp | 2 +- cpp/src/barrier/barrier.cu | 2 +- cpp/src/dual_simplex/simplex_solver_settings.hpp | 6 +++--- cpp/src/math_optimization/solver_settings.cu | 3 +-- cpp/src/pdlp/solve.cu | 3 +-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cpp/include/cuopt/mathematical_optimization/constants.h b/cpp/include/cuopt/mathematical_optimization/constants.h index d69d799f9d..222a713254 100644 --- a/cpp/include/cuopt/mathematical_optimization/constants.h +++ b/cpp/include/cuopt/mathematical_optimization/constants.h @@ -147,8 +147,10 @@ #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" -#define CUOPT_BARRIER_HYPER_INITIAL_POINT_SAFEGUARD "barrier_hyper_initial_point_safeguard" +#define CUOPT_QCQP_HYPER_RUIZ_EQUILIBRATION "qcqp_hyper_ruiz_equilibration" + +/* @brief Barrier initial point safeguard */ +#define CUOPT_BARRIER_INITIAL_POINT_SAFEGUARD "barrier_initial_point_safeguard" /* @brief MIP determinism mode constants */ #define CUOPT_MODE_OPPORTUNISTIC 0 diff --git a/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp b/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp index af751e7c69..d3acf2607e 100644 --- a/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp +++ b/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp @@ -303,7 +303,7 @@ class pdlp_solver_settings_t { i_t qcqp_ruiz_equilibration{-1}; // Margin used to push the barrier method's initial iterate into the interior of the // nonnegative orthant / SOC (values are shifted to be at least this far from the boundary). - f_t barrier_hyper_initial_point_safeguard{10.0}; + f_t barrier_initial_point_safeguard{10.0}; bool eliminate_dense_columns{true}; pdlp_precision_t pdlp_precision{pdlp_precision_t::DefaultPrecision}; bool barrier_iterative_refinement{true}; diff --git a/cpp/src/barrier/barrier.cu b/cpp/src/barrier/barrier.cu index 6c9237a244..936c446f33 100644 --- a/cpp/src/barrier/barrier.cu +++ b/cpp/src/barrier/barrier.cu @@ -2395,7 +2395,7 @@ int barrier_solver_t::initial_point(iteration_data_t& data) #endif } - const f_t epsilon_adjust = settings.barrier_hyper_initial_point_safeguard; + const f_t epsilon_adjust = settings.barrier_initial_point_safeguard; // Push entries into interior of nonnegative orthant and SOC. const bool has_soc = data.has_cones(); const i_t linear_end = has_soc ? data.cone_start() : lp.num_cols; diff --git a/cpp/src/dual_simplex/simplex_solver_settings.hpp b/cpp/src/dual_simplex/simplex_solver_settings.hpp index 94a8b2247d..a7b6e099a8 100644 --- a/cpp/src/dual_simplex/simplex_solver_settings.hpp +++ b/cpp/src/dual_simplex/simplex_solver_settings.hpp @@ -81,7 +81,7 @@ struct simplex_solver_settings_t { postsolve_info(-1), barrier_presolve_bound_free_variables(-1), qcqp_ruiz_equilibration(-1), - barrier_hyper_initial_point_safeguard(10.0), + barrier_initial_point_safeguard(10.0), check_Q(false), crossover(false), refactor_frequency(100), @@ -177,8 +177,8 @@ struct simplex_solver_settings_t { // 1 dual least squares, 2 SeDuMi mu-based i_t postsolve_info; // -1 automatic (disabled), 0 disabled, 1 enabled i_t barrier_presolve_bound_free_variables; // -1 automatic, 0 disabled, 1 enabled - i_t qcqp_ruiz_equilibration; // -1 automatic (imbalance heuristic), 0 disabled, 1 enabled - f_t barrier_hyper_initial_point_safeguard; // margin pushing the barrier initial iterate into + i_t qcqp_ruiz_equilibration; // -1 automatic (imbalance heuristic), 0 disabled, 1 enabled + f_t barrier_initial_point_safeguard; // margin pushing the barrier initial iterate into // the interior of the nonnegative orthant / SOC bool check_Q; // true to check if Q is positive semidefinite bool crossover; // true to do crossover, false to not diff --git a/cpp/src/math_optimization/solver_settings.cu b/cpp/src/math_optimization/solver_settings.cu index e3c4d02d19..b4cb4badc3 100644 --- a/cpp/src/math_optimization/solver_settings.cu +++ b/cpp/src/math_optimization/solver_settings.cu @@ -104,6 +104,7 @@ solver_settings_t::solver_settings_t() : pdlp_settings(), mip_settings {CUOPT_MIP_CUT_CHANGE_THRESHOLD, &mip_settings.cut_change_threshold, f_t(-1.0), std::numeric_limits::infinity(), f_t(-1.0)}, {CUOPT_MIP_CUT_MIN_ORTHOGONALITY, &mip_settings.cut_min_orthogonality, f_t(0.0), f_t(1.0), f_t(0.5)}, {CUOPT_BARRIER_STEP_SCALE, &pdlp_settings.barrier_step_scale, f_t(0.5), f_t(0.9999), f_t(0.9)}, + {CUOPT_BARRIER_INITIAL_POINT_SAFEGUARD, &pdlp_settings.barrier_initial_point_safeguard, f_t(0.0), std::numeric_limits::infinity(), f_t(10.0), "margin pushing the barrier initial iterate into the interior of the nonnegative orthant / SOC"}, // MIP heuristic hyper-parameters (hidden from default --help: name contains "hyper_") {CUOPT_MIP_HYPER_HEURISTIC_ROOT_LP_TIME_RATIO, &mip_settings.heuristic_params.root_lp_time_ratio, f_t(0.0), f_t(1.0), f_t(0.1), "fraction of total time for root LP"}, {CUOPT_MIP_HYPER_HEURISTIC_ROOT_LP_MAX_TIME, &mip_settings.heuristic_params.root_lp_max_time, f_t(0.0), std::numeric_limits::infinity(), f_t(15.0), "hard cap on root LP seconds"}, @@ -122,8 +123,6 @@ solver_settings_t::solver_settings_t() : pdlp_settings(), mip_settings {CUOPT_MIP_HYPER_SUBMIP_MIN_FIXRATE_CAP, &mip_settings.submip_params.min_fixrate_cap, f_t(0.0), f_t(1.0), f_t(0.1), "hard cap on the minimum fix rate for solving a sub-MIP"}, {CUOPT_MIP_HYPER_SUBMIP_TARGET_MIP_GAP, &mip_settings.submip_params.target_mip_gap, f_t(0.0), f_t(1.0), f_t(0.01), "MIP gap target for the sub-MIP"}, {CUOPT_MIP_HYPER_SUBMIP_ITERATION_LIMIT_RATIO, &mip_settings.submip_params.iteration_limit_ratio, f_t(0.0), f_t(1.0), f_t(0.8), "sub-MIP simplex-iteration limit as a factor of parent B&B iterations"}, - // QCQP (barrier) hyper-parameter (hidden from default --help: name contains "hyper_") - {CUOPT_BARRIER_HYPER_INITIAL_POINT_SAFEGUARD, &pdlp_settings.barrier_hyper_initial_point_safeguard, f_t(0.0), std::numeric_limits::infinity(), f_t(10.0), "margin pushing the barrier initial iterate into the interior of the nonnegative orthant / SOC"}, }; // Int parameters diff --git a/cpp/src/pdlp/solve.cu b/cpp/src/pdlp/solve.cu index d5f1c31353..493a250af9 100644 --- a/cpp/src/pdlp/solve.cu +++ b/cpp/src/pdlp/solve.cu @@ -510,8 +510,7 @@ std::tuple, simplex::lp_status_t, f_t, f_t, f_t barrier_settings.postsolve_info = settings.postsolve_info; barrier_settings.barrier_presolve_bound_free_variables = settings.barrier_presolve_bound_free_variables; - barrier_settings.barrier_hyper_initial_point_safeguard = - settings.barrier_hyper_initial_point_safeguard; + barrier_settings.barrier_initial_point_safeguard = settings.barrier_initial_point_safeguard; barrier_settings.barrier = true; barrier_settings.barrier_presolve = true; barrier_settings.crossover = settings.crossover; From e2d0e59b71efb0983dda065ff499380a3adc2033 Mon Sep 17 00:00:00 2001 From: yuwenchen95 Date: Mon, 17 Aug 2026 06:37:31 -0700 Subject: [PATCH 8/9] Make barrier_dual_initial_point itself ENUM Signed-off-by: yuwenchen95 --- .../pdlp/solver_settings.hpp | 2 +- .../utilities/internals.hpp | 15 +++++++ cpp/src/barrier/barrier.cu | 3 +- cpp/src/barrier/barrier.hpp | 16 +------- .../dual_simplex/simplex_solver_settings.hpp | 6 ++- cpp/src/grpc/codegen/field_registry.yaml | 1 + .../generated_pdlp_settings_to_proto.inc | 2 +- .../generated_proto_to_pdlp_settings.inc | 2 +- cpp/src/math_optimization/solver_settings.cu | 2 +- .../grpc/grpc_client_test.cpp | 40 ++++++++++--------- 10 files changed, 47 insertions(+), 42 deletions(-) diff --git a/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp b/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp index d3acf2607e..6e4024bb86 100644 --- a/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp +++ b/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp @@ -294,7 +294,7 @@ class pdlp_solver_settings_t { i_t augmented{-1}; i_t dualize{-1}; i_t ordering{-1}; - i_t barrier_dual_initial_point{-1}; + barrier_dual_initial_point_t barrier_dual_initial_point{barrier_dual_initial_point_t::Automatic}; i_t postsolve_info{-1}; i_t barrier_presolve_bound_free_variables{-1}; // -1 automatic, 0 disabled, 1 enabled // Ruiz equilibration for QCQP (barrier) scaling: -1 automatic (row/column diff --git a/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp b/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp index 25f3f34f7b..3736d59c22 100644 --- a/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp +++ b/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp @@ -142,5 +142,20 @@ enum presolver_t : int { PSLP = CUOPT_PRESOLVE_PSLP }; +/** + * @brief Barrier primal-dual initial-point strategy. + * + * Automatic: use Lustig-Marsten-Shanno for LP/QP; Sturm/SeDuMi mu-based point for conic problems. + * LustigMarstenShanno: Mehrotra-style dual start (Lustig, Marsten, Shanno, SIAM J. Optim. 1992). + * DualLeastSquares: solve augmented or ADAT dual least-squares system. + * SedumiMu: Sturm/SeDuMi mu-based primal+dual point (no factorization). + */ +enum barrier_dual_initial_point_t : int { + Automatic = CUOPT_BARRIER_DUAL_INITIAL_POINT_AUTOMATIC, + LustigMarstenShanno = CUOPT_BARRIER_DUAL_INITIAL_POINT_LUSTIG_MARSTEN_SHANNO, + DualLeastSquares = CUOPT_BARRIER_DUAL_INITIAL_POINT_DUAL_LEAST_SQUARES, + SedumiMu = CUOPT_BARRIER_DUAL_INITIAL_POINT_SEDUMI_MU +}; + } // namespace mathematical_optimization } // namespace cuopt diff --git a/cpp/src/barrier/barrier.cu b/cpp/src/barrier/barrier.cu index 936c446f33..b88fc12dc9 100644 --- a/cpp/src/barrier/barrier.cu +++ b/cpp/src/barrier/barrier.cu @@ -2204,8 +2204,7 @@ int barrier_solver_t::initial_point(iteration_data_t& data) const bool use_augmented = data.use_augmented; const bool has_direct_free_linear = data.n_direct_free_linear > 0; - const barrier_dual_initial_point_t input_strategy = - static_cast(settings.barrier_dual_initial_point); + const barrier_dual_initial_point_t input_strategy = settings.barrier_dual_initial_point; const barrier_dual_initial_point_t init_strategy = (data.has_cones() && input_strategy == barrier_dual_initial_point_t::Automatic) diff --git a/cpp/src/barrier/barrier.hpp b/cpp/src/barrier/barrier.hpp index 40fff5355b..f72b2ff728 100644 --- a/cpp/src/barrier/barrier.hpp +++ b/cpp/src/barrier/barrier.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -21,21 +22,6 @@ #include namespace cuopt::mathematical_optimization::barrier { -/** - * @brief Barrier primal-dual initial-point strategy. - * - * Automatic: use Lustig-Marsten-Shanno for LP/QP; Sturm/SeDuMi mu-based point for conic problems. - * LustigMarstenShanno: Mehrotra-style dual start (Lustig, Marsten, Shanno, SIAM J. Optim. 1992). - * DualLeastSquares: solve augmented or ADAT dual least-squares system. - * SedumiMu: Sturm/SeDuMi mu-based primal+dual point (no factorization). - */ -enum barrier_dual_initial_point_t : int { - Automatic = CUOPT_BARRIER_DUAL_INITIAL_POINT_AUTOMATIC, - LustigMarstenShanno = CUOPT_BARRIER_DUAL_INITIAL_POINT_LUSTIG_MARSTEN_SHANNO, - DualLeastSquares = CUOPT_BARRIER_DUAL_INITIAL_POINT_DUAL_LEAST_SQUARES, - SedumiMu = CUOPT_BARRIER_DUAL_INITIAL_POINT_SEDUMI_MU -}; - /** Validates SOC layout on an simplex::lp_problem_t before barrier presolve/solve. */ template bool validate_barrier_cone_layout(const simplex::lp_problem_t& problem, diff --git a/cpp/src/dual_simplex/simplex_solver_settings.hpp b/cpp/src/dual_simplex/simplex_solver_settings.hpp index a7b6e099a8..3fe6c940b5 100644 --- a/cpp/src/dual_simplex/simplex_solver_settings.hpp +++ b/cpp/src/dual_simplex/simplex_solver_settings.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -77,7 +78,7 @@ struct simplex_solver_settings_t { augmented(0), dualize(-1), ordering(-1), - barrier_dual_initial_point(-1), + barrier_dual_initial_point(barrier_dual_initial_point_t::Automatic), postsolve_info(-1), barrier_presolve_bound_free_variables(-1), qcqp_ruiz_equilibration(-1), @@ -173,7 +174,8 @@ struct simplex_solver_settings_t { i_t augmented; // -1 automatic, 0 to solve with ADAT, 1 to solve with augmented system i_t dualize; // -1 automatic, 0 to not dualize, 1 to dualize i_t ordering; // -1 automatic, 0 to use nested dissection, 1 to use AMD - i_t barrier_dual_initial_point; // -1 automatic, 0 Lustig-Marsten-Shanno, + barrier_dual_initial_point_t + barrier_dual_initial_point; // -1 automatic, 0 Lustig-Marsten-Shanno, // 1 dual least squares, 2 SeDuMi mu-based i_t postsolve_info; // -1 automatic (disabled), 0 disabled, 1 enabled i_t barrier_presolve_bound_free_variables; // -1 automatic, 0 disabled, 1 enabled diff --git a/cpp/src/grpc/codegen/field_registry.yaml b/cpp/src/grpc/codegen/field_registry.yaml index 2fb7896027..9d709375a6 100644 --- a/cpp/src/grpc/codegen/field_registry.yaml +++ b/cpp/src/grpc/codegen/field_registry.yaml @@ -534,6 +534,7 @@ pdlp_settings: - barrier_dual_initial_point: field_num: 26 type: int32 + from_proto_cast: "barrier_dual_initial_point_t" optional: true - eliminate_dense_columns: field_num: 27 diff --git a/cpp/src/grpc/codegen/generated/generated_pdlp_settings_to_proto.inc b/cpp/src/grpc/codegen/generated/generated_pdlp_settings_to_proto.inc index eb88b192d9..7c43ab5f08 100644 --- a/cpp/src/grpc/codegen/generated/generated_pdlp_settings_to_proto.inc +++ b/cpp/src/grpc/codegen/generated/generated_pdlp_settings_to_proto.inc @@ -31,7 +31,7 @@ pb_settings->set_augmented(settings.augmented); pb_settings->set_dualize(settings.dualize); pb_settings->set_ordering(settings.ordering); - pb_settings->set_barrier_dual_initial_point(settings.barrier_dual_initial_point); + pb_settings->set_barrier_dual_initial_point(static_cast(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); diff --git a/cpp/src/grpc/codegen/generated/generated_proto_to_pdlp_settings.inc b/cpp/src/grpc/codegen/generated/generated_proto_to_pdlp_settings.inc index 29e6c4cca2..e2ba05b1ba 100644 --- a/cpp/src/grpc/codegen/generated/generated_proto_to_pdlp_settings.inc +++ b/cpp/src/grpc/codegen/generated/generated_proto_to_pdlp_settings.inc @@ -68,7 +68,7 @@ settings.ordering = pb_settings.ordering(); } if (pb_settings.has_barrier_dual_initial_point()) { - settings.barrier_dual_initial_point = pb_settings.barrier_dual_initial_point(); + settings.barrier_dual_initial_point = static_cast(pb_settings.barrier_dual_initial_point()); } if (pb_settings.has_eliminate_dense_columns()) { settings.eliminate_dense_columns = pb_settings.eliminate_dense_columns(); diff --git a/cpp/src/math_optimization/solver_settings.cu b/cpp/src/math_optimization/solver_settings.cu index b4cb4badc3..9ad34771f5 100644 --- a/cpp/src/math_optimization/solver_settings.cu +++ b/cpp/src/math_optimization/solver_settings.cu @@ -137,7 +137,7 @@ solver_settings_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_DUAL_INITIAL_POINT, &pdlp_settings.barrier_dual_initial_point, -1, 2, -1}, + {CUOPT_BARRIER_DUAL_INITIAL_POINT, reinterpret_cast(&pdlp_settings.barrier_dual_initial_point), -1, 2, -1}, {CUOPT_POSTSOLVE_INFO, &pdlp_settings.postsolve_info, -1, 1, -1}, {CUOPT_MIP_CUT_PASSES, &mip_settings.max_cut_passes, -1, std::numeric_limits::max(), 10}, {CUOPT_MIP_MIXED_INTEGER_ROUNDING_CUTS, &mip_settings.mir_cuts, -1, 1, -1}, diff --git a/cpp/tests/linear_programming/grpc/grpc_client_test.cpp b/cpp/tests/linear_programming/grpc/grpc_client_test.cpp index f8fed6eee3..78aff4f867 100644 --- a/cpp/tests/linear_programming/grpc/grpc_client_test.cpp +++ b/cpp/tests/linear_programming/grpc/grpc_client_test.cpp @@ -2224,24 +2224,25 @@ TEST(MapperRoundtrip, PDLPSettingsAllFields) orig.tolerances.absolute_primal_tolerance = 5e-7; orig.tolerances.relative_primal_tolerance = 6e-7; - orig.time_limit = 99.5; - orig.iteration_limit = 10000; - orig.log_to_console = false; - orig.detect_infeasibility = true; - orig.strict_infeasibility = true; - orig.pdlp_solver_mode = pdlp_solver_mode_t::Fast1; - orig.method = method_t::Barrier; - orig.presolver = presolver_t::Default; - orig.dual_postsolve = true; - orig.crossover = true; - orig.num_gpus = 4; - orig.per_constraint_residual = true; - orig.cudss_deterministic = true; - orig.folding = 1; - orig.augmented = 1; - orig.dualize = 1; - orig.ordering = 2; - orig.barrier_dual_initial_point = 1; + orig.time_limit = 99.5; + orig.iteration_limit = 10000; + orig.log_to_console = false; + orig.detect_infeasibility = true; + orig.strict_infeasibility = true; + orig.pdlp_solver_mode = pdlp_solver_mode_t::Fast1; + orig.method = method_t::Barrier; + orig.presolver = presolver_t::Default; + orig.dual_postsolve = true; + orig.crossover = true; + orig.num_gpus = 4; + orig.per_constraint_residual = true; + orig.cudss_deterministic = true; + orig.folding = 1; + orig.augmented = 1; + orig.dualize = 1; + orig.ordering = 2; + orig.barrier_dual_initial_point = + cuopt::mathematical_optimization::barrier_dual_initial_point_t::LustigMarstenShanno; orig.eliminate_dense_columns = true; orig.barrier_iterative_refinement = false; // not the default true, to detect overwrite-on-decode orig.barrier_step_scale = 0.75; // not the default 0.9 @@ -2282,7 +2283,8 @@ TEST(MapperRoundtrip, PDLPSettingsAllFields) EXPECT_EQ(restored.augmented, 1); EXPECT_EQ(restored.dualize, 1); EXPECT_EQ(restored.ordering, 2); - EXPECT_EQ(restored.barrier_dual_initial_point, 1); + EXPECT_EQ(restored.barrier_dual_initial_point, + cuopt::mathematical_optimization::barrier_dual_initial_point_t::LustigMarstenShanno); EXPECT_EQ(restored.eliminate_dense_columns, true); EXPECT_EQ(restored.barrier_iterative_refinement, false); EXPECT_DOUBLE_EQ(restored.barrier_step_scale, 0.75); From 69742ba6608eb322586fd9fe994380e85ca91af9 Mon Sep 17 00:00:00 2001 From: yuwenchen95 Date: Mon, 17 Aug 2026 07:57:03 -0700 Subject: [PATCH 9/9] Rename to Signed-off-by: yuwenchen95 --- .../mathematical_optimization/constants.h | 10 +++++----- .../pdlp/solver_settings.hpp | 2 +- .../utilities/internals.hpp | 10 +++++----- cpp/src/barrier/barrier.cu | 14 ++++++------- .../dual_simplex/simplex_solver_settings.hpp | 11 +++++----- cpp/src/grpc/codegen/field_registry.yaml | 4 ++-- .../codegen/generated/cuopt_remote_data.proto | 2 +- .../generated_pdlp_settings_to_proto.inc | 2 +- .../generated_proto_to_pdlp_settings.inc | 4 ++-- cpp/src/math_optimization/solver_settings.cu | 2 +- cpp/src/pdlp/solve.cu | 20 +++++++++---------- .../grpc/grpc_client_test.cpp | 10 +++++----- docs/cuopt/source/convex-settings.rst | 6 +++--- .../source/cuopt-c/convex/convex-c-api.rst | 2 +- .../cuopt_server/tests/test_lp.py | 10 +++++----- .../linear_programming/data_definition.py | 4 ++-- 16 files changed, 56 insertions(+), 57 deletions(-) diff --git a/cpp/include/cuopt/mathematical_optimization/constants.h b/cpp/include/cuopt/mathematical_optimization/constants.h index 222a713254..9e7828880b 100644 --- a/cpp/include/cuopt/mathematical_optimization/constants.h +++ b/cpp/include/cuopt/mathematical_optimization/constants.h @@ -46,7 +46,7 @@ #define CUOPT_AUGMENTED "augmented" #define CUOPT_DUALIZE "dualize" #define CUOPT_ORDERING "ordering" -#define CUOPT_BARRIER_DUAL_INITIAL_POINT "barrier_dual_initial_point" +#define CUOPT_BARRIER_INITIAL_POINT "barrier_initial_point" #define CUOPT_POSTSOLVE_INFO "postsolve_info" #define CUOPT_BARRIER_PRESOLVE_BOUND_FREE_VARIABLES "barrier_presolve_bound_free_variables" #define CUOPT_BARRIER_ITERATIVE_REFINEMENT "barrier_iterative_refinement" @@ -205,10 +205,10 @@ #define CUOPT_METHOD_BARRIER 3 #define CUOPT_METHOD_UNSET 4 -#define CUOPT_BARRIER_DUAL_INITIAL_POINT_AUTOMATIC -1 -#define CUOPT_BARRIER_DUAL_INITIAL_POINT_LUSTIG_MARSTEN_SHANNO 0 -#define CUOPT_BARRIER_DUAL_INITIAL_POINT_DUAL_LEAST_SQUARES 1 -#define CUOPT_BARRIER_DUAL_INITIAL_POINT_SEDUMI_MU 2 +#define CUOPT_BARRIER_INITIAL_POINT_AUTOMATIC -1 +#define CUOPT_BARRIER_INITIAL_POINT_LUSTIG_MARSTEN_SHANNO 0 +#define CUOPT_BARRIER_INITIAL_POINT_DUAL_LEAST_SQUARES 1 +#define CUOPT_BARRIER_INITIAL_POINT_SEDUMI_MU 2 /* @brief PDLP precision mode constants */ #define CUOPT_PDLP_DEFAULT_PRECISION -1 diff --git a/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp b/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp index 6e4024bb86..c5c870c421 100644 --- a/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp +++ b/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp @@ -294,7 +294,7 @@ class pdlp_solver_settings_t { i_t augmented{-1}; i_t dualize{-1}; i_t ordering{-1}; - barrier_dual_initial_point_t barrier_dual_initial_point{barrier_dual_initial_point_t::Automatic}; + barrier_initial_point_t barrier_initial_point{barrier_initial_point_t::Automatic}; i_t postsolve_info{-1}; i_t barrier_presolve_bound_free_variables{-1}; // -1 automatic, 0 disabled, 1 enabled // Ruiz equilibration for QCQP (barrier) scaling: -1 automatic (row/column diff --git a/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp b/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp index 3736d59c22..502566072b 100644 --- a/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp +++ b/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp @@ -150,11 +150,11 @@ enum presolver_t : int { * DualLeastSquares: solve augmented or ADAT dual least-squares system. * SedumiMu: Sturm/SeDuMi mu-based primal+dual point (no factorization). */ -enum barrier_dual_initial_point_t : int { - Automatic = CUOPT_BARRIER_DUAL_INITIAL_POINT_AUTOMATIC, - LustigMarstenShanno = CUOPT_BARRIER_DUAL_INITIAL_POINT_LUSTIG_MARSTEN_SHANNO, - DualLeastSquares = CUOPT_BARRIER_DUAL_INITIAL_POINT_DUAL_LEAST_SQUARES, - SedumiMu = CUOPT_BARRIER_DUAL_INITIAL_POINT_SEDUMI_MU +enum barrier_initial_point_t : int { + Automatic = CUOPT_BARRIER_INITIAL_POINT_AUTOMATIC, + LustigMarstenShanno = CUOPT_BARRIER_INITIAL_POINT_LUSTIG_MARSTEN_SHANNO, + DualLeastSquares = CUOPT_BARRIER_INITIAL_POINT_DUAL_LEAST_SQUARES, + SedumiMu = CUOPT_BARRIER_INITIAL_POINT_SEDUMI_MU }; } // namespace mathematical_optimization diff --git a/cpp/src/barrier/barrier.cu b/cpp/src/barrier/barrier.cu index b88fc12dc9..9734de54a4 100644 --- a/cpp/src/barrier/barrier.cu +++ b/cpp/src/barrier/barrier.cu @@ -2204,11 +2204,11 @@ int barrier_solver_t::initial_point(iteration_data_t& data) const bool use_augmented = data.use_augmented; const bool has_direct_free_linear = data.n_direct_free_linear > 0; - const barrier_dual_initial_point_t input_strategy = settings.barrier_dual_initial_point; + const barrier_initial_point_t input_strategy = settings.barrier_initial_point; - const barrier_dual_initial_point_t init_strategy = - (data.has_cones() && input_strategy == barrier_dual_initial_point_t::Automatic) - ? barrier_dual_initial_point_t::SedumiMu + const barrier_initial_point_t init_strategy = + (data.has_cones() && input_strategy == barrier_initial_point_t::Automatic) + ? barrier_initial_point_t::SedumiMu : input_strategy; // SedumiMu: Sturm/SeDuMi-style mu-based primal+dual initial point. @@ -2216,7 +2216,7 @@ int barrier_solver_t::initial_point(iteration_data_t& data) // where e_K is the identity of the symmetric cone: // LP block: e = 1, SOC block: e = (sqrt(2), 0, ..., 0) // Full primal+dual point; no factorization/solve (main loop factorizes later). - if (init_strategy == barrier_dual_initial_point_t::SedumiMu) { + if (init_strategy == barrier_initial_point_t::SedumiMu) { const f_t norm_b = vector_norm_inf(lp.rhs); const f_t norm_c = vector_norm_inf(lp.objective); const f_t mu = std::sqrt((1.0 + norm_b) * (1.0 + norm_c)); @@ -2404,8 +2404,8 @@ int barrier_solver_t::initial_point(iteration_data_t& data) values, epsilon_adjust, linear_mask, linear_end, lp.second_order_cone_dims); }; - if (init_strategy == barrier_dual_initial_point_t::Automatic || - init_strategy == barrier_dual_initial_point_t::LustigMarstenShanno) { + if (init_strategy == barrier_initial_point_t::Automatic || + init_strategy == barrier_initial_point_t::LustigMarstenShanno) { // Use the dual starting point suggested by the paper // On Implementing Mehrotra’s Predictor–Corrector Interior-Point Method for Linear Programming // Irvin J. Lustig, Roy E. Marsten, and David F. Shanno diff --git a/cpp/src/dual_simplex/simplex_solver_settings.hpp b/cpp/src/dual_simplex/simplex_solver_settings.hpp index 3fe6c940b5..95a86bb9ae 100644 --- a/cpp/src/dual_simplex/simplex_solver_settings.hpp +++ b/cpp/src/dual_simplex/simplex_solver_settings.hpp @@ -78,7 +78,7 @@ struct simplex_solver_settings_t { augmented(0), dualize(-1), ordering(-1), - barrier_dual_initial_point(barrier_dual_initial_point_t::Automatic), + barrier_initial_point(barrier_initial_point_t::Automatic), postsolve_info(-1), barrier_presolve_bound_free_variables(-1), qcqp_ruiz_equilibration(-1), @@ -174,11 +174,10 @@ struct simplex_solver_settings_t { i_t augmented; // -1 automatic, 0 to solve with ADAT, 1 to solve with augmented system i_t dualize; // -1 automatic, 0 to not dualize, 1 to dualize i_t ordering; // -1 automatic, 0 to use nested dissection, 1 to use AMD - barrier_dual_initial_point_t - barrier_dual_initial_point; // -1 automatic, 0 Lustig-Marsten-Shanno, - // 1 dual least squares, 2 SeDuMi mu-based - i_t postsolve_info; // -1 automatic (disabled), 0 disabled, 1 enabled - i_t barrier_presolve_bound_free_variables; // -1 automatic, 0 disabled, 1 enabled + barrier_initial_point_t barrier_initial_point; // -1 automatic, 0 Lustig-Marsten-Shanno, + // 1 dual least squares, 2 SeDuMi mu-based + i_t postsolve_info; // -1 automatic (disabled), 0 disabled, 1 enabled + i_t barrier_presolve_bound_free_variables; // -1 automatic, 0 disabled, 1 enabled i_t qcqp_ruiz_equilibration; // -1 automatic (imbalance heuristic), 0 disabled, 1 enabled f_t barrier_initial_point_safeguard; // margin pushing the barrier initial iterate into // the interior of the nonnegative orthant / SOC diff --git a/cpp/src/grpc/codegen/field_registry.yaml b/cpp/src/grpc/codegen/field_registry.yaml index 9d709375a6..969d70c9cb 100644 --- a/cpp/src/grpc/codegen/field_registry.yaml +++ b/cpp/src/grpc/codegen/field_registry.yaml @@ -531,10 +531,10 @@ pdlp_settings: field_num: 25 type: int32 optional: true - - barrier_dual_initial_point: + - barrier_initial_point: field_num: 26 type: int32 - from_proto_cast: "barrier_dual_initial_point_t" + from_proto_cast: "barrier_initial_point_t" optional: true - eliminate_dense_columns: field_num: 27 diff --git a/cpp/src/grpc/codegen/generated/cuopt_remote_data.proto b/cpp/src/grpc/codegen/generated/cuopt_remote_data.proto index 4b1e36d134..dd6e843ee9 100644 --- a/cpp/src/grpc/codegen/generated/cuopt_remote_data.proto +++ b/cpp/src/grpc/codegen/generated/cuopt_remote_data.proto @@ -186,7 +186,7 @@ message PDLPSolverSettings { optional int32 augmented = 23; optional int32 dualize = 24; optional int32 ordering = 25; - optional int32 barrier_dual_initial_point = 26; + optional int32 barrier_initial_point = 26; optional bool eliminate_dense_columns = 27; bool save_best_primal_so_far = 28; bool first_primal_feasible = 29; diff --git a/cpp/src/grpc/codegen/generated/generated_pdlp_settings_to_proto.inc b/cpp/src/grpc/codegen/generated/generated_pdlp_settings_to_proto.inc index 7c43ab5f08..9ca1c286d5 100644 --- a/cpp/src/grpc/codegen/generated/generated_pdlp_settings_to_proto.inc +++ b/cpp/src/grpc/codegen/generated/generated_pdlp_settings_to_proto.inc @@ -31,7 +31,7 @@ pb_settings->set_augmented(settings.augmented); pb_settings->set_dualize(settings.dualize); pb_settings->set_ordering(settings.ordering); - pb_settings->set_barrier_dual_initial_point(static_cast(settings.barrier_dual_initial_point)); + pb_settings->set_barrier_initial_point(static_cast(settings.barrier_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); diff --git a/cpp/src/grpc/codegen/generated/generated_proto_to_pdlp_settings.inc b/cpp/src/grpc/codegen/generated/generated_proto_to_pdlp_settings.inc index e2ba05b1ba..e0b80ff2f5 100644 --- a/cpp/src/grpc/codegen/generated/generated_proto_to_pdlp_settings.inc +++ b/cpp/src/grpc/codegen/generated/generated_proto_to_pdlp_settings.inc @@ -67,8 +67,8 @@ if (pb_settings.has_ordering()) { settings.ordering = pb_settings.ordering(); } - if (pb_settings.has_barrier_dual_initial_point()) { - settings.barrier_dual_initial_point = static_cast(pb_settings.barrier_dual_initial_point()); + if (pb_settings.has_barrier_initial_point()) { + settings.barrier_initial_point = static_cast(pb_settings.barrier_initial_point()); } if (pb_settings.has_eliminate_dense_columns()) { settings.eliminate_dense_columns = pb_settings.eliminate_dense_columns(); diff --git a/cpp/src/math_optimization/solver_settings.cu b/cpp/src/math_optimization/solver_settings.cu index 9ad34771f5..03dddbe5e3 100644 --- a/cpp/src/math_optimization/solver_settings.cu +++ b/cpp/src/math_optimization/solver_settings.cu @@ -137,7 +137,7 @@ solver_settings_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_DUAL_INITIAL_POINT, reinterpret_cast(&pdlp_settings.barrier_dual_initial_point), -1, 2, -1}, + {CUOPT_BARRIER_INITIAL_POINT, reinterpret_cast(&pdlp_settings.barrier_initial_point), -1, 2, -1}, {CUOPT_POSTSOLVE_INFO, &pdlp_settings.postsolve_info, -1, 1, -1}, {CUOPT_MIP_CUT_PASSES, &mip_settings.max_cut_passes, -1, std::numeric_limits::max(), 10}, {CUOPT_MIP_MIXED_INTEGER_ROUNDING_CUTS, &mip_settings.mir_cuts, -1, 1, -1}, diff --git a/cpp/src/pdlp/solve.cu b/cpp/src/pdlp/solve.cu index 493a250af9..0e5fc80305 100644 --- a/cpp/src/pdlp/solve.cu +++ b/cpp/src/pdlp/solve.cu @@ -498,16 +498,16 @@ std::tuple, simplex::lp_status_t, f_t, f_t, f_t f_t norm_rhs = vector_norm2(user_problem.rhs); simplex::simplex_solver_settings_t barrier_settings; - barrier_settings.num_gpus = settings.num_gpus; - barrier_settings.time_limit = settings.time_limit; - barrier_settings.iteration_limit = settings.iteration_limit; - barrier_settings.concurrent_halt = settings.concurrent_halt; - barrier_settings.folding = settings.folding; - barrier_settings.augmented = settings.augmented; - barrier_settings.dualize = settings.dualize; - barrier_settings.ordering = settings.ordering; - barrier_settings.barrier_dual_initial_point = settings.barrier_dual_initial_point; - barrier_settings.postsolve_info = settings.postsolve_info; + barrier_settings.num_gpus = settings.num_gpus; + barrier_settings.time_limit = settings.time_limit; + barrier_settings.iteration_limit = settings.iteration_limit; + barrier_settings.concurrent_halt = settings.concurrent_halt; + barrier_settings.folding = settings.folding; + barrier_settings.augmented = settings.augmented; + barrier_settings.dualize = settings.dualize; + barrier_settings.ordering = settings.ordering; + barrier_settings.barrier_initial_point = settings.barrier_initial_point; + barrier_settings.postsolve_info = settings.postsolve_info; barrier_settings.barrier_presolve_bound_free_variables = settings.barrier_presolve_bound_free_variables; barrier_settings.barrier_initial_point_safeguard = settings.barrier_initial_point_safeguard; diff --git a/cpp/tests/linear_programming/grpc/grpc_client_test.cpp b/cpp/tests/linear_programming/grpc/grpc_client_test.cpp index 78aff4f867..fd9d95eef5 100644 --- a/cpp/tests/linear_programming/grpc/grpc_client_test.cpp +++ b/cpp/tests/linear_programming/grpc/grpc_client_test.cpp @@ -2241,8 +2241,8 @@ TEST(MapperRoundtrip, PDLPSettingsAllFields) orig.augmented = 1; orig.dualize = 1; orig.ordering = 2; - orig.barrier_dual_initial_point = - cuopt::mathematical_optimization::barrier_dual_initial_point_t::LustigMarstenShanno; + orig.barrier_initial_point = + cuopt::mathematical_optimization::barrier_initial_point_t::LustigMarstenShanno; orig.eliminate_dense_columns = true; orig.barrier_iterative_refinement = false; // not the default true, to detect overwrite-on-decode orig.barrier_step_scale = 0.75; // not the default 0.9 @@ -2283,8 +2283,8 @@ TEST(MapperRoundtrip, PDLPSettingsAllFields) EXPECT_EQ(restored.augmented, 1); EXPECT_EQ(restored.dualize, 1); EXPECT_EQ(restored.ordering, 2); - EXPECT_EQ(restored.barrier_dual_initial_point, - cuopt::mathematical_optimization::barrier_dual_initial_point_t::LustigMarstenShanno); + EXPECT_EQ(restored.barrier_initial_point, + cuopt::mathematical_optimization::barrier_initial_point_t::LustigMarstenShanno); EXPECT_EQ(restored.eliminate_dense_columns, true); EXPECT_EQ(restored.barrier_iterative_refinement, false); EXPECT_DOUBLE_EQ(restored.barrier_step_scale, 0.75); @@ -2436,7 +2436,7 @@ TEST(MapperRoundtrip, PDLPSettingsDefaultProtoPreservesAllCppDefaults) EXPECT_EQ(after.augmented, fresh.augmented); EXPECT_EQ(after.dualize, fresh.dualize); EXPECT_EQ(after.ordering, fresh.ordering); - EXPECT_EQ(after.barrier_dual_initial_point, fresh.barrier_dual_initial_point); + EXPECT_EQ(after.barrier_initial_point, fresh.barrier_initial_point); EXPECT_DOUBLE_EQ(after.barrier_step_scale, fresh.barrier_step_scale); // Enum-int32 fields (post-decode clamping defends out-of-range; default `0` // on the wire is in-range so the clamp does not fire, but the `optional` diff --git a/docs/cuopt/source/convex-settings.rst b/docs/cuopt/source/convex-settings.rst index 7bff025e5d..3e23070537 100644 --- a/docs/cuopt/source/convex-settings.rst +++ b/docs/cuopt/source/convex-settings.rst @@ -284,10 +284,10 @@ cuDSS Deterministic Mode .. note:: The default value is ``false``. Enable deterministic mode if reproducibility is more important than performance. -Dual Initial Point -"""""""""""""""""" +Initial Point +""""""""""""" -``CUOPT_BARRIER_DUAL_INITIAL_POINT`` controls the method used to compute the dual initial point for the barrier solver. The choice of initial point will affect the number of iterations performed by barrier. +``CUOPT_BARRIER_INITIAL_POINT`` controls the method used to compute the initial point for the barrier solver. The choice of initial point will affect the number of iterations performed by barrier. * ``-1``: Automatic (default) - cuOpt selects the best method * ``0``: Use an initial point from a heuristic approach based on the paper "On Implementing Mehrotra's Predictor–Corrector Interior-Point Method for Linear Programming" (SIAM J. Optimization, 1992) by Lustig, Martsten, Shanno. diff --git a/docs/cuopt/source/cuopt-c/convex/convex-c-api.rst b/docs/cuopt/source/cuopt-c/convex/convex-c-api.rst index 31a4516ca0..be7e55d0dd 100644 --- a/docs/cuopt/source/cuopt-c/convex/convex-c-api.rst +++ b/docs/cuopt/source/cuopt-c/convex/convex-c-api.rst @@ -203,7 +203,7 @@ These constants are used as parameter names in the :c:func:`cuOptSetParameter`, .. doxygendefine:: CUOPT_ORDERING .. doxygendefine:: CUOPT_ELIMINATE_DENSE_COLUMNS .. doxygendefine:: CUOPT_CUDSS_DETERMINISTIC -.. doxygendefine:: CUOPT_BARRIER_DUAL_INITIAL_POINT +.. doxygendefine:: CUOPT_BARRIER_INITIAL_POINT .. doxygendefine:: CUOPT_BARRIER_ITERATIVE_REFINEMENT .. doxygendefine:: CUOPT_BARRIER_STEP_SCALE .. doxygendefine:: CUOPT_DUAL_POSTSOLVE diff --git a/python/cuopt_server/cuopt_server/tests/test_lp.py b/python/cuopt_server/cuopt_server/tests/test_lp.py index 8ea85b60ab..2a3a636d2a 100644 --- a/python/cuopt_server/cuopt_server/tests/test_lp.py +++ b/python/cuopt_server/cuopt_server/tests/test_lp.py @@ -142,7 +142,7 @@ def test_sample_milp( ) @pytest.mark.parametrize( "folding, dualize, ordering, augmented, eliminate_dense, cudss_determ, " - "dual_initial_point", + "initial_point", [ # Test automatic settings (default) (-1, -1, -1, -1, True, False, -1), @@ -168,7 +168,7 @@ def test_barrier_solver_options( augmented, eliminate_dense, cudss_determ, - dual_initial_point, + initial_point, ): """ Test the barrier solver (method=3) with various configuration options: @@ -179,7 +179,7 @@ def test_barrier_solver_options( - eliminate_dense_columns: True to eliminate, False to not - cudss_deterministic: True for deterministic, False for nondeterministic - - barrier_dual_initial_point: (-1) automatic, (0) Lustig-Marsten-Shanno, + - barrier_initial_point: (-1) automatic, (0) Lustig-Marsten-Shanno, (1) dual least squares, (2) Sturm/SeDuMi mu-based primal+dual """ data = get_std_data_for_lp() @@ -194,7 +194,7 @@ def test_barrier_solver_options( data["solver_config"]["augmented"] = augmented data["solver_config"]["eliminate_dense_columns"] = eliminate_dense data["solver_config"]["cudss_deterministic"] = cudss_determ - data["solver_config"]["barrier_dual_initial_point"] = dual_initial_point + data["solver_config"]["barrier_initial_point"] = initial_point res = get_lp(client, data) @@ -204,7 +204,7 @@ def test_barrier_solver_options( print(f"folding={folding}, dualize={dualize}, ordering={ordering}") print(f"augmented={augmented}, eliminate_dense={eliminate_dense}") print(f"cudss_deterministic={cudss_determ}") - print(f"barrier_dual_initial_point={dual_initial_point}") + print(f"barrier_initial_point={initial_point}") print(res.json()) validate_lp_result( diff --git a/python/cuopt_server/cuopt_server/utils/linear_programming/data_definition.py b/python/cuopt_server/cuopt_server/utils/linear_programming/data_definition.py index 75998a347a..bac7b45ab7 100644 --- a/python/cuopt_server/cuopt_server/utils/linear_programming/data_definition.py +++ b/python/cuopt_server/cuopt_server/utils/linear_programming/data_definition.py @@ -496,9 +496,9 @@ class SolverConfig(BaseModel): description="Set the type of ordering to use for the barrier solver." "-1 for automatic, 0 to use cuDSS default ordering, 1 to use AMD", ) - barrier_dual_initial_point: Optional[int] = Field( + barrier_initial_point: Optional[int] = Field( default=-1, - description="Set the type of dual initial point to use for the barrier" + description="Set the type of initial point to use for the barrier" "solver. -1 for automatic, 0 to use Lustig, Marsten, and Shanno" "initial point, 1 to use initial point from a dual least squares" "problem, 2 to use Sturm/SeDuMi mu-based primal+dual"