最优化方法 三分法+黄金分割法+牛顿法


最优化_三等分法+黄金分割法+牛顿法

一、实验目的

  1. 掌握一维优化方法的集中算法;

  2. 编写三分法算法

  3. 编写黄金分割法算法

  4. 编写牛顿法算法

二、系统设计

三分法

1.编程思路:

三分法用于求解单峰函数的最值。对于单峰函数,在区间内用两个mid将区间分成三份,这样的查找算法称为三分查找,也就是三分法。在区间[a,b]内部取n=2个内等分点,区间被分为n+1=3等分,区间长度缩短率\(=\frac{1}{3}\) .

各分点的坐标为 \(x_k=a+\frac{b-a}{n+1}\cdot k\ \ (k=1,2)\)

然后计算出\(x_1,x_2,\cdots ;y_1,y_2,\cdots;\)
找出\(y_{min}=min\{y_k,k=1,2\}\) ,新区间\((a,b)\Leftarrow (x_{m-1},x_{m+1})\) .

coding中,建立\(left,mid1,mid2,right\) 四个变量用于计算,用新的结果赋值给旧区间即可。

2.算法描述

function [left]=gridpoint(left,right,f)
epsilon=1e-5;				%给定误差范围
while((left+epsilon)<right)		 %检查left,right区间精度
    margin=(right-left)/3;		%将区间三等分,每小段长度=margin
    m1=left+margin;			%left-m1-m2-right,三等分需要两个点
    m2=m1+margin;			%m2=left+margin+margin
    if(f(m1)<=f(m2))		
        right=m2;			%离极值点越近,函数值越小(也有可能越大,视函数而定)。
    else				%当f(m1)>f(m2),m2离极值点更近。缩小区间范围,逼近极值点
        left=m1;			%所以令left=m1.
    end
end					%这是matlab的.m文件,不用写return.

黄金分割法

1.编程思路

三分法进化版,区间长度缩短率\(\approx 0.618\).

在区间\([a,b]\)上取两个内试探点,\(p_i,q_i\) 要求满足下面两个条件:

\(1.[a_i,q_i]与[p_i,b_i]的长度相同,即b_i-p_i=q_i-a_i;\)

\(2.区间长度的缩短率相同,即b_{i+1}-a_{i+1}=t(b_i-a_i)]\)

image

2.算法描述

自己编写的:
function [s,func_s,E]=my_golds(func,left,right,delta)
tic
%输入:    func:目标函数,left,right:初始区间两个端点
%          delta:自变量的容许误差
%输出:    s,func_s:近似极小点和函数极小值
%           E=[ds,dfunc] ds,dfunc分别为s和dfunc的误差限
%0.618法的改进形式:每次缩小区间时,同时比较两内点和两端点处的函数值。
%当左边第一个或第二个点是这四个点中函数值最小的点时,丢弃右端点,构成新的搜索区间
%否则,丢弃左端点。
%left---------|--mu       lambda,mu为了两个试探点,且lambda<mu
%     lambda--|------right
%根据定理2.1.4 
%若f(lambda_k)<=f(mu_k) 
%   则left_(k+1)=a_k,        right_(k+1)=mu_k
%若f(lambda_k)>f(mu_k)  
%   则left_(k+1)=lambda_k,   right_(k+1)=right_k

t=(sqrt(5)-1)/2;h=right-left; %区间长度缩短率t
lambda=left+(1-t)*h;
mu=left+t*h;
func_left=feval(func,left);
func_right=feval(func,right);
func_lambda=feval(func,lambda);
func_mu=feval(func,mu);
k=1;
G=[func_left,func_lambda,func_mu,func_right];
while(abs(right-left)>delta)
    func_t=min(G);
    if(func_t==func_left|func_t==func_lambda)
        %当func_left,func_lambda较小时,丢弃右端点,即t<3,转步4
        right=mu;
        func_right=func_mu;
        mu=lambda;
        func_mu=func_lambda;
        h=right-left;%漏行!!!!!!!!!!!!
        lambda=left+(1-t)*h; 
        func_lambda=feval(func,lambda);%漏行!!!!!!!!        
    else %当func_mu,func_right较小时,丢弃左端点,即t不<3,转步3
        left=lambda;
        func_left=func_lambda;
        lambda=mu;
        func_lambda=func_mu;
        h=right-left;
        mu=left+t*h;
        func_mu=feval(func,mu);
    end
    k=k+1;
    G=[func_left,func_lambda,func_mu,func_right];
end
ds=abs(right-left);dfunc=abs(func_right-func_left);
if(func_lambda<=func_mu)
    s=lambda;func_s=func_lambda;
else
    s=mu;func_s=func_mu;
