Callback
In optimization, a callback is a function that is called during the optimization process to provide additional information or to perform additional tasks. Callback functions can be used for a variety of purposes, such as monitoring the optimization progress, adding additional constraints, or performing post-processing on the solution after the optimization has completed. By providing additional information or performing additional tasks, callback functions can help improve the quality of the solutions and make the optimization process more efficient. In particular, callback functions can be useful in solving large-scale optimization problems, where it may not be feasible to solve the entire problem at once or when the optimization algorithm is sensitive to the initial starting point or the problem structure. Overall, callbacks provide a way to customize the optimization process and obtain more information about the solutions.
Why Callback?
A callback is a function that is called during the optimization process to provide additional information or to perform additional tasks. Callback functions can be used for a variety of purposes, such as:
- Monitoring the optimization progress: Callback functions can be used to print out the current status of the optimization, such as the current objective function value, the values of the decision variables, and the current iteration number.
- Adding additional constraints: Callback functions can be used to add additional constraints to the optimization model as new solutions are found. This can be useful in solving mixed-integer optimization problems, where it may be difficult to formulate all the constraints upfront.
- Performing post-processing: Callback functions can be used to perform post-processing on the solution after the optimization has completed, such as computing additional statistics or generating plots.
Callback functions are important because they allow us to customize the optimization process and obtain more information about the solutions. By providing additional information or performing additional tasks, callback functions can help improve the quality of the solutions and make the optimization process more efficient. In particular, callback functions can be useful in solving large-scale optimization problems, where it may not be feasible to solve the entire problem at once, or when the optimization algorithm is sensitive to the initial starting point or the problem structure.
Callback code
Here's an example of a Python code that defines a Gurobi optimization model and uses a callback function to process intermediate solutions:
import gurobipy as gp
# Define a callback function to process intermediate solutions
def mycallback(model, where):
if where == gp.GRB.Callback.MIP:
# Access the best solution found so far
objbst = model.cbGet(gp.GRB.Callback.MIP_OBJBST)
# Access the solution gap
objbnd = model.cbGet(gp.GRB.Callback.MIP_OBJBND)
gap = abs(objbst - objbnd) / (1.0 + abs(objbst))
# Print the current solution status
print(f"Current solution status: {model.Status}, Best objective value: {objbst}, Solution gap: {gap}")
# Create a Gurobi model
m = gp.Model()
# Define decision variables
x = m.addVar(lb=0, ub=10, vtype=gp.GRB.CONTINUOUS, name="x")
y = m.addVar(lb=0, ub=10, vtype=gp.GRB.CONTINUOUS, name="y")
# Define the objective function
m.setObjective(3 * x + 4 * y, sense=gp.GRB.MAXIMIZE)
# Add constraints
m.addConstr(2 * x + y <= 10, name="c1")
m.addConstr(x + y <= 7, name="c2")
# Set up the callback function
m.Params.OutputFlag = 0
m.Params.LogToConsole = 0
m.Params.LazyConstraints = 1
m.optimize(mycallback)
# Print the optimal solution
print(f"Optimal solution: x={x.X}, y={y.X}, objective={m.ObjVal}")
The mycallback function is defined to process intermediate solutions. It is called every time a new integer feasible solution is found during the optimization process. The function accesses the best solution found so far and the solution gap, which is the difference between the best integer feasible solution and the lower bound on the objective value. It then prints the current solution status, best objective value, and solution gap.
The Gurobi model is created, and decision variables are defined. The objective function and constraints are added to the model. The LazyConstraints parameter is set to 1 to enable the use of lazy constraints in the optimization process.
The callback function is set up using the optimize method, which calls the function every time a new integer feasible solution is found. The OutputFlag and LogToConsole parameters are set to 0 to suppress output to the console.
What we can find?
The parameters that can be obtained by using a callback in optimization depend on the specific optimization solver and the type of callback being used. However, here are some commonly used parameters that can be obtained using callbacks in the Gurobi optimization solver:
- Best feasible solution found so far: This parameter represents the objective function value of the best feasible solution found so far in the optimization process.
- Best bound: This parameter represents the current best bound on the objective function value. It is an upper bound on the optimal objective function value.
- Gap: This parameter represents the relative gap between the best feasible solution found so far and the best bound. It is a measure of the optimality of the current solution.
- Current iteration: This parameter represents the current iteration number in the optimization process.
- Solution status: This parameter represents the status of the current solution, such as feasible, infeasible, or unbounded.
- Variable values: This parameter represents the current values of the decision variables in the optimization model.
- Dual values: This parameter represents the dual values associated with the constraints in the optimization model.
- Reduced costs: This parameter represents the reduced costs associated with the decision variables in the optimization model.
These parameters can be used to perform a variety of tasks, such as monitoring the optimization progress, adding additional constraints or variable bounds, or performing post-processing on the solution. The specific parameters that can be obtained and used in a callback function will depend on the specific optimization solver and the type of optimization problem being solved.
| Parameter | Option Code |
|---|---|
| Best feasible solution found so far | GRB.Callback.MIPSOL_OBJ |
| Best bound | GRB.Callback.MIPSOL_OBJBND |
| Gap | GRB.Callback.MIPSOL_GAP |
| Current iteration | GRB.Callback.MIPNODE_NODCNT |
| Solution status | GRB.Callback.MIPSOL_SOL |
| Variable values | GRB.Callback.MIPSOL_VAL |
| Dual values | GRB.Callback.MIPSOL_OBJBND with where parameter set to GRB.Callback.MIPSOL_OBJBST |
| Reduced costs | GRB.Callback.MIPSOL_RC |
Here's an example Python code for a Gurobi callback that uses some of the parameters listed in the table I provided earlier:
import gurobipy as gp
# Define a callback function
def my_callback(model, where):
if where == gp.GRB.Callback.MIP:
# Get the best feasible solution found so far
obj_val = model.cbGet(gp.GRB.Callback.MIPSOL_OBJ)
# Get the current best bound
obj_bound = model.cbGet(gp.GRB.Callback.MIPSOL_OBJBND)
# Get the gap between the best feasible solution found so far and the best bound
gap = model.cbGet(gp.GRB.Callback.MIPSOL_GAP)
# Get the current iteration number
iter_num = model.cbGet(gp.GRB.Callback.MIPNODE_NODCNT)
# Get the solution status
sol_status = model.cbGet(gp.GRB.Callback.MIPSOL_SOL)
# Print the obtained parameters
print(f"Objective value: {obj_val}, Best bound: {obj_bound}, Gap: {gap}, Iteration: {iter_num}, Status: {sol_status}")
# Create a Gurobi model
model = gp.Model()
# ... add variables and constraints to the model ...
# Set the callback function
model.setCallback(my_callback)
# Optimize the model
model.optimize()