我正在使用SciPy root函数来寻找一个涉及ODE的函数的根(在传递给root的函数中,我调用SciPy solve_ivp)。当在root中使用“krylov”方法时,它可以毫无问题地解决这个问题。但是当我使用任何其他方法时,它会引发ValueError:ValueError: could not broadcast input array from shape (2,1) into shape (2,) . 任何帮助都是非常感谢的。 谢谢你,库罗什
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,)
2条答案
按热度按时间92vpleto1#
您在错误报告中发布的代码(为什么不在此处发布?):
运行的情况:
故障情况,用FULL TRACEBACK
基于
root
source中的分支,它还适用于以下任何一种情况:根据
root
文档,x0
应该是一个numpy数组:问题的根源在于
因此,
ode_fun
会根据x0
是np.array(.5)
还是np.array([.5])
而产生不同的结果。在问题的情况下,ode_fun
会传回(2,1)数组(或变成它的清单),而它应该是平面(2,)数组。根据
solve_ivp
文档,fun
应该返回一个在形状上与y
匹配的数组,因此,
ode_fun
应返回:zsbz8rwp2#
所以,我想我弄清楚了问题出在哪里。我会把它贴在这里,以防别人也有同样的问题。
问题是当使用
krylov
和其他方法时,scipy root
函数如何区别对待x0
。对于除krylov
之外的每个方法,它都将x0
视为长度为1的数组(因为在我的情况下,我正在解1个方程,而不是方程组)。这可能会导致上面提到的广播错误。我也在scipy
github page中报告了这个问题。这可以通过将x0
从数组转换为标量来解决(例如,使用.item()
方法)。