在学习了之前几期一维搜索算法后,今天我们来分析两种最新的算法,分别是两点三次插值法和两点插值法。之前的几种算法,在整个搜索过程中只对函数值进行了比较,在删除“坏”的区间时,已经计算出的函数值并没有得到充分的利用。今天介绍的两种方法是利用低次多项式P(x)在搜索区间上逼近目标函数,然而用近似多项式P(x)的极小点作为新区间的分割点的方法。近似多项式P(x)取二次多项式,则得二次插值法;取三次多项式,则得三次插值法。

二次插值法:

算法分析:

基本思想:在极小点附近,用二次三项式P(x)逼近目标函数f(x),P(x)与f(x)在三点x_{1}< x_{2}< x_{3}有相同的函数值,并假设:

f(x_{1})> f(x_{2}),f(x_{2})< f(x_{3})

令                                                      P(x) = a + bx + cx^{2},

又令                                          P(x_{1}) = a + bx_{1} + cx_{1}^{2}= f(x_{1})

P(x_{2}) = a + bx_{2} + cx_{2}^{2}= f(x_{2})

P(x_{3}) = a + bx_{3} + cx_{3}^{2}= f(x_{3})

记                B_{1}=(x_{2}^{2}-x_{3}^{2})f(x_{1}),B_{2}=(x_{3}^{2}-x_{1}^{2})f(x_{2}),B_{3}=(x_{1}^{2}-x_{2}^{2})f(x_{3})

C_{1}=(x_{2}-x_{3})f(x_{1}),C_{2}=(x_{3}-x_{1})f(x_{2}),C_{3}=(x_{1}-x_{2})f(x_{3})

D=(x_{1}-x_{2})(x_{2}-x_{3})(x_{3}-x_{1})

则可得:

b=\frac{B_{1}+B_{2}+B_{3}}{D}

c=-\frac{C_{1}+C_{2}+C_{3}}{D}

P'(x)=0\Rightarrow x=-\frac{b}{2c},将P(x)的驻点x记作\bar{x_{k}},则\bar{x_{k}}=\frac{B_{1}+B_{2}+B_{3}}{2(C_{1}+C_{2}+C_{3})}

这样,把\bar{x_{k}}作为f(x)的极小点的一个估计,再从x_{1}, x_{2}, x_{3},\bar{x_{k}}中选择目标函数值最小的点,以及其左右两点,给予相应的下标,代入上式,求出极小点的新的估计值\bar{x_{k+1}},以此类推,产生点列{\bar{x_{k}}},满足\left | f(\bar{x_{k+1}})- f(\bar{x_{k}})\right |< \epsilon或者\left | \left | \bar{x_{k+1}}-\bar{x_{k}} \right | \right |< \delta,终止迭代。

例题分析:

下面我们通过例题来进一步探讨:

例题:用二次插值法求函数f(x)=3x^{4}-4x^{3}-12x^{2}的极小点,迭代三次给定x_{1}=-1.2,x_{2}=-1.1,x_{3}=-0.8.

解:由已知三个点,可求出(-1.2,-4.1472),(-1.1,-4.8037),(-0.8,-4.4032)

由迭代公式:

B_{1}=(x_{2}^{2}-x_{3}^{2})f(x_{1}),B_{2}=(x_{3}^{2}-x_{1}^{2})f(x_{2}),B_{3}=(x_{1}^{2}-x_{2}^{2})f(x_{3})

C_{1}=(x_{2}-x_{3})f(x_{1}),C_{2}=(x_{3}-x_{1})f(x_{2}),C_{3}=(x_{1}-x_{2})f(x_{3})

D=(x_{1}-x_{2})(x_{2}-x_{3})(x_{3}-x_{1})

\therefore \bar{x_{k}}=\frac{B_{1}+B_{2}+B_{3}}{2(C_{1}+C_{2}+C_{3})}=-0.984

迭代次数x_{1}x_{2}x_{3}x_{4}
第一次x-1.2-1.1-0.8-0.984
f-4.147-4.804-4.403-4.996
第二次x-1.1-0.984-0.8-0.990
f-4.804-4.996-4.403-4.998
第三次x-1.1-0.990-0.984-1.008
f-4.804-4.998-4.996-4.999

那么我们看这个迭代结果,不难发现,求出的极小点是x=-1的近似值,并不是问题的全局最优解(x=2),由此,我们可以确定二次插值法对于初始点的要求较高,有时求出的并不是全局最优解,而是局部最优解。


算法代码:

'''
二次插值算法(抛物线法)
2023.10.9
'''


def fun(x):
    return x ** 2 + 2 * x - 10
