• Gurobi Staff

Hi Lukas,

An easier approach might be to use the SolutionLimit parameter as a termination criterion. By setting the SolutionLimit parameter to 1, the optimization would terminate as soon as one feasible solution is found.

To answer your question about the callback, the error occurs because the self.cb is not a function. It is an instance method of an object. There is a difference between methods and functions in Python. A method is invoked by an object and it cannot exist without an object calling to it. However, a function is independent and is invoked by its name.

There are two options to fix this:

• The first option is to make the self.cb method a static method as shown below:
class Method:    @staticmethod    def cb(model, where):         if where == GRB.Callback.MIPSOL:             model._ub = model.cbGet(GRB.Callback.MIPSOL_OBJ)            model.terminate()
• The second option is to define the callback as a function outside the class and pass it as an argument to the method calling the optimize() method.

To pass data to the callback function, you should do it through the Model object. You should define the statement model._ub = float("inf") before the optimization begins, then your callback function can query the value of model._ub. Note that the name of the user data field must begin with an underscore.

You might find the snippet below useful as a minimum working example of what you are interested in.

import gurobipyfrom gurobipy import GRBclass Model:    def__init__(self):        self.model = gurobipy.read("examples/data/glass4.mps")        # Initialize the upper bound        self.model._ub = float("inf")    @staticmethod    def cb(model, where):        if where == GRB.Callback.MIPSOL:            model._ub = model.cbGet(GRB.Callback.MIPSOL_OBJ)            model.terminate()    def get_first_solution(self):        self.model.optimize(Model.cb)        print(f"ub: {self.model._ub}")if __name__ == "__main__":    model = Model()    model.get_first_solution()

Best regards,

Maliheh

Hi Maliheh,

thank you for the fast answer, the solution approach with the SolutionLimit set to 1 is perfectly feasible for my use case. Also thank you for explaining the problems with callbacks!

Best,

Lukas

Is the following way of using the nested function a reasonable way to do this? I have a lot of instance attributes that I need to pass to the callback.
I am curious if there is any latency that might arise if callback accesses instance data (e.g., large data matrix) from a nested function.

import gurobipyfrom gurobipy import GRBclass Model:    def __init__(self):        self.model = gurobipy.read("examples/data/glass4.mps")        # Initialize the upper bound        # self.model._ub = float("inf")        self.ub=float("inf)    def get_first_solution(self):        def cb(model, where):            if where == GRB.Callback.MIPSOL:                self.ub = model.cbGet(GRB.Callback.MIPSOL_OBJ) # note the use of self here                model.terminate()        self.model.optimize(cb)        print(f"ub: {self.ub}")