Adding variables by a cross-product in Pyomo - pyomo

I am trying to create a ConcreteModel using Pyomo. I have a list including the indices of the variable x_ij.
Xindex = [(619, 0), (620, 0), (621, 0), (622, 0), (623, 0), (624, 0), (625, 0), (626, 0), (627, 0), (628, 0), (619, 1), (620, 1), (621, 1), (622, 1), (623, 1), (624, 1), (625, 1), (626, 1), (627, 1), (628, 1), (1098, 2), (1099, 2), (1100, 2), (1101, 2), (1102, 2), (1103, 2), (1104, 2), (1105, 2), (1106, 2), (1107, 2), (1098, 3), (1099, 3), (1100, 3), (1101, 3), (1102, 3), (1103, 3), (1104, 3), (1105, 3), (1106, 3), (1107, 3), (619, 4), (620, 4), (621, 4), (622, 4), (623, 4), (624, 4), (625, 4), (626, 4), (627, 4), (628, 4), (1098, 5), (1099, 5), (1100, 5), (1101, 5), (1102, 5), (1103, 5), (1104, 5), (1105, 5), (1106, 5), (1107, 5), (1098, 6), (1099, 6), (1100, 6), (1101, 6), (1102, 6), (1103, 6), (1104, 6), (1105, 6), (1106, 6), (1107, 6), (1098, 7), (1099, 7), (1100, 7), (1101, 7), (1102, 7), (1103, 7), (1104, 7), (1105, 7), (1106, 7), (1107, 7), (1098, 8), (1099, 8), (1100, 8), (1101, 8), (1102, 8), (1103, 8), (1104, 8), (1105, 8), (1106, 8), (1107, 8), (1098, 9), (1099, 9), (1100, 9), (1101, 9), (1102, 9), (1103, 9), (1104, 9), (1105, 9), (1106, 9), (1107, 9), (1098, 10), (1099, 10), (1100, 10), (1101, 10), (1102, 10), (1103, 10), (1104, 10), (1105, 10), (1106, 10), (1107, 10), (1098, 11), (1099, 11), (1100, 11), (1101, 11), (1102, 11), (1103, 11), (1104, 11), (1105, 11), (1106, 11), (1107, 11), (1098, 12), (1099, 12), (1100, 12), (1101, 12), (1102, 12), (1103, 12), (1104, 12), (1105, 12), (1106, 12), (1107, 12)]
The first element of each tuple corresponds to an i and second one to a j. Using this list, I would like to add my variables to the model m. But, I do not see a straightforward method in the Pyomo User Manual. I tried the following and did not work.
m.Xindexi = Set(initialize=[i[0] for i in Xindex])
m.Xindexj = Set(initialize=[j[1] for j in Xindex])
m.Xindex = Set(within = m.Xindexi*m.Xindexj)
m.x = Var(m.Xindexi, m.Xindexj,domain=NonNegativeReals)
Isn't there a way to do this like a dictionary creation (similar to the one Gurobi's Python uses)? For example:
m.x = {}
for i in Xindex:
m.x[i[0],i[1]] = Var(domain=NonNegativeReals)
Based on the accepted answer, this is what I have done to resolve the issue. Adding it here for future reference...
m.Xindexi = Set(initialize=set([i[0] for i in Xindex]))
m.Xindexj = Set(initialize=set([j[1] for j in Xindex]))
m.Xindex = Set(within = m.Xindexi*m.Xindexj,
initialize=Xindex)
m.x = Var(m.Xindex,domain=NonNegativeReals)

