Hi,
I’m implementing a MIP cut generation algorithm on JuMP+Gurobi using MOI.LazyConstraintCallback
.
Theoretically, the algorithm is correct. However, running tests on a large batch of instances and cross-checking with another pure MIP, 1 out of the 500 instances yields a slightly wrong answer.
I’ve tested by hand and my check does detect the optimal integer point as infeasible, the constraint also cuts it off. But upon closer inspection, it appears that Gurobi accepts it as incumbent without giving me the opportunity to reject it. The call-back function is in fact not called at all.
A particularity(?) of this issue is that this incumbent is within 0.01% of the LB.
I’ve tried to produce a MWE to no avail, but I’d gladly share the source code in private if necessary.
A portion of the log :
Nodes | Current Node | Objective Bounds | Work
Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time
[...]
10624 940 cutoff 40 270.35700 270.32800 0.01% 17.7 20s
17174 989 270.32800 55 1 270.35700 270.32800 0.01% 15.5 25s
23761 1275 cutoff 41 270.35700 270.32800 0.01% 14.6 30s
30166 1346 270.32800 44 2 270.35700 270.32800 0.01% 14.0 35s
36625 1444 270.32800 31 7 270.35700 270.32800 0.01% 13.7 40s
43289 1411 270.32800 49 3 270.35700 270.32800 0.01% 13.4 45s
50075 1464 270.32800 36 2 270.35700 270.32800 0.01% 13.2 50s
*51325 2 38 270.3280000 270.32800 0.00% 13.1 50s
The optimal objective value should be 270.357.
Based on this @miles.lubin reply
Gurobi could ignore the lazy constraint if it’s satisfied within Gurobi’s tolerances.
from this thread, the program would’ve ended earlier if it were a tolerance issue.
Do you have any insights?
Many thanks!