【MATLAB学习笔记】数值方法——二次插值法(求极小值)

前言

  二次插值法是一种数值优化方法,用于求解函数的极小值。其基本思想是通过对函数进行二次插值来逼近极小值点的位置,并通过求解插值函数的极小值点来得到函数的极小值。

具体步骤如下:

  1. 选择一个起始点,并计算该点处的函数值和一阶导数值;
  2. 根据起始点和一阶导数值,构造一个二次插值函数,通常采用二次多项式来表示;
  3. 求解二次插值函数的极小值点,得到新的近似极小值点;
  4. 判断新的近似极小值点与前一次的近似极小值点之间的误差是否小于预设的精度要求,如果满足则停止迭代,否则返回步骤2,继续迭代。

  需要注意的是,二次插值法可能会因为插值函数的形状而导致迭代过程不稳定,因此在实际应用中需要根据具体情况选择合适的起始点和迭代策略,以确保能够得到准确的极小值点。

算法流程图

在这里插入图片描述
注:其中的 h h h表示区间消去法的步长,具体可以看这篇文章

算法代码

function Paowuxian_minValue(f_sym,x0,eps,N,h)
    % f_sym为所求函数, 符号函数
    % x0为初始点,默认为0
    % eps为允许误差, 默认为1e-4
    % N为最大迭代次数, 默认为500
    % h为区间消去法迭代步长, 默认为0.01
    if nargin < 2, x0 = 0; end
    if nargin < 3, eps = 1e-4; end
    if nargin < 4, N = 500; end
    if nargin < 5, h = 0.01; end
    
    f = matlabFunction(f_sym);
    y = f(x0);

    x = x0;
    k = 0;
    fprintf('函数f=%s迭代开始:\n',f_sym)
    while true
        k = k + 1;
        c1 = (y(3) - y(1))/(x(3)-x(1));
        c2 = ( (y(2)-y(1))/(x(2)-x(1)) - c1 ) / (x(2)-x(3));
        xp = (1/2)*(x(1) + x(3) - c1/c2 );
        yp = f(xp);

        fprintf('k=%2.d, x1=%.4f, x2=%.4f, x3=%.4f, xp=%.4f, fp=%.4f\n',k,x(1),x(2),x(3),xp,yp);
        
        if abs((y(2)-yp)/y(2)) < eps
            if y(2)<yp
                x_star = x(2);
            else
                x_star = xp;
            end
            y_star = f(x_star);
            fprintf('已收敛!结果如下:\nk=%2.d, x1=%.4f, x2=%.4f, x3=%.4f, x_star=%.4f, f_star=%.4f',...
                k,x(1),x(2),x(3),x_star,y_star);
            break
        end

        if (xp - x(2))*h > 0
            if y(2) >= yp
                x(1) = x(2);
                y(1) = y(2);
                x(2) = xp;
                y(2) = yp;
            else
                x(3) = xp;
                y(3) = yp;
            end
        else
            if y(2) >= yp
                x(3) = x(2);
                y(3) = y(2);
                x(2) = xp;
                y(2) = yp;
            else
                x(1) = xp;
                y(1) = yp;
            end
        end

        if k > N
            fprintf('已经超出最大迭代次数%d!\n',N)
            break
        end

    end
    fprintf('\n\n')

end

测试

测试函数如下:

syms x
f1_sym = (1/4)*x.^4 - (4/3)*x.^3 + (5/2)*x.^2 - 2*x ;
f2_sym = 8*x.^3 - 2*x.^2 - 7*x + 3;

解析解

% 解析解
f1 = diff(f1_sym);
x1_min = double(vpa(solve(f1,x)));
f2 = diff(f2_sym);
x2_min = double(vpa(solve(f2,x)));
x1_minx2_min
2.00000.6298

注:上表格仅展示了局部解。

算法解

x01 = [1,0,3];
x02 = [0,1,2];
eps1 = 1e-6;
eps2 = 1e-6;
N = 100;
Paowuxian_minValue(f1_sym,x01,eps1,N)
Paowuxian_minValue(f2_sym,x02,eps2,N)

迭代过程如下:

