如何有效地找到包含平滑函数值的数组中的最大值?

时间:2010-07-29 00:00:43

标签: math

我有一个带浮点数的函数并返回一个浮点数。可以假设,如果你要绘制这个函数的输出,它将是'n'形的,即。将存在单个最大点,并且在具有零斜率的函数上没有其他点。我们还知道产生这个最大输出的输入值将介于两个已知点之间,可能是0.0和1.0。

我需要有效地找到输出值,以产生最大输出值到某种程度的近似值,而无需进行详尽的搜索。

我正在寻找类似于Newton's Method的东西,它找到了函数的根,但由于我的函数是不透明的,我无法得到它的衍生物。

6 个答案:

答案 0 :(得分:4)

由于各种原因,我想向目前为止所有其他答案,但我不会。

当导数不可用时,用于最小化(或最大化)平滑函数的优秀且有效的方法是抛物线插值。编写算法是很常见的,因此当抛物线插值不像黄金分割那样快时,它会暂时切换到黄金分割搜索(布伦特的最小化)。

我用C ++编写了这样一个算法。有什么优惠吗?

更新:GSL中有一个C版本的Brent minimalizer。档案在这里:ftp://ftp.club.cc.cmu.edu/gnu/gsl/请注意,它会被某种GNU“copyleft”所覆盖。

在我写这篇文章时,最新和最好的似乎是gsl-1.14.tar.gz。最小化器位于文件gsl-1.14 / min / brent.c中。它似乎具有与我实施的类似的终止标准。我还没有研究过它如何决定转向黄金分割,但对于OP来说,这可能没什么问题。

更新2 :我搜索了一个从FORTRAN翻译过的公共域java版本。我无法保证其质量。 http://www1.fpl.fs.fed.us/Fmin.java我注意到硬编码的机器效率(评论中的“机器精度”)是当今典型PC的值的1/2。 将eps 的值更改为2.22045e-16。

答案 1 :(得分:3)

编辑2: Jive Dadson中描述的方法是一种更好的方法。如果速度不是太大问题,那我就更容易实现,因为它更容易实现。

使用二进制搜索的形式,结合数值导数近似值。

给定区间[a,b],设x =(a + b)/ 2 让epsilon成为非常小的东西。

(f(x + epsilon) - f(x))是正的吗?如果是,函数仍然在x增长,所以你递归搜索区间[x,b] 否则,搜索区间[a,x]。

如果最大值位于x和x + epsilon之间,可能会出现问题,但您可以尝试一下。

编辑:此方法的优势在于它利用了相关函数的已知属性。也就是说,我假设为“n”形,你的意思是,增加 - 最大 - 减少。这是我为编写算法而编写的一些Python代码:

def f(x):
    return -x * (x - 1.0)

def findMax(function, a, b, maxSlope):
    x = (a + b) / 2.0
    e = 0.0001
    slope = (function(x + e) - function(x)) / e
    if abs(slope) < maxSlope:
        return x
    if slope > 0:
        return findMax(function, x, b, maxSlope)
    else:
        return findMax(function, a, x, maxSlope)

键入findMax(f, 0, 3, 0.01)应根据需要返回0.504

答案 2 :(得分:2)

为了优化函数,这是您正在讨论的函数类型,在不评估导数的情况下,我会使用secant method

鉴于两个初始值x[0]=0.0x[1]=1.0,我将继续计算下一个近似值:

def next_x(x, xprev):
    return x - f(x) * (x - xprev) / (f(x) - f(xprev))

然后计算x[2], x[3], ...,直到x的变化变得足够小。

编辑:正如Jive所解释的那样,此解决方案适用于根发现,这不是提出的问题。为了优化,正确的解决方案是布伦特最小化器,如他的答案所述。

答案 3 :(得分:0)

您可以将其缩小为三角形上的简单线性拟合,找到它穿过x轴的位置。线性拟合可以非常快速地完成。

或者只需要3分(左/上/右)并修复抛物线。

我认为这主要取决于x和y之间潜在关系的性质。

编辑这是因为你有一个数组的值,比如问题的标题状态。当你有一个功能时,请选择Newton-Raphson。

答案 4 :(得分:0)

Levenberg-Marquardt algorithm是牛顿的方法,就像优化器一样。它有一个C / C ++实现levmar,不需要你定义派生函数。相反,它将评估当前邻域中的目标函数以移动到最大值。

顺便说一句:自从我上次访问该网站以来,该网站似乎已经更新,希望它与我记忆中的相同。显然它现在也支持其他语言。

答案 5 :(得分:0)

鉴于它只是单个变量的函数并且在区间中有一个极值,所以你并不需要牛顿方法。某种线搜索算法应该足够了。如果细节不足,这wikipedia article实际上并不是一个糟糕的起点。请特别注意,您可以使用“直接搜索”中描述的方法,从您的间隔的结束点开始作为您的两点。

我不确定你是否认为这是一个“详尽的搜索”,但它实际上应该非常快我认为这种功能(也就是说,一个连续的,平滑的函数,只有一个局部极值)给定间隔)。