Search code examples
pyomogurobi

Pyomo and Gurobi: Does Pyomo support solver callbacks to Gurobi?


I have started using Pyomo for modelling of MILPs and need to add problem specific cutting planes at certain MILP-feasible solutions. I know that it is possible to do that via callbacks in Gurobi's own gurobipy API. However, since I am using Pyomo atm I would like to stick to it if possible. I have seen that there exist persistent/direct solver IO options, however, I could not figure out how to make use of those options for my purposes.

Any help is appreciated.


Solution

  • Callbacks and lazy constraints are currently supported by Pyomo for the Gurobi Persistent solver interface. Here is a small example from the documentation of that interface:

    from gurobipy import GRB
    import pyomo.environ as pe
    from pyomo.core.expr.taylor_series import taylor_series_expansion
    
    m = pe.ConcreteModel()
    m.x = pe.Var(bounds = (0, 4))
    m.y = pe.Var(within = pe.Integers, bounds = (0, None))
    m.obj = pe.Objective(expr = 2 * m.x + m.y)
    m.cons = pe.ConstraintList()  # for the cutting planes
    
    
    def _add_cut(xval):
        # a function to generate the cut
        m.x.value = xval
        return m.cons.add(m.y >= taylor_series_expansion((m.x - 2) ** 2))
    
    
    _add_cut(0)  # start with 2 cuts at the bounds of x
    _add_cut(4)  # this is an arbitrary choice
    
    opt = pe.SolverFactory('gurobi_persistent')
    opt.set_instance(m)
    opt.set_gurobi_param('PreCrush', 1)
    opt.set_gurobi_param('LazyConstraints', 1)
    
    
    def my_callback(cb_m, cb_opt, cb_where):
        if cb_where == GRB.Callback.MIPSOL:
            cb_opt.cbGetSolution(vars = [m.x, m.y])
            if m.y.value < (m.x.value - 2) ** 2 - 1e-6:
                print('adding cut')
                cb_opt.cbLazy(_add_cut(m.x.value))
    
    
    opt.set_callback(my_callback)
    opt.solve()
    assert abs(m.x.value - 1) <= 1e-6
    assert abs(m.y.value - 1) <= 1e-6
    
    Changed value of parameter PreCrush to 1
       Prev: 0  Min: 0  Max: 1  Default: 0
    Changed value of parameter LazyConstraints to 1
       Prev: 0  Min: 0  Max: 1  Default: 0
    adding cut
    adding cut
    adding cut
    adding cut
    adding cut
    adding cut
    adding cut
    adding cut
    

    For further details on the methods available within this Pyomo callback interface, see the GurobiPersistent class.