In [37]: from scipy import optimize
Фиктивные массивы, только для тестирования фигур:
In [39]: D = np.eye(4,3); y = np.ones((4,1))
In [40]: D
Out[40]:
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.],
[0., 0., 0.]])
In [41]: y
Out[41]:
array([[1.],
[1.],
[1.],
[1.]])
In [42]: x0 = np.ones((D.shape[1],))
Ваши последние функции:
In [57]: def square_sum(x):
...: return np.dot(x,x)
...:
...: def lessObsConstrain(x,D,y):
...: temp = y - np.dot(D,x.reshape(len(x),1))
...: temp = temp.reshape(1,len(temp))
...: return np.asscalar(np.dot(temp,temp.T))
С оригинальными версиями они оба создали 2d массивы:
In [44]: square_sum(x0)
Out[44]: array([[3.]])
In [45]: lessObsConstrain(x0,D,y)
Out[45]: array([[1.]])
и обработчик ограничений жаловался, что он не может соединить ограничения равенства и неравенства (я не уверен, что именно он объединяет):
c = concatenate((c_eq, c_ieq))
ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 2 dimension(s) and the array at index 1 has 1 dimension(s)
С asscalar
lessObsConstrain
скалярно, и объединение работает.
In [60]: optimize.minimize(square_sum, x0, args=(), method='SLSQP', jac=None, bo
...: unds=optimize.Bounds(0, 1), constraints=[{'type':'eq','fun':lessObsCons
...: train,'args':(D,y)}], tol=None, callback=None, options={'maxiter': 100,
...: 'ftol': 1e-06, 'iprint': 1, 'disp': False, 'eps': 1.4901161193847656e-
...: 08})
/usr/local/bin/ipython3:7: DeprecationWarning: np.asscalar(a) is deprecated since NumPy v1.16, use a.item() instead
Out[60]:
fun: 2.9994000807884227
jac: array([1.99980003, 1.99980003, 1.99980003])
message: 'Positive directional derivative for linesearch'
nfev: 218
nit: 20
njev: 16
status: 8
success: False
x: array([0.99990001, 0.99990001, 0.99990001])
Я рекомендовал простой dot
, который не требует изменения формы.Но y
также необходимо 1d (например, x0
):
In [61]: def square_sum(x):
...: return np.dot(x,x)
...:
...: def lessObsConstrain(x,D,y):
...: #Dy=x equals (Dy-x)^2=0
...: temp = y - np.dot(D,x)
...: return np.dot(temp,temp)
In [62]: y = np.ones((4))
При вызове минимизации получается то же самое:
In [56]: optimize.minimize(square_sum, x0, args=(), method='SLSQP', jac=None, bo
...: unds=optimize.Bounds(0, 1), constraints=[{'type':'eq','fun':lessObsCons
...: train,'args':(D,y)}], tol=None, callback=None, options={'maxiter': 100,
...: 'ftol': 1e-06, 'iprint': 1, 'disp': False, 'eps': 1.4901161193847656e-
...: 08})
Out[56]:
fun: 2.9994000807884227
jac: array([1.99980003, 1.99980003, 1.99980003])
message: 'Positive directional derivative for linesearch'
nfev: 218
nit: 20
njev: 16
status: 8
success: False
x: array([0.99990001, 0.99990001, 0.99990001])
Более внимательный взгляд на lessObsConstrain
.Первая точка создает массив размера M ((MxN с N):
In [62]: np.dot(D,x0)
Out[62]: array([1., 1., 1., 0.])
In [63]: y # (N,1)
Out[63]:
array([[1.],
[1.],
[1.],
[1.]])
In [65]: lessObsConstrain(x0,D,y)
Out[65]:
array([[0., 0., 0., 1.],
[0., 0., 0., 1.],
[0., 0., 0., 1.],
[0., 0., 0., 1.]])
(N, 1) передает с (N,) для получения (N, N). Если вместо этого y
(N,), temp
равно 1d, а dot
является скаляром:
In [66]: lessObsConstrain(x0,D,np.ones((4,)))
Out[66]: 1.0
dot
объединяет последнюю ось A со 2-й по последнюю из B. Но с массивом 1dэто скалярная векторная точка, величина:
In [67]: np.dot(np.arange(3),np.arange(3))
Out[67]: 5
In [68]: np.dot(np.arange(3)[:,None],np.arange(3)[None,:])
Out[68]:
array([[0, 0, 0], # (3,1) with (1,3) => (3,3)
[0, 1, 2],
[0, 2, 4]])
In [69]: np.dot(np.arange(3)[None,:],np.arange(3)[:,None])
Out[69]: array([[5]]) # (1,3) with (3,1) => (1,1)