我想知道如何仅通过使用其中一个索引来操作 pyomo 多个索引对象。
这个问题可能有点愚蠢,但我还没有找到可能的解决方案。在我的模型中,决策变量 (x) 是每年 (t) 中每种作物 (j) 的面积。因此,x 是一个多索引变量:
model.x = pyomo.Var(model.crop, model.t, domain = pyomo.NonNegativeIntegers)
例如,model.x 应该像 model.x[crop,year] 那样进行索引
我想创建两个资源约束,将耕作面积和用水量(只有 j 指数)限制在每年既定的最大值。类似下面的代码:
def area_constr(model, year):
return sum(model.x[crop, year] for crop in model.crop for year in model.t) <=\
model.total_cropping_area_n[year]
model.area_constr = pyomo.Constraint(model.a, model.n, rule = area_constr,
doc = 'Restricción de superficie disponible')
def water_constr(model, crop, year):
return sum(model.x\[crop, year\] \* model.crop_water_demand\[crop\]
for crop in model.a for year in model.n) \<= total_water_endowment\[year\]
model.water_constr = pyomo.Constraint(model.a, model.n, rule = water_constr)
自从我收到以下消息以来,我无法使其工作:
KeyError: "Index '0' is not valid for indexed component 'x'"
对于面积约束和 f 以及水约束,将所有年份中所有作物的耗水量相加,而不是逐年计算。
如何只使用一个索引进行操作?或者还有其他解决方案吗?
您的
area_constr
的问题在于,虽然您正确地将年份值传递给规则,因为您想要为每年设置面积约束,但您通过在规则内部再次提供变量 year
来覆盖该限制。总结。
这是一个示例,显示了我认为您的意图。请注意,在这两个约束中,您应该使用作为函数参数传入的值,如图所示。
如果您的区域限制逐年变化,那么您可以(并且应该)使用字典中的
(crop, year)
元组索引该数据,并以相同的方式索引相应的参数。
import pyomo.environ as pyo
### DATA
years = [2023, 2024, 2025]
water_demand = { 'corn': 1.5,
'rice': 2.3,
'wheat': 1.1}
water_limit = { 2023: 10.1,
2024: 12.3,
2025: 9.8}
area_limit = { 'corn': 10_000,
'rice': 12_500,
'wheat': 8_800}
### MODEL
m = pyo.ConcreteModel('crops')
# SETS
m.Y = pyo.Set(initialize=years, doc='year')
m.C = pyo.Set(initialize=water_demand.keys(), doc='crop')
# PARAMS
m.demand = pyo.Param(m.C, initialize=water_demand)
m.limit = pyo.Param(m.Y, initialize=water_limit)
m.area_limit = pyo.Param(m.C, initialize=area_limit)
# VARS
m.plant = pyo.Var(m.C, m.Y, domain=pyo.NonNegativeReals, doc='amount to plant of crop c in year y')
# CONSTRAINTS
# 1. Don't bust the water limit FOR EVERY YEAR
def water_lim_constraint(m, y):
# the "y" in this comes from the function params, we just need to supply "c" internally
return sum(m.plant[c, y]*water_demand[c] for c in m.C) <= m.limit[y]
m.C1 = pyo.Constraint(m.Y, rule=water_lim_constraint, doc='total water limit by year')
# 2. Don't overplant FOR EVERY CROP, FOR EVERY YEAR
def plant_limit(m, c, y):
# in this constraint, the limit is applied for every year and crop, which
# are supplied as function arguments
return m.plant[c, y] <= m.area_limit[c]
m.C2 = pyo.Constraint(m.C, m.Y, rule=plant_limit, doc='area planting limit by crop and year')
m.pprint()
4 Set Declarations
C : crop
Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'corn', 'rice', 'wheat'}
C2_index : Size=1, Index=None, Ordered=True
Key : Dimen : Domain : Size : Members
None : 2 : C*Y : 9 : {('corn', 2023), ('corn', 2024), ('corn', 2025), ('rice', 2023), ('rice', 2024), ('rice', 2025), ('wheat', 2023), ('wheat', 2024), ('wheat', 2025)}
Y : year
Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {2023, 2024, 2025}
plant_index : Size=1, Index=None, Ordered=True
Key : Dimen : Domain : Size : Members
None : 2 : C*Y : 9 : {('corn', 2023), ('corn', 2024), ('corn', 2025), ('rice', 2023), ('rice', 2024), ('rice', 2025), ('wheat', 2023), ('wheat', 2024), ('wheat', 2025)}
3 Param Declarations
area_limit : Size=3, Index=C, Domain=Any, Default=None, Mutable=False
Key : Value
corn : 10000
rice : 12500
wheat : 8800
demand : Size=3, Index=C, Domain=Any, Default=None, Mutable=False
Key : Value
corn : 1.5
rice : 2.3
wheat : 1.1
limit : Size=3, Index=Y, Domain=Any, Default=None, Mutable=False
Key : Value
2023 : 10.1
2024 : 12.3
2025 : 9.8
1 Var Declarations
plant : amount to plant of crop c in year y
Size=9, Index=plant_index
Key : Lower : Value : Upper : Fixed : Stale : Domain
('corn', 2023) : 0 : None : None : False : True : NonNegativeReals
('corn', 2024) : 0 : None : None : False : True : NonNegativeReals
('corn', 2025) : 0 : None : None : False : True : NonNegativeReals
('rice', 2023) : 0 : None : None : False : True : NonNegativeReals
('rice', 2024) : 0 : None : None : False : True : NonNegativeReals
('rice', 2025) : 0 : None : None : False : True : NonNegativeReals
('wheat', 2023) : 0 : None : None : False : True : NonNegativeReals
('wheat', 2024) : 0 : None : None : False : True : NonNegativeReals
('wheat', 2025) : 0 : None : None : False : True : NonNegativeReals
2 Constraint Declarations
C1 : total water limit by year
Size=3, Index=Y, Active=True
Key : Lower : Body : Upper : Active
2023 : -Inf : 1.5*plant[corn,2023] + 2.3*plant[rice,2023] + 1.1*plant[wheat,2023] : 10.1 : True
2024 : -Inf : 1.5*plant[corn,2024] + 2.3*plant[rice,2024] + 1.1*plant[wheat,2024] : 12.3 : True
2025 : -Inf : 1.5*plant[corn,2025] + 2.3*plant[rice,2025] + 1.1*plant[wheat,2025] : 9.8 : True
C2 : area planting limit by crop and year
Size=9, Index=C2_index, Active=True
Key : Lower : Body : Upper : Active
('corn', 2023) : -Inf : plant[corn,2023] : 10000.0 : True
('corn', 2024) : -Inf : plant[corn,2024] : 10000.0 : True
('corn', 2025) : -Inf : plant[corn,2025] : 10000.0 : True
('rice', 2023) : -Inf : plant[rice,2023] : 12500.0 : True
('rice', 2024) : -Inf : plant[rice,2024] : 12500.0 : True
('rice', 2025) : -Inf : plant[rice,2025] : 12500.0 : True
('wheat', 2023) : -Inf : plant[wheat,2023] : 8800.0 : True
('wheat', 2024) : -Inf : plant[wheat,2024] : 8800.0 : True
('wheat', 2025) : -Inf : plant[wheat,2025] : 8800.0 : True
10 Declarations: Y C demand limit area_limit plant_index plant C1 C2_index C2
[Finished in 267ms]