Hi all,
As the core developers of JuMP already know, I have become a fan of JuMP at the beginning of this year. I am very grateful for their work and introducing me to JuMP. I have an issue now with writing a callback function and I believe that JuMP is very well capable of handling it. I just do not know how to do it in a neat way.
There are many stopping criteria for solvers, such as the relative or absolute gap between the upper and lower bound, that can be set with standard parameters. In Gurobi examples of these parameters are
MIPGap and
MIPGapAbs. I want a different criterion. Namely, I want to stop solving my minimization problem when the current solution drops below a certain absolute value or when the lower bound exceeds a certain absolute value.
Surprisingly, and to the best of my knowledge, there is no parameter in the most popular solvers (Gurobi, Cplex) to set my absolute bound stopping criteria. These stopping criteria are for instance useful when you are satisfied with any solution that has an objective value smaller than zero. Also, once the lower bound is larger than zero I know that there do not exist such solutions and I can just as well stop the solver process. This feature is also asked for in many other languages (a small sample: google groups:
[1],
[2],
[3],
[4],
[5], Cplex FAQ:
[6]). For AMPL they suggest (for the upper bound) to set the
CutOff parameter to
0 and the
SolutionLimit to
1, or to turn the problem into a feasibility problem. Both of these approaches have serious disadvantages.
Fortunately JuMP has some support for callbacks! In pseudo code, the callback should do the following:
Callback for Absolute Stopping criterion (treshold 0):
- Query objective value (objval), lower bound (LB) and current solution.
- If objval < 0 or LB > 0, then return the values above and gently stop the solver process.
When I tried to implement this callback in JuMP I ran into a few difficulties, namely:
- In the JuMP callback documentation it is advised to use throw(CallbackAbort()) to exit the optimization process earlier than a solver would. I want the solver process to be stopped in a "gentle" way. With "gentle" I mean that the solver stops the same way as it would stop with a parameter setting, so not by throwing an error.
- cbgetobj(cb) is not callable in the state :MIPSol and cbgetmipsolution(cb) is not callable in state :MIPInfo.
I came up with the following haphazard implementation. It does work, but any comments or suggestions to implement this in a better/more neat way are highly appreciated.
# Above here a model 'm' with (mixed) integer variables x have been defined and objective function 'dot(c,x)'.
type solutionInfoType
obj
bestbound
solution
end
solutiondata = solutionInfoType(Inf,-Inf,NaN)
function AbsoluteStoppingCriterion(cb)
currentsol = getValue(x)
currentobj = dot(c,currentsol) #MathProgBase.cbgetobj(cb) does not work in state MIPSol.
currentbestbound = MathProgBase.cbgetbestbound(cb)
# If current best integer solution drops below 0 or lower bound
# exceeds 0, then stop.
if currentobj <= 0 || currentbestbound >= 0
solutiondata = solutionInfoType(currentobj,currentbestbound,currentsol)
# Make the problem obviously infeasible so that the optimization process is "gently" exited
# Non gentle alternative: throw(CallbackAbort())
@addLazyConstraint(cb, x[1] >= 1)
@addLazyConstraint(cb, x[1] <= 0)
end
end
addLazyCallback(m, AbsoluteStoppingCriterion)