diff --git a/cpp/include/cuopt/mathematical_optimization/constants.h b/cpp/include/cuopt/mathematical_optimization/constants.h index 467aa7fce3..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" @@ -149,6 +149,9 @@ /* @brief QCQP (barrier) scaling hyper-parameters */ #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 #define CUOPT_MODE_DETERMINISTIC 1 @@ -202,6 +205,11 @@ #define CUOPT_METHOD_BARRIER 3 #define CUOPT_METHOD_UNSET 4 +#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 #define CUOPT_PDLP_SINGLE_PRECISION 0 diff --git a/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp b/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp index 0882f75e0f..c5c870c421 100644 --- a/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp +++ b/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp @@ -294,13 +294,16 @@ 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_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 // 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_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/include/cuopt/mathematical_optimization/utilities/internals.hpp b/cpp/include/cuopt/mathematical_optimization/utilities/internals.hpp index 25f3f34f7b..502566072b 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_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 } // namespace cuopt diff --git a/cpp/src/barrier/barrier.cu b/cpp/src/barrier/barrier.cu index c164296a25..9734de54a4 100644 --- a/cpp/src/barrier/barrier.cu +++ b/cpp/src/barrier/barrier.cu @@ -97,6 +97,34 @@ 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) +{ + // 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; + 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) @@ -2176,41 +2204,54 @@ 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 barrier_initial_point_t input_strategy = settings.barrier_initial_point; + + 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. + // 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 == 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)); + 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); @@ -2353,9 +2394,18 @@ int barrier_solver_t::initial_point(iteration_data_t& data) #endif } - float64_t epsilon_adjust = 10.0; + 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; + auto ensure_interior = [&](dense_vector_t& values, + const std::vector& linear_mask) { + ensure_initial_point_interior( + values, epsilon_adjust, linear_mask, linear_end, lp.second_order_cone_dims); + }; - if (settings.barrier_dual_initial_point == -1 || settings.barrier_dual_initial_point == 0) { + 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 @@ -2424,7 +2474,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); @@ -2448,7 +2497,6 @@ 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 @@ -2466,6 +2514,7 @@ int barrier_solver_t::initial_point(iteration_data_t& data) 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); @@ -2474,7 +2523,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) { diff --git a/cpp/src/barrier/barrier.hpp b/cpp/src/barrier/barrier.hpp index 46fe91dcd4..f72b2ff728 100644 --- a/cpp/src/barrier/barrier.hpp +++ b/cpp/src/barrier/barrier.hpp @@ -8,6 +8,8 @@ #include +#include +#include #include #include #include diff --git a/cpp/src/dual_simplex/simplex_solver_settings.hpp b/cpp/src/dual_simplex/simplex_solver_settings.hpp index c7fe06ed4a..95a86bb9ae 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,10 +78,11 @@ struct simplex_solver_settings_t { augmented(0), dualize(-1), ordering(-1), - barrier_dual_initial_point(-1), + barrier_initial_point(barrier_initial_point_t::Automatic), postsolve_info(-1), barrier_presolve_bound_free_variables(-1), qcqp_ruiz_equilibration(-1), + barrier_initial_point_safeguard(10.0), check_Q(false), crossover(false), refactor_frequency(100), @@ -172,11 +174,13 @@ 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 - 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 + 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 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/grpc/codegen/field_registry.yaml b/cpp/src/grpc/codegen/field_registry.yaml index 2fb7896027..969d70c9cb 100644 --- a/cpp/src/grpc/codegen/field_registry.yaml +++ b/cpp/src/grpc/codegen/field_registry.yaml @@ -531,9 +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_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 eb88b192d9..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(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 29e6c4cca2..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 = 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 2a193cd70b..03dddbe5e3 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"}, @@ -136,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, 1, -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 80b3da2c18..0e5fc80305 100644 --- a/cpp/src/pdlp/solve.cu +++ b/cpp/src/pdlp/solve.cu @@ -498,18 +498,19 @@ 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; barrier_settings.barrier = true; barrier_settings.barrier_presolve = true; barrier_settings.crossover = settings.crossover; diff --git a/cpp/tests/linear_programming/grpc/grpc_client_test.cpp b/cpp/tests/linear_programming/grpc/grpc_client_test.cpp index f8fed6eee3..fd9d95eef5 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_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 @@ -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_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); @@ -2434,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 e3a683f8de..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,8 +179,8 @@ 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, - (1) dual least squares + - 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 6cd8f7828a..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,12 +496,13 @@ 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", + "problem, 2 to use Sturm/SeDuMi mu-based primal+dual" + "point", ) eliminate_dense_columns: Optional[bool] = Field( default=True,