scipy.optimize.elementwise.

find_root#

scipy.optimize.elementwise.find_root(f, init, /, *, args=(), tolerances=None, maxiter=None, callback=None)[source]#

查找实变量单调实值函数的根。

对于 f 输出的每个元素,find_root 寻找使该元素为 0 的标量根。此函数当前使用 Chandrupatla 的区间算法 [1],因此要求参数 init 提供一个包含根的区间:两个端点处的函数值必须具有相反的符号。

如果提供了一个有效区间,并且函数在该区间内是连续的,则 find_root 保证收敛到满足所提供 tolerances 的解。

initargs 包含(可广播的)数组时,此函数按元素工作。

参数:
f可调用对象

需要求根的函数。签名必须是

f(x: array, *args) -> array

其中 x 的每个元素都是一个有限实数,args 是一个元组,可能包含任意数量的与 x 可广播的数组。

f 必须是逐元素函数:对于所有索引 if(x)[i] 必须等于 f(x[i])。它不得修改数组 xargs 中的数组。

find_root 寻找一个数组 x,使得 f(x) 是一个零数组。

init2-元组,浮点数组类

包围所需根的区间的下限和上限。如果数组 xl, xr = init 逐元素满足 xl < xrsign(f(xl)) == -sign(f(xr)),则该区间有效。数组必须可相互广播并与 args 广播。

args数组类元组,可选

要传递给 f 的附加位置数组参数。数组必须可相互广播并与 init 的数组广播。如果需要求根的可调用对象需要与 x 不可广播的参数,则将该可调用对象用 f 包装,使得 f 只接受 x 和可广播的 *args

tolerances浮点数字典,可选

根和函数值的绝对和相对容差。字典的有效键是

  • xatol - 根的绝对容差

  • xrtol - 根的相对容差

  • fatol - 函数值的绝对容差

  • frtol - 函数值的相对容差

有关默认值和明确终止条件,请参阅注释。

maxiter整型,可选

要执行的算法的最大迭代次数。默认值是相关 dtype 的(正常)浮点数内可能的最大二分法次数。

callback可调用对象,可选

一个可选的用户提供函数,在第一次迭代之前和每次迭代之后调用。以 callback(res) 的形式调用,其中 res 是一个 _RichResult,类似于 find_root 返回的对象(但包含当前迭代的所有变量值)。如果 callback 引发 StopIteration,算法将立即终止,并且 find_root 将返回结果。callback 不得修改 res 或其属性。

返回:
res_RichResult

一个类似于 scipy.optimize.OptimizeResult 实例的对象,具有以下属性。描述假定值为标量;但是,如果 f 返回一个数组,则输出将是相同形状的数组。

success布尔数组

算法成功终止(状态 0)的位置为 True;否则为 False

status整型数组

表示算法退出状态的整数。

  • 0:算法收敛到指定的容差。

  • -1:初始区间无效。

  • -2:达到最大迭代次数。

  • -3:遇到非有限值。

  • -4:迭代被 callback 终止。

  • 1:算法正常进行中(仅在 callback 中)。

x浮点数组

如果算法成功终止,则为函数的根。

f_x浮点数组

x 处求得的 f 的值。

nfev整型数组

为找到根而对 f 求值时的横坐标数量。这与 f调用次数不同,因为函数可以在一次调用中在多个点处求值。

nit整型数组

执行的算法迭代次数。

bracket浮点数组元组

最终区间的下限和上限。

f_bracket浮点数组元组

在区间的下限和上限处求得的 f 的值。

另请参阅

bracket_root

注释

根据 Chandrupatla 的原始论文 [1] 实现。

  • a, b = init 为初始区间的左端点和右端点,

  • xlxr 为最终区间的左端点和右端点,

  • xmin = xl if abs(f(xl)) <= abs(f(xr)) else xr 为函数值较小的最终区间端点,以及

  • fmin0 = min(f(a), f(b)) 为在初始区间端点处求得的函数值的最小值。

当满足以下条件时,算法被认为已收敛:

  • abs(xr - xl) < xatol + abs(xmin) * xrtol

  • fun(xmin) <= fatol + abs(fmin0) * frtol.

这等效于 [1] 中描述的终止条件,其中 xrtol = 4e-10, xatol = 1e-5, 且 fatol = frtol = 0。然而,tolerances 字典的默认值是 xatol = 4*tiny, xrtol = 4*eps, frtol = 0, 和 fatol = tiny,其中 epstiny 分别是函数输入和输出结果 dtype 的精度和最小正规数。

参考文献

[1] (1,2,3)

Chandrupatla, Tirupathi R. “A new hybrid quadratic/bisection algorithm for finding the zero of a nonlinear function without using derivatives”. Advances in Engineering Software, 28(3), 145-149. https://doi.org/10.1016/s0965-9978(96)00051-8

示例

假设我们希望找到以下函数的根。

>>> def f(x, c=5):
...     return x**3 - 2*x - c

首先,我们必须找到一个有效区间。该函数不是单调的,但 bracket_root 可能能够提供一个区间。

>>> from scipy.optimize import elementwise
>>> res_bracket = elementwise.bracket_root(f, 0)
>>> res_bracket.success
True
>>> res_bracket.bracket
(2.0, 4.0)

实际上,函数在区间端点处的值具有相反的符号。

>>> res_bracket.f_bracket
(-1.0, 51.0)

一旦我们有了一个有效区间,就可以使用 find_root 来提供精确的根。

>>> res_root = elementwise.find_root(f, res_bracket.bracket)
>>> res_root.x
2.0945514815423265

最终区间只有几个 ULPs 宽,因此在此值与真实根之间的误差在双精度算术可表示的值内不可能小得多。

>>> import numpy as np
>>> xl, xr = res_root.bracket
>>> (xr - xl) / np.spacing(xl)
2.0
>>> res_root.f_bracket
(-8.881784197001252e-16, 9.769962616701378e-15)

bracket_rootfind_root 接受数组作为大多数参数。例如,一次性查找参数 c 的几个值的根

>>> c = np.asarray([3, 4, 5])
>>> res_bracket = elementwise.bracket_root(f, 0, args=(c,))
>>> res_bracket.bracket
(array([1., 1., 2.]), array([2., 2., 4.]))
>>> res_root = elementwise.find_root(f, res_bracket.bracket, args=(c,))
>>> res_root.x
array([1.8932892 , 2.        , 2.09455148])