Looks like I need to quote the relevant parts of the minimize
docs
x0 - ndarray, shape (n,)
Initial guess. Array of real elements of size (n,),
where n is the number of independent variables.
np.array([w1,w2])
is a (2,3) array. Check the minimize
code, but I think it will be flattened to (6,). You could also test the x
that is passed to objective
.
In [96]: w1 = [1,2,3]
...: w2 = [4,5,6]
...: w = [w1,w2]
In [97]: def objective(x):
...: print('x.shape', x.shape)
...: a = x[0][0]**2+x[0][1]**2+x[0][2]**2+x[1][0]**2+x[1][1]**2+x[1][2]**2
...: return a
Run with the 2d initial condition, the objective
returns:
In [99]: objective(np.array(w))
x.shape (2, 3)
Out[99]: 91
but called via minimize
:
In [100]: minimize(objective, w)
x.shape (6,)
3 a = x[0][0]**2+x[0][1]**2+x[0][2]**2+x[1][0]**2+x[1][1]**2+x[1][2]**2
IndexError: invalid index to scalar variable.
x
is (6,) but your function expects a 2 element list of 3 element lists, or a (2,3) array.
And that's not even getting to the bounds
.
So with n
being 6
, it is expecting the bounds to be 6 tuples:
In [102]: minimize(objective,x0=w,bounds=(bnds_1,bnds_2))
282 bounds = [(None, None)] * n
283 if len(bounds) != n:
--> 284 raise ValueError('length of x0 != length of bounds')
The key when using scipy
functions like minimize
is that YOU have to conform to its usage. It is in control, not you.
Adapting objective
to work with this (6,) input:
In [110]: def objective(x):
...: #print('x.shape', x.shape)
...: x = x.reshape(2,3)
...: a = x[0][0]**2+x[0][1]**2+x[0][2]**2+x[1][0]**2+x[1][1]**2+x[1][2]**2
...: return a
...:
And changing the bounds
to by (6,2):
In [111]: minimize(objective,x0=w,bounds=np.array((bnds_1,bnds_2)).reshape(-1,2))
Out[111]:
fun: 0.030000000000000006
hess_inv: <6x6 LbfgsInvHessProduct with dtype=float64>
jac: array([2.00000010e-01, 2.00000010e-01, 2.00000010e-01, 1.00613962e-08,
1.00613962e-08, 1.00613962e-08])
message: 'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL'
nfev: 14
nit: 1
njev: 2
status: 0
success: True
x: array([0.1, 0.1, 0.1, 0. , 0. , 0. ])