diff --git a/cpp/src/linear_programming/solve.cu b/cpp/src/linear_programming/solve.cu index df3d3d1e1..c06985997 100644 --- a/cpp/src/linear_programming/solve.cu +++ b/cpp/src/linear_programming/solve.cu @@ -467,7 +467,7 @@ void run_dual_simplex_thread( template optimization_problem_solution_t run_concurrent( - optimization_problem_t& op_problem, + const optimization_problem_t& op_problem, detail::problem_t& problem, pdlp_solver_settings_t const& settings, bool is_batch_mode) @@ -540,7 +540,7 @@ optimization_problem_solution_t run_concurrent( template optimization_problem_solution_t solve_lp_with_method( - optimization_problem_t& op_problem, + const optimization_problem_t& op_problem, detail::problem_t& problem, pdlp_solver_settings_t const& settings, bool is_batch_mode) @@ -714,6 +714,12 @@ optimization_problem_solution_t solve_lp( bool problem_checking, \ bool use_pdlp_solver_mode); \ \ + template optimization_problem_solution_t solve_lp_with_method( \ + const optimization_problem_t& op_problem, \ + detail::problem_t& problem, \ + pdlp_solver_settings_t const& settings, \ + bool is_batch_mode = false); \ + \ template optimization_problem_t mps_data_model_to_optimization_problem( \ raft::handle_t const* handle_ptr, \ const cuopt::mps_parser::mps_data_model_t& data_model); diff --git a/cpp/src/linear_programming/solve.cuh b/cpp/src/linear_programming/solve.cuh index bd7eee8df..3024d6774 100644 --- a/cpp/src/linear_programming/solve.cuh +++ b/cpp/src/linear_programming/solve.cuh @@ -30,4 +30,11 @@ cuopt::linear_programming::optimization_problem_t mps_data_model_to_op raft::handle_t const* handle_ptr, const cuopt::mps_parser::mps_data_model_t& data_model); +template +cuopt::linear_programming::optimization_problem_solution_t solve_lp_with_method( + const optimization_problem_t& op_problem, + detail::problem_t& problem, + pdlp_solver_settings_t const& settings, + bool is_batch_mode = false); + } // namespace cuopt::linear_programming diff --git a/cpp/src/mip/solve.cu b/cpp/src/mip/solve.cu index dcfcdd0b1..841770c4d 100644 --- a/cpp/src/mip/solve.cu +++ b/cpp/src/mip/solve.cu @@ -125,10 +125,12 @@ mip_solution_t run_mip(detail::problem_t& problem, running_mip); cuopt_func_call(auto saved_problem = scaled_problem); - if (settings.mip_scaling) { scaling.scale_problem(); } - if (settings.initial_solutions.size() > 0) { - for (const auto& initial_solution : settings.initial_solutions) { - scaling.scale_primal(*initial_solution); + if (settings.mip_scaling) { + scaling.scale_problem(); + if (settings.initial_solutions.size() > 0) { + for (const auto& initial_solution : settings.initial_solutions) { + scaling.scale_primal(*initial_solution); + } } } // only call preprocess on scaled problem, so we can compute feasibility on the original problem diff --git a/cpp/src/mip/solver.cu b/cpp/src/mip/solver.cu index a60aa77b5..0f2117991 100644 --- a/cpp/src/mip/solver.cu +++ b/cpp/src/mip/solver.cu @@ -23,6 +23,9 @@ #include "local_search/rounding/simple_rounding.cuh" #include "solver.cuh" +#include +#include + #include #include #include @@ -124,6 +127,27 @@ solution_t mip_solver_t::run_solver() return sol; } + // if the problem was reduced to a LP: run concurrent LP + if (context.problem_ptr->n_integer_vars == 0) { + CUOPT_LOG_INFO("Problem reduced to a LP, running concurrent LP"); + pdlp_solver_settings_t settings{}; + settings.time_limit = timer_.remaining_time(); + settings.method = method_t::Concurrent; + + auto opt_sol = solve_lp_with_method( + *context.problem_ptr->original_problem_ptr, *context.problem_ptr, settings); + + solution_t sol(*context.problem_ptr); + sol.copy_new_assignment(host_copy(opt_sol.get_primal_solution())); + if (opt_sol.get_termination_status() == pdlp_termination_status_t::Optimal || + opt_sol.get_termination_status() == pdlp_termination_status_t::PrimalInfeasible || + opt_sol.get_termination_status() == pdlp_termination_status_t::DualInfeasible) { + sol.set_problem_fully_reduced(); + } + context.problem_ptr->post_process_solution(sol); + return sol; + } + namespace dual_simplex = cuopt::linear_programming::dual_simplex; std::future branch_and_bound_status_future; dual_simplex::user_problem_t branch_and_bound_problem; diff --git a/cpp/tests/mip/empty_fixed_problems_test.cu b/cpp/tests/mip/empty_fixed_problems_test.cu index 06ad24df2..30d1ecf1d 100644 --- a/cpp/tests/mip/empty_fixed_problems_test.cu +++ b/cpp/tests/mip/empty_fixed_problems_test.cu @@ -78,4 +78,11 @@ TEST(mip_solve, empty_max_problem_with_objective_test) EXPECT_NEAR(obj_val, 11, 1e-5); } +TEST(mip_solve, mip_presolved_to_lp) +{ + auto [termination_status, obj_val, lb] = test_mps_file("mip/mip-presolved-to-lp.mps", 5, false); + EXPECT_EQ(termination_status, mip_termination_status_t::Optimal); + EXPECT_NEAR(obj_val, 0, 1e-5); +} + } // namespace cuopt::linear_programming::test diff --git a/datasets/mip/mip-presolved-to-lp.mps b/datasets/mip/mip-presolved-to-lp.mps new file mode 100644 index 000000000..755bcc328 --- /dev/null +++ b/datasets/mip/mip-presolved-to-lp.mps @@ -0,0 +1,32 @@ +NAME LP_PROBLEM +ROWS + N OBJ + E R001 + E R002 + E R003 + L R004 + L R005 + L R006 + L R007 +COLUMNS + X001 OBJ 1.000000 + X001 R004 -1.000000 + X001 R006 -1.000000 + X002 OBJ 1.000000 + X002 R005 -1.000000 + X002 R007 -1.000000 + X003 R001 1.000000 + X003 R004 1.000000 + X003 R006 -1.000000 + X004 R002 1.000000 + X004 R005 1.000000 + X004 R007 -1.000000 + X005 R001 -1.000000 + X005 R002 -1.000000 + X005 R003 1.000000 +RHS +BOUNDS + LO BND1 X005 0.000000 + UP BND1 X005 1.000000 + BV BND1 X005 +ENDATA