#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. Спасибо за советы. Я буду следовать им.