GurobiError: 无法将参数转换为表达式

1 投票
2 回答
6683 浏览
提问于 2025-04-18 06:21

有人能帮我解决这个错误吗?当我遇到这个错误: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 个回答

0

这个问题在 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 作为表达式。

0

如果你试图添加一个没有模型变量的约束,Gurobi会报错。看起来在某些变量组合下,列表的枚举会生成一个空列表,也就是说:

m.addConstr(quicksum([]) - 1 == 0)

也可以写成:

m.addConstr(-1 == 0)

这显然是不可能的。实际上,即使在下面这个例子中,Gurobi也会报错,因为虽然这个表达式看起来是可行的,但它里面没有任何变量。

m.addConstr(-1 <= 0)

要解决这个问题,只需要在添加约束之前检查一下列表是否为空即可。

撰写回答