PYOMO: работа с наборами абстрактной модели

#python #model #set #abstract #pyomo

#python #Модель #набор #аннотация #pyomo

Вопрос:

Я хочу работать с абстрактными наборами. Но это не работает.

 from pyomo.environ import *
m = AbstractModel()
m.A = Set(initialize=[0,1,2])
m.B = Set(initialize=[0])
m.C = m.A-m.B
instance = m.create_instance()
for c in instance.C.value:
    print(c)
  

Ошибка типа: объект ‘NoneType’ не может быть повторен

Ответ №1:

Основываясь на том, что вы рассказали Ци Чену, вот рабочий пример вашего кода, если вы использовали формулировку AbstractModel. Дело в том, что с абстрактными моделями это не намного больше, чем задержка преобразования вашей модели в конкретную модель. Итак, он знает, какие наборы будут использоваться, но у него нет возможности узнать его содержимое, пока вы его не инициализируете. Например, он знает, что param p использует set s в качестве домена, но нет способа узнать, каковы значения p и элементы s .

При этом то, что вы пытаетесь сделать, это заполнить ваш m.C набор из унифицированных наборов m.a и m.b . Я согласен с Ци Ченом, ConcreteModels — это просто лучший вариант для вас. Однако вот три способа использования абстрактных моделей.

Вариант 1 Здесь вы заполняете свой m.C набор после инициализации вашей модели. create_instance() в основном превратите свою абстрактную модель в конкретную модель, заполнив ее. Он возвращает соответствующее ConcreteModel . Таким образом, у вас есть достаточный AbstractModel (помните, AbstractModel не обязательно иметь заполненные наборы, только знать, какие наборы используются). Итак, следующий код заполняет ваш m.C набор в ConcreteModel после его инициализации:

 m = AbstractModel()
m.A = Set(initialize=[0, 1, 2])
m.B = Set(initialize=[0])
m.C = Set()
instance = m.create_instance() # Here instance becomes your ConcreteModel
instance.C = instance.A - instance.B # The equivalent of line "m.C = m.A-m.B" but with your ConcreteModel
for c in instance.C:
    print(c)
  

Вариант 2
Здесь, поскольку вы, кажется, знаете, каково содержимое ваших наборов, вы можете определить его еще до создания своего AbstractModel . Это просто напоминание о том, что каждый набор обычно инициализируется с помощью Python list или set . Итак, сначала просто создайте свои наборы (на этот раз с использованием встроенных наборов Python) в момент определения наборов вашей модели. Вот код:

 from pyomo.environ import *
# Define the content of your model' Sets using built-in set
A = {0,1,2}
B = {0}
C = A - B

# You have all you need now to continue
m = AbstractModel()
m.A = Set(initialize=A)
m.B = Set(initialize=B)
m.C = Set(initialize=C)
instance = m.create_instance()
for c in instance.C:
    print(c)
  

Но, опять же, поскольку ваши наборы уже определены, то, что я только что показал вам, — это просто более причудливый и сложный способ создания ConcreteModel , поскольку, по сути, он делает то же самое, то есть создает модель с заполненными значениями и наборами.

Вариант 3 Используя способ варианта 1 и варианта 2, вы не сможете впоследствии изменять элементы своих наборов. Например, следующий код

 from pyomo.environ import *
A = {0, 1, 2}
B = {0}
C = A - B
m = AbstractModel()
m.A = Set(initialize=A)
m.B = Set(initialize=B)
m.C = Set(initialize=C)

# Pyomo's Sets are initialized, now, let's try to change their value:
A = {4, 5, 6}
B = {4}

instance = m.create_instance()
for c in instance.C:
    print(c)
  

все равно будет выводить

 1
2 
  

даже если мы попытаемся напечатать

 5
6
  

Это очень неудобно, особенно когда мы пытаемся использовать AbstractModel класс в качестве пустой модели для ввода данных. Если вы хотите использовать его таким образом, и, ИМХО, это единственная веская причина для использования AbstractModel , тогда вам следует рассмотреть возможность чтения на этой странице:https://pyomo.readthedocs.io/en/latest/working_abstractmodels/data/index.html и затем перейдите на эту страницу:https://pyomo.readthedocs.io/en/latest/working_abstractmodels/data/raw_dicts.html , где показан пример того, как заполнить пробел AbstractModel из данных, в данном случае данные предоставляются в виде словаря Python. Говорят, в первой ссылке я показал вам, что это не единственный способ предоставления данных модели, но там есть полный рабочий пример.

Основная идея состояла бы в том, чтобы построить ваш проект следующим образом:

 from pyomo.environ import *
A = {0, 1, 2}
B = {0}

m = AbstractModel()
m.A = Set()
m.B = Set()
m.C = Set()

# ...

# Let's suppose you have completed your AbstractModel here (Params, Vars, Constraints and so on). 
# This is the part where you put your data into a dictionary. 
data = {None: {
    'A': {None: A},
    'B': {None: B},
    'C': {None: A - B}
}}

# And here is the part where you initialize your model:
instance = m.create_instance(data)
for c in instance.C:
    print(c)
  

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

Комментарии:

1. Спасибо за полезный и подробный ответ. В частности, последний раздел хорошо решил проблему.

Ответ №2:

Если вы хотите моделировать таким образом, вам следует использовать ConcreteModel и пропустить строку create instance. Ваша модель и экземпляр будут одинаковыми.

Комментарии:

1. Спасибо за ответ. Вы правы, это работает с ConcreteModel. Но мне нужно моделировать с подмножествами, используя AbstactModels.

2. Подмножества все равно должны работать с ConcreteModel. Есть ли причина, по которой вам нужно использовать Abstract?

3. Я знаю, что подмножества работают с конкретными моделями. Но мне нужно работать с абстрактными моделями.

Ответ №3:

Так что, может быть, я должен сказать, какова моя мотивация. Я хочу определить ограничение, основанное на подмножестве m.C внутри моей AbstractModel, например

 def rule_name(m, c):
    return something depends on c
m.rule_name = Constraint(m.C, rule=rule_name)
  

Комментарии:

1. Ишь, это звучит как отдельный вопрос. Вам следует рассмотреть возможность открытия нового для этого, поскольку построение вашего ограничения — это абсолютно не та же проблема, что и ваша ошибка ‘NoneType’. В буквальном смысле это похоже на две отдельные проблемы. Попробуйте исправить первый и вернитесь к нам с вашим новым вопросом, если вам все еще нужно. Кстати, я предлагаю вам избегать комментариев в местах «ответов» здесь, моды переполнения стека очень строги в этом отношении, поскольку это не веб-сайт в стиле форума, а сайт вопросов и ответов.

2. Тем не менее, это похоже на деталь, которую нужно добавить к вашему вопросу в любом случае. Чтобы вы могли отредактировать его. Просто будьте осторожны, здесь ваш первоначальный вопрос был о вашей нетипичной ошибке, поэтому было бы неправильно менять его на «Как я могу создать свое ограничение». Но я согласен, это может быть уместной информацией. Хотя, легко догадаться, что вы хотите добавить ограничения и другие важные элементы в свою модель, такие как переменные, целевые функции, параметры и так далее. Просто будьте осторожны, так как этот веб-сайт скорее увидит много маленьких вопросов к большой проблеме, чем много маленьких проблем в большом вопросе. Будьте осторожны

3. Спасибо за советы. Я буду следовать им.