一维搜索中的划界(Bracket)算法

本文详细介绍了单峰区间和单峰函数的概念,解释了如何通过‘高→低→高’的三个点来实现划界(Bracket)过程,以及划界算法的实现步骤。进一步讨论了加快划界速度的方法——逆抛物内插技术,使其能够实现超线性收敛。文章还提供了简化版的划界算法步骤,并阐述了如何通过逆抛物内插快速逼近极小点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明出处:http://www.codelast.com/

很多最优化算法需要用到一维搜索(line search)子算法,而在众多的一维搜索算法中,大多数都要求函数被限制在一个单峰区间内,也就是说,在进行一维搜索的区间内,函数是一个单峰函数。尽管有一些改进的一维搜索算法(例如  Ho¨pfinger  建议的一种改进过的黄金搜索算法)可以处理函数非单峰的情况,但是,在没有确定函数在一个区间内是单峰的之前,即使在搜索过程中,函数值持续减小,我们也不能说极小值是一定存在的,因此,找出一个区间,在此区间之内使函数是单峰的,这个过程是必需的(我更倾向于接受这种观点)。这个过程就叫作划界Bracket)。Bracket这个单词是括号的意思,很形象——用括号包住一个范围,就是划界。在某些书中,划界算法也被称为进退法

【1】什么是单峰区间?什么是单峰函数?
从字面上理解,“单峰”即函数只有一个峰,如下图所示(在区间[-8,8]内是单峰的):

文章来源:http://www.codelast.com/
而下面的这个函数,在区间[2,14]内就不是单峰函数了:

现在,我们再用数学的话来定义一下单峰区间和单峰函数:
[a,b]  为  R  的子集,存在  α[a,b]  ,使得  f(α)  在  [a,α]  上严格单调减,在  [α,b]  上严格单调增,则称  [a,b]  是  f(α)  的单峰区间,  f(α)  是  [a,b]  上的单峰函数。
文章来源:http://www.codelast.com/
【2】“划界”是如何实现的
方法是:寻找使函数值达到“高→低→高”的3个点

如上图所示,当我们找到  a,b,c  这样3个点的时候,它们就能确定一个单峰区间了。
一定有人会有疑问说:这不一定,万一  b,c  之间还有一个峰怎么办?确实,这里举的例子并不是一个完善的例子,在一个实用的划界程序中,它所做的考虑会非常多,各种意外情况都要处理,此处只是为了说明“划界”是怎么一回事,以及一个最简单的划界程序是怎么做的。
文章来源:http://www.codelast.com/
与各种教科书上仅有令人讨厌的公式说明不同(从不考虑读者的感受),我把几个简单的划界步骤画成了几幅图,我觉得有小学文凭已经足够理解了(一图胜千言):

文章来源:http://www.codelast.com/
起始点为  x0  ,假设一开始向右寻找,步长为  h  ,图中的  k  表示迭代的次数。
则第一点挪动到了  x1=x0+h  ,计算函数值,发现  f(x1)<f(x0)  ,很好,“高→低→高”的3点中,我们已经有了两点。
然后下一点我们挪动到  x2=x1+t×h,t>1  ,这里用加倍系数  t  来乘以步长是为了加速搜索的过程。再计算函数值,发现  f(x2)>f(x1)  ,很好,我们已经找到了“高→低→高”的3点。任务完成,  [a,b]  即为所求区间。
总结一下步骤就是:
x1=x0+h  
x2=x1+t×h  
文章来源:http://www.codelast.com/

如果运气没那么好,例如:

文章来源:http://www.codelast.com/
即:
和①一样,搜索也经历了  x0,x1,x2  这几个点,与①不同的是,到了  x2  点之后,我们发现其函数值仍然小于  x1  点处的函数值,也就是说,我们还没有找到“高→低→高”的3点。
于是我们继续放大步长,令  x3=x2+t×t×h  ,再计算函数值,发现  f(x3)>f(x2)  ,很好,我们已经找到了“高→低→高”的3点。任务完成,  [a,b]  即为所求区间。
总结一下步骤就是:
x1=x0+h  
x2=x1+t×h  (加大步长)
x3=x2+t×t×h  (继续加大步长)
文章来源:http://www.codelast.com/

①是向右搜索,如果我们运气更差一些,一开始就是个错误(应该向左搜索),怎么办?

文章来源:http://www.codelast.com/
如上图,起始点为  x0  ,第一个挪动到的点起始点为  x1  ,而  x1  处的函数值竟然比起始点  x0  处的函数值要大(函数值不降反升)。于是我们可以向左搜索(将步长  h  设为负值),并且把  x1  挪到  x0  ,继续按①的节奏进行下去。
总结一下步骤就是:
x1=x0+h  (发现函数值不降反升)
h=h  (步长设为负值,向左搜索)
x1=x0  (重置  x1  点)
x2=x1+h  
x3=x2+t×h  (加大步长,函数值回升,停止搜索)
文章来源:http://www.codelast.com/
【3】加快划界的速度:逆抛物内插
有没有什么办法可以加快划界的速度呢?有,逆抛物内插Inverse Parabolic Interpolation)就是一种技术,它可以使得划界算法超线性收敛
为了解释什么是逆抛物内插,这里用书上的一幅图来讲解:

