find_root#
- scipy.optimize.elementwise.find_root(f, init, /, *, args=(), tolerances=None, maxiter=None, callback=None)[源代码]#
寻找实变量的单调实值函数的根。
对于 f 的输出的每个元素,
find_root
寻找使元素为 0 的标量根。 此函数目前使用 Chandrupatla 的包围算法 [1],因此需要参数 init 提供根的包围:两个端点的函数值必须具有相反的符号。如果提供了有效的包围,且函数在该包围内是连续的,则保证
find_root
会收敛到满足所提供的 tolerances 的解。当 init 和 args 包含(可广播的)数组时,此函数按元素方式工作。
- 参数:
- f可调用对象
需要求根的函数。签名必须是
f(x: array, *args) -> array
其中
x
的每个元素都是一个有限实数,而args
是一个元组,可能包含任意数量的可与x
广播的数组。f 必须是逐元素的函数:对于所有索引
i
,每个元素f(x)[i]
必须等于f(x[i])
。它不得改变数组x
或args
中的数组。find_root
寻找一个数组x
,使得f(x)
是一个零数组。- init浮点数数组的 2 元组,类数组
围绕所需根的包围的下限和上限端点。如果数组
xl, xr = init
满足xl < xr
和sign(f(xl)) == -sign(f(xr))
(按元素方式),则包围有效。数组可以彼此广播,也可以与 args 广播。- args数组类元组,可选
要传递给 f 的其他位置数组参数。数组必须彼此广播,并且与 init 的数组广播。如果求根的可调用对象需要与 x 不可广播的参数,请使用 f 包装该可调用对象,使得 f 仅接受 x 和可广播的
*args
。- tolerances浮点数字典,可选
根和函数值的绝对和相对公差。字典的有效键是
xatol
- 根的绝对公差xrtol
- 根的相对公差fatol
- 函数值的绝对公差frtol
- 函数值的相对公差
有关默认值和显式终止条件,请参阅“注释”。
- maxiterint,可选
要执行的算法的最大迭代次数。默认值是相关 dtype 的(正常)浮点数中可能的最大二分次数。
- callback可调用对象,可选
一个可选的用户提供的函数,在第一次迭代之前和每次迭代之后调用。作为
callback(res)
调用,其中res
是一个_RichResult
,类似于find_root
返回的_RichResult
(但包含所有变量的当前迭代值)。如果 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 的值。
参见
注释
基于 Chandrupatla 的原始论文 [1] 实现。
令
a, b = init
是初始包围的左端点和右端点,xl
和xr
是最终包围的左端点和右端点,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
,其中eps
和tiny
是函数输入和输出结果dtype
的精度和最小正规数。参考文献
[1] (1,2,3)Chandrupatla, Tirupathi R. “一种新的混合二次/二分法算法,用于在不使用导数的情况下寻找非线性函数的零点”。《工程软件进展》,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
最终的区间只有几个ULP(最小单位的精度)宽,因此此值与真实根之间的误差在双精度算术中可表示的值范围内不会小太多。
>>> 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_root
和find_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])