end
E=[ds,dfunc];toc;  
书上例程:
%黄金分割法(0.618)
function [s,phi_s,k,G,E]=golds(phi,left,right,delta,epsilon)
tic;
%输入:phi:目标函数;left,right:搜索区间两个端点
% delta,epsilon:自变量和函数值的容许误差
%输出:s,phi_s:近似极小点和极小值,G为n*4矩阵
% 其第k行分别为left,m1,m2,right的第k次迭代值[ak,m1k,m2k,nk]
% E=[ds,dphi] ,分别为s,phis的误差限
t=(sqrt(5)-1)/2;
h=right-left;
phi_left=feval(phi,left);phi_right=feval(phi,right);		
%[y1,y2,...] = feval(fhandle,x1,x2,...,xn)
m1=left+(1-t)*h;m2=left+t*h;
phi_m1=feval(phi,m1);phi_m2=feval(phi,m2);
k=1;
G(k,:)=[left,m1,m2,right];
while((abs(phi_m2-phi_m1)>epsilon)|(h>delta))
	if(phi_m1<phi_m2)
		right=m2;phi_right=phi_m2;
		m2=m1;phi_m2=phi_m1;
		h=right-left;
		m1=left+(1-t)*h;phi_m1=feval(phi,m1);
	else
		left=m1;phi_left=phi_m1;
		m1=m2;phi_m1=phi_m2;
		h=right-left;
		m2=left+t*h;phi_m2=feval(phi,m2);
	end
	k=k+1;G(k,:)=[left,m1,m2,right];
end
ds=abs(right-left);dphi=abs(phi_right-phi_left);
if(phi_m1<=phi_m2)
	s=m1;phi_s=phi_m1;
else
	s=m2;phi_s=phi_m2;
end
E=[ds,dphi]	;toc;

牛顿法

1.编程思路

牛顿法用于求解无约束优化问题,基本思想是用迭代点\(x_k\)处的一阶导数(梯度)和二阶导数(Hessian阵)对目标函数进行二次函数近似,然后用二次模型的极小点作为新的迭代点,并不断重复,直到求得满足精度要求的近似极小点。

其迭代公式为:\(x_{k+1}=x_k-G^{-1}_kg_k\)
image
image
image
image
image

【书上的推导看得脑壳痛,还是PPT简单易懂】

image

2.算法描述

DIY:
function [min,k]=NR1(f,x0,epsilon,var)
%x0表示起始点
%f为函数
%epsilon表示误差范围
%var表示函数变量名
error=epsilon+1;
k=0;
diff(f)
while((error>epsilon)&(k<1000))
    if(subs(diff(f),var,x0)==0)
        break
    end
    x1=x0-subs(diff(f),var,x0)/subs(diff(f,2),var,x0);
    x1=double(x1);
    error=abs(x1-x0);
    x0=x1;k=k+1;
end
min=x0;

例程:

  • 修正牛顿法

  • 阻尼牛顿法

    function [x,val,k]=dampnm(fun,gfun,Hess,x0)
    %功能:用阻尼牛顿法求解无约束问题:min f(x)
    %输入:x0是初始点,fun,gfun,Hess分别求目标函数值,梯度,Hessian阵的函数
    %输出:x,val分别为近似最优点和最优值,k为迭代次数
    maxk=100;		%给出最大迭代次数
    rho=0.55;sigma=0.4;
    k=0;epsilon=1e-5;
    while(k<maxk)
    	gk=feval(gfun,x0);	%计算梯度
    	Gk=feval(Hess,x0);	%计算Hessian阵
    	dk=-Gk/gk;			%解方程组Gk*dk=-gk,计算搜索方向
    	if(norm(gk)<epsilon)%n=norm(A,p),计算矩阵范数
    		break;
    	end
    	m=0;mk0;
    	while(m<20)			%用Armijo搜索求步长
    		if(feval(fun,x0+rho^m*dk)<feval(fun,x0)+sigma*rho^m*gk'*dk)
    			mk=m;
    			break;
    		end
    		m=m+1;
    	end
    	x0=x0+rho^mk*dk;
    	k=k+1;
    end
    x=x0;
    val=feval(fun,x);
    

    举例:求解无约束优化问题:\(\mathop{min}\limits_{x\in\mathbb{R}^2} f(x)=100(x^2_1-x_2)^2+(x_1-1)^2\)

    minx∈R2⁡f(x)=100(x12−x2)2+(x1−1)2
    \mathop{min}\limits_{x\in\mathbb{R}^2} f(x)=100(x^2_1-x_2)^2+(x_1-1)^2 
    

    先建立两个分别计算目标函数和梯度的.m文件

    function f=fun(x)
    
    function g=gfun(x)
    

    再建立求\(Hessian\)阵的.m文件

    function He=Hess(x)
    n=length(X);
    He=zeros(n,n);
    He=[1200*x(1)^2-400*x(2)+2,-400*x(1);
    	-400*x(1),				200		];
    

    终止准则取为\(\parallel \nabla f(x_k)\parallel\leqslant10^{-5}\)

    ∥∇f(xk)∥⩽10−5 \parallel \nabla f(x_k)\parallel\leqslant10^{-5}
    

    程序调用方式为:

    \(x0=[-1.2,1]'\)

    \([x,val,k]=dampnm('fun','gfun','Hess',x0)\)

三、测试

三分法

image

黄金分割法

image

牛顿法

image

四、总结

matlab 不用声明变量,科学计算的时候很方便,不过没声明的变量编译默认为0,可能会带来奇怪的bug.


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM