Gurobi callback in JuMP for submitting heuristic solution

Dear All,

I am trying to implement the fix-and-dive heuristic for the traveling salesman problem in JuMP with Gurobi based on the Python+Gurobi code available here: https://github.com/Gurobi/pres-mipheur/blob/master/mipheurs.md#callback-for-fix-and-dive-heuristic. This heuristic works as follows: when a fractional solution contains some variables at 1, we fix those and solve the smaller submodel, whose solution is then submitted as a heuristic solution. For convenience, I am recording the Python+Gurobi code below:


# Callback for fix-and-dive heuristic
# -------------------------------------------

def fixcb(subcb=None):
    def inner(model, where):
        if where == GRB.Callback.MIPNODE:
            if model.cbGet(GRB.Callback.MIPNODE_STATUS) == GRB.OPTIMAL:
                # Try solving the fixed submodel
                fixed = model._fixed
                # Relaxed values near 1.0 get the lower bound set to 1.0
                for k,v in model.cbGetNodeRel(model._vars).items():
                    fixed._vars[k].LB = math.floor(v+0.01)
                # Set a cutoff for the fixed model, based on the current best solution
                if model.cbGet(GRB.Callback.MIPNODE_SOLCNT) > 0:
                    fixed.Params.Cutoff = model.cbGet(GRB.Callback.MIPNODE_OBJBST)
                fixed.optimize(tspcb(subcb)) # call subproblem callback
                if fixed.status == GRB.OPTIMAL:
                    fixedvals = fixed.getAttr('x', fixed._vars)
                    model.cbSetSolution(model._vars, fixedvals)
    return inner

# Create the fixed model
# ------------------------------

def tspmipwithfixed(n, dist):
    m = tspmip(n, dist) # main model
    m._fixed = tspmip(n, dist) # fixed model
    m._fixed.Params.OutputFlag = 0
    m._fixed._parent = m
    return m

The code requires to look at the existing fractional solution via cbGetNodeRel, and I am not sure how to do that in the Gurobi specific callback in https://github.com/jump-dev/Gurobi.jl#callbacks. I will appreciate any tips/suggestion how to do the same thing via Gurobi specific callback or solver independent callback in Julia.

Use callback_value in a solver-independent callback:

Call Gurobi.load_callback_variable_primal(cb_data, cb_where) in a solver-dependent callback:

The solver-specific callbacks use the C API, so you should look at those examples, not the Python ones.

Sounds good, thanks @odow !

1 Like