I have an LP with a set of vectors as input parameter containing 2 to 12 elements:
[1,2,0,0,3]
[1,0,0,0,0,1,2]
[5,0,0,1,0,7]
for each node:
model.Nodes = pyo.Set(initialize = range(0, len(nodes))
so basically:
0:[1,2,0,0,3]
1:[1,0,0,0,0,1,2]
2:[5,0,0,1,0,7]
and additionally would like to define a parameter construct as follows:
{0,1,2,3,4}
{0,1,2,3,4,5,6}
{0,1,2,3,4,5}
containing the numbers 0 to the number of components in each vector. Again linked with the nodes:
0:{0,1,2,3,4}
1:{0,1,2,3,4,5,6}
2:{0,1,2,3,4,5}
I don't really know how to deal with the varying size of the different parameters (the number of nodes is also not fix for different problems). As long as the set stays in order it should in general be "linked" sufficiently.
Some variation of the below is probably what you are looking for. It isn't too clear from your post what you want to do with the parameter of integers? I'm assuming you have (a) a list of nodes, (b) some arbitrary length vector of data with each node, and (c) some indexing system (integers) to get at the data.
The piece that I think you are missing is an indexed set
which is a construct to use 1 set (nodes in this case) as an index to a "set of sets". This is more clear in the printout of vecs
below. Of course, you then need an index into the inner set, in this case I used a set of integers sufficiently long to index any of the internal sets.
Lastly, I'm not sure of a better way to use that combination of things to hold data (parameter) other than how I do it below, which is to "flatten out" the membership from the indexed set, and use that to hold the parameters. Note this has the advantage of being a sparse set, less than the size of the full x-product of nodes x elements, but you must use the appropriate set (vecs_flat
) when doing summations, etc.
import pyomo.environ as pyo
some_vectors = {
'SF': [4, 5, 9, 22],
'LA': [6, 0],
'NY': [8,]
}
longest_vec_length = max({len(value) for value in some_vectors.values()})
# make model
m = pyo.ConcreteModel('nodes and vectors')
# SETs
m.nodes = pyo.Set(initialize=some_vectors.keys())
m.elements = pyo.Set(initialize=list(range(longest_vec_length)))
# this is an "indexed set" where the members are indexed by another set..
def vec_init(m, node):
return list(range(len(some_vectors[node])))
m.vecs = pyo.Set(m.nodes, within=m.elements, initialize=vec_init)
m.vecs_flat = pyo.Set(within=m.nodes*m.elements,
initialize=[(n, e) for n in m.nodes for e in m.vecs[n]])
# PARAMs
def data_init(m, node, element):
return some_vectors[node][element]
m.data = pyo.Param(m.vecs_flat, initialize=data_init)
m.pprint()
5 Set Declarations
elements : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 4 : {0, 1, 2, 3}
nodes : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'SF', 'LA', 'NY'}
vecs : Size=3, Index=nodes, Ordered=Insertion
Key : Dimen : Domain : Size : Members
LA : 1 : elements : 2 : {0, 1}
NY : 1 : elements : 1 : {0,}
SF : 1 : elements : 4 : {0, 1, 2, 3}
vecs_flat : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 2 : vecs_flat_domain : 7 : {('SF', 0), ('SF', 1), ('SF', 2), ('SF', 3), ('LA', 0), ('LA', 1), ('NY', 0)}
vecs_flat_domain : Size=1, Index=None, Ordered=True
Key : Dimen : Domain : Size : Members
None : 2 : nodes*elements : 12 : {('SF', 0), ('SF', 1), ('SF', 2), ('SF', 3), ('LA', 0), ('LA', 1), ('LA', 2), ('LA', 3), ('NY', 0), ('NY', 1), ('NY', 2), ('NY', 3)}
1 Param Declarations
data : Size=7, Index=vecs_flat, Domain=Any, Default=None, Mutable=False
Key : Value
('LA', 0) : 6
('LA', 1) : 0
('NY', 0) : 8
('SF', 0) : 4
('SF', 1) : 5
('SF', 2) : 9
('SF', 3) : 22
6 Declarations: nodes elements vecs vecs_flat_domain vecs_flat data