I would like to know how to operate over pyomo multiple index objects just by employing one of the index.
This question may be a bit stupid, but I have not found a possible solution. In my model, the decision variable (x) is the surface of each crop (j) in each year (t). Therefore, x is a multi-index variable:
model.x = pyomo.Var(model.crop, model.t, domain = pyomo.NonNegativeIntegers)
Eg, model.x should be indexed like model.x[crop, year]
I want to create two resources constraints that limit the cropping area and the water consumption (which has only the j index) to the established maximum per year. Something like the following code:
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)
I'm not able to make it work since I obtained the following message:
KeyError: "Index '0' is not valid for indexed component 'x'"
for the area constraint and f and for the water constraint add up the water consumption of all crops in all years, not year by year.
How can I operate using just one index? or is there another solution?
The problem with your area_constr
is that while you are correctly passing in the year value to the rule because you want to make an area constraint for each year you are overriding that by supplying the variable year
again inside of the summation.
Here is an example that shows what I think you intend. Realize that in each of the 2 constraints, you should be using the values that are passed in as function parameters as shown.
If your area limits change by year then you could (and should) index that data with (crop, year)
tuples in the dictionary and index the corresponding parameter the same way.
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]