scipy.optimize.elementwise.

find_minimum#

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

查找实变量的单峰实值函数的最小值。

对于 f 输出的每个元素,find_minimum 寻求使该元素最小化的标量最小值点。此函数目前使用 Chandrupatla 的区间最小化算法 [1],因此要求参数 init 提供一个三点最小化区间:x1 < x2 < x3func(x1) >= func(x2) <= func(x3),其中一个不等式是严格的。

如果函数在区间内是连续的,则提供有效区间后,find_minimum 保证收敛到满足所提供 tolerances 的局部最小值。

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

参数:
f可调用对象

需要其最小值点的函数。函数签名必须为

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

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

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

find_minimum 寻求一个数组 x,使得 f(x) 是一个局部最小值数组。

init浮点数类数组的3元组

标准标量最小化区间的横坐标。如果数组 x1, x2, x3 = init 满足 x1 < x2 < x3func(x1) >= func(x2) <= func(x3),其中一个不等式是严格的,则该区间有效。数组必须彼此可广播,并与 args 的数组可广播。

args类数组元组,可选

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

tolerances浮点数字典,可选

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

  • xatol - 根的绝对容差

  • xrtol - 根的相对容差

  • fatol - 函数值的绝对容差

  • frtol - 函数值的相对容差

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

maxiter整型,默认值: 100

算法执行的最大迭代次数。

callback可调用对象,可选

一个可选的用户提供函数,在第一次迭代之前和每次迭代之后调用。调用形式为 callback(res),其中 res 是一个 _RichResult 对象,类似于 find_minimum 返回的结果(但包含当前迭代的所有变量值)。如果 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_minimum

备注

基于 Chandrupatla 的原始论文 [1] 实现。

如果 xl < xm < xr 是区间的点,并且 fl >= fm <= fr (其中一个不等式是严格的) 是在这些点评估的 f 值,那么当满足以下条件时,算法被认为已收敛:

  • abs(xr - xm)/2 <= abs(xm)*xrtol + xatol

  • (fl - 2*fm + fr)/2 <= abs(fm)*frtol + fatol.

xrtol 的默认值是相应数据类型精度的平方根,而 xatol = fatol = frtol 是相应数据类型的最小正规数。

参考文献

[1] (1,2)

Chandrupatla, Tirupathi R. (1998). “An efficient quadratic fit-sectioning algorithm for minimization without derivatives”(用于无导数最小化的有效二次拟合-分段算法)。Computer Methods in Applied Mechanics and Engineering, 152 (1-2), 211-217. https://doi.org/10.1016/S0045-7825(97)00190-4

示例

假设我们要最小化以下函数。

>>> def f(x, c=1):
...     return (x - c)**2 + 2

首先,我们必须找到一个有效区间。该函数是单峰的,因此 bracket_minium 将很容易找到一个区间。

>>> from scipy.optimize import elementwise
>>> res_bracket = elementwise.bracket_minimum(f, 0)
>>> res_bracket.success
True
>>> res_bracket.bracket
(0.0, 0.5, 1.5)

确实,区间点是有序的,并且中间区间点的函数值小于周围点的值。

>>> xl, xm, xr = res_bracket.bracket
>>> fl, fm, fr = res_bracket.f_bracket
>>> (xl < xm < xr) and (fl > fm <= fr)
True

一旦我们有了有效区间,就可以使用 find_minimum 来提供最小值点的估计。

>>> res_minimum = elementwise.find_minimum(f, res_bracket.bracket)
>>> res_minimum.x
1.0000000149011612

函数值在区间内仅变化几个 ULPs,因此仅通过评估函数无法更精确地确定最小值点(即,我们需要其导数才能做得更好)。

>>> import numpy as np
>>> fl, fm, fr = res_minimum.f_bracket
>>> (fl - fm) / np.spacing(fm), (fr - fm) / np.spacing(fm)
(0.0, 2.0)

因此,函数的精确最小值由以下给出:

>>> res_minimum.f_x
2.0

bracket_minimumfind_minimum 接受大多数参数的数组。例如,若要一次性查找参数 c 的几个值的最小值点和最小值:

>>> c = np.asarray([1, 1.5, 2])
>>> res_bracket = elementwise.bracket_minimum(f, 0, args=(c,))
>>> res_bracket.bracket
(array([0. , 0.5, 0.5]), array([0.5, 1.5, 1.5]), array([1.5, 2.5, 2.5]))
>>> res_minimum = elementwise.find_minimum(f, res_bracket.bracket, args=(c,))
>>> res_minimum.x
array([1.00000001, 1.5       , 2.        ])
>>> res_minimum.f_x
array([2., 2., 2.])