For SCIP and GLPK the following test pass since integer round leading to empty bound is correctly managed
We should try to improve xpress_solver to have the same behaviour...
|
TEST_P(SimpleMipTest, FractionalBoundsContainNoInteger) { |
|
if (GetParam().solver_type == SolverType::kGurobi) { |
|
// TODO(b/272298816): Gurobi bindings are broken here. |
|
GTEST_SKIP() << "TODO(b/272298816): Gurobi bindings are broken here."; |
|
} |
|
if (GetParam().solver_type == SolverType::kXpress) { |
|
// Xpress rounds bounds of integer variables on input, so the bounds |
|
// specified here result in [1,0]. Xpress also checks that bounds are |
|
// not contradicting, so it rejects creation of such a variable. |
|
GTEST_SKIP() << "Xpress does not support contradictory bounds."; |
|
} |
|
Model model; |
|
const Variable x = model.AddIntegerVariable(0.5, 0.6, "x"); |
|
model.Maximize(x); |
|
EXPECT_THAT(Solve(model, GetParam().solver_type), |
|
IsOkAndHolds(TerminatesWith(TerminationReason::kInfeasible))); |
|
} |
ref: GLPK implem...
|
std::optional<SolveResultProto> GlpkSolver::EmptyIntegerBoundsResult() { |
|
const int num_cols = glp_get_num_cols(problem_); |
|
for (int c = 1; c <= num_cols; ++c) { |
|
if (!variables_.IsInteger(problem_, c)) { |
|
continue; |
|
} |
|
const double lb = variables_.unrounded_lower_bounds[c - 1]; |
|
const double ub = variables_.unrounded_upper_bounds[c - 1]; |
|
if (lb > ub) { |
|
// Unrounded bounds are inverted; this case is covered by |
|
// ListInvertedBounds(). We don't want to depend on the order of calls of |
|
// the two functions here so we exclude this case. |
|
continue; |
|
} |
|
if (std::ceil(lb) <= std::floor(ub)) { |
|
continue; |
|
} |
|
|
|
// We found a variable with empty integer bounds (that is lb <= ub but |
|
// ceil(lb) > floor(ub)). |
|
return ResultForIntegerInfeasible( |
|
/*is_maximize=*/glp_get_obj_dir(problem_) == GLP_MAX, |
|
/*bad_variable_id=*/variables_.ids[c - 1], |
|
/*lb=*/lb, /*ub=*/ub); |
|
} |
|
|
|
return std::nullopt; |
|
} |
|
// Deal with empty integer bounds that result in inverted bounds due to bounds |
|
// rounding. |
|
{ // Limit scope of `result`. |
|
std::optional<SolveResultProto> result = EmptyIntegerBoundsResult(); |
|
if (result.has_value()) { |
|
RETURN_IF_ERROR(set_solve_time(result.value())); |
|
return std::move(result).value(); |
|
} |
|
} |
For SCIP and GLPK the following test pass since integer round leading to empty bound is correctly managed
We should try to improve xpress_solver to have the same behaviour...
or-tools/ortools/math_opt/solver_tests/mip_tests.cc
Lines 141 to 157 in 4336f9f
ref: GLPK implem...
or-tools/ortools/math_opt/solvers/glpk_solver.cc
Lines 1782 to 1809 in 4336f9f
or-tools/ortools/math_opt/solvers/glpk_solver.cc
Lines 1090 to 1098 in 4336f9f