问题
I want to operate on abstract sets. But it dosen't work.
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)
TypeError: 'NoneType' object is not iterable
回答1:
Based on what you told to Qi Chen, here is a working example of your code if you used the AbstractModel formulation. The thing, with abstract models, is that it doesn't do much more than delay the iniatilazion of your model into a concrete model. So, it knows what sets is going to be used, but it has no way of knowing its content until you initialize it. For example, it knows that param p
use the set s
as a domain, but there is no way of knowing what are the values of p
and the elements of s
.
That being said, what you are trying to do is populationg your m.C
set from unititialized sets m.a
and m.b
. I stand with Qi Chen, ConcreteModels are just the best option for you. However, here are three ways of using AbstractModels.
Option 1
Here you populate your m.C
set after initializing your model. create_instance()
basically turn your abstract model into a concrete model, by populating it. It returns the corresponding ConcreteModel
. This way, you have a sufficient AbstractModel
(remember, AbstractModel
doesn't need to have populated sets, only to know which sets are being used). So, the following code populates your m.C
set in a ConcreteModel
, after it has been initialized:
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)
Option 2
Here, since you seem to know what are the content of your sets, you can define it before even making your AbstractModel
. This is just a reminder that each set is usually initalized with a Python list
or set
. So, just create your sets first (this time using Python's built-in sets), at the moment of the definition of your model' Sets. Here is the code:
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)
But, again, since your sets are already defined, what I just showed you is just a fancier, harder way of creating a ConcreteModel
, since basically, it does the same thing, that is to create a model with populated values and sets.
Option 3 Using the way of Option 1 and Option 2, you will not be able to change the elements of your sets afterward. For example, the following code
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)
will still prints
1
2
even if we tried to print
5
6
That's a major inconvenient, especially when we try to use the AbstractModel
class as a blank model to put data in. If you want to use it this way, and IMHO, this is the only good reason to use an AbstractModel
, then you should consider having a read on this page: 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 , where it shows you an example of how to populate a blank AbstractModel
from data, in this case, the data is provided in form of a Python dictionary. They say, in the first link I showed you, that it is not the only way of providing data to the model, but it has a complete working example in there.
The main idea would be to build your project as following:
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)
There exist other ways of importing data to your model, but this is just to show you an easy example.
回答2:
If you want to model that way, you should use ConcreteModel and skip needing the create instance line. Your model and instance would be the same.
回答3:
So maybe i should say what is my motivation. I want to define a Constraint based on the subset m.C inside my AbstractModel like
def rule_name(m, c):
return something depends on c
m.rule_name = Constraint(m.C, rule=rule_name)
来源:https://stackoverflow.com/questions/55552809/pyomo-operation-on-sets-of-abstract-model