我是Pyomo的新手。
我想知道是否存在一种优雅的方式来编写包含我们可能想要或不希望包含的变量的约束。包含这些选项的选项将在模型求解时就知道,并且将基于从数据库读取的设置。
一个很好的例子可能是约束中有懈怠,有时候我们想要,有时我们不想。
我在下面为仓库位置示例开发了一个小演示。在方程式[[buildLimit中,我添加了一个松弛量,以允许仓库数量超过构建限制[代码可能包含一些我没有运行过的语法错误]
# Import pyomo
from pyomo.environ import *
from pyomo.opt import SolverStatus, TerminationCondition
N = ['Harlingen', 'Memphis', 'Ashland']
M = ['NYC', 'LA', 'Chicago', 'Houston']
d = {('Harlingen', 'NYC'): 1956, \
('Harlingen', 'LA'): 1606, \
('Harlingen', 'Chicago'): 1410, \
('Harlingen', 'Houston'): 330, \
('Memphis', 'NYC'): 1096, \
('Memphis', 'LA'): 1792, \
('Memphis', 'Chicago'): 531, \
('Memphis', 'Houston'): 567, \
('Ashland', 'NYC'): 485, \
('Ashland', 'LA'): 2322, \
('Ashland', 'Chicago'): 324, \
('Ashland', 'Houston'): 1236 }
P = 2
model = ConcreteModel("warehouse location problem")
model.N = Set(dimen=1, initialize=N)
model.M = Set(dimen=1, initialize=M)
model.d = Param(model.N, model.M, within=PositiveIntegers, initialize=d)
model.P = Param(initialize=P)
model.y = Var(model.N, within=Binary)
model.x = Var(model.N, model.M, bounds=(0,1))
##########################
model.buildLimitSlack = Var(within=NonNegativeIntegers)
model.useSlacks = Param() # assume some data read will populate this at some stage before the solve
##########################
# Objective, minimise delivery costs
def obj_rule(model):
return sum(model.d[n,m] * model.x[n,m] for n in model.N for m in model.M) + 99*model.buildLimitSlack
model.obj = Objective(rule=obj_rule)
# All customer demand must be met
def demand_rule(model, m):
return sum(model.x[n,m] for n in model.N) == 1
model.demand = Constraint(model.M, rule=demand_rule)
# Can only ship from a warehouse if that warehouse is built
def supplyOnlyIfBuilt_rule(model, m, n):
return model.x[n,m] <= model.y[n]
model.supplyOnlyIfBuilt = Constraint(model.M, model.N, rule=supplyOnlyIfBuilt_rule)
##############################
#### WE WANT THE SLACK IN THIS EQUATION TO BE OPTIONAL BASED ON DATA SETTINGS
def buildLimit_rule(model):
return sum(model.y[n] for n in model.N) <= model.P + model.buildLimitSlack
model.buildLimit = Constraint(rule=buildLimit_rule)
##############################
我想我们可以在约束中包含if语句,如下所示。但是我们不希望那样,因为我们的模型方程可能会在相同的约束中具有many这样的可选变量,而且我也不想嵌套大量的if语句[除非有一种不错的方法? ]。
def buildLimit_rule(model): if model.useSlacks: return sum(model.y[n] for n in model.N) <= model.P + model.buildLimitSlack else: return sum(model.y[n] for n in model.N) <= model.P model.buildLimit = Constraint(rule=buildLimit_rule)
有什么建议吗?提前感谢
EDIT 1-稀疏组件:有关稀疏性的问题,请参见以下问题:Create a variable with sparse index in pyomo本质上,您应该初始化sets,以便它们仅包含“有效”值,这将自动确保您仅在初始化必需的组件。
EDIT 2-可选组件:有几种方法可以向模型添加可选组件。一个简单的if
语句是一种策略,或者您可以考虑BuildActions。另一种选择是创建Expressions
(参数和变量的组合),然后“可选地”更改它们,而不是约束定义本身。
def buildLimit_rule(m):
return sum(m.y[n] for n in m.N) <= m.P + m.buildLimitSlack * m.useSlacks
如果您有多个带有独立on / off参数的松弛变量:
def buildLimit_rule(m): return sum(m.y[n] for n in m.N) <= m.P + m.v1 * m.use_v1 + m.v2 * m.use_v2 + ...
最通用(但更难理解)的方法是索引所有潜在的松弛变量:
model.SLACKS = Set(...) # set for slack variables model.slack = Var(model.SLACKS) model.use_slack = Param(model.SLACKS, within=Binary) def buildLimit_rule(m): return sum(m.y[n] for n in m.N) <= m.P + sum(m.slack[i] * m.use_slack[i] for i in m.SLACKS)
另一种方法是fix
不需要的变量:
if not m.useSlacks: m.Slack.fix(0) m.OtherSlack.fix(0)