diff --git a/cpp/include/cuopt/mathematical_optimization/constants.h b/cpp/include/cuopt/mathematical_optimization/constants.h index 9ea2f052e6..bb32e838b5 100644 --- a/cpp/include/cuopt/mathematical_optimization/constants.h +++ b/cpp/include/cuopt/mathematical_optimization/constants.h @@ -222,12 +222,12 @@ #define CUOPT_PDLP_SOLVER_MODE_FAST1 3 #define CUOPT_PDLP_SOLVER_MODE_STABLE3 4 -#define CUOPT_METHOD_CONCURRENT 0 -#define CUOPT_METHOD_PDLP 1 -#define CUOPT_METHOD_DUAL_SIMPLEX 2 -#define CUOPT_METHOD_BARRIER 3 -#define CUOPT_METHOD_PRIMAL 4 -#define CUOPT_METHOD_UNSET 5 +#define CUOPT_METHOD_CONCURRENT 0 +#define CUOPT_METHOD_PDLP 1 +#define CUOPT_METHOD_DUAL_SIMPLEX 2 +#define CUOPT_METHOD_BARRIER 3 +#define CUOPT_METHOD_PRIMAL_SIMPLEX 4 +#define CUOPT_METHOD_UNSET 5 #define CUOPT_BARRIER_DUAL_INITIAL_POINT_AUTOMATIC -1 #define CUOPT_BARRIER_DUAL_INITIAL_POINT_LUSTIG_MARSTEN_SHANNO 0 diff --git a/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp b/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp index 3c02fdd815..b56d4f409a 100644 --- a/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp +++ b/cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp @@ -62,18 +62,18 @@ enum pdlp_solver_mode_t : int { * PDLP: Use the PDLP method. * DualSimplex: Use the dual simplex method. * Barrier: Use the barrier method - * Primal: Use the (experimental) primal simplex method. + * PrimalSimplex: Use the primal simplex method. * Unset: The value was not set. * * @note Default method is Concurrent. */ enum method_t : int { - Concurrent = CUOPT_METHOD_CONCURRENT, - PDLP = CUOPT_METHOD_PDLP, - DualSimplex = CUOPT_METHOD_DUAL_SIMPLEX, - Barrier = CUOPT_METHOD_BARRIER, - Primal = CUOPT_METHOD_PRIMAL, - Unset = CUOPT_METHOD_UNSET + Concurrent = CUOPT_METHOD_CONCURRENT, + PDLP = CUOPT_METHOD_PDLP, + DualSimplex = CUOPT_METHOD_DUAL_SIMPLEX, + Barrier = CUOPT_METHOD_BARRIER, + PrimalSimplex = CUOPT_METHOD_PRIMAL_SIMPLEX, + Unset = CUOPT_METHOD_UNSET }; /// Returns the corresponding string from the enum `method_t`. @@ -84,7 +84,7 @@ inline std::string method_to_string(method_t method) case method_t::PDLP: return "PDLP"; case method_t::Barrier: return "Barrier"; case method_t::Concurrent: return "Concurrent"; - case method_t::Primal: return "Primal Simplex"; + case method_t::PrimalSimplex: return "Primal Simplex"; default: return "Unset"; } } diff --git a/cpp/include/cuopt/mathematical_optimization/pdlp/solver_solution.hpp b/cpp/include/cuopt/mathematical_optimization/pdlp/solver_solution.hpp index 0c3e09f274..c3e2edbe43 100644 --- a/cpp/include/cuopt/mathematical_optimization/pdlp/solver_solution.hpp +++ b/cpp/include/cuopt/mathematical_optimization/pdlp/solver_solution.hpp @@ -92,7 +92,7 @@ class optimization_problem_solution_t : public base_solution_t { /** Solve time in seconds */ double solve_time{std::numeric_limits::signaling_NaN()}; - /** Whether the problem was solved by PDLP, Barrier or Dual Simplex */ + /** The method that solved the problem. */ method_t solved_by = method_t::Unset; }; diff --git a/cpp/src/dual_simplex/simplex_solver_settings.hpp b/cpp/src/dual_simplex/simplex_solver_settings.hpp index 04cb708dec..79fd9176e3 100644 --- a/cpp/src/dual_simplex/simplex_solver_settings.hpp +++ b/cpp/src/dual_simplex/simplex_solver_settings.hpp @@ -199,7 +199,7 @@ struct simplex_solver_settings_t { i_t ordering; // -1 automatic, 0 to use nested dissection, 1 to use AMD i_t initial_perturbation; // -1 automatic, 0 to not perturb, 1 to perturb i_t remove_perturbation; // -1 automatic, 0 disabled, 1 enabled - i_t primal_pricing; // 0 Dantzig (default), 1 Devex + i_t primal_pricing; // 0 Dantzig, 1 Devex (default) barrier_dual_initial_point_t barrier_dual_initial_point; // -1 automatic, 0 Lustig-Marsten-Shanno, // 1 dual least squares, 2 SeDuMi mu-based diff --git a/cpp/src/grpc/codegen/field_registry.yaml b/cpp/src/grpc/codegen/field_registry.yaml index e248f26cfd..17afea9e97 100644 --- a/cpp/src/grpc/codegen/field_registry.yaml +++ b/cpp/src/grpc/codegen/field_registry.yaml @@ -190,6 +190,7 @@ enums: - PDLP - DualSimplex - Barrier + - PrimalSimplex variable_type: domain: problem @@ -622,9 +623,10 @@ pdlp_settings: optional: true - method: description: >- - Method used to solve the LP. Concurrent runs PDLP, dual simplex and - barrier in parallel. Default accuracy differs per method: PDLP 1e-4 - relative, barrier 1e-8 relative, dual simplex 1e-6 absolute. + Method used to solve the LP: Concurrent, PDLP, dual simplex, barrier, + or primal simplex. Concurrent runs PDLP, dual simplex and barrier in + parallel. Default accuracy differs per method: PDLP 1e-4 relative, + barrier 1e-8 relative, dual simplex and primal simplex 1e-6 absolute. default: "Concurrent" field_num: 15 type: lp_method diff --git a/cpp/src/grpc/codegen/generated/cuopt_mcp_schema.json b/cpp/src/grpc/codegen/generated/cuopt_mcp_schema.json index 9c3e3de6ec..83bd86a48d 100644 --- a/cpp/src/grpc/codegen/generated/cuopt_mcp_schema.json +++ b/cpp/src/grpc/codegen/generated/cuopt_mcp_schema.json @@ -84,15 +84,17 @@ "Concurrent", "PDLP", "DualSimplex", - "Barrier" + "Barrier", + "PrimalSimplex" ], "x-enum-values": { "Concurrent": 0, "PDLP": 1, "DualSimplex": 2, - "Barrier": 3 + "Barrier": 3, + "PrimalSimplex": 4 }, - "description": "Method used to solve the LP. Concurrent runs PDLP, dual simplex and barrier in parallel. Default accuracy differs per method: PDLP 1e-4 relative, barrier 1e-8 relative, dual simplex 1e-6 absolute. Default: Concurrent." + "description": "Method used to solve the LP: Concurrent, PDLP, dual simplex, barrier, or primal simplex. Concurrent runs PDLP, dual simplex and barrier in parallel. Default accuracy differs per method: PDLP 1e-4 relative, barrier 1e-8 relative, dual simplex and primal simplex 1e-6 absolute. Default: Concurrent." }, "presolver": { "type": "integer", diff --git a/cpp/src/grpc/codegen/generated/cuopt_remote_data.proto b/cpp/src/grpc/codegen/generated/cuopt_remote_data.proto index e36456df71..e346621bd6 100644 --- a/cpp/src/grpc/codegen/generated/cuopt_remote_data.proto +++ b/cpp/src/grpc/codegen/generated/cuopt_remote_data.proto @@ -42,6 +42,7 @@ enum LPMethod { PDLP = 1; DualSimplex = 2; Barrier = 3; + PrimalSimplex = 4; } enum VariableType { diff --git a/cpp/src/grpc/codegen/generated/generated_enum_converters_settings.inc b/cpp/src/grpc/codegen/generated/generated_enum_converters_settings.inc index 7086570f65..521acd6723 100644 --- a/cpp/src/grpc/codegen/generated/generated_enum_converters_settings.inc +++ b/cpp/src/grpc/codegen/generated/generated_enum_converters_settings.inc @@ -33,6 +33,7 @@ cuopt::remote::LPMethod to_proto_lp_method(method_t v) case method_t::PDLP: return cuopt::remote::PDLP; case method_t::DualSimplex: return cuopt::remote::DualSimplex; case method_t::Barrier: return cuopt::remote::Barrier; + case method_t::PrimalSimplex: return cuopt::remote::PrimalSimplex; } throw std::invalid_argument("Unknown method_t: " + std::to_string(static_cast(v))); } @@ -44,6 +45,7 @@ method_t from_proto_lp_method(cuopt::remote::LPMethod v) case cuopt::remote::PDLP: return method_t::PDLP; case cuopt::remote::DualSimplex: return method_t::DualSimplex; case cuopt::remote::Barrier: return method_t::Barrier; + case cuopt::remote::PrimalSimplex: return method_t::PrimalSimplex; } throw std::invalid_argument("Unknown cuopt::remote::LPMethod: " + std::to_string(static_cast(v))); } diff --git a/cpp/src/math_optimization/solver_settings.cu b/cpp/src/math_optimization/solver_settings.cu index 985d3c2a42..2f4d3c559a 100644 --- a/cpp/src/math_optimization/solver_settings.cu +++ b/cpp/src/math_optimization/solver_settings.cu @@ -172,8 +172,8 @@ solver_settings_t::solver_settings_t() : pdlp_settings(), mip_settings {CUOPT_ITERATION_LIMIT, &pdlp_settings.iteration_limit, 0, std::numeric_limits::max(), std::numeric_limits::max()}, {CUOPT_NODE_LIMIT, &mip_settings.node_limit, 0, std::numeric_limits::max(), std::numeric_limits::max()}, {CUOPT_PDLP_SOLVER_MODE, reinterpret_cast(&pdlp_settings.pdlp_solver_mode), CUOPT_PDLP_SOLVER_MODE_STABLE1, CUOPT_PDLP_SOLVER_MODE_STABLE3, CUOPT_PDLP_SOLVER_MODE_STABLE3}, - {CUOPT_METHOD, reinterpret_cast(&pdlp_settings.method), CUOPT_METHOD_CONCURRENT, CUOPT_METHOD_PRIMAL, CUOPT_METHOD_CONCURRENT}, - {CUOPT_METHOD, reinterpret_cast(&mip_settings.method), CUOPT_METHOD_CONCURRENT, CUOPT_METHOD_PRIMAL, CUOPT_METHOD_CONCURRENT}, + {CUOPT_METHOD, reinterpret_cast(&pdlp_settings.method), CUOPT_METHOD_CONCURRENT, CUOPT_METHOD_PRIMAL_SIMPLEX, CUOPT_METHOD_CONCURRENT}, + {CUOPT_METHOD, reinterpret_cast(&mip_settings.method), CUOPT_METHOD_CONCURRENT, CUOPT_METHOD_PRIMAL_SIMPLEX, CUOPT_METHOD_CONCURRENT}, {CUOPT_CONCURRENT_NNZ_CUTOFF, &pdlp_settings.concurrent_nnz_cutoff, -1, std::numeric_limits::max(), 50'000'000, "skip Barrier and dual simplex in concurrent solves at this reduced NNZ; -1 disables the cutoff"}, {CUOPT_CONCURRENT_NNZ_CUTOFF, &mip_settings.concurrent_nnz_cutoff, -1, std::numeric_limits::max(), 50'000'000, "skip Barrier and dual simplex in concurrent solves at this reduced NNZ; -1 disables the cutoff"}, {CUOPT_NUM_CPU_THREADS, &mip_settings.num_cpu_threads, -1, std::numeric_limits::max(), -1}, diff --git a/cpp/src/pdlp/solve.cu b/cpp/src/pdlp/solve.cu index 8e5bb6dc96..8d18fc29c7 100644 --- a/cpp/src/pdlp/solve.cu +++ b/cpp/src/pdlp/solve.cu @@ -751,7 +751,7 @@ optimization_problem_solution_t run_primal( std::get<2>(sol_primal), std::get<3>(sol_primal), std::get<4>(sol_primal), - method_t::Primal); + method_t::PrimalSimplex); } #if PDLP_INSTANTIATE_FLOAT || CUOPT_INSTANTIATE_FLOAT @@ -1950,7 +1950,7 @@ optimization_problem_solution_t solve_lp_with_method( if constexpr (std::is_same_v) { if (settings.method == method_t::DualSimplex) { return run_dual_simplex(problem, settings, timer); - } else if (settings.method == method_t::Primal) { + } else if (settings.method == method_t::PrimalSimplex) { return run_primal(problem, settings, timer); } else if (settings.method == method_t::Barrier) { return run_barrier(problem, settings, timer, settings.barrier_cache); diff --git a/cpp/tests/linear_programming/unit_tests/pdlp_memory_test.cu b/cpp/tests/linear_programming/unit_tests/pdlp_memory_test.cu index c5172b869d..04c0e33591 100644 --- a/cpp/tests/linear_programming/unit_tests/pdlp_memory_test.cu +++ b/cpp/tests/linear_programming/unit_tests/pdlp_memory_test.cu @@ -210,7 +210,7 @@ INSTANTIATE_TEST_SUITE_P(PresolversAndMethods, method_t::Concurrent, method_t::DualSimplex, method_t::Barrier, - method_t::Primal))); + method_t::PrimalSimplex))); TEST(PdlpMemoryProblem, PresolvedCsrRemainsAvailableForFp32Conversion) { diff --git a/java/cuopt/src/main/java/com/nvidia/cuopt/mathematicaloptimization/SolverMethod.java b/java/cuopt/src/main/java/com/nvidia/cuopt/mathematicaloptimization/SolverMethod.java index 9413705baa..7c85751146 100644 --- a/java/cuopt/src/main/java/com/nvidia/cuopt/mathematicaloptimization/SolverMethod.java +++ b/java/cuopt/src/main/java/com/nvidia/cuopt/mathematicaloptimization/SolverMethod.java @@ -10,6 +10,7 @@ public enum SolverMethod { PDLP(CuOptConstants.CUOPT_METHOD_PDLP), DUAL_SIMPLEX(CuOptConstants.CUOPT_METHOD_DUAL_SIMPLEX), BARRIER(CuOptConstants.CUOPT_METHOD_BARRIER), + PRIMAL_SIMPLEX(CuOptConstants.CUOPT_METHOD_PRIMAL_SIMPLEX), UNSET(CuOptConstants.CUOPT_METHOD_UNSET); private final int nativeValue; diff --git a/java/cuopt/src/test/java/com/nvidia/cuopt/mathematicaloptimization/ProblemModelingTest.java b/java/cuopt/src/test/java/com/nvidia/cuopt/mathematicaloptimization/ProblemModelingTest.java index 51faa03763..c1f1321cf8 100644 --- a/java/cuopt/src/test/java/com/nvidia/cuopt/mathematicaloptimization/ProblemModelingTest.java +++ b/java/cuopt/src/test/java/com/nvidia/cuopt/mathematicaloptimization/ProblemModelingTest.java @@ -17,6 +17,8 @@ final class ProblemModelingTest { @Test void generatedSolverEnumsMatchCuOptConstants() { assertEquals(CuOptConstants.CUOPT_METHOD_PDLP, SolverMethod.PDLP.nativeValue()); + assertEquals( + CuOptConstants.CUOPT_METHOD_PRIMAL_SIMPLEX, SolverMethod.PRIMAL_SIMPLEX.nativeValue()); assertEquals( CuOptConstants.CUOPT_PDLP_SOLVER_MODE_STABLE1, PDLPSolverMode.STABLE1.nativeValue()); diff --git a/python/cuopt/cuopt/linear_programming/solution/solution.py b/python/cuopt/cuopt/linear_programming/solution/solution.py index 24a548fa19..89f0dcc613 100644 --- a/python/cuopt/cuopt/linear_programming/solution/solution.py +++ b/python/cuopt/cuopt/linear_programming/solution/solution.py @@ -125,8 +125,8 @@ class Solution: Solve time in seconds solved_by: enum Note: Applicable to only LP - Whether the LP was solved by Dual Simplex, PDLP or Barrier. This is populated - by the solver using the values from SolverMethod. + The method that solved the LP. This is populated by the solver using the + values from SolverMethod. """ def __init__( @@ -330,7 +330,7 @@ def get_solve_time(self): def get_solved_by(self): """ - Returns whether the LP was solved by Dual Simplex, PDLP or Barrier. See SolverMethod for all possible values. + Returns the method that solved the LP. See SolverMethod for all possible values. """ return self.solved_by diff --git a/python/cuopt/cuopt/linear_programming/solver_settings/solver_settings.pxd b/python/cuopt/cuopt/linear_programming/solver_settings/solver_settings.pxd index 03958d2286..9cd5203225 100644 --- a/python/cuopt/cuopt/linear_programming/solver_settings/solver_settings.pxd +++ b/python/cuopt/cuopt/linear_programming/solver_settings/solver_settings.pxd @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # noqa +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 @@ -28,6 +28,7 @@ cdef extern from "cuopt/mathematical_optimization/pdlp/solver_settings.hpp" name PDLP "cuopt::mathematical_optimization::method_t::PDLP" # noqa DualSimplex "cuopt::mathematical_optimization::method_t::DualSimplex" # noqa Barrier "cuopt::mathematical_optimization::method_t::Barrier" # noqa + PrimalSimplex "cuopt::mathematical_optimization::method_t::PrimalSimplex" # noqa Unset "cuopt::mathematical_optimization::method_t::Unset" # noqa cdef extern from "cuopt/mathematical_optimization/solver_settings.hpp" namespace "cuopt::mathematical_optimization": # noqa diff --git a/python/cuopt/cuopt/linear_programming/solver_settings/solver_settings.pyx b/python/cuopt/cuopt/linear_programming/solver_settings/solver_settings.pyx index 73a2ccccf9..390d535983 100644 --- a/python/cuopt/cuopt/linear_programming/solver_settings/solver_settings.pyx +++ b/python/cuopt/cuopt/linear_programming/solver_settings/solver_settings.pyx @@ -62,7 +62,7 @@ class SolverMethod(IntEnum): PDLP = auto() DualSimplex = auto() Barrier = auto() - Primal = auto() + PrimalSimplex = auto() Unset = auto() def __str__(self): diff --git a/python/cuopt_mcp/tests/test_schema.py b/python/cuopt_mcp/tests/test_schema.py index e0fecd15db..314f3693a1 100644 --- a/python/cuopt_mcp/tests/test_schema.py +++ b/python/cuopt_mcp/tests/test_schema.py @@ -78,6 +78,7 @@ def test_settings_schema_is_closed(): def test_validate_accepts_known_settings(): schema.validate_settings("pdlp_settings", {"time_limit": 5.0}) schema.validate_settings("pdlp_settings", {"method": "Barrier"}) + schema.validate_settings("pdlp_settings", {"method": "PrimalSimplex"}) def test_validate_rejects_unknown_setting_with_suggestion(): @@ -111,6 +112,7 @@ def test_enum_parameters_carry_a_name_to_integer_mapping(): assert mapping["PDLP"] == 1 assert mapping["DualSimplex"] == 2 assert mapping["Barrier"] == 3 + assert mapping["PrimalSimplex"] == 4 def test_non_enum_parameters_have_no_mapping(): diff --git a/python/cuopt_self_hosted/cuopt_sh_client/thin_client_solver_settings.py b/python/cuopt_self_hosted/cuopt_sh_client/thin_client_solver_settings.py index fca85b33c3..a21e635e60 100644 --- a/python/cuopt_self_hosted/cuopt_sh_client/thin_client_solver_settings.py +++ b/python/cuopt_self_hosted/cuopt_sh_client/thin_client_solver_settings.py @@ -16,6 +16,7 @@ class SolverMethod(IntEnum): PDLP = auto() DualSimplex = auto() Barrier = auto() + PrimalSimplex = auto() def __str__(self): """Convert the solver method to a string. diff --git a/python/cuopt_self_hosted/tests/test_solver_settings.py b/python/cuopt_self_hosted/tests/test_solver_settings.py new file mode 100644 index 0000000000..4d471195dc --- /dev/null +++ b/python/cuopt_self_hosted/tests/test_solver_settings.py @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +from cuopt_sh_client import SolverMethod + + +def test_primal_solver_method_matches_native_value(): + assert SolverMethod.PrimalSimplex == 4