文章来源:http://www.codelast.com/
如图,实线为目标函数曲线。在该曲线上,如果我们要尽快逼近极小值点,可以这样做:通过①②③三点作一条抛物线(图中粗虚线所示),可以计算出该抛物线的极小值点的横坐标,从而可以找到同一横坐标下,目标函数上的点,即点④;然后再过①②④三点作一条抛物线(图中细虚线所示),可以计算出该抛物线的极小值点的横坐标,从而又可以找到同一横坐标下,目标函数上的点,即点⑤。这样,我们就很快地逼近了极小值。

那么,过三点的抛物线,其极小值点的横坐标怎么求?
已知函数  f(x)  ,过  f(a),f(b),f(c)  三点的抛物线,其极小值点的横坐标  x  为:

文章来源:http://www.codelast.com/
注:为什么叫“”?因为上面的方法是用来求横坐标  x  ,而不是求  y  的。

有人会问:划界的目标就是找到3个点,而你怎么会预先知道3个点的坐标,从而进行逆抛物内插?这不是因果倒置了吗?
其实,这里的三个点,并不是划界的结果,而是初始的猜测,通过初始的猜测点进行逆抛物内插,再根据内插点的不同情况,分别作不同的处理,最终可以找到划界的3个点。
例如,我们总要知道两个初始点  a,b  吧?好吧,如果你已知的真的只有一个点  a  ,那么  b  就随便取比  a  大一点的值好了,这也能凑够两个点啊。通过这两个点,可以通过  c=b+COE×(ba) 来得到猜测的第一个  c  点(这里的  COE  表示一个系数,例如1.618),从而可以通过这3点开始逆抛物内插。
文章来源:http://www.codelast.com/
一个实用的划界程序还是挺复杂的——这里的复杂是比较于上面陈述的最简单的划界算法来说的,因为要保证程序在很多“意外情况”下都能正确运行,必须做很多工作。这里就不分析具体的程序了,大家可以到网上找来看一下。

一维焓法并不是一个常见的术语,但在数值优化领域中,“一维搜索”通常指的是在一维空间内寻找某个函数的最小值或最大值的过程。这可能是指您提到的“一维焓法”的概念背景。基于您的需求以及现有引用中的相关内容,这里尝试解释并提供一种类似的实现思路。 ### 一维焓法的理解 在一维搜索过程中,目标是最小化或最大化某一特定的目标函数 \( f(x) \),其中 \( x \) 是单一变量。虽然“焓”这一词更多见于热力学领域,指代系统的能量状态之一,在此假设它可能是对某种物理现象建模后的抽象表达形式。因此,我们可以将其视为一种特殊的一维搜索问题[^1]。 #### 方法概述 对于一维焓法的具体实现,可以借鉴已知的一维搜索技术如进退法、平分法等的思想来进行设计: 1. **初始化参数** 需要设定初始点 \( x_0 \) 和步长增量 \( h_0 \),同时定义停止准则(例如误差容忍度 \( \epsilon \))。 2. **确定搜索区间** 使用类似于进退法的方法找到包含极值点的一个有限闭合区间 [\( a, b \)]。该过程确保所选区域至少覆盖了一个局部极小值位置[^2]。 3. **逐步逼近最佳解** 应用精确或者近似策略进一步缩小区间范围直到满足预设精度要求为止。比如利用黄金分割法、斐波那契查找或者其他更高效的算法完成最终定位工作[^4]。 以下是基于MATLAB伪代码框架下的一种简化版实现方案示例: ```matlab function result = oneDimEnthalpyMethod(fx, x_start, step_size, tol) % fx为目标函数句柄; % x_start为起始猜测值; % step_size初试移动距离; % tol允许的最大绝对误差 f = @(x) eval(fx); % Step 1: Find bracketing interval using similar approach as 'JT' method. [interval_a, interval_b] = findBracketInterval(f, x_start, step_size); % Step 2: Refine solution within the found brackets via chosen technique e.g., Bisection Method here. current_width = abs(interval_b - interval_a); while current_width > tol midpoint = (interval_a + interval_b)/2; if sign(diff([f(midpoint), f(interval_a)])) ~= ... sign(diff([f(midpoint), f(interval_b)])) interval_b = midpoint; else interval_a = midpoint; end current_width = abs(interval_b - interval_a); endwhile result = (interval_a + interval_b)/2; endfunction % Helper Function to Bracket Interval function [a, b] = findBracketInterval(func, init_x, delta) direction = 1; prev_val = func(init_x); next_x = init_x + direction * delta; curr_val = func(next_x); while curr_val >= prev_val direction = -direction; next_x = init_x + direction * delta; curr_val = func(next_x); endwhile a = min(init_x, next_x); b = max(init_x, next_x); endfunction ``` 以上脚本展示了如何通过不断调整方向来锁定潜在最优解所在的子域,并随后运用二分查找原理细化候选集直至达到指定准确率级别。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值