Python 用延迟约束回调实现TSP
我正在尝试使用惰性约束回调来实现TSP。根据给出的答案和,我尝试使用链接中的代码,并能够添加回拨功能。现在,我正在努力解决Python 用延迟约束回调实现TSP,python,cplex,docplex,docplexcloud,Python,Cplex,Docplex,Docplexcloud,我正在尝试使用惰性约束回调来实现TSP。根据给出的答案和,我尝试使用链接中的代码,并能够添加回拨功能。现在,我正在努力解决添加惰性约束问题 这是我当前的代码:它是一个9节点的TSP import docplex.mp.model as cpx from cplex.callbacks import LazyConstraintCallback from docplex.mp.callbacks.cb_mixin import * class DOLazyCallback(Constraint
添加惰性约束问题
这是我当前的代码:它是一个9节点的TSP
import docplex.mp.model as cpx
from cplex.callbacks import LazyConstraintCallback
from docplex.mp.callbacks.cb_mixin import *
class DOLazyCallback(ConstraintCallbackMixin, LazyConstraintCallback):
def __init__(self, env):
LazyConstraintCallback.__init__(self, env)
ConstraintCallbackMixin.__init__(self)
self.nb_lazy_cts = 0
def add_lazy_constraints(self, cts):
self.register_constraints(cts)
@print_called('--> lazy constraint callback called: #{0}')
def __call__(self):
# fetch variable values into a solution
sol = self.make_solution()
# for each lazy constraint, check whether it is verified,
unsats = self.get_cpx_unsatisfied_cts(self.cts, sol, tolerance=1e-6)
for ct, cpx_lhs, sense, cpx_rhs in unsats:
self.add(cpx_lhs, sense, cpx_rhs)
self.nb_lazy_cts += 1
print(' -- new lazy constraint[{0}]: {1!s}'.format(self.nb_lazy_cts, ct))
DST = [[0, 0.238, 0.608, 0.5442, 0.6097, 1.2337, 0.5574, 0.8691, 1.3394],
[0.238, 0, 0.37, 0.6694, 0.6039, 0.9957, 0.6826, 0.8633, 1.23],
[0.608, 0.37, 0, 1.0394, 0.9739, 0.6257, 1.0526, 1.2333, 0.860],
[0.5442, 0.6694, 1.0394, 0, 0.0655, 0.903, 0.0132, 0.3249, 0.7952],
[0.6097, 0.6039, 0.9739, 0.0655, 0, 0.8375, 0.0787, 0.2594, 0.7297],
[1.2337, 0.9957, 0.6257, 0.903, 0.8375, 0, 0.9162, 0.7046, 0.2343],
[0.5574, 0.6826, 1.0526, 0.0132, 0.0787, 0.9162, 0, 0.3381, 0.8084],
[0.8691, 0.8633, 1.2333, 0.3249, 0.2594, 0.7046, 0.3381, 0, 0.4703],
[1.3394, 1.23, 0.860, 0.7952, 0.7297, 0.2343, 0.8084, 0.4703, 0]]
n = 9
set_n = range(9)
opt_model = cpx.Model(name="MIP Model")
x = {(i, j): opt_model.binary_var(name="x_{0}_{1}".format(i, j)) for i in set_n for j in set_n if not i == j}
objective = opt_model.sum(DST[i][j] * x[i, j] for i in set_n for j in set_n if not i == j)
# one incoming edge one outgoing edge
for i in set_n:
xp = opt_model.sum(x[j, i] for j in set_n if not i == j) - opt_model.sum(x[i, k] for k in set_n if not i == k)
opt_model.add_constraint(xp == 0)
for j in set_n:
opt_model.add_constraint(opt_model.sum(x[i, j] for i in set_n if not i == j) == 1)
lazyct_cb = opt_model.register_callback(DOLazyCallback)
lazyct_cb.add_lazy_constraints( ?? WHAT TO ADD HERE ?? )
opt_model.lazy_callback = lazyct_cb
url = "URLL"
api = "APII"
#opt_model.parameters.mip.tolerances.mipgap = 0
opt_model.minimize(objective)
print(opt_model.print_information())
solv = opt_model.solve(url=url, key=api)
print(solv.solve_status)
print(solv.solve_details)
我认为您不想事先调用add\u lazy\u约束。如果您这样做了,那么您可以直接将惰性约束添加到模型中
相反,您希望在回调中包含一些分离约束的代码。根据sol
中的值,您可以找到一个违反的subtour消除约束并将其添加。好的,因此在def\uu call\uuuu(self):
中,我需要以某种方式获取二进制变量x
的值,并检查是否有子路由,如果有,然后添加一个消除它的约束。我是否正确?在枚举(self.get_values())中为I,v使用以下代码:如果v>0:print(self.index_to_var(I),v)
insidedef\u调用(self):
我得到了x_0_1.0 x_1.0 x_2_0 1.0 x_3_4 1.0 x_4_6 1.0 x_5_7 1.0 x_6_3 1.0 x_7 1.0 x_8_5 1.0
我可以清楚地看到周期5-7-8-5
,0-1-2-0
,3-4-6-3,现在我如何消除这些周期。我是否需要一些算法来找到循环,获取它们的节点并添加约束。下一步在def\uu call\uuuuu(self)中:
我可以添加self.add\u lazy\u constraints()
,但是在它里面写什么,即如何访问变量x
正确,一旦你有了解向量,你就需要从中导出一个违反的约束。您可以查看CPLEX附带的opl/examples/opl/models/TravelingSalesmanProblem
,其中包含一个用于在opl中分离子任务的示例。一旦您找到了一个subtour,您就可以为这个subtour构造一个subtour消除约束,将它作为一个单例列表输入到get\u cpx\u unsatisfied\u cts
中,然后按照您已经引用的示例进行操作。我执行了这一行unsats=self.get\u cpx\u unsatisfied\u cts(self.cts,sol,tolerance=1e-6)
和unsats
是empy数组,因为我没有任何不满意的、有意义的惰性约束,但假设我知道节点5-7-8-5
之间有一个子巡更。我不知道如何在get\u cpx\u unsatisfied\u cts
中添加此约束,我的约束类似于x[5,7]+x[7,8]+x[8,5],我在这里创建了一个带有惰性约束的TSP示例: