GurobiError: 无法将参数转换为表达式
有人能帮我解决这个错误吗?当我遇到这个错误:GurobiError: 无法将参数转换为表达式时,我应该去哪里查找问题?我还要补充一下,我是在用Python的Gurobi库。
from gurobipy import*
m=Model('mymodel')
def label(c):
return "x" + str(c).translate(None, " '")
shifts = [1,2]
hours = [1,2]
games = ['bj', 'cr']
pits = [1,2]
order1 = [1,2]
order2 = [1,2,3]
combo, oi = multidict( {
(1,1,'bj',1,1,1): 100,
(1,1,'bj',1,1,2):200,
(1,1,'bj',1,1,3):200,
(1,1,'bj',1,2,1):50,
(1,1,'bj',1,2,2):70,
(1,1,'bj',1,2,3):70,
(1,1,'cr',1,1,1):400,
(1,1,'cr',1,1,2):450
})
combo= tuplelist(combo)
for s in shifts:
for t in hours:
for i in games:
for n in order1:
m.addConstr(quicksum(x[s,t,i,p,n,k] for s,t,i,p,n,k in combo.select(s,t,i,'*',n,'*'))- int(1)== 0, name=label((s,t,i,p,n,k))
2 个回答
这个问题在 Gurobi 6.0.0 版本中已经修复了。在这个版本里,quicksum([])
会返回一个值为 0 的线性表达式(而不是浮点数 0.0),这就解决了原来的问题。
在 5.6.3 版本及之前的版本中,问题出在使用了所谓的 TempConstr。
当你调用 addConstr 时,可以使用明确的“左边”、“运算符”、“右边”的方式来处理:
m.addConstr(quicksum([]), GRB.EQUAL, 0)
这样做不会有问题。
如果你使用 TempConstr 并且在一个空列表上使用 quicksum
,实际上发生的事情是这样的:
m.addConstr(quicksum([]) == 0)
quicksum
在列表为空时返回 0,所以你的表达式是:
m.addConstr(0 == 0)
而 0 == 0
会被转换为 True
,所以你实际上调用的是:
m.addConstr(True)
这显然是 Gurobi 无法处理的(不过它可以给出更好的错误描述)。
总结一下:如果你使用 quicksum,并且有可能列表是空的,你可以选择检查列表是否为空,正如 blueenvelope 所建议的,或者使用明确的方法,或者如果这种情况经常发生,可以使用一个小的包装方法:
def add_constr(model, expression, name=""):
if expression is True:
return model.addConstr(0, GRB.EQUAL, 0, name)
elif expression is False:
raise Exception('`False` as constraint for {}'.format(name))
else:
return model.addConstr(expression, name)
这个包装方法仅适用于 TempConstr 作为表达式。
如果你试图添加一个没有模型变量的约束,Gurobi会报错。看起来在某些变量组合下,列表的枚举会生成一个空列表,也就是说:
m.addConstr(quicksum([]) - 1 == 0)
也可以写成:
m.addConstr(-1 == 0)
这显然是不可能的。实际上,即使在下面这个例子中,Gurobi也会报错,因为虽然这个表达式看起来是可行的,但它里面没有任何变量。
m.addConstr(-1 <= 0)
要解决这个问题,只需要在添加约束之前检查一下列表是否为空即可。