JUMP - Get MIP Gap during optimization

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:

Implementing this will require you to understand Gurobi’s C API for callbacks.

1 Like

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.

1 Like

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.

2 Likes

Thank you very much for your answers.

I am currently using Xpress. I see here https://jump.dev/JuMP.jl/v0.21.1/callbacks/ that callbacks are possible for CPLEX, GUROBI and GLPK. Are you aware if callbacks are possible for Xpress?

Thank you very much!

Not yet: https://github.com/jump-dev/Xpress.jl/pull/85

1 Like