IndexError:Scipy.Optimize中数组的索引太多

时间:2018-01-05 14:30:29

标签: python-3.x scipy

我正试图用Scipy.Optimize对一些代码进行debbug。 这个bug来自constante:没有它,优化工作正常。 constante本身似乎在scipy.optimize之外工作正常(变量 testconst 通常计算)。代码如下:

from scipy.optimize import minimize
import numpy as np


def totaldist(dy):
    n = np.shape(dy)[0]
    temp = 0
    for i in range(n):
        temp += dy[i] ** 2

    return -0.5 * temp


def create_bond(dy_max):

    n = np.shape(dy_max)[0]
    bond = np.zeros((n, 2))
    for i in range(n):
        bond[i, :] = [0, dy_max[i]]

    tot = tuple([tuple(row) for row in bond])
    return tot


# def create_const(type_x, dx, gamma, P):
def create_const(dy, *args):
    arg = np.asarray(args)
    n = np.shape(dy)[0]
    dx = np.zeros((n, 2))
    bnd = np.zeros((n, 2))

    # from args to numpy array
    type_x = np.zeros(n)
    dP = 0
    delta1 = np.zeros(n)
    delta2 = np.zeros(n)
    gamma = np.zeros((n, n))

    for i in range(n):
        a, b = bndr(arg[0, i])
        delta1[i] = arg[0, i + n + 1]
        delta2[i] = arg[0, i + 2*n + 1]
        dx[i, 0] = (b - a) * dy[i]

    gamma = GammaApprox(delta1, delta2, dx[:, 1], dx[:, 0])

    d = np.dot(delta2, dx[:, 0])
    g = np.dot(dx[:, 0], gamma)
    g = np.dot(g, dx[:, 0])
    dP = float(arg[0, n])
    return d + 0.5 * g - dP


def GammaApprox(delta1, delta2, x1, x2):
    n = np.shape(delta1)[0]
    gamma = np.zeros((n, n))
    for i in range(n):
        if x2[i] == x1[i]:
            gamma[i, i] = 0
        else:
            gamma[i, i] = (delta2[i] - delta1[i]) / (x2[i] - x1[i])

    return gamma


def GetNewPoint(x1, x2, delta1, delta2, type_x, P):
    n = np.shape(delta1)[0]
    dmax = np.zeros(n)
    dy0 = np.zeros(n)

    # create the inequality data and initial points
    for i in range(n):
        a, b = bndr(type_x[i])
        if x2[i] > x1[i]:
            dmax[i] = (x2[i] - x1[i])/(b - a)
            dy0[i] = 1 / (b - a) * (x2[i] - x1[i]) / 2
        else:
            dmax[i] = (x1[i] - x2[i])/(b - a)
            dy0[i] = 1 / (b - a) * (x1[i] - x2[i]) / 2

    bond = create_bond(dmax)

    # create the args tuple
    arg = ()
    # type x
    for i in range(n):
        arg = arg + (type_x[i],)
    # dP
    arg = arg + (abs(P[0] - P[1]), )

    # delta1
    for i in range(n):
        arg = arg + (delta1[i], )
    # delta1
    for i in range(n):
        arg = arg + (delta2[i], )

    testconst = create_const(dy0, arg)

    # create the equality constraint
    con1 = {'type': 'eq', 'fun': create_const}
    cons = ([con1, ])
    solution = minimize(totaldist, dy0, args=arg, method='SLSQP', bounds=bond, constraints=cons, options={'disp': True})
    x = solution.x
    print(x)
    return x


def bndr(type_x):
    if type_x == 'normal':
        x_0 = -5
        x_f = 1.5
    if type_x == 'lognorm':
        x_0 = 0.0001
        x_f = 5
    if type_x == 'chisquare':
        x_0 = 0.0001
        x_f = (0.8 * (10 ** .5))

    return x_0, x_f


def test():
    x1 = np.array([0.0001, 0.0001, -5])
    x2 = np.array([1.6673, 0.84334, -5])
    delta1 = np.array([0, 0, 0])
    delta2 = np.array([2.44E-7, 2.41E-6, 4.07E-7])
    type_x = np.array(['lognorm', 'chisquare', 'normal'])
    P = (0, 6.54E-8)
    f = GetNewPoint(x1, x2, delta1, delta2, type_x, P)
    return f


test()

错误信息如下:

Traceback (most recent call last):
  File "D:/Anaconda Project/TestQP - Simplified/QP.py", line 134, in <module>
    test()
  File "D:/Anaconda Project/TestQP - Simplified/QP.py", line 130, in test
    f = GetNewPoint(x1, x2, delta1, delta2, type_x, P)
  File "D:/Anaconda Project/TestQP - Simplified/QP.py", line 103, in GetNewPoint
    solution = minimize(totaldist, dy0, args=arg, method='SLSQP', bounds=bond, constraints=cons, options={'disp': True})
  File "C:\Program Files\Anaconda\lib\site-packages\scipy\optimize\_minimize.py", line 458, in minimize
    constraints, callback=callback, **options)
  File "C:\Program Files\Anaconda\lib\site-packages\scipy\optimize\slsqp.py", line 311, in _minimize_slsqp
    meq = sum(map(len, [atleast_1d(c['fun'](x, *c['args'])) for c in cons['eq']]))
  File "C:\Program Files\Anaconda\lib\site-packages\scipy\optimize\slsqp.py", line 311, in <listcomp>
    meq = sum(map(len, [atleast_1d(c['fun'](x, *c['args'])) for c in cons['eq']]))
  File "D:/Anaconda Project/TestQP - Simplified/QP.py", line 40, in create_const
    a, b = bndr(arg[0, i])
IndexError: too many indices for array

我在网站上发现大致类似的错误:IndexError: index 1 is out of bounds for axis 0 with size 1/ForwardEuler

...但我没有看到它真的是同样的问题。

1 个答案:

答案 0 :(得分:0)

args不会传递给约束函数(自动)!

这在docs

中有说明
  

args:元组,可选

     

传递给目标函数及其衍生物的额外参数(Jacobian,Hessian)。

您可以通过添加打印件轻松查看问题:

def create_const(dy, *args):
    print('args:')
    print(args)
    arg = np.asarray(args)
    ...

将输出如下内容:

args:
(('lognorm', 'chisquare', 'normal', 6.54e-08, 0, 0, 0, 2.4400000000000001e-07, 2.4099999999999998e-06, 4.0699999999999998e-07),)
args:
()
ERROR...

如果删除测试(手动传递args;哪个有效)testconst = create_const(dy0, arg),您将只看到不工作的输出:

args:
()
ERROR...

约束有自己的传递args的机制,如文档中所述:

  

约束:dict或dict序列,可选

     

约束定义(仅适用于COBYLA和SLSQP)。每个约束都在字典中定义,字段为:

     

类型:str   约束类型:'eq'表示相等,'ineq'表示不等式。

     好玩:可驯服   定义约束的函数。

     

jac:可调用,可选   雅各比风趣(仅适用于SLSQP)。

     

args:sequence,optional   要传递给函数和Jacobian的额外参数。

     

等式约束意味着约束函数结果为零,而不等式意味着它是非负的。请注意,COBYLA仅支持不等式约束。

在你的情况下:

con1 = {'type': 'eq', 'fun': create_const}                  # incomplete!
con1 = {'type': 'eq', 'fun': create_const, 'args': (arg,)}  # (,)
                                                            # to make it behave as needed
                                                            # for your code!

这将使其运行直到发生一些其他问题