
[英]Gurobi Python API - How to add new variables to existing constraints
[英]How do I add Gurobi constraints and variables from lists of strings in an automated way?
目标:从变量列表和约束列表中将变量和约束循环添加到 Gurobi model,其中每个变量和约束都存储为字符串
问题: Gurobi 只接受 Gurobi 线性表达式类型中的变量和约束。 我需要以自动方式执行此操作,因为约束列表可能很长。 所以我需要以某种方式将这些字符串转换为 Gurobi LinExpr 类型。
数据:我有一个变量列表,如本例所示:
variables=["y1","y2","y3","y4","y5","y6","y7"]
我有一个这样的约束列表:
['y6+y7-d*y1>=0', '1*y2+1*y3-1*u1*d-y6-y7+d*y1>=0', '1*y4+1*y5-u2*1*d-y6-y7+d*y1>=0', '1*x1+1*x2-1*d-1*y2-1*y3+1*u1*d-1*y4-1*y5+u2*1*d+y6+y7-d*y1>=0']
所需的解决方案:
我想将这些变量添加到我的 Gurobi model 中,如下例所示:
y1 = model.addVar(vtype=GRB.CONTINUOUS, name = "y1", lb=0)
y2 = model.addVar(vtype=GRB.CONTINUOUS, name = "y2", lb=0)
y3 = model.addVar(vtype=GRB.CONTINUOUS, name = "y3", lb=0)
y4 = model.addVar(vtype=GRB.CONTINUOUS, name = "y4", lb=0)
y5 = model.addVar(vtype=GRB.CONTINUOUS, name = "y5", lb=0)
y6 = model.addVar(vtype=GRB.CONTINUOUS, name = "y6", lb=0)
y7 = model.addVar(vtype=GRB.CONTINUOUS, name = "y7", lb=0)
和这样的约束:
c1 = model.addConstr(y1+y2-d*y1>=0,"c1")
c2 = model.addConstr(1*y2+1*y3-1*y5*d-y6-y7+d*y1>=0,"c2")
c3 = model.addConstr(1*y4+1*y5-u2*1*d-y6-y7+d*y1>=0,"c3")
c4 = model.addConstr(1*y1+1*y2-1*d-1*y2-1*y3+1*u1*d-1*y4-1*y5+u2*1*d+y6+y7-d*y1>=0,"c4")
我的尝试:
我尝试将数据存储在字典中并使用更新 function 来存储变量和约束,如下所示:
y_dict={}
for y_variable in range(y_count-1):
y_dict['y{}'.format(y_variable+1)]=model.addVar(vtype=GRB.CONTINUOUS, name = "y{}".format(y_variable+1), lb=0)
locals().update(c_dict)
c_dict={}
for idx, constraint in enumerate(list_of_constraints):
c_dict['c{}'.format(idx+1)]=model.addConstr(eval(constraint),"c{}".format(idx+1))
locals().update(c_dict)
但是,我设定目标时得到的错误是
GurobiError: Variable not in model
有没有办法将字符串转换为 Gurobi 线性表达式类型?
为了完整起见,另一种值得一提的方法是将约束字符串中的所有变量转换为索引符号,例如y1
变为y[1]
。 使用正则表达式,这很简单:
import re
def clean_constr_str(s, var_names):
for var_name in var_names:
s = re.sub(r"(" + var_name + r")(\d*)", r"\1[\2]", s)
return s
这里, s
是约束字符串, var_names
是一个包含所有变量名的迭代。 鉴于您已经知道变量名称,这允许您一次添加所有变量作为 tupledict,然后在不修改逻辑符号表的情况下解析约束:
import gurobipy as gp
variables = ["y1","y2","y3","y4","y5","y6","y7"]
list_of_constraints = [
'y6+y7-d*y1>=0',
'1*y2+1*y3-1*u1*d-y6-y7+d*y1>=0',
'1*y4+1*y5-u2*1*d-y6-y7+d*y1>=0',
'1*x1+1*x2-1*d-1*y2-1*y3+1*u1*d-1*y4-1*y5+u2*1*d+y6+y7-d*y1>=0'
]
model = gp.Model()
# Add all variables
y = model.addVars(range(1, len(variables)+1), vtype="C", name="y")
d = model.addVar(vtype="C", name="d")
u = model.addVars(range(1, 3), vtype="C", name="u")
x = model.addVars(range(1, 3), vtype="C", name="x")
# add the constraints
c = {}
for i, constraint in enumerate(list_of_constraints, 1):
con = eval(clean_constr_str(constraint, ["y", "u", "x"]))
c[i] = model.addConstr(con, name=f"c{i}")
model.update()
print(model.display())
产量
Minimize
<gurobi.LinExpr: 0.0>
Subject To
c1: <gurobi.QuadExpr: y[6] + y[7] + [ -1.0 y[1] * d ]> >= 0
c2: <gurobi.QuadExpr: y[2] + y[3] + -1.0 y[6] + -1.0 y[7] + [ y[1] * d + -1.0 d * u[1]
]> >= 0
c3: <gurobi.QuadExpr: y[4] + y[5] + -1.0 y[6] + -1.0 y[7] + [ y[1] * d + -1.0 d * u[2]
]> >= 0
c4: <gurobi.QuadExpr: -1.0 y[2] + -1.0 y[3] + -1.0 y[4] + -1.0 y[5] + y[6] + y[7] +
-1.0 d + x[1] + x[2] + [ -1.0 y[1] * d + d * u[1] + d * u[2] ]> >= 0
这是您问题的简明答案,但请记住,这是非常不安全且容易出错的,切勿在实际代码中使用:
import gurobipy as gp
m = gp.Model()
variables = ["y1", "y2", "y3", "y4", "y5", "y6", "y7"]
constraints = ["y1+3*y2-y3>=2", "y4+y5+y6+y7==2"]
for v in variables:
exec(f"{v} = m.addVar(name = '{v}')")
for c in constraints:
exec(f"m.addConstr({c})")
m.write("out.lp")
out.lp:
Minimize
Subject To
R0: y1 + 3 y2 - y3 >= 2
R1: y4 + y5 + y6 + y7 = 2
Bounds
End
类似的问题已在 SO 上多次提出(例如,在此处和链接的重复项中),使用“字符串作为变量名”的最佳方式就是字典。
使用addVars()是根据您指定的名称列表创建变量集的正确方法:
v = m.addVars(variables)
m.update()
print(v)
output
:
{'y1': <gurobi.Var C0>, 'y2': <gurobi.Var C1>, 'y3': <gurobi.Var C2>,
'y4': <gurobi.Var C3>, 'y5': <gurobi.Var C4>, 'y6': <gurobi.Var C5>,
'y7': <gurobi.Var C6>
}
但是,这对于列表约束是不可能的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.