scipy.optimize.elementwise.

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 的解。

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

参数:
f可调用对象

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

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

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

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

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

init浮点数数组的 2 元组,类数组

围绕所需根的包围的下限和上限端点。如果数组 xl, xr = init 满足 xl < xrsign(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 的值。

参见

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-10xatol = 1e-5,以及 fatol = frtol = 0。然而,tolerances 字典的默认值是 xatol = 4*tinyxrtol = 4*epsfrtol = 0fatol = tiny,其中 epstiny 是函数输入和输出结果 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_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])