def run(x1, x2, x3):
    B1 = (x2 * x2 - x3 * x3) * fun(x1)
    B2 = (x3 * x3 - x1 * x1) * fun(x2)
    B3 = (x1 * x1 - x2 * x2) * fun(x3)
    C1 = (x2 - x3) * fun(x1)
    C2 = (x3 - x1) * fun(x2)
    C3 = (x1 - x2) * fun(x3)
    D = (x1 - x2) * (x2 - x3) * (x3 - x1)
    if (B1 + B2 + B3) == 0:
        x0 = 0
    else:
        x0 = (B1 + B2 + B3) / (2 * (C1 + C2 + C3))
    Arr = [x0, x1, x2, x3]
    Arr.sort()
    if fun(x0) > fun(x2):
        index = Arr.index(x2)
        x1 = Arr[index - 1]
        x3 = Arr[index + 1]
    else:
        index = Arr.index(x0)
        x2 = x0
        x1 = Arr[index - 1]
        x3 = Arr[index + 1]
    return x1, x2, x3
def text(x1, x2, x3, ε):
    count = 0
    while abs(x3 - x1) and abs(x3 - x2) and abs(x2 - x1) > ε:
        count = count + 1
        print("第{}次迭代".format(count))
        Arr2 = run(x1, x2, x3)
        x1 = Arr2[0]
        x2 = Arr2[1]
        x3 = Arr2[2]
        print(Arr2)
    print("该精度下的最优解为:%f" % x2)
    print("函数在该精度上的最小值为",fun(x2))
    return
text(-3, 0.5, 4, 0.0001)

用该代码所运算的结果为:

第1次迭代
(-3, -1.0, 0.5)
第2次迭代
(-3, -1.0, -1.0)
该精度下的最优解为:-1.000000
函数在该精度上的最小值为 -11.0

总结:

二次插值法的优点在于对于局部最优解迭代速度较快,但是缺点也较明显,对于选定的三点,要求较高,有时求出的不是全局最高解而是局部最优解。


三次插值法:

算法分析:

基本思想:首先选取两个初始点x_{1},x_{2},(x_{1}<x_{2}),使得f'(x_{1})< 0,f'(x_{2})> 0,这样,在区间(x_{1}x_{2})内存在极小点,然后利用这两点的函数值和导数值,构造一个三次多项式P(x),使它与f(x)x_{1},x_{2}具有相同的函数值和导数值,用P(x)逼近函数f(x),进而用P(x)的极小点估计f(x)的极小点。

令                                P(x) = a(x-x_{1}) ^{3}+ b(x-x_{1}) ^{2} + c(x-x_{1}) +d

满足:            P(x_{1}) = f(x_{1})P'(x_{1}) = f'(x_{1})P(x_{2}) = f(x_{2})P'(x_{2}) = f'(x_{2})

代入可得:                                                  d = f(x_{1})

c = f'(x_{1})

a(x_{2}-x_{1}) ^{3}+ b(x_{2}-x_{1}) ^{2} + c(x_{2}-x_{1}) +d=f(x_{2})

3a(x_{2}-x_{1}) ^{2}+ 2b(x_{2}-x_{1}) + c =f'(x_{2})

解上述方程组,可求出系数a,b,c,d,从而确定三次多项式函数

求P(x)的极小点,由极小点的必备条件,既求满足P'(x)=0,P''(x)> 0的点,

由                  P'(x)=3a(x-x_{1}) ^{2}+ 2b(x-x_{1}) + c,P''(x)=6a(x-x_{1})+2b

P'(x)=0,                        3a(x-x_{1}) ^{2}+ 2b(x-x_{1}) + c=0

解方程,有两种情形:

(1)当a=0时,\bar{x}-x_{1}=-\frac{c}{2b}

(2)当a\neq0时,\bar{x}-x_{1}=\frac{-b\pm \sqrt{b^{2}-3ac}}{3a}

第一种情况下,由假设c = P'(x_{1})<0,P'(x_{2})>0,x_{1}<x_{2}

以及3a(x_{2}-x_{1}) ^{2}+ 2b(x_{2}-x_{1}) + c =P'(x_{2}),可得b>0,

因此P''(x)=2b> 0,故\bar{x}是P(x)的极小点。

第二种情况下,代入,由

P''(\bar{x})=6a(\bar{x}-x_{1})+2b=6a\frac{-b\pm \sqrt{b^{2}-3ac}}{3a}+2b=\pm 2\sqrt{b^{2}-3ac}

要使P''(x)> 0,则取               \bar{x}-x_{1}=\frac{-b+\sqrt{b^{2}-3ac}}{3a}=\frac{-c}{b+\sqrt{b^{2}-3ac}}

故两种情况,极小点可以统一写成            \bar{x}-x_{1}=\frac{-c}{b+\sqrt{b^{2}-3ac}}

记:

s=\frac{3[f(x_{2}-f(x_{1}))]}{x_{2}-x_{1}},z=s-f'(x_{1})-f'(x_{2}),w^{2}=z^{2}-f'(x_{1})f'(x_{2}),(w>0)

可推断出:

s=3[a(x_{2}-x_{1}) ^{2}+ 2b(x_{2}-x_{1}) + c]

