From e559d29120a68fd165e136a566e09a41077fce28 Mon Sep 17 00:00:00 2001 From: Nicolas Blin Date: Tue, 17 Jun 2025 13:41:00 +0000 Subject: [PATCH 1/2] fix issue when problem has an empty problem in pdlp --- cpp/src/linear_programming/solve.cu | 18 ++++++++-- cpp/src/mip/problem/problem.cu | 14 -------- cpp/tests/linear_programming/pdlp_test.cu | 35 ++++++++++++++++++++ datasets/linear_programming/empty_matrix.mps | 11 ++++++ 4 files changed, 62 insertions(+), 16 deletions(-) create mode 100644 datasets/linear_programming/empty_matrix.mps diff --git a/cpp/src/linear_programming/solve.cu b/cpp/src/linear_programming/solve.cu index ed2a30bcf..b1d8fd53f 100644 --- a/cpp/src/linear_programming/solve.cu +++ b/cpp/src/linear_programming/solve.cu @@ -346,14 +346,28 @@ optimization_problem_solution_t run_dual_simplex( std::get<4>(sol_dual_simplex)); } +template +static optimization_problem_solution_t run_pdlp_solver( + detail::problem_t& problem, + pdlp_solver_settings_t const& settings, + const std::chrono::high_resolution_clock::time_point& start_time) +{ + if (problem.n_constraints == 0) { + CUOPT_LOG_INFO("No constraints in the problem: PDLP can't be run, use Dual Simplex instead."); + return optimization_problem_solution_t{pdlp_termination_status_t::NumericalError, + problem.handle_ptr->get_stream()}; + } + detail::pdlp_solver_t solver(problem, settings); + return solver.run_solver(start_time); +} + template optimization_problem_solution_t run_pdlp(detail::problem_t& problem, pdlp_solver_settings_t const& settings) { auto start_solver = std::chrono::high_resolution_clock::now(); f_t start_time = dual_simplex::tic(); - detail::pdlp_solver_t solver(problem, settings); - auto sol = solver.run_solver(start_solver); // Passing it for time limit + auto sol = run_pdlp_solver(problem, settings, start_solver); auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(end - start_solver); sol.set_solve_time(duration.count() / 1000.0); diff --git a/cpp/src/mip/problem/problem.cu b/cpp/src/mip/problem/problem.cu index 5b8511b92..1b48ccda9 100644 --- a/cpp/src/mip/problem/problem.cu +++ b/cpp/src/mip/problem/problem.cu @@ -54,20 +54,6 @@ void problem_t::op_problem_cstr_body(const optimization_problem_t op_problem = + cuopt::mps_parser::parse_mps(path); + + auto solver_settings = pdlp_solver_settings_t{}; + solver_settings.method = cuopt::linear_programming::method_t::PDLP; + + optimization_problem_solution_t solution = + solve_lp(&handle_, op_problem, solver_settings); + EXPECT_EQ((int)solution.get_termination_status(), CUOPT_TERIMINATION_STATUS_NUMERICAL_ERROR); +} + +// Should run thanks to Dual Simplex +TEST(pdlp_class, run_empty_matrix_dual_simplex) +{ + const raft::handle_t handle_{}; + + auto path = make_path_absolute("linear_programming/empty_matrix.mps"); + cuopt::mps_parser::mps_data_model_t op_problem = + cuopt::mps_parser::parse_mps(path); + + auto solver_settings = pdlp_solver_settings_t{}; + solver_settings.method = cuopt::linear_programming::method_t::Concurrent; + + optimization_problem_solution_t solution = + solve_lp(&handle_, op_problem, solver_settings); + EXPECT_EQ((int)solution.get_termination_status(), CUOPT_TERIMINATION_STATUS_OPTIMAL); + EXPECT_FALSE(solution.get_additional_termination_information().solved_by_pdlp); +} + } // namespace cuopt::linear_programming::test CUOPT_TEST_PROGRAM_MAIN() diff --git a/datasets/linear_programming/empty_matrix.mps b/datasets/linear_programming/empty_matrix.mps new file mode 100644 index 000000000..e387ee780 --- /dev/null +++ b/datasets/linear_programming/empty_matrix.mps @@ -0,0 +1,11 @@ +NAME +ROWS + N OBJ +COLUMNS + x1 OBJ -3 +RHS +RANGES +BOUNDS + MI bounds x1 + UP bounds x1 2 +ENDATA From 13b5cdb304d82a86abcc955c4a22f4079138d22d Mon Sep 17 00:00:00 2001 From: Nicolas Blin Date: Tue, 17 Jun 2025 13:58:08 +0000 Subject: [PATCH 2/2] fix style --- cpp/src/linear_programming/solve.cu | 8 ++++---- cpp/src/mip/problem/problem.cu | 4 +--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/cpp/src/linear_programming/solve.cu b/cpp/src/linear_programming/solve.cu index b1d8fd53f..c3ba4f2c7 100644 --- a/cpp/src/linear_programming/solve.cu +++ b/cpp/src/linear_programming/solve.cu @@ -355,7 +355,7 @@ static optimization_problem_solution_t run_pdlp_solver( if (problem.n_constraints == 0) { CUOPT_LOG_INFO("No constraints in the problem: PDLP can't be run, use Dual Simplex instead."); return optimization_problem_solution_t{pdlp_termination_status_t::NumericalError, - problem.handle_ptr->get_stream()}; + problem.handle_ptr->get_stream()}; } detail::pdlp_solver_t solver(problem, settings); return solver.run_solver(start_time); @@ -367,9 +367,9 @@ optimization_problem_solution_t run_pdlp(detail::problem_t& { auto start_solver = std::chrono::high_resolution_clock::now(); f_t start_time = dual_simplex::tic(); - auto sol = run_pdlp_solver(problem, settings, start_solver); - auto end = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::duration_cast(end - start_solver); + auto sol = run_pdlp_solver(problem, settings, start_solver); + auto end = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(end - start_solver); sol.set_solve_time(duration.count() / 1000.0); CUOPT_LOG_INFO("PDLP finished"); if (sol.get_termination_status() != pdlp_termination_status_t::ConcurrentLimit) { diff --git a/cpp/src/mip/problem/problem.cu b/cpp/src/mip/problem/problem.cu index 1b48ccda9..e036696de 100644 --- a/cpp/src/mip/problem/problem.cu +++ b/cpp/src/mip/problem/problem.cu @@ -53,9 +53,7 @@ template void problem_t::op_problem_cstr_body(const optimization_problem_t& problem_) { // Mark the problem as empty if the op_problem has an empty matrix. - if (problem_.get_constraint_matrix_values().is_empty()) { - empty = true; - } + if (problem_.get_constraint_matrix_values().is_empty()) { empty = true; } // Set variables bounds to default if not set and constraints bounds if user has set a row type set_bounds_if_not_set(*this);