Callback¶
Attention
The behavior of callback function highly depends on the optimizer and the specific problem. Please refer to the official documentation of the optimizer for more details.
In most optimization problems, we build the model, set the parameters, and then call the optimizer to solve the problem. However, in some cases, we may want to monitor the optimization process and intervene in the optimization process. For example, we may want to stop the optimization process when a certain condition is met, or we may want to record the intermediate results of the optimization process. In these cases, we can use the callback function. The callback function is a user-defined function that is called by the optimizer at specific points during the optimization process. Callback is especially useful for mixed-integer programming problems, where we can control the branch and bound process in callback functions.
Callback is not supported for all optimizers. Currently, we only support callback for Gurobi and COPT optimizer. Because callback is tightly coupled with the optimizer, we choose not to implement a strictly unified API for callback. Instead, we try to unify the common parts of the callback API of Gurobi and COPT and aims to provide all callback features included in vendored Python bindings of Gurobi and COPT.
In PyOptInterface, the callback function is simply a Python function that takes two arguments:
model
: The instance of the optimization modelwhere
: The flag indicates the stage of optimization process when our callback function is invoked. For Gurobi, the value ofwhere
is CallbackCodes. For COPT, the value ofwhere
is called as callback contexts such asCOPT.CBCONTEXT_MIPNODE
andCOPT.CBCONTEXT_MIPRELAX
.
In the function body of the callback function, we can do the following four kinds of things:
Query the current information of the optimization process. For scalar information, we can use
model.cb_get_info
function to get the information, and its argument is the value ofwhat
in Gurobi and the value of callback information in COPT. For array information such as the MIP solution or relaxation, PyOptInterface provides special functions such asmodel.cb_get_solution
andmodel.cb_get_relaxation
.Add lazy constraint: Use
model.cb_add_lazy_constraint
just likemodel.add_linear_constraint
except for thename
argument.Add user cut: Use
model.cb_add_user_cut
just likemodel.add_linear_constraint
except for thename
argument.Set a heuristic solution: Use
model.set_solution
to set individual values of variables and usemodel.cb_submit_solution
to submit the solution to the optimizer immediately (model.cb_submit_solution
will be called automatically in the end of callback ifmodel.set_solution
is called).Terminate the optimizer: Use
model.cb_exit
.
Here is an example of a callback function that stops the optimization process when the objective value reaches a certain threshold:
import pyoptinterface as poi
from pyoptinterface import gurobi, copt
GRB = gurobi.GRB
COPT = copt.COPT
def cb_gurobi(model, where):
if where == GRB.Callback.MIPSOL:
obj = model.cb_get_info(GRB.Callback.MIPSOL_OBJ)
if obj < 10:
model.cb_exit()
def cb_copt(model, where):
if where == COPT.CBCONTEXT_MIPSOL:
obj = model.cb_get_info("MipCandObj")
if obj < 10:
model.cb_exit()
To use the callback function, we need to call model.set_callback(cb)
to pass the callback function to the optimizer. For COPT, model.set_callback
needs an additional argument where
to specify the context where the callback function is invoked. For Gurobi, the where
argument is not needed.
model_gurobi = gurobi.Model()
model_gurobi.set_callback(cb_gurobi)
model_copt = copt.Model()
model_copt.set_callback(cb_copt, COPT.CBCONTEXT_MIPSOL)
# callback can also be registered for multiple contexts
model_copt.set_callback(cb_copt, COPT.CBCONTEXT_MIPSOL + COPT.CBCONTEXT_MIPNODE)
In order to help users to migrate code using gurobipy and/or coptpy to PyOptInterface, we list a translation table as follows.
gurobipy |
PyOptInterface |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
coptpy |
PyOptInterface |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
For a detailed example to use callbacks in PyOptInterface, we provide a concrete callback example to solve the Traveling Salesman Problem (TSP) with callbacks in PyOptInterface, gurobipy and coptpy. The example is adapted from the official Gurobi example tsp.py.