coin-or / python-mip

Python-MIP: collection of Python tools for the modeling and solution of Mixed-Integer Linear programs
Eclipse Public License 2.0
513 stars 88 forks source link

FIX: unbounded/infeasible status mismatch for CBC relaxed models #342

Open modosist opened 1 year ago

modosist commented 1 year ago

Hi, thanks for the awesome work on the library! I believe that I found a small bug in handling of result from CBC relaxed models.

Current version of python-mip (tested version 1.15.0 on Apple M1) does not work correctly for the relaxations of following ILPs

import mip
m = mip.Model(solver_name="CBC")
x = m.add_var(var_type=mip.INTEGER)
m += x >= 1
m += x <= -1
m.objective = mip.maximize(x)
print(m.optimize(relax=True))
# returns OptimizationStatus.UNBOUNDED, although program is infeasible
import mip
m = mip.Model(solver_name="CBC")
x = m.add_var(var_type=mip.INTEGER)
m.objective = mip.maximize(x)
print(m.optimize(relax=True))
# returns OptimizationStatus.INFEASIBLE, although program is unbounded

Comparing the python-mip CBC solver

https://github.com/coin-or/python-mip/blob/6044fc8f0414d71430e94b8a08573b695dc35b5a/mip/cbc.py#L1110-L1113

and actual CBC code for Cbc_solveLinearProgram

https://github.com/coin-or/Cbc/blob/f3a8af7b627ac068853d847c67d05614dcd99d39/src/Attic/Cbc_C_Interface.cpp#L1753-L1761

I concluded that the status codes for infeasible and unbounded programs are swapped in the python-mip code. Moreover, looking at CBC code, I believe that status 3 from Cbc_solveLinearProgram should be interpreted as primal formulation is either unbounded or infeasible (as dual infeasibility may lead primal to be either unbounded or infeasible); however, I could not find documentation for CBC on these status codes so I cannot be certain what the CBC developers meant by this status code. Therefore, I added a followup check for this status code to see whether the primal formulation is infeasible or unbounded.

I never worked with CBC before so hopefully I did not miss some detail.

CLAassistant commented 1 year ago

CLA assistant check
All committers have signed the CLA.

sebheger commented 1 year ago

@modosist Thanks for fixing this bug. Would you please add the tests you posted to the code base?

modosist commented 1 year ago

@modosist Thanks for fixing this bug. Would you please add the tests you posted to the code base?

Sure, I will prepare some tests! Hopefully I will get to it within a week.

BTW: I found out that similar issue is also within Gurobi wrapper (although it is not related to relaxed models)

https://github.com/coin-or/python-mip/blob/6044fc8f0414d71430e94b8a08573b695dc35b5a/mip/gurobi.py#L777-L778

However, this one probably needs more discussion: should python-mip also return UNBOUNDED_OR_INFEASIBLE status or should python-mip check which of the outcomes actually holds? I do not know whether Gurobi has similar API to asking for primal formulation infeasibility, but their recommendation is to re-run the optimization with setting of specific parameter see here. Should I open an issue for this?

rschwarz commented 1 year ago

BTW: I found out that similar issue is also within Gurobi wrapper

Yes, and something related happens with the (WIP) HiGHS wrapper as well. The status codes from the solver and the mip library don't map one-to-one, see https://github.com/coin-or/python-mip/blob/9082252dfc5cebfacc9dd170049c45ab7441660d/mip/highs.py#L1005-L1008

sebheger commented 1 year ago

Might be closely related to this here https://github.com/coin-or/python-mip/issues/285

modosist commented 1 year ago

I added a few tests for the relaxed models. The tests will fail on Gurobi (and looking at code from @rschwarz , HiGHS should fail as well). I will address the remaining solvers in another issue.