SciPy根根据方法给出ValueError

muk1a3rh  于 2022-11-10  发布在  其他
关注(0)|答案(2)|浏览(121)

我正在使用SciPy root函数来寻找一个涉及ODE的函数的根(在传递给root的函数中,我调用SciPy solve_ivp)。当在root中使用“krylov”方法时,它可以毫无问题地解决这个问题。但是当我使用任何其他方法时,它会引发ValueError:ValueError: could not broadcast input array from shape (2,1) into shape (2,) .
任何帮助都是非常感谢的。
谢谢你,库罗什

92vpleto

92vpleto1#

您在错误报告中发布的代码(为什么不在此处发布?):

In [1]: from scipy.optimize import root
   ...: from scipy.integrate import solve_ivp
   ...: 
   ...: 
   ...: def fun_d(x, d0):
   ...:     return(d0 * x)
   ...: 
   ...: 
   ...: def ode_fun(t, z, a, b, c, d0):
   ...:     x, y = z
   ...:     d = fun_d(x, d0)
   ...:     u = a*d*x - b*x*y
   ...:     v = -c*y + d*x*y
   ...:     return([u, v])
   ...: 
   ...: 
   ...: def fun_err(d0, a, b, c):
   ...:     sol = solve_ivp(ode_fun, t_span=[0, 15], y0=[10, 5],
   ...:                     method='RK45', args=(a, b, c, d0), t_eval=[12, ],
   ...:                     rtol=1e-11, atol=1e-13)
   ...:     obj_sol = solve_ivp(ode_fun, t_span=[0, 15], y0=[10, 5],
   ...:                         method='RK45', args=(1.5, 1, 3, 1), t_eval=[12, ],
   ...:                         rtol=1e-11, atol=1e-13)
   ...:     obj_x = obj_sol.y[0][-1]
   ...:     return(sol.y[0][-1] - obj_x)
   ...: 
   ...: 
   ...: a = 1.5
   ...: b = 1
   ...: c = 3
   ...:

运行的情况:

In [2]: d_sol = root(fun_err, x0=0.5, args=(a, b, c), method='krylov')
/usr/local/lib/python3.8/dist-packages/scipy/optimize/_nonlin.py:366: RuntimeWarning: invalid value encountered in double_scalars
  and dx_norm/self.x_rtol <= x_norm))
In [3]: d_sol
Out[3]: 
     fun: array([1.82191151e-06])
 message: 'A solution was found at the specified tolerance.'
     nit: 2
  status: 1
 success: True
       x: array(0.53107372)

故障情况,用FULL TRACEBACK

In [4]: d_sol = root(fun_err, x0=0.5, args=(a, b, c), method='hybr')
Traceback (most recent call last):
  Input In [4] in <cell line: 1>
    d_sol = root(fun_err, x0=0.5, args=(a, b, c), method='hybr')
  File /usr/local/lib/python3.8/dist-packages/scipy/optimize/_root.py:234 in root
    sol = _root_hybr(fun, x0, args=args, jac=jac,**options)
  File /usr/local/lib/python3.8/dist-packages/scipy/optimize/_minpack_py.py:226 in _root_hybr
    shape, dtype = _check_func('fsolve', 'func', func, x0, args, n, (n,))
  File /usr/local/lib/python3.8/dist-packages/scipy/optimize/_minpack_py.py:24 in _check_func
    res = atleast_1d(thefunc(*((x0[:numinputs],) + args)))
  Input In [1] in fun_err
    sol = solve_ivp(ode_fun, t_span=[0, 15], y0=[10, 5],
  File /usr/local/lib/python3.8/dist-packages/scipy/integrate/_ivp/ivp.py:580 in solve_ivp
    message = solver.step()
  File /usr/local/lib/python3.8/dist-packages/scipy/integrate/_ivp/base.py:181 in step
    success, message = self._step_impl()
  File /usr/local/lib/python3.8/dist-packages/scipy/integrate/_ivp/rk.py:144 in _step_impl
    y_new, f_new = rk_step(self.fun, t, y, self.f, h, self.A,
  File /usr/local/lib/python3.8/dist-packages/scipy/integrate/_ivp/rk.py:61 in rk_step
    K[0] = f
ValueError: could not broadcast input array from shape (2,1) into shape (2,)

基于root source中的分支,它还适用于以下任何一种情况:

`broyden1', 'broyden2', 'anderson', 'linearmixing',
 'diagbroyden', 'excitingmixing', 'krylov'

根据root文档,x0应该是一个numpy数组:

Parameters
fun : callable
A vector function to find a root of.

x0 : ndarray
Initial guess.

问题的根源在于

def fun_d(x, d0):
    return(d0 * x)

因此,ode_fun会根据x0np.array(.5)还是np.array([.5])而产生不同的结果。在问题的情况下,ode_fun会传回(2,1)数组(或变成它的清单),而它应该是平面(2,)数组。
根据solve_ivp文档,fun应该返回一个在形状上与y匹配的数组,

[If] y: It can either have shape (n,); then fun must return array_like with shape (n,).

因此,ode_fun应返回:

return np.ravel([u, v])
zsbz8rwp

zsbz8rwp2#

所以,我想我弄清楚了问题出在哪里。我会把它贴在这里,以防别人也有同样的问题。
问题是当使用krylov和其他方法时,scipy root函数如何区别对待x0。对于除krylov之外的每个方法,它都将x0视为长度为1的数组(因为在我的情况下,我正在解1个方程,而不是方程组)。这可能会导致上面提到的广播错误。我也在scipygithub page中报告了这个问题。这可以通过将x0从数组转换为标量来解决(例如,使用.item()方法)。

相关问题