函数f=(5*x^2)/2 - 2*x - (4*x^3)/3 + x^4/4迭代开始:
k= 1, x1=1.0000, x2=0.0000, x3=3.0000, xp=1.2000, fp=-0.5856
k= 2, x1=0.0000, x2=1.2000, x3=3.0000, xp=1.1951, fp=-0.5854
k= 3, x1=1.1951, x2=1.2000, x3=3.0000, xp=1.2341, fp=-0.5869
k= 4, x1=1.2000, x2=1.2341, x3=3.0000, xp=1.2589, fp=-0.5880
k= 5, x1=1.2341, x2=1.2589, x3=3.0000, xp=1.2962, fp=-0.5901
k= 6, x1=1.2589, x2=1.2962, x3=3.0000, xp=1.3351, fp=-0.5927
k= 7, x1=1.2962, x2=1.3351, x3=3.0000, xp=1.3820, fp=-0.5966
k= 8, x1=1.3351, x2=1.3820, x3=3.0000, xp=1.4336, fp=-0.6017
k= 9, x1=1.3820, x2=1.4336, x3=3.0000, xp=1.4907, fp=-0.6082
k=10, x1=1.4336, x2=1.4907, x3=3.0000, xp=1.5507, fp=-0.6160
k=11, x1=1.4907, x2=1.5507, x3=3.0000, xp=1.6120, fp=-0.6247
k=12, x1=1.5507, x2=1.6120, x3=3.0000, xp=1.6718, fp=-0.6335
k=13, x1=1.6120, x2=1.6718, x3=3.0000, xp=1.7279, fp=-0.6417
k=14, x1=1.6718, x2=1.7279, x3=3.0000, xp=1.7784, fp=-0.6488
k=15, x1=1.7279, x2=1.7784, x3=3.0000, xp=1.8223, fp=-0.6544
k=16, x1=1.7784, x2=1.8223, x3=3.0000, xp=1.8594, fp=-0.6585
k=17, x1=1.8223, x2=1.8594, x3=3.0000, xp=1.8900, fp=-0.6615
k=18, x1=1.8594, x2=1.8900, x3=3.0000, xp=1.9146, fp=-0.6634
k=19, x1=1.8900, x2=1.9146, x3=3.0000, xp=1.9342, fp=-0.6647
k=20, x1=1.9146, x2=1.9342, x3=3.0000, xp=1.9496, fp=-0.6655
k=21, x1=1.9342, x2=1.9496, x3=3.0000, xp=1.9615, fp=-0.6660
k=22, x1=1.9496, x2=1.9615, x3=3.0000, xp=1.9707, fp=-0.6663
k=23, x1=1.9615, x2=1.9707, x3=3.0000, xp=1.9778, fp=-0.6664
k=24, x1=1.9707, x2=1.9778, x3=3.0000, xp=1.9832, fp=-0.6665
k=25, x1=1.9778, x2=1.9832, x3=3.0000, xp=1.9873, fp=-0.6666
k=26, x1=1.9832, x2=1.9873, x3=3.0000, xp=1.9904, fp=-0.6666
k=27, x1=1.9873, x2=1.9904, x3=3.0000, xp=1.9927, fp=-0.6666
k=28, x1=1.9904, x2=1.9927, x3=3.0000, xp=1.9945, fp=-0.6667
k=29, x1=1.9927, x2=1.9945, x3=3.0000, xp=1.9959, fp=-0.6667
k=30, x1=1.9945, x2=1.9959, x3=3.0000, xp=1.9969, fp=-0.6667
k=31, x1=1.9959, x2=1.9969, x3=3.0000, xp=1.9977, fp=-0.6667
k=32, x1=1.9969, x2=1.9977, x3=3.0000, xp=1.9982, fp=-0.6667
k=33, x1=1.9977, x2=1.9982, x3=3.0000, xp=1.9987, fp=-0.6667
k=34, x1=1.9982, x2=1.9987, x3=3.0000, xp=1.9990, fp=-0.6667
已收敛!结果如下:
k=34, x1=1.9982, x2=1.9987, x3=3.0000, x_star=1.9990, f_star=-0.6667