There are a bunch of ways to do this. The basic idea here is to make a sparse set of combinations of (i, j). You can either strictly enumerate that sparse set or if for other parts of your model, you need a fuller set of (i, j) and you only need this sparse set for some of the variables/parameters, you can construct it on-the-fly from data or from any set rules you gin up.
Here are some examples:
# pyomo set patterns
from pyomo.environ import *
m = ConcreteModel()
# initialize two sets from data
I_vals = {1, 5, 9}
m.I = Set(initialize=I_vals)
m.J = Set(initialize={2, 4, 88}) # either way works
# crossed set from list of known combinations
my_sparse_indices = {(1, 4), (1, 88), (5, 4)}
m.IJ = Set(within=m.I * m.J, initialize=my_sparse_indices)
# make a variable X, indexed by this sparse set
m.X = Var(m.IJ, domain=NonNegativeReals)
# make a parameter from the same sparse indices
limit_dict = {(1, 4): 10, (1, 88): 20, (5,4): 30}
m.lim = Param(m.IJ, initialize=limit_dict)
m.pprint()
#############
m2 = ConcreteModel()
m2.I = Set(initialize=range(4))
m2.J = Set(initialize=range(3))
# make full x-product
m2.IJ = Set(within=m2.I * m2.J,
initialize=[(i, j) for i in m2.I for j in m2.J])
# make a sparse set from selected values
selected_vals = [(2,1), (1,1)]
m2.IJ_selected = Set(within=m2.IJ, initialize=selected_vals)
# make a sparse set by excluding prohibited values
prohibited={(2,2), (3,1), (0,0)}
IJ_without_prohibited = {(i, j) for i in m2.I
for j in m2.J
if (i, j) not in prohibited}
m2.IJ_without_prohibited = Set(within=m2.IJ, initialize=IJ_without_prohibited)
m2.pprint()
The output for these is:
4 Set Declarations
I : Dim=0, Dimen=1, Size=3, Domain=None, Ordered=False, Bounds=(1, 9)
[1, 5, 9]
IJ : Dim=0, Dimen=2, Size=3, Domain=IJ_domain, Ordered=False, Bounds=None
[(1, 4), (1, 88), (5, 4)]
IJ_domain : Dim=0, Dimen=2, Size=9, Domain=None, Ordered=False, Bounds=None
Virtual
J : Dim=0, Dimen=1, Size=3, Domain=None, Ordered=False, Bounds=(2, 88)
[2, 4, 88]
1 Param Declarations
lim : Size=3, Index=IJ, Domain=Any, Default=None, Mutable=False
Key : Value
(1, 4) : 10
(1, 88) : 20
(5, 4) : 30
1 Var Declarations
X : Size=3, Index=IJ
Key : Lower : Value : Upper : Fixed : Stale : Domain
(1, 4) : 0 : None : None : False : True : NonNegativeReals
(1, 88) : 0 : None : None : False : True : NonNegativeReals
(5, 4) : 0 : None : None : False : True : NonNegativeReals
6 Declarations: I J IJ_domain IJ X lim
Second model:
6 Set Declarations
I : Dim=0, Dimen=1, Size=4, Domain=None, Ordered=False, Bounds=(0, 3)
[0, 1, 2, 3]
IJ : Dim=0, Dimen=2, Size=12, Domain=IJ_domain, Ordered=False, Bounds=None
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2), (3, 0), (3, 1), (3, 2)]
IJ_domain : Dim=0, Dimen=2, Size=12, Domain=None, Ordered=False, Bounds=None
Virtual
IJ_selected : Dim=0, Dimen=2, Size=2, Domain=IJ, Ordered=False, Bounds=None
[(1, 1), (2, 1)]
IJ_without_prohibited : Dim=0, Dimen=2, Size=9, Domain=IJ, Ordered=False, Bounds=None
[(0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (3, 0), (3, 2)]
J : Dim=0, Dimen=1, Size=3, Domain=None, Ordered=False, Bounds=(0, 2)
[0, 1, 2]
6 Declarations: I J IJ_domain IJ IJ_selected IJ_without_prohibited
[Finished in 2.6s]

Related

Counterintuitive behavior in nested list comprehensions

I'm experiencing some counterintuitive behavior on nested list comprehensions
data = 'what is wrong with the nested iterator'
[ (u, i) for i in xrange(0,len(u),1) for u in [ v for v in data.split(' ')]]
what I was hoping is that the nested loop would iterate over the range of characters for each word in the first loop. What is happening however is that it seems to be looping the string array first, and iterate on the last value of u:
[('what', 0), ('is', 0), ('wrong', 0), ('with', 0), ('the', 0), ('nested', 0), ('iterator', 0), ('what', 1), ('is', 1), ('wrong', 1), ('with', 1), ('the', 1), ('nested', 1), ('iterator', 1), ('what', 2), ('is', 2), ('wrong', 2), ('with', 2), ('the', 2), ('nested', 2), ('iterator', 2), ('what', 3), ('is', 3), ('wrong', 3), ('with', 3), ('the', 3), ('nested', 3), ('iterator', 3), ('what', 4), ('is', 4), ('wrong', 4), ('with', 4), ('the', 4), ('nested', 4), ('iterator', 4), ('what', 5), ('is', 5), ('wrong', 5), ('with', 5), ('the', 5), ('nested', 5), ('iterator', 5), ('what', 6), ('is', 6), ('wrong', 6), ('with', 6), ('the', 6), ('nested', 6), ('iterator', 6), ('what', 7), ('is', 7), ('wrong', 7), ('with', 7), ('the', 7), ('nested', 7), ('iterator', 7)]
To understand these nested type of list comprehensions you could imagine them as two nested for-loops like this:
result = []
for i in xrange(0,len(u),1):
for u in [ v for v in data.split(' '):
result.append((u, i))
with the order of both loops preserved. From this it should be pretty clear that you need to switch their positions in order to get the desired result.

Replacing the values of `edgelist` with those of a `labels` dictionary

I am new to both Python and NetworkX. I have a square, regular graph G with NxN nodes (a lattice). Such nodes are labelled by means of a dict (see code below). Now I want the edgelist to return the start and endpoint of each edge not by referring to the node coordinates but to the label the node has been given.
Example:
N = 3
G=nx.grid_2d_graph(N,N)
labels = dict( ((i, j), i + (N-1-j) * N ) for i, j in G.nodes() )
#This gives nodes an attribute ID that is identical to their labels
for (i,j) in labels:
G.node[(i,j)] ['ID']= labels[(i,j)]
edgelist=G.edges() #This gives the list of all edges in the format (Start XY, End XY)
If I run it with N=3 I get:
In [14]: labels
Out[14]: {(0, 0): 6, (0, 1): 3, (0, 2): 0, (1, 0): 7, (1, 1): 4, (1, 2): 1, (2, 0): 8, (2, 1): 5, (2, 2): 2}
This scheme labels the upper left node as 0, with node (N-1)th being placed in the lower right corner. And this is what I want. Now the problem with edgelist:
In [15]: edgelist
Out [15]: [((0, 1), (0, 0)), ((0, 1), (1, 1)), ((0, 1), (0, 2)), ((1, 2), (1, 1)), ((1, 2), (0, 2)), ((1, 2), (2, 2)), ((0, 0), (1, 0)), ((2, 1), (2, 0)), ((2, 1), (1, 1)), ((2, 1), (2, 2)), ((1, 1), (1, 0)), ((2, 0), (1, 0))]
I tried to solve the problem with these lines (inspiration from here: Replace items in a list using a dictionary):
allKeys = {}
for subdict in (labels):
allKeys.update(subdict)
new_edgelist = [allKeys[edge] for edge in edgelist]
but I get this wonderful thing which enlightens my monday:
TypeError: cannot convert dictionary update sequence element #0 to a sequence
To sum up, I want to be able to replace the elements of the edgelist list with the values of the labels dictionary so that, say, the edge from ((2,0),(1,0)) (which correspond to nodes 8 and 7) is returned (8,7). Endless thanks!
I believe what you are looking for is simply nx.relabel_nodes(G,labels,False) here is the documentation
Here is the output when I printed the nodes of G before and after calling the relabel nodes function.
# Before relabel_nodes
[(0, 1), (1, 0), (0, 0), (1, 1)]
# After relabel_nodes
[0, 1, 2, 3]
After doing this, the edge labels automatically becomes what you expect.
# Edges before relabelling nodes
[((0, 1), (0, 0)), ((0, 1), (1, 1)), ((1, 0), (0, 0)), ((1, 0), (1, 1))]
# Edges after relabelling nodes
[(0, 1), (0, 2), (1, 3), (2, 3)]
Also, I have replied to this question in the chat that you created but it seems you were not notified.

convert a list of x and y coordinates into multistring

I have a set of x and y coordinates as follows:
x = (1,1,2,2,3,4)
y= (0,1,2,3,4,5)
What is the best way of going about transforming this list into a multiline string format, e.g:
x_y = [((1,0)(1,1)),((1,1)(2,2)),((2,2)(2,3)),((2,3)(3,4)),((3,4)(4,5))]
You can pair up the elements of x and y with zip():
>>> x = (1,1,2,2,3,4)
>>> y = (0,1,2,3,4,5)
>>> xy = zip(x, y)
>>> xy
[(1, 0), (1, 1), (2, 2), (2, 3), (3, 4), (4, 5)]
Then you can rearrange this into the kind of list in your example with a list comprehension:
>>> x_y = [(xy[i], xy[i+1]) for i in xrange(len(xy)-1)]
>>> x_y
[((1, 0), (1, 1)), ((1, 1), (2, 2)), ((2, 2), (2, 3)), ((2, 3), (3, 4)), ((3, 4), (4, 5))]
If you don't care about efficiency, the second part could also be written as:
>>> x_y = zip(xy, xy[1:])

Ocaml: function cannot return complete resulting list

I am working on the question from this site, one of the question is asking to return Goldbach conjecture in a given range.
My answer works fine for small ranges, but for large range (e.g. 2 - 2000), it only return part of the solution like the following:
[(2, (2, 0)); (4, (2, 2)); (6, (3, 3)); (8, (3, 5)); (10, (3, 7));
(12, (5, 7)); (14, (3, 11)); (16, (3, 13)); (18, (5, 13)); (20, (3, 17));
(22, (3, 19)); (24, (5, 19)); (26, (3, 23)); (28, (5, 23)); (30, (7, 23));
(32, (3, 29)); (34, (3, 31)); (36, (5, 31)); (38, (7, 31)); (40, (3, 37));
(42, (5, 37)); (44, (3, 41)); (46, (3, 43)); (48, (5, 43)); (50, (3, 47));
(52, (5, 47)); (54, (7, 47)); (56, (3, 53)); (58, (5, 53)); (60, (7, 53));
(62, (3, 59)); (64, (3, 61)); (66, (5, 61)); (68, (7, 61)); (70, (3, 67));
(72, (5, 67)); (74, (3, 71)); (76, (3, 73)); (78, (5, 73)); (80, (7, 73));
(82, (3, 79)); (84, (5, 79)); (86, (3, 83)); (88, (5, 83)); (90, (7, 83));
(92, (3, 89)); (94, (5, 89)); (96, (7, 89)); (98, (9, 89)); (100, (3, 97));
(102, (5, 97)); (104, (3, 101)); (106, (3, 103)); (108, (5, 103));
(110, (3, 107)); (112, (3, 109)); (114, (5, 109)); (116, (3, 113));
(118, (5, 113)); (120, (7, ...)); ...]
I tried to use the solution provided by the website, but same thing happens. I wonder if there is a way to return the complete list of solutions.
Thanks!
I think you mean that the toplevel is only showing a prefix of the list. You can solve this by writing your own code to show the list.
Something like this would work:
let p (a, (b, c)) = Printf.printf "(%d, (%d, %d))\n" a b c
let printMyList l = List.iter p l
This is because the toplevel doesn't show values that are too long. You can change this lenght by using a pragma:
#print_length n;;
The other solution, perhaps better, is to write your own printing function. ;)

Flattening a complex list of tuples

I have a list of tuples, with nested tuples and lists, that looks like the list bellow:
a= [('Maria', [1, [2, {'teste': (2, 1.0)}]]),
('Lisa ', [2, [4, {'field': (4, 0.75), 'bola': (4, 0.25)}]]),
('John ', [4, [5, {'engine': (5, 0.2), 'wheel': (5, 0.4), 'wheels': (5, 0.2)}]]),
('Tracy ', [4, [6, {'pizza': (6, 0.16), 'fish': (6, 0.1), 'animals': (6, 0.1)}]])]
I want to flat out this list to look like:
a.modified = ('Maria', 1, 2, {'teste': (2, 1.0)}]]),
('Lisa ', 2, 4, {'field': (4, 0.75), 'bola': (4, 0.25)}]]),
('John ', 4, 5, {'engine': (5, 0.2), 'wheel': (5, 0.4), 'wheels': (5, 0.2)}]]),
('Tracy ', 4, 6, {'pizza': (6, 0.16), 'fish': (6, 0.1), 'animals': (6, 0.1}]])])
I have tried doing it step by step, using:
a2=[item for sublist in a for item in sublist]
and
a2 = list(itertools.chain.from_iterable(a))
and also:
a2 = list(item for sublist in a for item in sublist)
Nothing seems to work. I know this is too basic, but any tips on how to solve this would be really helpful. Thanks!
So it appears you have a list of tuples and linked-list-like structures. Whenever operating on linked-lists, you should think, recursion.
def flatten(items):
from itertools import chain
def flatten_link(link):
if isinstance(link, list):
yield link[0]
for item in flatten_link(link[1]):
yield item
elif link is not None:
yield link
return list(tuple(chain(item[:1], flatten_link(item[1]))) for item in items)
a = [
('Maria', [1, [2, {'teste': (2, 1.0)}]]),
('Lisa ', [2, [4, {'field': (4, 0.75), 'bola': (4, 0.25)}]]),
('John ', [4, [5, {'engine': (5, 0.2), 'wheel': (5, 0.4), 'wheels': (5, 0.2)}]]),
('Tracy', [4, [6, {'pizza': (6, 0.16), 'fish': (6, 0.1), 'animals': (6, 0.1)}]]),
]
print(flatten(a))
Which yields:
[
('Maria', 1, 2, {'teste': (2, 1.0)}),
('Lisa ', 2, 4, {'bola': (4, 0.25), 'field': (4, 0.75)}),
('John ', 4, 5, {'engine': (5, 0.2), 'wheel': (5, 0.4), 'wheels': (5, 0.2)}),
('Tracy', 4, 6, {'fish': (6, 0.1), 'animals': (6, 0.1), 'pizza': (6, 0.16)})
]