查找给定区间内任意插值函数的所有根

Find all roots of an arbitrary interpolated function in a given interval

我试图在定义的区间内找到任意函数的 所有 根。我已经在寻找解决方案,但没有找到任何可以轻松解决我的问题的方法。

例如,我得到了积分,我使用 interp1d 创建了这些积分的函数。假设一个余弦函数:

x_p = np.linspace(0,2*pi,100)
y_p = np.cos(x_p)

接下来,我使用 interp1d 生成所需的函数

f = interp1d(x_p,y_p,kind="cubic")

我已经尝试使用 fsolve,但它只能根据起点找到一个根

fsolve(lambda x: f(x),0.1)

当我尝试时

brentq(f,0,6)

我收到错误

f(a) and f(b) must have different signs

我猜 brentq 不是正确答案,因为在区间内我得到了不止 1 个根。 这个问题有没有优雅的解决方案?

非常感谢您。

一般来说,找到任意函数的所有根是不可能的(参见 1 & 2)。

对于插值函数,它们通常由多项式串联构成,可以确定根数并找到所有根。但是你必须知道interp1d下的多项式系数才能解决问题。

现实中,一个未知函数被采样得到一系列数据点。在您的例子中,未知函数的样本由 cos() 给出。插值函数 f 用于模拟行为。可发现根的最小间距受采样间隔限制。这是因为root-finding的存在性定理告诉我们,如果f(a) * f(b) <= 0,那么[a, b]之间就有一个根。换句话说,如果符号在f(a)f(b)处没有变化,我们对[a,b]之间的根没有结论。这解释了错误 f(a) and f(b) must have different signs.

对于fsolve(lambda x: f(x),0.1),我得到了

ValueError: A value in x_new is above the interpolation range.

这意味着初始猜测 0.1 是错误的,背后的算法可能 运行 x 在区间 [0, 2*pi].

之外

为了做出有根据的猜测,它应该尽可能靠近根。因此,应该选择符号变化的左/右点。

f_p = f(x_p)
indices, = np.nonzero(f_p[:-1] * f_p[1:] <= 0)
for i in range(indices.shape[0]):
      guess = x_p[indices[i]]
      print('root', i + 1, 'x=', fsolve(f, guess))

输出:

root 1 x= [1.57079633]
root 2 x= [4.71238898]