【最优化】简单线搜索(黄金分割法,斐波那契法,固定步长法......)

黄金分割法(Golden Section Method)和斐波那契法(Fibonacci Method)极为相似,唯一的区别就是试探点的公式不一样而已。相比较,斐波那契法更为灵活更为强大。斐波那契法介于二分搜索和黄金分割法之间。

Fibonacci数列:1,1,2,3,5,8,13,21,34,55,89,144......

可见,相邻两项的比值从0.5渐渐变为0.618并趋近于0.618。

而固定步长法(Fixed Step Method)其实就是线搜索里面的“进退法”。

一、进退法(Fixed固定步长法)

选取初始值和固定的步长,然后向前计算试探点及其函数值,找到最低点直到该方向的函数值变大而停止迭代。

二、黄金分割法的算法如下:

三、斐波那契法算法如下:

 

Python程序:

所用函数如下:

f(x)=min{x/2, 2-(x-3)^2, 2-x/2}

# -*- coding: utf-8 -*-
# @Author : ZhaoKe
# @Time : 2022-10-09 15:29
import numpy as np
import matplotlib.pyplot as plt

def fun(x):
    f1 = x / 2
    f2 = 2-(x-3)**2
    f3 = 2-x/2
    f = np.vstack((f1, f2, f3))
    # print(f)
    return -np.min(f, axis=0)


def fun_grad(x):
    return [2*x[0], 2*x[1]]

def golden_section(f, left, right, eps):
    print("===========Golden Section Search==========")
    lam = left + 0.382*(right-left)
    mu = left + 0.618*(right-left)
    k = 1
    tol = right - left
    flam, fmu = 0, 0
    while tol > eps and k < 100000:
        flam = f(lam)
        fmu = f(mu)
        print("k=", k)
        print(f"lam={lam}, mu={mu}, flam={flam}, fmu={fmu}")
        if flam > fmu:
            left = lam
            lam = mu
            mu = left + 0.618*(right-left)
        else:
            right = mu
            mu = lam
            lam = left + 0.382*(right-left)
        k = k + 1
        tol = np.abs(right-left)
        print(f"left={left}, right={right}")
    if k == 100000:
        print("找不到最小值")
        x = None
        minf = None
        return
    x = (left + right) / 2
    min_f = f(x)
    print("极值点:", x, ",函数值: ", min_f)


def fibonacci_search(f, left, right, eps):
    print("===========Fibonacci Search==========")
    N = (right-left) / eps
    n = 1
    Fib = [1, 1]
    c = Fib[1] - N
    flam, fmu = 0, 0
    while c < 0:
        n += 1
        Fib.append(Fib[n-1] + Fib[n-2])
        c = Fib[n] - N
    print(Fib[0:12])
    lam = left + Fib[n-2]/Fib[n] * (right - left)
    mu = left + Fib[n-1]/Fib[n] * (right - left)
    k = 1
    while k < n-3:
        flam = fun(lam)
        fmu = fun(mu)
        if flam > fmu:
            left = lam
            lam = mu
            mu = left + Fib[n-1-k]/Fib[n-k] * (right-left)
        else:
            right = mu
            mu = lam
            lam = left + Fib[n-2-k]/Fib[n-k] * (right-left)
        k += 1
    x = (left + right) / 2
    min_f = f(x)
    print("极值点:", x, ",函数值: ", min_f)


def fixedStepMethod(f, left, right, eps):
    print("===========Fixed Step Search==========")
    delta_s = 2
    dire = 1
    alpha = 1
    x0 = (left + right)/2
    old_x0 = None
    new_x0 = x0 + delta_s
    fx0 = f(x0)
    fx1 = f(new_x0)
    # print(f"fx0={fx0}, fx1={fx1}")
    k = 0
    x_list = [x0, new_x0]
    while True:
        fx0 = fx1
        fx1 = f(new_x0)
        if fx1 < fx0:
            # print("fx1 < fx0")
            alpha += 1
            delta_s = delta_s + dire * alpha * delta_s
            old_x0 = x0
            x0 = new_x0
            new_x0 = x0 + delta_s
            k += 1
        else:
            # print("fx1 >= fx0")
            if k == 0:
                # print("--k=0---")
                dire = -dire
                delta_s = delta_s + 2*dire * alpha * delta_s
                old_x0 = x0
                new_x0 = x0 + delta_s
                fx1 = f(new_x0)
                k = 1
            else:
                # print('--k>0--')
                left = old_x0 if old_x0 < new_x0 else new_x0
                right = old_x0 if old_x0 > new_x0 else new_x0
                break
        x_list.append(new_x0)
        # print("k: ", k)
        # print(f"old x new={old_x0},{x0},{new_x0}")
        # print(f"f0 f1={fx0}, {fx1}")
        # print("step", delta_s)
    # print(left, right)
    x_min = (left + right) / 2
    f_min = f(x_min)
    print(f"x={x_min}, f={f_min}")
    # plt.figure(0)
    # p_x = np.arange(-1, 9, 0.05)
    # p_y = fun(p_x)
    # plt.plot(p_x, p_y)
    # plt.plot(x_list, f(np.array(x_list)))
    # plt.show()

def draw():
    plt.figure(0)
    p_x = np.arange(-1, 9, 0.05)
    p_y = fun(p_x)
    plt.plot(p_x, p_y)
    plt.show()


if __name__ == '__main__':
    golden_section(fun, 0, 8, 0.05)
    fibonacci_search(fun, 0, 8, 0.05)
    fixedStepMethod(fun, 0, 8, 0.05)
    # draw()

 

计算结果:

C:\Users\zhaoke\.conda\envs\tacotron2cn\python.exe D:/PythonWorkspace/tacotron2cn/course-optimization/unconstrained/GoldenFibonacci.py
===========Golden Section Search==========
left=1.993884615308544, right=2.0341002823564076
极值点: 2.013992448832476 ,函数值:  [-0.99300378]
===========Fibonacci Search==========
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
极值点: 1.9742489270386265 ,函数值:  [-0.94783474]
===========Fixed Step Search==========
x=3.0, f=[-0.5]

显然两个算法所得结果都与真实值极为相近(见上图。)

 

posted @ 2022-10-09 15:54  倦鸟已归时  阅读(1368)  评论(0编辑  收藏  举报