Hello,
I was wondering if it was possible to obtain the value of the MIP Gap at each step of the optimization process.
Thank you in advance,
KR
Hello,
I was wondering if it was possible to obtain the value of the MIP Gap at each step of the optimization process.
Thank you in advance,
KR
In general, no. Although some solvers (e.g., Gurobi or CPLEX) offer callbacks that you can access this information.
For example, here is an example setting a Gurobi-specific callback:
https://github.com/jump-dev/Gurobi.jl/blob/183a1c5916ff6253193e7242eba48a172ea7365f/test/MOI/MOI_callbacks.jl#L315-L344
Implementing this will require you to understand Gurobi’s C API for callbacks.
Another option is to parse the text output log of the solver and extract the gap-overtime information from there. This is also a solver-specific solution.
Using CPLEX 12.9, I do this within solver-specific callbacks via function CPXcallbackgetinfodbl
. For convenience define:
const CPXCALLBACKINFO_THREADID = convert(Cint,0)
const CPXCALLBACKINFO_NODECOUNT = convert(Cint,1)
const CPXCALLBACKINFO_ITCOUNT = convert(Cint,2)
const CPXCALLBACKINFO_BEST_SOL = convert(Cint,3)
const CPXCALLBACKINFO_BEST_BND = convert(Cint,4)
const CPXCALLBACKINFO_THREADS = convert(Cint,5)
const CPXCALLBACKINFO_FEASIBLE = convert(Cint,6)
const CPXCALLBACKINFO_TIME = convert(Cint,7)
const CPXCALLBACKINFO_DETTIME = convert(Cint,8)
and functions:
#current current best bound
function cpx_get_best_bnd( cb_data::CPLEX.CallbackContext )
data_p = Ref{Cdouble}()
return_status = CPLEX.@cpx_ccall(callbackgetinfodbl,
Cint,
(Ptr{Cvoid}, Cint, Ref{Cdouble}),
cb_data.context, CPXCALLBACKINFO_BEST_BND, data_p)
best_bnd = data_p[]
if return_status != 0
@warn "error retrieving best_bound"
end
return best_bnd::Float64
end
#current current best sol
function cpx_get_best_sol( cb_data::CPLEX.CallbackContext )
data_p = Ref{Cdouble}()
return_status = CPLEX.@cpx_ccall(callbackgetinfodbl,
Cint,
(Ptr{Cvoid}, Cint, Ref{Cdouble}),
cb_data.context, CPXCALLBACKINFO_BEST_SOL, data_p)
best_sol = data_p[]
if return_status != 0
@warn "error retrieving best_sol"
end
return best_sol::Float64
end
and then compute the current gap according to the CPLEX documentation as:
#compute current mip gap [%]
function cpx_get_mip_gap( cb_data::CPLEX.CallbackContext )
mip_gap::Float64 = 0.0
best_bnd = cpx_get_best_bnd( cb_data )
best_sol = cpx_get_best_sol( cb_data )
mip_gap = ((best_bnd - best_sol) / (0.0000000001 + best_sol)) * 100
return mip_gap::Float64
end
Then simply call, e.g., mygap = cpx_get_mip_gap( cb_data )
within a callback.
Thank you very much for your answers.
I am currently using Xpress. I see here Callbacks · JuMP that callbacks are possible for CPLEX, GUROBI and GLPK. Are you aware if callbacks are possible for Xpress?
Thank you very much!