1. callback函数的定义
所谓callback函数,即应用以参数的形式传入API的函数。cplex的callback分为3种:
- Informational callbacks:不干涉优化过程,仅获取信息。
- Query callbacks(也叫diagnostic callbacks):与优化过程相互交涉的获取信息过程。
- Control callbacks:会改变优化过程的函数。
下面是
2. MIP control callback案例分析
本文案例是一个location问题,有4个备选仓库,9个客户,x1x_1x1~x4x_4x4表示是否选择这4个仓库,启用仓库有启动成本。yijy_{ij}yij表示仓库与客户之间的距离,运输有成本。每个客户只能从一个仓库供货;每个仓库的库存量有限。
数学模型如下:
# Given a set of locations J and a set of clients C
# Minimize
# sum(j in J) fixedCost[j]*used[j] + sum(j in J)sum(c in C)cost[c][j]*supply[c][j]
# Subject to
# sum(j in J) supply[c][j] == 1 for all c in C
# sum(c in C) supply[c][j] <= Capacity[j]* used[j] for all j in J
# supply[c][j] <= used[j] for all c in C, j in J
# supply[c][j] in { 0, 1 } for all c in C, j in J
# used[j] in { 0, 1 } for all j in J
3. 自定义UserCutCallback
我们可以在主问题中不添加第3条约束,而把它作为UserCutCallback。代码如下:
import sys
from cplex.callbacks import UserCutCallback
from docplex.mp.callbacks.cb_mixin import *
from docplex.mp.model import Model
class MyCutCallback(ConstraintCallbackMixin, UserCutCallback):
# Callback constructor. Model object is set after registration.
def __init__(self, env):
UserCutCallback.__init__(self, env)
ConstraintCallbackMixin.__init__(self)
self.eps = 1e-6
self.nb_cuts = 0
def add_cut_constraint(self, ct):
self.register_constraint(ct)
@print_called("--> custom cut callback called: #{0}")
def __call__(self):
# fetch variable solution values at this point.
sol = self.make_solution()
# fetch those constraints which are not satisfied.
unsats = self.get_cpx_unsatisfied_cts(self.cts, sol, self.eps)
for ct, cut, sense, rhs in unsats:
# Method add() here is CPLEX's CutCallback.add()
self.add(cut, sense, rhs)
self.nb_cuts += 1
print('-- add new cut[{0}]: [{1!s}]'.format(self.nb_cuts, ct))
在主代码中如下:
cut_cb = m.register_callback(MyCutCallback)
for l in range_locations:
location_used = used[l]
for c in range_clients:
cut_cb.add_cut_constraint(supply[c, l] <= location_used)
print('* add cut constraints callback with {0} cuts'.format(len(cut_cb.cts)))
m.cut_callback = cut_cb