scipy / optimize / slsqp.py c = concatenate ((c_eq, c_ieq)) ValueError: все входные массивы должны иметь одинаковое количество измерений - PullRequest
0 голосов
/ 20 сентября 2019

Я новичок в scipy.optimize, после просмотра учебника и референции я все еще не могу понять, что я сделал неправильно в своем коде.Я прочитал это и не могу понять: функция Scipy optimize.minimize

Здесь D - матрица M * N, y - матрица M * 1.x должен быть матрицей N * 1 (потому что мне нужно это вычислить).Мне нужно минимизировать норму L2 в x, убедиться, что все элементы в x больше 0. Также с учетом Dx = y.В заключение:

свести к минимуму || x || 2

Dx = y

x> = 0

import scipy
from numpy import *

def square_sum(x):
    #x must be 1*N?
    x = x.reshape(len(x),1)
    y = dot(x.T,x)
    return y

def lessObsConstrain(x,D,y):
    #Dy=x equals (Dy-x)^2=0
    temp = y - dot(D,x.reshape(len(x),1))
    temp = temp.reshape(1,len(temp))
    return dot(temp,temp.T)

x0=ones((D.shape[1],))
result = scipy.optimize.minimize(square_sum, x0, args=(), method='SLSQP', jac=None, bounds=scipy.optimize.Bounds(0, 1), constraints=[{'type':'eq','fun':lessObsConstrain,'args':(D,y)}], tol=None, callback=None, options={'maxiter': 100, 'ftol': 1e-06, 'iprint': 1, 'disp': False, 'eps': 1.4901161193847656e-08})

Но я получаю эту ошибку:

scipy / optimize / slsqp.py ", строка 417, в _minimize_slsqp c = concatenate ((c_eq, c_ieq)) ValueError: все входные массивы должны иметь одинаковое количестворазмеры

Может кто-нибудь сказать мне, как исправить мой код, пожалуйста?

Ответы [ 2 ]

0 голосов
/ 22 сентября 2019
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)
0 голосов
/ 21 сентября 2019

Я нашел ужасный способ пропустить эту ошибку.Оказывается, матрица 1 * 1 отличается от скаляра.Таким образом, проблема заключается в измерении данных.

import scipy
from numpy import *

def square_sum(x):
    return dot(x,x)

def lessObsConstrain(x,D,y):
    temp = y - dot(D,x.reshape(len(x),1))
    temp = temp.reshape(1,len(temp))
    return asscalar(dot(temp,temp.T))

x0=ones((D.shape[1],))
result = scipy.optimize.minimize(square_sum, x0, args=(), method='SLSQP', jac=None, bounds=scipy.optimize.Bounds(0, 1), constraints=[{'type':'eq','fun':lessObsConstrain,'args':(D,y)}], tol=None, callback=None, options={'maxiter': 100, 'ftol': 1e-06, 'iprint': 1, 'disp': False, 'eps': 1.4901161193847656e-08})
...