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
8 changes: 7 additions & 1 deletion cpp/src/mip/presolve/gf2_presolve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@

namespace cuopt::linear_programming::detail {

template <typename i_t>
static inline i_t positive_modulo(i_t i, i_t n)
{
return (i % n + n) % n;
}

// this is kind-of a stopgap implementation (as in practice MIPLIB2017 only contains a couple of GF2
// problems and they're small) but cuDSS could be used for this since A is likely to be sparse and
// low-bandwidth (i think?) unlikely to occur in real-world problems however. doubt it'd be worth
Expand Down Expand Up @@ -178,7 +184,7 @@ papilo::PresolveStatus GF2Presolve<f_t>::execute(const papilo::Problem<f_t>& pro
gf2_constraints.emplace_back((size_t)cstr_idx,
std::move(constraint_bin_vars),
std::pair<size_t, f_t>{key_var_idx, key_var_coeff},
((size_t)rhs) % 2);
positive_modulo((int)rhs, 2));
continue;
not_valid:
continue;
Expand Down
3 changes: 3 additions & 0 deletions cpp/src/mip/presolve/third_party_presolve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ papilo::Problem<f_t> build_papilo_problem(const optimization_problem_t<i_t, f_t>
if (!h_var_lb.empty() && !h_var_ub.empty()) {
builder.setColLbAll(h_var_lb);
builder.setColUbAll(h_var_ub);
if (op_problem.get_variable_names().size() == h_var_lb.size()) {
builder.setColNameAll(op_problem.get_variable_names());
}
}

for (size_t i = 0; i < h_var_types.size(); ++i) {
Expand Down
12 changes: 12 additions & 0 deletions cpp/tests/mip/termination_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,18 @@ TEST(termination_status, crossing_bounds_infeasible)
EXPECT_EQ(termination_status, mip_termination_status_t::Infeasible);
}

TEST(termination_status, gf2_presolve_optimal)
{
auto [termination_status, obj_val, lb] = test_mps_file("mip/enlight_hard.mps", 0.5, true);
EXPECT_EQ(termination_status, mip_termination_status_t::Optimal);
}

TEST(termination_status, gf2_presolve_infeasible)
{
auto [termination_status, obj_val, lb] = test_mps_file("mip/enlight11.mps", 0.5, true);
EXPECT_EQ(termination_status, mip_termination_status_t::Infeasible);
}

TEST(termination_status, bb_infeasible_test)
{
// First, check that presolve doesn't reduce the problem to infeasibility
Expand Down
1 change: 1 addition & 0 deletions datasets/mip/download_miplib_test_dataset.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ INSTANCES=(
"neos5"
"swath1"
"enlight_hard"
"enlight11"
"supportcase22"
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ def test_time_limit_solver():
settings.set_optimality_tolerance(1e-12)
time_limit_seconds = 0.2
settings.set_parameter(CUOPT_TIME_LIMIT, time_limit_seconds)
# Solver mode isn't what's tested here.
# Set it to Stable2 as CI is more reliable with this mode
settings.set_parameter(CUOPT_PDLP_SOLVER_MODE, PDLPSolverMode.Stable2)
# Setting both to make sure the lowest one is picked
settings.set_parameter(CUOPT_ITERATION_LIMIT, 99999999)

Expand Down