Generating a 'sequence of dicts' for scipy.optimize.minimize
Question:
I’m using scipy.optimize.minimize with constraints. The example in the documentation ( at http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.optimize.minimize.html ) uses for constraints:
cons = ({'type': 'ineq', 'fun': lambda x: x[0] - 2 * x[1] + 2},
{'type': 'ineq', 'fun': lambda x: -x[0] - 2 * x[1] + 6},
{'type': 'ineq', 'fun': lambda x: -x[0] + 2 * x[1] + 2})
I’d like to do something similar but generate the elements of this sequence in a loop, but I’m having trouble.
I’ve tried treating cons as a tuple, an example of the same form as above:
cons = (,)
for i in range(4):
cons += ({'type': 'ineq', 'fun': lambda x: x[0] - 2 * x[1] + i})
but I get TypeError: unsupported operand type(s) for +=: 'dict' and 'dict'
.
I also tried using str
and eval
:
cons = (str({'type': 'ineq', 'fun': lambda x: x[0] - 2 * x[1]}))
for i in range(3):
cons += (str({'type': 'ineq', 'fun': lambda x: x[0] - 2 * x[1] + i + 1}))
cons = eval(cons)
but that didn’t work either, I get something like
cons = eval(cons)
File "<string>", line 1
{'fun': <function <lambda> at 0x062964F0>, 'type': 'eq'}{'fun': <function <lambda> at 0x062964F0>, 'type': 'eq'}{'fun': <function <lambda> at 0x062964F0>, 'type': 'eq'}{'fun': <function <lambda> at 0x062964F0>, 'type': 'eq'}
^
SyntaxError: invalid syntax
Answers:
Instead of adding a dict (parentheses are not doing anything here):
for i in range(4):
cons += ({'type': 'ineq', 'fun': lambda x: x[0] - 2 * x[1] + i})
add a tuple, adding a comma after the dict:
for i in range(4):
cons += ({'type': 'ineq', 'fun': lambda x: x[0] - 2 * x[1] + i},)
>>> cons
({'fun': <function <lambda> at 0xb746de2c>, 'type': 'ineq'}, {'fun': <function <lambda> at 0xb747656c>, 'type': 'ineq'}, {'fun': <function <lambda> at 0xb74765a4>, 'type': 'ineq'}, {'fun': <function <lambda> at 0xb74765dc>, 'type': 'ineq'})
—
Note that as @Jivan indicates in its answer, you should use lists for this kind of job.
Once you have created a tuple, you cannot modify the number of the elements in there, or their order.
You can do that way:
cons = []
for i in range(4):
cons.append({'type': 'ineq', 'fun': lambda x: x[0] - 2 * x[1] + i})
Which will give you a list of dictionaries. Once your list is done, if you want to change it into a tuple, you can do:
cons = tuple(cons)
The result:
>>> cons
({'fun': <function <lambda> at 0x106e2cb18>, 'type': 'ineq'},
{'fun': <function <lambda> at 0x106e2cf50>, 'type': 'ineq'},
{'fun': <function <lambda> at 0x106e335f0>, 'type': 'ineq'},
{'fun': <function <lambda> at 0x106e33cf8>, 'type': 'ineq'})
—
Note that Raymond Hettinger himself said not so long ago:
Generally, lists are for looping; tuples for structs. Lists are
homogeneous; tuples heterogeneous.Lists for variable length.
So in your case, you might want to keep the list unless a tuple is needed by some third-part module.
This is an older question, but both of the proposed solutions seem wrong. Or am I missing something?
def generate_constraints_wrong(n_params):
cons = []
for i in range(n_params):
cons.append({'type': 'ineq', 'fun': lambda x: x[i]})
return tuple(cons)
def generate_constraints_wrong2(n_params):
cons = tuple()
for i in range(n_params):
cons += ({'type': 'ineq', 'fun': lambda x: x[i]},)
return cons
def generate_constraints_right(n_params):
# let's create a function generator that uses closure to pass i to the generated function
def wrapper_fun(x, i):
def fun(x):
return x[i]
return fun
cons = []
for i in range(n_params):
f = wrapper_fun(x, i)
cons.append({'type': 'ineq', 'fun': f})
return tuple(cons)
# verify the generated functions
n_params = 3
x = [1,10, 100]
cons1 = generate_constraints_wrong(n_params)
cons2 = generate_constraints_wrong2(n_params)
cons3 = generate_constraints_right(n_params)
print(cons1[0]['fun'](x)) # this should be 1 but instead we end up modifying all of our lambda objects to have the last i
print(cons1[1]['fun'](x))
print(cons2[0]['fun'](x))
print(cons2[1]['fun'](x))
print(cons3[0]['fun'](x))
print(cons3[1]['fun'](x))
prints:
100
100
100
100
1
10
The problem is that the closure of each lambda points to the object i, rather than to the value the object i had at a particular loop iteration. For more details see:
Python lambda closure scoping
I’m using scipy.optimize.minimize with constraints. The example in the documentation ( at http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.optimize.minimize.html ) uses for constraints:
cons = ({'type': 'ineq', 'fun': lambda x: x[0] - 2 * x[1] + 2},
{'type': 'ineq', 'fun': lambda x: -x[0] - 2 * x[1] + 6},
{'type': 'ineq', 'fun': lambda x: -x[0] + 2 * x[1] + 2})
I’d like to do something similar but generate the elements of this sequence in a loop, but I’m having trouble.
I’ve tried treating cons as a tuple, an example of the same form as above:
cons = (,)
for i in range(4):
cons += ({'type': 'ineq', 'fun': lambda x: x[0] - 2 * x[1] + i})
but I get TypeError: unsupported operand type(s) for +=: 'dict' and 'dict'
.
I also tried using str
and eval
:
cons = (str({'type': 'ineq', 'fun': lambda x: x[0] - 2 * x[1]}))
for i in range(3):
cons += (str({'type': 'ineq', 'fun': lambda x: x[0] - 2 * x[1] + i + 1}))
cons = eval(cons)
but that didn’t work either, I get something like
cons = eval(cons)
File "<string>", line 1
{'fun': <function <lambda> at 0x062964F0>, 'type': 'eq'}{'fun': <function <lambda> at 0x062964F0>, 'type': 'eq'}{'fun': <function <lambda> at 0x062964F0>, 'type': 'eq'}{'fun': <function <lambda> at 0x062964F0>, 'type': 'eq'}
^
SyntaxError: invalid syntax
Instead of adding a dict (parentheses are not doing anything here):
for i in range(4):
cons += ({'type': 'ineq', 'fun': lambda x: x[0] - 2 * x[1] + i})
add a tuple, adding a comma after the dict:
for i in range(4):
cons += ({'type': 'ineq', 'fun': lambda x: x[0] - 2 * x[1] + i},)
>>> cons
({'fun': <function <lambda> at 0xb746de2c>, 'type': 'ineq'}, {'fun': <function <lambda> at 0xb747656c>, 'type': 'ineq'}, {'fun': <function <lambda> at 0xb74765a4>, 'type': 'ineq'}, {'fun': <function <lambda> at 0xb74765dc>, 'type': 'ineq'})
—
Note that as @Jivan indicates in its answer, you should use lists for this kind of job.
Once you have created a tuple, you cannot modify the number of the elements in there, or their order.
You can do that way:
cons = []
for i in range(4):
cons.append({'type': 'ineq', 'fun': lambda x: x[0] - 2 * x[1] + i})
Which will give you a list of dictionaries. Once your list is done, if you want to change it into a tuple, you can do:
cons = tuple(cons)
The result:
>>> cons
({'fun': <function <lambda> at 0x106e2cb18>, 'type': 'ineq'},
{'fun': <function <lambda> at 0x106e2cf50>, 'type': 'ineq'},
{'fun': <function <lambda> at 0x106e335f0>, 'type': 'ineq'},
{'fun': <function <lambda> at 0x106e33cf8>, 'type': 'ineq'})
—
Note that Raymond Hettinger himself said not so long ago:
Generally, lists are for looping; tuples for structs. Lists are
homogeneous; tuples heterogeneous.Lists for variable length.
So in your case, you might want to keep the list unless a tuple is needed by some third-part module.
This is an older question, but both of the proposed solutions seem wrong. Or am I missing something?
def generate_constraints_wrong(n_params):
cons = []
for i in range(n_params):
cons.append({'type': 'ineq', 'fun': lambda x: x[i]})
return tuple(cons)
def generate_constraints_wrong2(n_params):
cons = tuple()
for i in range(n_params):
cons += ({'type': 'ineq', 'fun': lambda x: x[i]},)
return cons
def generate_constraints_right(n_params):
# let's create a function generator that uses closure to pass i to the generated function
def wrapper_fun(x, i):
def fun(x):
return x[i]
return fun
cons = []
for i in range(n_params):
f = wrapper_fun(x, i)
cons.append({'type': 'ineq', 'fun': f})
return tuple(cons)
# verify the generated functions
n_params = 3
x = [1,10, 100]
cons1 = generate_constraints_wrong(n_params)
cons2 = generate_constraints_wrong2(n_params)
cons3 = generate_constraints_right(n_params)
print(cons1[0]['fun'](x)) # this should be 1 but instead we end up modifying all of our lambda objects to have the last i
print(cons1[1]['fun'](x))
print(cons2[0]['fun'](x))
print(cons2[1]['fun'](x))
print(cons3[0]['fun'](x))
print(cons3[1]['fun'](x))
prints:
100
100
100
100
1
10
The problem is that the closure of each lambda points to the object i, rather than to the value the object i had at a particular loop iteration. For more details see:
Python lambda closure scoping