Как l oop внутри словарей с несколькими ключами для определения проблемы оптимизации в Pyomo? - PullRequest
0 голосов
/ 27 мая 2020

В рамках задачи оптимизации я пытаюсь oop использовать словарь с несколькими ключами (см. UNIT_TASKS). В частности, у меня есть проблема с циклическим просмотром индексов для определения цели и ограничения, поскольку Python возвращает «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])

1 Ответ

0 голосов
/ 27 мая 2020

Пара вещей, которые нужно очистить ... :)

Во-первых, когда вы делаете ограничение, для которого вы получаете ключевую ошибку, это потому, что вы используете там несколько выражений 'for' который будет создавать перекрестное произведение всех элементов ... попробуйте его на стороне.

У вас разреженная матрица значений, поэтому вы должны инициализировать набор только этими значениями и использовать его . Мне также нравится использовать Pyomo's 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}

Здесь это предлагаемая очистка. Обратите внимание, что при этом вы получите несколько «предупреждений», потому что мы используем части ключей вашего словаря для создания наборов, и есть некоторая избыточность.

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))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...