如何在 Pyomo 约束中模拟逻辑或或量词
how to model logical-OR or quantifiers in Pyomo-constraints
我正在使用 PYOMO,我想在 "P_constraint_rule" 中实现逻辑或,但我做不到。
我的模型有一些部分:
model.s = Param(within=NonNegativeIntegers)
model.S = RangeSet(1, model.s)
model.f = Param(within=NonNegativeIntegers)
model.F = RangeSet(1, model.f)
model.p = Param(within=NonNegativeIntegers)
model.P = RangeSet(0, model.p)
model.m = Param(within=NonNegativeIntegers)
model.M = RangeSet(1, model.m)
model.g = Param(model.M, default=5.0)
model.b2 = Param(model.F,model.F, within=Binary, default=0)
model.xf1f2 = Var(model.F, model.F, within=Binary)
model.y = Var(model.M, within=Binary)
model.xf = Var(model.F, within=Binary)
model.aff = Param(model.F,model.F, within=NonNegativeIntegers, default=0)
...
model.x = Var(model.index_sfpm, within=Binary)
model.b1 = Param(model.index_sfpm, within=Binary, default=0)
def Obj_rule(model):
expr = 0.0
for (s,f,p,m) in model.index_sfpm:
expr += model.g[m] * model.xf[f] * model.b1[s,f,p,m] * model.x[s,f,p,m]
for m in model.M:
expr += model.g[m] * model.y[m]
return expr
model.OBJ = Objective(rule=Obj_rule, sense=maximize)
def P_constraint_rule (model, f1, f2):
expr = 0.0
for (s,m) in model.index_sm:
expr += model.b2[f1,f2] * model.xf[f1] * model.b1[s,f1,1,m] * model.x[s,f1,1,m]
expr += model.xf[f2] * model.b1[s,f2,1,m] * model.x[s,f2,1,m]
e.g. in my .dat : param aff:= 1 7 10
return expr == model.aff[f1,f2] | expr == 0
model.PConstraint = Constraint(model.index_f1f2, rule=P_constraint_rule)
当我使用“|”时,出现以下错误:
ERROR: Rule failed when generating expression for constraint PConstraint with index (7, 3):
TypeError: unsupported operand type(s) for |: 'int' and '_SumExpression' ERROR: Constructing component 'PConstraint' from data=None failed:
TypeError: unsupported operand type(s) for |: 'int' and '_SumExpression' [ 1.72] Pyomo Finished ERROR: Unexpected exception while running model:
unsupported operand type(s) for |: 'int' and '_SumExpression'
当我使用“||”时
ERROR: Unexpected exception while loading model:
invalid syntax
评论该约束时,模型和 gurobi 运行 没问题。
有人可以帮助我解决这些错误吗?
是否还有另一种使用量词的可能性?
不等式 P1.constraint 应该对模型有效。index_f1f2
等式 P2Constraint 应该对 model.F 的 2 个元素或模型的 1 个元素有效。index_f1f2
像这样:
def P1_constraint_rule (model, f1, f2):
expr = 0.0
for (s,m) in model.index_sm:
expr += model.b2[f1,f2] * model.xf[f1] * model.b1[s,f1,1,m] * model.x[s,f1,1,m]
expr += model.xf[f2] * model.b1[s,f2,1,m] * model.x[s,f2,1,m]
return expr <= model.aff[f1,f2]
model.P1Constraint = Constraint(model.index_f1f2, rule=P1_constraint_rule)
def P2_constraint_rule (model, f1, f2):
expr = 0.0
for (s,m) in model.index_sm:
expr += model.b2[f1,f2] * model.xf[f1] * model.b1[s,f1,1,m] * model.x[s,f1,1,m]
expr += model.xf[f2] * model.b1[s,f2,1,m] * model.x[s,f2,1,m]
#this equation should be valid for 2 elements of model.F or 1 element of model.index_f1f2
return expr == model.aff[f1,f2]
model.P2Constraint = Constraint(model.index_f1f2, rule=P2_constraint_rule)
提前谢谢你,拉拉
错误是因为您试图指定一个非代数约束。从概念上讲,以下将定义逻辑析取:
expr == model.aff[f1,f2] | expr == 0
对于特定的语法问题:
|
是二元或。它比关系运算符绑定更紧密,因此不会执行您想要的操作。
||
无效 Python 语法
- 概念上你想要的是逻辑或,在Python中用
or
实现。这将是很好的支持语法 - 但是,Pyomo 目前不支持它。
您有两个选项来指定这样的约束:(1) 使用 pyomo.gdp
扩展将其指定为析取,然后利用 pyomo.gdp
中的转换将析取程序放宽到MIP,或 (2) 使用例如 Big-M 松弛显式松弛析取。要执行前者,您需要定义两个析取,然后定义析取:
from pyomo.gdp import *
def P_disjunct_rule (b, f1, f2, i):
model = b.model()
expr = 0.0
for (s,m) in model.index_sm:
expr += model.b2[f1,f2] * model.xf[f1] * model.b1[s,f1,1,m] * model.x[s,f1,1,m]
expr += model.xf[f2] * model.b1[s,f2,1,m] * model.x[s,f2,1,m]
if i:
return expr == model.aff[f1,f2]
else:
return expr == 0
model.PDisjunct = Disjunct(model.index_f1f2, [0,1], rule=P_constraint_rule)
def P_disjunction_rule(m,f1,f2):
return [ m.PDisjunct[f1,f2,i] for i in [0,1] ]
model.PDisjunction = Disjunction(model.index_f1f2, rule=P_Disjunction_rule)
然后您需要调用一个转换来将析取转换回代数约束。注意:转换要么需要你的 Pyomo 变量都有下限和上限,要么你需要通过模型上的 BigM
后缀指定有效的 "Big-M" 值。您可以:
- 在 Pyomo 命令行上指定转换(例如,
--transform=gdp.bigm
或 --transform=gdp.chull
)
在 BuildAction
中指定转换
def xfrm(m):
TransformationFactory('gdp.bigm').apply_to(m)
model.xfrm = BuildAction(rule=xfrm)
明确调用转换作为自定义驱动程序脚本的一部分。
pyomo.gdp
的替代方法是自己明确实施放宽。您需要添加一个二元变量(我们称之为 y
)来指示析取的哪一侧必须为真,然后使用该二元变量显式放宽两个析取。从概念上讲,你会转
expr == model.aff[f1,f2] | expr == 0
进入
expr - model.aff[f1.f2] <= M1 * y
model.aff[f1.f2] - expr <= M2 * y
expr <= M3 * (1-y)
expr >- M4 * (1-y)
请注意,根据 expr
和 aff
的界限,其中一些约束可能是多余的。此外,四个 "Big-M's"(大常量)可能不一定需要不同,但如果您可以确定每个 M 的最小有效值,问题会更好地解决。
谢谢@jsiirola。
我用 Big-M-relaxation 实现了约束。它有效。
此外,我简化了 expr- 和 return- 语句。
对于每个 f(以前的 f1,f2)S 和 M 的总和 (model.b[s,f,1,m] * model.x[s,f,1,m ]) 应等于 0 或 model.af[f](前 model.aff[f1,f2])。
model.af[f]也用作绑定M.
## Big-M Relaxation
def P1_constraint_rule (model, f):
expr = 0
for (s,m) in model.index_sm:
expr += model.b[s,f,1,m] * model.x[s,f,1,m]
return expr <= model.af[f] * model.xf[f]
model.P1Constraint = Constraint(model.F, rule=P1_constraint_rule)
def P2_constraint_rule (model, f):
expr = 0
for (s,m) in model.index_sm:
expr += model.b[s,f,1,m] * model.x[s,f,1,m]
return expr >= model.af[f] * model.xf[f]
model.P2Constraint = Constraint(model.F, rule=P2_constraint_rule)
def P3_constraint_rule (model, f):
expr = 0
for (s,m) in model.index_sm:
expr += model.b[s,f,1,m] * model.x[s,f,1,m]
return expr - model.af[f] <= model.af[f] * (1- model.xf[f])
model.P3Constraint = Constraint(model.F, rule=P3_constraint_rule)
def P4_constraint_rule (model, f):
expr = 0
for (s,m) in model.index_sm:
expr += model.b[s,f,1,m] * model.x[s,f,1,m]
return model.af[f] - expr <= model.af[f] * (1- model.xf[f])
model.P4Constraint = Constraint(model.F, rule=P4_constraint_rule)
我正在使用 PYOMO,我想在 "P_constraint_rule" 中实现逻辑或,但我做不到。
我的模型有一些部分:
model.s = Param(within=NonNegativeIntegers)
model.S = RangeSet(1, model.s)
model.f = Param(within=NonNegativeIntegers)
model.F = RangeSet(1, model.f)
model.p = Param(within=NonNegativeIntegers)
model.P = RangeSet(0, model.p)
model.m = Param(within=NonNegativeIntegers)
model.M = RangeSet(1, model.m)
model.g = Param(model.M, default=5.0)
model.b2 = Param(model.F,model.F, within=Binary, default=0)
model.xf1f2 = Var(model.F, model.F, within=Binary)
model.y = Var(model.M, within=Binary)
model.xf = Var(model.F, within=Binary)
model.aff = Param(model.F,model.F, within=NonNegativeIntegers, default=0)
...
model.x = Var(model.index_sfpm, within=Binary)
model.b1 = Param(model.index_sfpm, within=Binary, default=0)
def Obj_rule(model):
expr = 0.0
for (s,f,p,m) in model.index_sfpm:
expr += model.g[m] * model.xf[f] * model.b1[s,f,p,m] * model.x[s,f,p,m]
for m in model.M:
expr += model.g[m] * model.y[m]
return expr
model.OBJ = Objective(rule=Obj_rule, sense=maximize)
def P_constraint_rule (model, f1, f2):
expr = 0.0
for (s,m) in model.index_sm:
expr += model.b2[f1,f2] * model.xf[f1] * model.b1[s,f1,1,m] * model.x[s,f1,1,m]
expr += model.xf[f2] * model.b1[s,f2,1,m] * model.x[s,f2,1,m]
e.g. in my .dat : param aff:= 1 7 10
return expr == model.aff[f1,f2] | expr == 0
model.PConstraint = Constraint(model.index_f1f2, rule=P_constraint_rule)
当我使用“|”时,出现以下错误:
ERROR: Rule failed when generating expression for constraint PConstraint with index (7, 3):
TypeError: unsupported operand type(s) for |: 'int' and '_SumExpression' ERROR: Constructing component 'PConstraint' from data=None failed:
TypeError: unsupported operand type(s) for |: 'int' and '_SumExpression' [ 1.72] Pyomo Finished ERROR: Unexpected exception while running model:
unsupported operand type(s) for |: 'int' and '_SumExpression'
当我使用“||”时
ERROR: Unexpected exception while loading model:
invalid syntax
评论该约束时,模型和 gurobi 运行 没问题。
有人可以帮助我解决这些错误吗?
是否还有另一种使用量词的可能性? 不等式 P1.constraint 应该对模型有效。index_f1f2 等式 P2Constraint 应该对 model.F 的 2 个元素或模型的 1 个元素有效。index_f1f2 像这样:
def P1_constraint_rule (model, f1, f2):
expr = 0.0
for (s,m) in model.index_sm:
expr += model.b2[f1,f2] * model.xf[f1] * model.b1[s,f1,1,m] * model.x[s,f1,1,m]
expr += model.xf[f2] * model.b1[s,f2,1,m] * model.x[s,f2,1,m]
return expr <= model.aff[f1,f2]
model.P1Constraint = Constraint(model.index_f1f2, rule=P1_constraint_rule)
def P2_constraint_rule (model, f1, f2):
expr = 0.0
for (s,m) in model.index_sm:
expr += model.b2[f1,f2] * model.xf[f1] * model.b1[s,f1,1,m] * model.x[s,f1,1,m]
expr += model.xf[f2] * model.b1[s,f2,1,m] * model.x[s,f2,1,m]
#this equation should be valid for 2 elements of model.F or 1 element of model.index_f1f2
return expr == model.aff[f1,f2]
model.P2Constraint = Constraint(model.index_f1f2, rule=P2_constraint_rule)
提前谢谢你,拉拉
错误是因为您试图指定一个非代数约束。从概念上讲,以下将定义逻辑析取:
expr == model.aff[f1,f2] | expr == 0
对于特定的语法问题:
|
是二元或。它比关系运算符绑定更紧密,因此不会执行您想要的操作。||
无效 Python 语法- 概念上你想要的是逻辑或,在Python中用
or
实现。这将是很好的支持语法 - 但是,Pyomo 目前不支持它。
您有两个选项来指定这样的约束:(1) 使用 pyomo.gdp
扩展将其指定为析取,然后利用 pyomo.gdp
中的转换将析取程序放宽到MIP,或 (2) 使用例如 Big-M 松弛显式松弛析取。要执行前者,您需要定义两个析取,然后定义析取:
from pyomo.gdp import *
def P_disjunct_rule (b, f1, f2, i):
model = b.model()
expr = 0.0
for (s,m) in model.index_sm:
expr += model.b2[f1,f2] * model.xf[f1] * model.b1[s,f1,1,m] * model.x[s,f1,1,m]
expr += model.xf[f2] * model.b1[s,f2,1,m] * model.x[s,f2,1,m]
if i:
return expr == model.aff[f1,f2]
else:
return expr == 0
model.PDisjunct = Disjunct(model.index_f1f2, [0,1], rule=P_constraint_rule)
def P_disjunction_rule(m,f1,f2):
return [ m.PDisjunct[f1,f2,i] for i in [0,1] ]
model.PDisjunction = Disjunction(model.index_f1f2, rule=P_Disjunction_rule)
然后您需要调用一个转换来将析取转换回代数约束。注意:转换要么需要你的 Pyomo 变量都有下限和上限,要么你需要通过模型上的 BigM
后缀指定有效的 "Big-M" 值。您可以:
- 在 Pyomo 命令行上指定转换(例如,
--transform=gdp.bigm
或--transform=gdp.chull
) 在
中指定转换BuildAction
def xfrm(m): TransformationFactory('gdp.bigm').apply_to(m) model.xfrm = BuildAction(rule=xfrm)
明确调用转换作为自定义驱动程序脚本的一部分。
pyomo.gdp
的替代方法是自己明确实施放宽。您需要添加一个二元变量(我们称之为 y
)来指示析取的哪一侧必须为真,然后使用该二元变量显式放宽两个析取。从概念上讲,你会转
expr == model.aff[f1,f2] | expr == 0
进入
expr - model.aff[f1.f2] <= M1 * y
model.aff[f1.f2] - expr <= M2 * y
expr <= M3 * (1-y)
expr >- M4 * (1-y)
请注意,根据 expr
和 aff
的界限,其中一些约束可能是多余的。此外,四个 "Big-M's"(大常量)可能不一定需要不同,但如果您可以确定每个 M 的最小有效值,问题会更好地解决。
谢谢@jsiirola。
我用 Big-M-relaxation 实现了约束。它有效。
此外,我简化了 expr- 和 return- 语句。
对于每个 f(以前的 f1,f2)S 和 M 的总和 (model.b[s,f,1,m] * model.x[s,f,1,m ]) 应等于 0 或 model.af[f](前 model.aff[f1,f2])。
model.af[f]也用作绑定M.
## Big-M Relaxation
def P1_constraint_rule (model, f):
expr = 0
for (s,m) in model.index_sm:
expr += model.b[s,f,1,m] * model.x[s,f,1,m]
return expr <= model.af[f] * model.xf[f]
model.P1Constraint = Constraint(model.F, rule=P1_constraint_rule)
def P2_constraint_rule (model, f):
expr = 0
for (s,m) in model.index_sm:
expr += model.b[s,f,1,m] * model.x[s,f,1,m]
return expr >= model.af[f] * model.xf[f]
model.P2Constraint = Constraint(model.F, rule=P2_constraint_rule)
def P3_constraint_rule (model, f):
expr = 0
for (s,m) in model.index_sm:
expr += model.b[s,f,1,m] * model.x[s,f,1,m]
return expr - model.af[f] <= model.af[f] * (1- model.xf[f])
model.P3Constraint = Constraint(model.F, rule=P3_constraint_rule)
def P4_constraint_rule (model, f):
expr = 0
for (s,m) in model.index_sm:
expr += model.b[s,f,1,m] * model.x[s,f,1,m]
return model.af[f] - expr <= model.af[f] * (1- model.xf[f])
model.P4Constraint = Constraint(model.F, rule=P4_constraint_rule)