I have to try to move from the non-class-based coding style into class-based coding style, but facing an issue. The optimize() function takes a callback function mycallback(). The code works perfectly fine in Non-class-based method, but when I moved it to class-based method, I got an error "mycallback() takes exactly 3 arguments (1 given)".
What is the right way to pass a callback function in the class-based method?
(A) Non-class-based method:
def mycallback(model, where):
pass
model = Model()
model.optimize(mycallback)
(B) Class-based method:
class A:
def __init__(self):
self.model = Model()
def solve(self):
# Try method 1:
self.model.optimize(self.mycallback()) <--- Error: mycallback() takes exactly 3 arguments (1 given)
# Try method 2:
# self.model.optimize(self.mycallback) <--- Error: Callback argument must be a function
def mycallback(self, model, where):
pass
While this is a problem regarding passing a callback function to Gurobi's (an optimization solver) built-in function, I believe it is a more general question on how to pass a callback function defined in a class to another function in Python.
Error For method 2:
self.model.optimize(self.mycallback)
File "model.pxi", line 458, in gurobipy.Model.optimize (../../src/python/gurobipy.c:34263)
gurobipy.GurobiError: Callback argument must be a function
Looks like it is likely to be Gurobi API issue. Wonder if any Gurobi dev will response.
First define two functions, the callback and the calling code, then pass the callback function into the calling code. The callback function has access to the variables and parameters of the calling function.
A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action. The above example is a synchronous callback, as it is executed immediately.
__call__ in Python The __call__ method enables Python programmers to write classes where the instances behave like functions and can be called like a function. When the instance is called as a function; if this method is defined, x(arg1, arg2, ...) is a shorthand for x.
The callback function looks like this: It accepts a value v, the current value of the series. It returns True and the value it found once it finds a value that can be evenly divided by 17. It returns True and None if it reaches the safety limit we set.
In general, self.model.optimize(self.mycallback)
should work (note: no parens after mycallback
).
It may fail if the code serializes the callable e.g., to be send via pipe/socket to another process (even on different machine):
from multiprocessing import Pool
class C:
def method(self, i):
return "called", i
if __name__=="__main__":
print(Pool().map(C().method, range(10)))
It works on recent Python versions where methods are pickable.
Or it may fail if model.optimize()
has a bug and check for the exact function type instead of accepting any callable.
This issue still persists in gurobi 9.1
. A simple workaround I found is to put the callback inside a method in your class, for instance:
def solve(self):
self.model.update()
def lazyCallback(model, where):
...
self.model.optimize(lazyCallback)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With