函数f=8*x^3 - 2*x^2 - 7*x + 3迭代开始:
k= 1, x1=0.0000, x2=1.0000, x3=2.0000, xp=0.5227, fp=-0.0629
k= 2, x1=0.0000, x2=0.5227, x3=1.0000, xp=0.5491, fp=-0.1223
k= 3, x1=0.5227, x2=0.5491, x3=1.0000, xp=0.6131, fp=-0.1998
k= 4, x1=0.5491, x2=0.6131, x3=1.0000, xp=0.6207, fp=-0.2024
k= 5, x1=0.6131, x2=0.6207, x3=1.0000, xp=0.6274, fp=-0.2034
k= 6, x1=0.6207, x2=0.6274, x3=1.0000, xp=0.6287, fp=-0.2034
k= 7, x1=0.6274, x2=0.6287, x3=1.0000, xp=0.6295, fp=-0.2034
k= 8, x1=0.6287, x2=0.6295, x3=1.0000, xp=0.6297, fp=-0.2034
k= 9, x1=0.6295, x2=0.6297, x3=1.0000, xp=0.6297, fp=-0.2034
已收敛!结果如下:
k= 9, x1=0.6295, x2=0.6297, x3=1.0000, x_star=0.6297, f_star=-0.2034

总代码

clc;clear;close all
%% 
syms x
f1_sym = (1/4)*x.^4 - (4/3)*x.^3 + (5/2)*x.^2 - 2*x ;
f2_sym = 8*x.^3 - 2*x.^2 - 7*x + 3;

% 解析解
f1 = diff(f1_sym);
x1_min = double(vpa(solve(f1,x)));
f2 = diff(f2_sym);
x2_min = double(vpa(solve(f2,x)));

x01 = [1,0,3];
x02 = [0,1,2];
eps1 = 1e-6;
eps2 = 1e-6;
N = 100;
Paowuxian_minValue(f1_sym,x01,eps1,N)
Paowuxian_minValue(f2_sym,x02,eps2,N)

%% 
function Paowuxian_minValue(f_sym,x0,eps,N,h)
    % f_sym为所求函数, 符号函数
    % x0为初始点,默认为0
    % eps为允许误差, 默认为1e-4
    % N为最大迭代次数, 默认为500
    % h为区间消去法迭代步长, 默认为0.01
    if nargin < 2, x0 = 0; end
    if nargin < 3, eps = 1e-4; end
    if nargin < 4, N = 500; end
    if nargin < 5, h = 0.01; end
    
    f = matlabFunction(f_sym);
    y = f(x0);

    x = x0;
    k = 0;
    fprintf('函数f=%s迭代开始:\n',f_sym)
    while true
        k = k + 1;
        c1 = (y(3) - y(1))/(x(3)-x(1));
        c2 = ( (y(2)-y(1))/(x(2)-x(1)) - c1 ) / (x(2)-x(3));
        xp = (1/2)*(x(1) + x(3) - c1/c2 );
        yp = f(xp);

        fprintf('k=%2.d, x1=%.4f, x2=%.4f, x3=%.4f, xp=%.4f, fp=%.4f\n',k,x(1),x(2),x(3),xp,yp);
        
        if abs((y(2)-yp)/y(2)) < eps
            if y(2)<yp
                x_star = x(2);
            else
                x_star = xp;
            end
            y_star = f(x_star);
            fprintf('已收敛!结果如下:\nk=%2.d, x1=%.4f, x2=%.4f, x3=%.4f, x_star=%.4f, f_star=%.4f',...
                k,x(1),x(2),x(3),x_star,y_star);
            break
        end

        if (xp - x(2))*h > 0
            if y(2) >= yp
                x(1) = x(2);
                y(1) = y(2);
                x(2) = xp;
                y(2) = yp;
            else
                x(3) = xp;
                y(3) = yp;
            end
        else
            if y(2) >= yp
                x(3) = x(2);
                y(3) = y(2);
                x(2) = xp;
                y(2) = yp;
            else
                x(1) = xp;
                y(1) = yp;
            end
        end

        if k > N
            fprintf('已经超出最大迭代次数%d!\n',N)
            break
        end

    end
    fprintf('\n\n')

end

总结

  这只是一个基础的示例,实际中还会有更具体的、更细致的要求,这就需要再做额外调整;另外本人也仍在学习中,这只是个人的学习笔记,可能还有一些不足之处,欢迎指正。

参考文献

主编白清顺. 机械优化设计.第6版 [M]. 2017.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Infww

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值