我一直在尝试用cplex来解决最佳的运输问题。问题模型通常非常大(在我的描述中,变量的总数是1048576(= 1024 ^ 2),并且约束的数量是2048)。我的问题是添加约束的过程太慢而不实用(虽然解决模型的时间很长)。我搜索了这个问题,有一些提示,但我仍然无法找到可行的解决方案。
问题如下:给定两个相同长度1024的非负向量 a 和 b ,以及1024×1024非负矩阵 C < / strong>即可。假设 a 的所有元素的总和与 b (np.sum(a)== np.sum(b))的总和相同。我想找到1024×1024非负矩阵 X ,使得C [i,j] * X [i,j]的总和最小化,受制于所有总和的约束 i X 行的元素等于 a 的 i -th元素和 x 的 j 列的所有元素等于 b 的 j -th元素,对于所有可能我和 j ,即
Minimize:
C[0,0] * X[0,0] + C[0,1] * X[0,1] + ... + C[1023,1023] * X[1023,1023]
Subject to:
All X[i,j] >= 0
X[0,0] + X[0,1] + ... + X[0,1023] == a[0]
X[1,0] + X[1,1] + ... + X[1,1023] == a[1]
...
X[1023,0] + X[1023,1] + ... X[1023,1023] == a[1023]
X[0,0] + X[1,0] + ... + X[1023,0] == b[0]
X[0,1] + X[1,1] + ... + X[1023,1] == b[1]
...
X[0,1023] + X[1,1023] + ... X[1023,1023] == b[1023]
我的代码大致如下:(在下面的代码中,DOT是传输模型; a和b是长度为1024的列表,C是长度为1048576(= 1024 ** 2)的列表。
from __future__ import print_function
import cplex
DOT = cplex.Cplex()
DOT.objective.set_sense(DOT.objective.sense.minimize)
size = 1024
# set up names of variables
nms = ["x{0}".format(i) for i in range(size * size)]
# add variables to the model
DOT.variables.add(obj = C, names = nms) # C is a nonnegative list with length 1048576
constraints = list()
for i in range(size):
constraints.append([nms[i * size : (i + 1) * size], [1.0] * size])
for i in range(size):
constraints.append(cplex.SparsePair(nms[i : size * size : size], [1.0] * size))
rhs = a + b # a, b are nonnegative lists with the same length and sum
constraint_senses = ["E"] * (size * 2)
# the following line: adding constraints to model is too slow
DOT.linear_constraints.add(lin_expr = constraints, senses = constraint_senses, rhs = rhs)
# solve the model
DOT.solve()
# print some information
print("Solution status :", DOT.solution.get_status())
print("Cost : {0:.5f}".format(DOT.solution.get_objective_value()))
print()
当我在评论中写道时,向模型添加约束的过程太慢了。有没有办法加快它?
任何帮助将不胜感激。提前谢谢!
答案 0 :(得分:0)
使用索引而不是名称,您将获得更好的性能。这在文档here中进行了讨论。
以下是使用索引的示例(只是模型构建部分)的修改版本:
from __future__ import print_function
import cplex
DOT = cplex.Cplex()
DOT.objective.set_sense(DOT.objective.sense.minimize)
size = 1024
C = [1.0] * (size * size) # dummy data
# set up names of variables
nms = ["x{0}".format(i) for i in range(size * size)]
# add variables to the model and store indices as a list
nmindices = list(DOT.variables.add(obj = C, names = nms))
constraints = list()
for i in range(size):
constraints.append([nmindices[i * size : (i + 1) * size], [1.0] * size])
for i in range(size):
constraints.append(cplex.SparsePair(nmindices[i : size * size : size], [1.0] * size))
rhs = [1.0] * (size * 2) # dummy data
constraint_senses = ["E"] * (size * 2)
# the following line: adding constraints to model is faster now
DOT.linear_constraints.add(lin_expr = constraints, senses = constraint_senses, rhs = rhs)
# write out the model in LP format for debugging
DOT.write("test.lp")