Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions cpp/src/linear_programming/solve.cu
Original file line number Diff line number Diff line change
Expand Up @@ -346,16 +346,30 @@ optimization_problem_solution_t<i_t, f_t> run_dual_simplex(
std::get<4>(sol_dual_simplex));
}

template <typename i_t, typename f_t>
static optimization_problem_solution_t<i_t, f_t> run_pdlp_solver(
detail::problem_t<i_t, f_t>& problem,
pdlp_solver_settings_t<i_t, f_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<i_t, f_t>{pdlp_termination_status_t::NumericalError,
problem.handle_ptr->get_stream()};
}
detail::pdlp_solver_t<i_t, f_t> solver(problem, settings);
return solver.run_solver(start_time);
}

template <typename i_t, typename f_t>
optimization_problem_solution_t<i_t, f_t> run_pdlp(detail::problem_t<i_t, f_t>& problem,
pdlp_solver_settings_t<i_t, f_t> const& settings)
{
auto start_solver = std::chrono::high_resolution_clock::now();
f_t start_time = dual_simplex::tic();
detail::pdlp_solver_t<i_t, f_t> solver(problem, settings);
auto sol = solver.run_solver(start_solver); // Passing it for time limit
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(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<std::chrono::milliseconds>(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) {
Expand Down
18 changes: 1 addition & 17 deletions cpp/src/mip/problem/problem.cu
Original file line number Diff line number Diff line change
Expand Up @@ -53,23 +53,7 @@ template <typename i_t, typename f_t>
void problem_t<i_t, f_t>::op_problem_cstr_body(const optimization_problem_t<i_t, f_t>& problem_)
{
// Mark the problem as empty if the op_problem has an empty matrix.
if (problem_.get_constraint_matrix_values().is_empty()) {
cuopt_assert(problem_.get_constraint_matrix_indices().is_empty(),
"Problem is empty but constraint matrix indices are not empty.");
cuopt_assert(problem_.get_constraint_matrix_offsets().size() == 1,
"Problem is empty but constraint matrix offsets are not empty.");
cuopt_assert(problem_.get_objective_coefficients().is_empty(),
"Problem is empty but objective coefficients are not empty.");
cuopt_assert(problem_.get_variable_lower_bounds().is_empty(),
"Problem is empty but variable lower bounds are not empty.");
cuopt_assert(problem_.get_variable_upper_bounds().is_empty(),
"Problem is empty but variable upper bounds are not empty.");
cuopt_assert(problem_.get_constraint_lower_bounds().is_empty(),
"Problem is empty but constraint lower bounds are not empty.");
cuopt_assert(problem_.get_constraint_upper_bounds().is_empty(),
"Problem is empty but constraint upper bounds are not 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);
Expand Down
35 changes: 35 additions & 0 deletions cpp/tests/linear_programming/pdlp_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,41 @@ TEST(dual_simplex, afiro)
afiro_primal_objective, solution.get_additional_termination_information().primal_objective));
}

// Should return a numerical error
TEST(pdlp_class, run_empty_matrix_pdlp)
{
const raft::handle_t handle_{};

auto path = make_path_absolute("linear_programming/empty_matrix.mps");
cuopt::mps_parser::mps_data_model_t<int, double> op_problem =
cuopt::mps_parser::parse_mps<int, double>(path);

auto solver_settings = pdlp_solver_settings_t<int, double>{};
solver_settings.method = cuopt::linear_programming::method_t::PDLP;

optimization_problem_solution_t<int, double> 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<int, double> op_problem =
cuopt::mps_parser::parse_mps<int, double>(path);

auto solver_settings = pdlp_solver_settings_t<int, double>{};
solver_settings.method = cuopt::linear_programming::method_t::Concurrent;

optimization_problem_solution_t<int, double> 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()
11 changes: 11 additions & 0 deletions datasets/linear_programming/empty_matrix.mps
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
NAME
ROWS
N OBJ
COLUMNS
x1 OBJ -3
RHS
RANGES
BOUNDS
MI bounds x1
UP bounds x1 2
ENDATA