如何使用多个键在字典内部循环以定义 Pyomo 中的优化问题?
How to loop inside dictionaries with multiple keys to define an Optimization Problem in Pyomo?
作为优化问题的一部分,我试图在具有多个键的字典中循环(看 UNIT_TASKS)。特别是我在遍历索引以定义 Objective 和约束时遇到问题,因为 Python returns "Key Error: ('Reactor_2', 'Reaction_3','Juan') "。脚本片段如下:
import numpy as np
from pyomo.environ import *
from pyomo.gdp import
STATES = {
'Feed_A' : {'capacity': 500, 'initial': 500, 'price': 0},
'Feed_B' : {'capacity': 500, 'initial': 500, 'price': 0},
'Feed_C' : {'capacity': 500, 'initial': 500, 'price': 0},
'Hot_A' : {'capacity': 100, 'initial': 0, 'price': -1},
'Int_AB' : {'capacity': 200, 'initial': 0, 'price': -1},
'Int_BC' : {'capacity': 150, 'initial': 0, 'price': -1},
'Impure_E' : {'capacity': 100, 'initial': 0, 'price': -1},
'Product_1': {'capacity': 500, 'initial': 0, 'price': 10},
'Product_2': {'capacity': 500, 'initial': 0, 'price': 10},
}
UNIT_TASKS = {
('Heater', 'Heating', 'Pablo') : {'Bmin': 0, 'Bmax': 100},
('Reactor_1', 'Reaction_1', 'Juan'): {'Bmin': 0, 'Bmax': 80},
('Reactor_1', 'Reaction_2', 'Pedro'): {'Bmin': 0, 'Bmax': 80},
('Reactor_1', 'Reaction_3', 'Pablo'): {'Bmin': 0, 'Bmax': 80},
('Reactor_2', 'Reaction_1', 'Pablo'): {'Bmin': 0, 'Bmax': 80},
('Reactor_2', 'Reaction_2', 'Juan'): {'Bmin': 0, 'Bmax': 80},
('Reactor_2', 'Reaction_3', 'Pablo'): {'Bmin': 0, 'Bmax': 80},
('Still', 'Separation', 'Pablo'): {'Bmin': 0, 'Bmax': 200},
('Heater', 'Heating', 'Juan') : {'Bmin': 0, 'Bmax': 300},
}
TASKS = set([i for (j,i,k) in UNIT_TASKS])
UNITS = set([j for (j,i,k) in UNIT_TASKS])
NAMES = set([k for (j,i,k) in UNIT_TASKS])
TIME = range(0,11)
TIME = np.array(TIME)
model = ConcreteModel()
model.W = Var(TASKS, UNITS, TIME, domain = Boolean)
model.B = Var(TASKS, UNITS, TIME, domain = NonNegativeReals)
model.S = Var(STATES.keys(), TIME, domain = NonNegativeReals)
model.Q = Var(UNITS, TIME, domain = NonNegativeReals)
Bmax = {(i,j,k): UNIT_TASKS[(j,i,k)]['Bmax'] for (j,i,k) in UNIT_TASKS}
UNITS_DIC = {j: set() for j in UNITS}
for (j,i,k) in UNIT_TASKS:
UNITS_DIC[j].add(i)
UNITS_DIC_N = {j: set() for j in UNITS}
for (j,i,k) in UNIT_TASKS:
UNITS_DIC_N[j].add(k)
NAMES_DIC = {k: set() for k in NAMES}
for (j,i,k) in UNIT_TASKS:
NAMES_DIC[k].add(i)
TASKS_DIC = {i: set() for i in TASKS}
for (j,i,k) in UNIT_TASKS:
TASKS_DIC[i].add(k)
TASKS_DIC_U = {i: set() for i in TASKS}
for (j,i,k) in UNIT_TASKS:
TASKS_DIC_U[i].add(j)
model.Cost = Var(domain=NonNegativeReals)
model.costc = Constraint(expr = model.Cost == sum([UNIT_TASKS[(j,i,k)]['Bmin']*model.W[i,j,t]
+ UNIT_TASKS[(j,i,k)]['Bmax']*model.B[i,j,t] for i in TASKS for j in TASKS_DIC_U[i] for k in UNITS_DIC_N[j] for t in TIME]))
model.cons = ConstraintList()
for t in TIME:
for j in UNITS:
for i in UNITS_DIC[j]:
for k in TASKS_DIC[i]:
model.cons.add(model.B[i,j,t] <= model.W[i,j,t]*Bmax[i,j,k])
有几件事需要清理...:)
首先,当您进行约束时会出现关键错误,这是因为您在那里使用了多个 'for' 表达式,这将创建所有项目的叉积...在旁边试试。
您有一个稀疏值矩阵,因此您应该仅使用这些值初始化一个集合并使用它。我也喜欢在制作模型时使用 Pyomo 的 Set(注意大写 S),尽管您可以使用其中之一。
此外,您的指数很难遵循。如果您使用 (i,j,k),请按该顺序(标准)使用它们,而不是 (j,i,k)(混淆)。当你有名字时,我喜欢使用更直观的名字......它增加了可读性。
另请注意,在上面的代码中,您在这一行中翻转了索引:
Bmax = {(i,j,k): UNIT_TASKS[(j,i,k)]['Bmax'] for (j,i,k) in UNIT_TASKS}
这是建议的清理。请注意,您会得到一些 "warnings",因为我们正在使用您的部分字典键来制作集合,并且存在一些冗余。
model = ConcreteModel()
model.TASKS = Set(initialize = (i for (j,i,k) in UNIT_TASKS)) # note capital "S" Set for pyomo set
model.UNITS = Set(initialize = (j for (j,i,k) in UNIT_TASKS))
model.NAMES = Set(initialize = (k for (j,i,k) in UNIT_TASKS))
model.UTN = Set(within=model.UNITS * model.TASKS * model.NAMES,
initialize=UNIT_TASKS.keys()) # this is now a Set of the keys (U, T, N)
model.TIMES = Set(initialize=range(0,11))
#TIME = np.array(TIME)
model.W = Var(model.TASKS, model.UNITS, model.TIMES, domain = Boolean)
model.B = Var(model.TASKS, model.UNITS, model.TIMES, domain = NonNegativeReals)
model.S = Var(STATES.keys(), model.TIMES, domain = NonNegativeReals)
model.Q = Var(model.UNITS, model.TIMES, domain = NonNegativeReals)
Bmax = {key: UNIT_TASKS[key]['Bmax'] for key in model.UTN} # NOTE: YOU HAD FLIPPED (i,j,k) -> (j, i, k)
# none of these "helper" dictionaries should be required!! You should be able to delete these lines
# UNITS_DIC = {j: set() for j in UNITS} # UNIT: {TASKS}
# for (j,i,k) in UNIT_TASKS:
# UNITS_DIC[j].add(i)
# UNITS_DIC_N = {j: set() for j in UNITS} # UNIT: {NAMES}
# for (j,i,k) in UNIT_TASKS:
# UNITS_DIC_N[j].add(k)
# NAMES_DIC = {k: set() for k in NAMES} # NAME: {TASKS}
# for (j,i,k) in UNIT_TASKS:
# NAMES_DIC[k].add(i)
# TASKS_DIC = {i: set() for i in TASKS} # TASK: {NAMES}
# for (j,i,k) in UNIT_TASKS:
# TASKS_DIC[i].add(k)
# TASKS_DIC_U = {i: set() for i in TASKS} # TASK: {UNITS}
# for (j,i,k) in UNIT_TASKS:
# TASKS_DIC_U[i].add(j)
# for k in UNIT_TASKS:
# print (k, UNIT_TASKS[k])
model.Cost = Var(domain=NonNegativeReals)
model.costc = Constraint(expr = model.Cost == sum( UNIT_TASKS[(u,t,n)]['Bmin']*model.W[t,u,time]
+ UNIT_TASKS[(u,t,n)]['Bmax']*model.B[t,u,time]
for u,t,n in model.UTN
for time in model.TIMES))
作为优化问题的一部分,我试图在具有多个键的字典中循环(看 UNIT_TASKS)。特别是我在遍历索引以定义 Objective 和约束时遇到问题,因为 Python returns "Key Error: ('Reactor_2', 'Reaction_3','Juan') "。脚本片段如下:
import numpy as np
from pyomo.environ import *
from pyomo.gdp import
STATES = {
'Feed_A' : {'capacity': 500, 'initial': 500, 'price': 0},
'Feed_B' : {'capacity': 500, 'initial': 500, 'price': 0},
'Feed_C' : {'capacity': 500, 'initial': 500, 'price': 0},
'Hot_A' : {'capacity': 100, 'initial': 0, 'price': -1},
'Int_AB' : {'capacity': 200, 'initial': 0, 'price': -1},
'Int_BC' : {'capacity': 150, 'initial': 0, 'price': -1},
'Impure_E' : {'capacity': 100, 'initial': 0, 'price': -1},
'Product_1': {'capacity': 500, 'initial': 0, 'price': 10},
'Product_2': {'capacity': 500, 'initial': 0, 'price': 10},
}
UNIT_TASKS = {
('Heater', 'Heating', 'Pablo') : {'Bmin': 0, 'Bmax': 100},
('Reactor_1', 'Reaction_1', 'Juan'): {'Bmin': 0, 'Bmax': 80},
('Reactor_1', 'Reaction_2', 'Pedro'): {'Bmin': 0, 'Bmax': 80},
('Reactor_1', 'Reaction_3', 'Pablo'): {'Bmin': 0, 'Bmax': 80},
('Reactor_2', 'Reaction_1', 'Pablo'): {'Bmin': 0, 'Bmax': 80},
('Reactor_2', 'Reaction_2', 'Juan'): {'Bmin': 0, 'Bmax': 80},
('Reactor_2', 'Reaction_3', 'Pablo'): {'Bmin': 0, 'Bmax': 80},
('Still', 'Separation', 'Pablo'): {'Bmin': 0, 'Bmax': 200},
('Heater', 'Heating', 'Juan') : {'Bmin': 0, 'Bmax': 300},
}
TASKS = set([i for (j,i,k) in UNIT_TASKS])
UNITS = set([j for (j,i,k) in UNIT_TASKS])
NAMES = set([k for (j,i,k) in UNIT_TASKS])
TIME = range(0,11)
TIME = np.array(TIME)
model = ConcreteModel()
model.W = Var(TASKS, UNITS, TIME, domain = Boolean)
model.B = Var(TASKS, UNITS, TIME, domain = NonNegativeReals)
model.S = Var(STATES.keys(), TIME, domain = NonNegativeReals)
model.Q = Var(UNITS, TIME, domain = NonNegativeReals)
Bmax = {(i,j,k): UNIT_TASKS[(j,i,k)]['Bmax'] for (j,i,k) in UNIT_TASKS}
UNITS_DIC = {j: set() for j in UNITS}
for (j,i,k) in UNIT_TASKS:
UNITS_DIC[j].add(i)
UNITS_DIC_N = {j: set() for j in UNITS}
for (j,i,k) in UNIT_TASKS:
UNITS_DIC_N[j].add(k)
NAMES_DIC = {k: set() for k in NAMES}
for (j,i,k) in UNIT_TASKS:
NAMES_DIC[k].add(i)
TASKS_DIC = {i: set() for i in TASKS}
for (j,i,k) in UNIT_TASKS:
TASKS_DIC[i].add(k)
TASKS_DIC_U = {i: set() for i in TASKS}
for (j,i,k) in UNIT_TASKS:
TASKS_DIC_U[i].add(j)
model.Cost = Var(domain=NonNegativeReals)
model.costc = Constraint(expr = model.Cost == sum([UNIT_TASKS[(j,i,k)]['Bmin']*model.W[i,j,t]
+ UNIT_TASKS[(j,i,k)]['Bmax']*model.B[i,j,t] for i in TASKS for j in TASKS_DIC_U[i] for k in UNITS_DIC_N[j] for t in TIME]))
model.cons = ConstraintList()
for t in TIME:
for j in UNITS:
for i in UNITS_DIC[j]:
for k in TASKS_DIC[i]:
model.cons.add(model.B[i,j,t] <= model.W[i,j,t]*Bmax[i,j,k])
有几件事需要清理...:)
首先,当您进行约束时会出现关键错误,这是因为您在那里使用了多个 'for' 表达式,这将创建所有项目的叉积...在旁边试试。
您有一个稀疏值矩阵,因此您应该仅使用这些值初始化一个集合并使用它。我也喜欢在制作模型时使用 Pyomo 的 Set(注意大写 S),尽管您可以使用其中之一。
此外,您的指数很难遵循。如果您使用 (i,j,k),请按该顺序(标准)使用它们,而不是 (j,i,k)(混淆)。当你有名字时,我喜欢使用更直观的名字......它增加了可读性。
另请注意,在上面的代码中,您在这一行中翻转了索引:
Bmax = {(i,j,k): UNIT_TASKS[(j,i,k)]['Bmax'] for (j,i,k) in UNIT_TASKS}
这是建议的清理。请注意,您会得到一些 "warnings",因为我们正在使用您的部分字典键来制作集合,并且存在一些冗余。
model = ConcreteModel()
model.TASKS = Set(initialize = (i for (j,i,k) in UNIT_TASKS)) # note capital "S" Set for pyomo set
model.UNITS = Set(initialize = (j for (j,i,k) in UNIT_TASKS))
model.NAMES = Set(initialize = (k for (j,i,k) in UNIT_TASKS))
model.UTN = Set(within=model.UNITS * model.TASKS * model.NAMES,
initialize=UNIT_TASKS.keys()) # this is now a Set of the keys (U, T, N)
model.TIMES = Set(initialize=range(0,11))
#TIME = np.array(TIME)
model.W = Var(model.TASKS, model.UNITS, model.TIMES, domain = Boolean)
model.B = Var(model.TASKS, model.UNITS, model.TIMES, domain = NonNegativeReals)
model.S = Var(STATES.keys(), model.TIMES, domain = NonNegativeReals)
model.Q = Var(model.UNITS, model.TIMES, domain = NonNegativeReals)
Bmax = {key: UNIT_TASKS[key]['Bmax'] for key in model.UTN} # NOTE: YOU HAD FLIPPED (i,j,k) -> (j, i, k)
# none of these "helper" dictionaries should be required!! You should be able to delete these lines
# UNITS_DIC = {j: set() for j in UNITS} # UNIT: {TASKS}
# for (j,i,k) in UNIT_TASKS:
# UNITS_DIC[j].add(i)
# UNITS_DIC_N = {j: set() for j in UNITS} # UNIT: {NAMES}
# for (j,i,k) in UNIT_TASKS:
# UNITS_DIC_N[j].add(k)
# NAMES_DIC = {k: set() for k in NAMES} # NAME: {TASKS}
# for (j,i,k) in UNIT_TASKS:
# NAMES_DIC[k].add(i)
# TASKS_DIC = {i: set() for i in TASKS} # TASK: {NAMES}
# for (j,i,k) in UNIT_TASKS:
# TASKS_DIC[i].add(k)
# TASKS_DIC_U = {i: set() for i in TASKS} # TASK: {UNITS}
# for (j,i,k) in UNIT_TASKS:
# TASKS_DIC_U[i].add(j)
# for k in UNIT_TASKS:
# print (k, UNIT_TASKS[k])
model.Cost = Var(domain=NonNegativeReals)
model.costc = Constraint(expr = model.Cost == sum( UNIT_TASKS[(u,t,n)]['Bmin']*model.W[t,u,time]
+ UNIT_TASKS[(u,t,n)]['Bmax']*model.B[t,u,time]
for u,t,n in model.UTN
for time in model.TIMES))