z=b(x_{2}-x_{1}) + c

w^{2}=(x_{2}-x_{1})^{2}(b^{2}-3ac)

继续推导:

b=\frac{z-c}{x_{2}-x_{1}}=\frac{z-f'(x_{1})}{x_{2}-x_{1}}

b^{2}-3ac=\frac{w^{2}}{(x_{2}-x_{1})^{2}}

代入得:

\bar{x}-x_{1}=\frac{-f'(x_{1})(x_{2}-x_{1})}{z-f'(x_{1})+2w}

又将等式右端上下同时乘以f'(x_{2}),得到下式:

\bar{x}-x_{1}=\frac{-f'(x_{1})(x_{2}-x_{1})f'(x_{2})}{[z-f'(x_{1})+2w]f'(x_{2})}=\frac{(x_{2}-x_{1})(w+z)}{f'(x_{2})+(w-z)}

将两个式子相加,我们可以得到:

\bar{x}-x_{1}=\frac{(x_{2}-x_{1})[w+z-f'(x_{1})]}{f'(x_{2})-f'(x_{1})+2w}

化简为:

\bar{x}=x_{1}+(x_{2}-x_{1})[1-\frac{w+z+f'(x_{2})}{f'(x_{2})-f'(x_{1})+2w}]

其中,f'(x_{2})-f'(x_{1})+2w>0成立。由此,可利用f(x_{1})f'(x_{1})f(x_{2})f'(x_{2})就可以求出P(x)的极小点。若\left | f(\bar{x})\right |充分小,就可以将P(x)的极小点作为f(x)的可接受的极小点;否则,可以从x_{1},x_{2}\bar{x}中确定两个点重复以上过程。

例题分析:

下面我们通过例题来进一步加深对算法的理解,

例题:用三次插值法求解下列问题:min f(x)=x^{3}-3x+1,s.t. 0\leq x\leq 2,初始点取x_{1}=0,x_{2}=2

解:                                          x_{1}=0,x_{2}=2x_{2}-x_{1}=2

f(x)=x^{3}-3x+1,f'(x)=3x^{2}-3,f''(x)=6x

f(x_{1})=1,f'(x_{1})=-3,f''(x_{1})=0

f(x_{2})=3,f'(x_{2})=9,f''(x_{2})=12

s=\frac{3[f(x_{2}-f(x_{1}))]}{x_{2}-x_{1}}=3

z=s-f'(x_{1})-f'(x_{2})=-3

w^{2}=z^{2}-f'(x_{1})f'(x_{2})=36

\bar{x}=x_{1}+(x_{2}-x_{1})[1-\frac{w+z+f'(x_{2})}{f'(x_{2})-f'(x_{1})+2w}]=1

f(\bar{x})=f(1)=-1,f'(\bar{x})=0

经过一次迭代,就可以达到最优解。


算法代码:

'''
三次插值算法
2023.10.9
'''
from sympy import *
x = symbols("x")
f_x = x**3-12*x-20

def run(x1,x2,ε):
    count = 0
    # 一阶求导
    first_grad = diff(f_x,x)
    # 判断给定区间内是否存在极小点
    if first_grad.subs({x: x1}) * first_grad.subs({x: x2}) > 0:
        print("该函数在该区间不存在极小点")
    else:
        print("该函数在该区间存在极小点")
        while abs(x2-x1) >= ε:
            count = count+1
            print("第{}次迭代".format(count))
            s = 3*( f_x.subs(x,x2) - f_x.subs(x,x1) )/(x2-x1)
            z = s - first_grad.subs({x: x1})-first_grad.subs({x: x2})
            w = (z * z -first_grad.subs({x: x1})*first_grad.subs({x: x2}))**0.5
            x0 = x1 + (x2-x1)*(1-((first_grad.subs({x: x2}))+w+z)/(first_grad.subs({x: x2})-first_grad.subs({x: x1})+2*w))
            if first_grad.subs({x: x0}) == 0:
                print("该精度下的最优解为:%f"%x0)
                break
            elif first_grad.subs({x: x0}) > 0:
                x1 = x0
            elif first_grad.subs({x: x0}) < 0:
                x2 = x0
        print("该精度下的最优解为:%f" % x0)
        return

run(1,5,0.001)

用该代码所运算的结果为:

该函数在该区间存在极小点
第1次迭代
该精度下的最优解为:2.000000
该精度下的最优解为:2.000000

总结:

三次插值法的收敛阶为2,一般认为要优于二次插值法。

算法比较:

从上面的一些例子,不难看出:在一维搜索方法中,利用导数的算法一般优于不利于导数的直接法,比如两分法,牛顿切线法,三次插值法优于成功—失败法,黄金分割算法和二次插值法;利用二阶导数的算法优于利用一阶导数的算法,如牛顿切线法优于二分法,当然也不尽然。

(行文中若有纰漏,希望大家指正)

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