PYOMO:对抽象模型集的操作

PYOMO: Operation on sets of abstract model

我想对抽象集进行操作。但是没用。

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'对象不可迭代

如果你想以这种方式建模,你应该使用 ConcreteModel 并跳过创建实例行。您的模型和实例将是相同的。

所以也许我应该说说我的动机是什么。我想根据我的 AbstractModel 中的子集 m.C 定义约束,例如

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

根据你告诉 Qi Chen 的内容,如果你使用 AbstractModel 公式,这里有一个代码的工作示例。对于抽象模型,问题在于它只是延迟将模型初始化为具体模型。因此,它 知道 将使用什么集合,但在您初始化它之前它无法知道其内容。例如,它知道 param p 使用集合 s 作为域,但是无法知道 p 的值和 s 的元素是什么.

也就是说,您要做的是从单元化集 m.am.b 填充您的 m.C 集。我支持 Qi Chen,ConcreteModels 是您最好的选择。但是,这里有三种使用 AbstractModels 的方法。

选项 1 在 初始化您的模型后,您在此处填充 m.Ccreate_instance() 基本上是通过填充将您的抽象模型变成具体模型。它returns对应ConcreteModel。这样,您就有了足够的 AbstractModel(请记住,AbstractModel 不需要填充集,只需要知道正在使用哪些集)。因此,以下代码在 ConcreteModel 初始化后填充 m.C 集:

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 listset 初始化。因此,在定义模型的集合时,首先创建集合(这次使用 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 class 作为空白模型来放入数据时。如果你想这样使用它,恕我直言,这是使用 AbstractModel 的唯一充分理由,那么您应该考虑阅读此页面:https://pyomo.readthedocs.io/en/latest/working_abstractmodels/data/index.html and then, skip to this page: https://pyomo.readthedocs.io/en/latest/working_abstractmodels/data/raw_dicts.html,其中向您展示了如何从数据中填充空白 AbstractModel 的示例,在这种情况下,数据以 Python 字典的形式提供。他们说,在我向您展示的第一个 link 中,这不是向模型提供数据的唯一方法,但它有一个完整的工作示例。

主要想法是按如下方式构建您的项目:

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)

还有其他方法可以将数据导入您的模型,但这只是为了向您展示一个简单的示例。