最优化实验报告

无约束最优化上机实验报告

数学与应用数学091

梁启凡

090080

实验一

实验目的:

编程并测试算法A.1 Gaussian Elimination with Row Partial Pivoting 和A.2 Cholesky Factorization

实验过程

一、A.1 Gaussian Elimination with Row Partial Pivoting

根据书上附录提供的伪代码,用MATLAB写出程序。用随机方阵测试,将测试结果与MATLAB自带的lu()函数产生的结果对比。

程序代码:

function [L,U,P]=GaussElimination(A)

%判断A是否奇异

if det(A)==0

    error('matrix A is singular!')

    stop

end

n=length(A);%求方阵A的维数

L=zeros(n);

P=eye(n);

for i=1:1:n

     [m,t]=max(abs(A(i:n,i)));%找到A下三角阵中每列的最大值

     j=t+i-1;%返回该最大值的行坐标

     if(i~=j)

         %交换A的i,j列

         temp=A(i,1:n);

         A(i,1:n)=A(j,1:n);

         A(j,1:n)=temp;

         %交换P的i,j列

         temp=P(i,1:n);

         P(i,1:n)=P(j,1:n);

         P(j,1:n)=temp;

         %交换L的i,j列

         temp=L(i,1:n);

         L(i,1:n)=L(j,1:n);

         L(j,1:n)=temp;

     end

      L(i,i)=1;

      for k=i+1:n

          L(k,i)=A(k,i)/A(i,i);

          for l=i+1:n

              A(k,l)=A(k,l)-L(k,i)*A(i,l);

          end

      end

end

U=triu(A);%U为变化后的A的上三角部分

测试:

生成5维随机矩阵A:

>> A=rand(5)

A =

    0.8147    0.0975    0.1576    0.1419    0.6557

    0.9058    0.2785    0.9706    0.4218    0.0357

    0.1270    0.5469    0.9572    0.9157    0.8491

    0.9134    0.9575    0.4854    0.7922    0.9340

    0.6324    0.9649    0.8003    0.9595    0.6787

对A进行分解:

>> [L,U,P]=GaussElimination(A)

L =

    1.0000    0            0       0            0

    0.8920    1.0000    0            0            0

    0.1390    -0.5469   1.0000    0            0

    0.9917    0.8870    0.9924    1.0000    0

    0.6923    -0.3991   0.4794    0.1476    1.0000

U =

    0.9134    0.9575    0.4854    0.7922    0.9340

    0            -0.7565   -0.2753   -0.5648   -0.1774

    0       0            0.7391    0.4967    0.6223

    0       0            0            -0.3559   -1.3507

    0       0            0            0            -0.1376

P =

     0     0     0     1     0

     1     0     0     0     0

     0     0     1     0     0

     0     1     0     0     0

     0     0     0     0     1

与MATLAB自带的lu函数结果完全相同:

二、A.2 Cholesky Factorization

根据书上附录提供的伪代码,用MATLAB写出程序。用随机方阵测试,将测试结果与MATLAB自带的chol()函数产生的结果对比。

程序代码:

function [L]=cholesky(A)

n=length(A);

for i=1:n

    L(i,i)=sqrt(A(i,i));

    for j=i+1:n

        L(j,i)=A(j,i)/L(i,i);

        for k=i+1:j

            A(j,k)=A(j,k)-L(j,i)*L(k,i);

        end

    end

end

测试:

由于Cholesky分解要求被分解方阵是对称正定的,这里选取5阶帕斯卡矩阵进行测试。

  即A。

用MATLAB自带函数chol()

与自己编写的分解函数所得结果互为转置。

实验分析:

以上两个程序均得到了正确结果,变换不同的维数的矩阵,也皆能得到正确的结果,说明程序是正确的。

对第二个程序,由于没有对称正定检测,所以哪怕输如不满足条件的矩阵也能得出结果。所以应当在输入A时确保A是对称正定的。

 

 

 

 

 

 

 

 

 

 

 

 

 

无约束最优化测试问题

 ,  ,

     ,

 

 ,

实验二

实验目的:

使用最速下降法,编程并求解。比较不同的终止参数和步长的选取。

实验过程及方案:

问题一的解决

终止参数选择:梯度的范数小于目标精确值

步长选择:固定步长 ,Armijo搜索

A:代码(固定步长)

function SDP1

syms x1 x2;

f=100*(x2-x1^2)^2+(1-x1)^2;

x0=[-1.2 1]';

eps=10e-3;

d1=jacobian(f);

d1=d1';

d2=jacobian(d1);

a=subs(d1,{x1,x2},{x0(1),x0(2)});

n=0;

while(norm(a)>eps)

    p=-a;

    step=0.0005;

    x0=x0+step*p

    a=subs(d1,{x1,x2},{x0(1),x0(2)});

    n=n+1;

end

x0

n %迭代步数

结果:

x0 =

    0.9889

    0.9779

n =

       18179

迭代步长为0.0005,目标精度值为,得,共迭代了18179步,非常慢。

B:代码(Armijo搜索)

定义两个函数

%目标函数

function f=fun(x)

f=100*(x(1)^2-x(2))^2+(x(1)-1)^2+(x(3)-1)^2+90*(x(3)^2-x(4))^2+10.1*((x(2)-1)^2+(x(4)-1)^2)+19.8*(x(2)-1)*(x(4)-1);

%目标函数的梯度,用jacobian()函数求得

function gf=gfun(x)

gf=[ 2*x(1) - 400*x(1)*(- x(1)^2 + x(2)) - 2, - 200*x(1)^2 + (1101*x(2))/5 + (99*x(4))/5 - 40, 2*x(3) - 360*x(3)*(- x(3)^2 + x(4)) - 2, - 180*x(3)^2 + (99*x(2))/5 + (1001*x(4))/5 - 40]';

function SDP1(fun,gfun)

syms x

x0=[-1.2 1]';

maxk=5000000;%最大迭代步数

rho=0.5;

sigma=0.4;

k=0;

eps=10e-3;

while(k<maxk)

    g=feval(gfun,x0);计算梯度值

    d=-g;

    if(norm(d)<eps),break;end

    m=0;mk=0;

    while(m<20)%Armoji搜索

        if(feval(fun,x0+rho^m*d)<feval(fun,x0)+sigma*rho^m*g'*d)

            mk=m;break;

        end

        m=m+1;

    end

        x0=x0+rho^mk*d;

        k=k+1;

end

x0 %最优点

 k %迭代次数

结果:

x0 =

    0.9895

    0.9791

k =

        1202

达到同样的精度速度是很快的。

将精度改为10e-5

x0 =

    1.0000

    1.0000

k =

        1435

精度相差10e2,搜索次数仅仅增加了200余次,效果拔群。

问题二的解决

终止参数选择:梯度的范数小于目标精确值

步长选择:Armijo搜索,wolfe线搜索条件

A:代码(Armijo搜索)

定义两个函数

%目标函数

function f=fun(x)

f=100*(x(1)^2-x(2))^2+(x(1)-1)^2+(x(3)-1)^2+90*(x(3)^2-x(4))^2+10.1*((x(2)-1)^2+(x(4)-1)^2)+19.8*(x(2)-1)*(x(4)-1);

%目标函数的梯度,用jacobian()函数求得

function gf=gfun(x)

gf=[ 2*x(1) - 400*x(1)*(- x(1)^2 + x(2)) - 2, - 200*x(1)^2 + (1101*x(2))/5 + (99*x(4))/5 - 40, 2*x(3) - 360*x(3)*(- x(3)^2 + x(4)) - 2, - 180*x(3)^2 + (99*x(2))/5 + (1001*x(4))/5 - 40]';

function SDP2(fun,gfun)

syms x

x0=[-3 -1 -3 -1]';

maxk=5000000;%最大迭代步数

rho=0.5;

sigma=0.4;

k=0;

eps=10e-5;

while(k<maxk)

    g=feval(gfun,x0);%计算梯度值

    d=-g;

    if(norm(d)<eps),break;end

    m=0;mk=0;

    while(m<20)%Armoji搜索

        if(feval(fun,x0+rho^m*d)<feval(fun,x0)+sigma*rho^m*g'*d)

            mk=m;break;

        end

        m=m+1;

    end

        x0=x0+rho^mk*d;

        k=k+1;

end

x0 %最优点

 k %迭代次数

结果:

x0 =

    1.0000

    1.0001

    1.0000

    0.9999

k =

        7156

非常精确。

B:代码(wolfe线搜索条件)fun函数和gfun函数不变

function SDP2(fun,gfun)

syms x

x0=[-3 -1 -3 -1]';

maxk=5000000;%最大迭代步数

c1=10e-4;

c2=0.9;

k=0;

eps=10e-5;

while(k<maxk)

    g=feval(gfun,x0);%计算梯度值

    d=-g;

    if(norm(d)<eps),break;end

    m=0;mk=0;

    step=1;

    while(step>0.0005)%wolfe搜索÷

        if(feval(fun,x0+step*d)<feval(fun,x0)+c1*step*feval(gfun,x0)'*d && feval(gfun,x0)'*d>c2*feval(gfun,x0)'*d)

            step=step;break;

        end

        step=step*0.8;

    end

        x0=x0+step*d

        k=k+1

end

x0 %最优点

 k %迭代次数

结果:

x0 =

    1.0000

    1.0001

    1.0000

    0.9999

k =

       21471

相同精度要求下,没有Armoji搜索快。

问题三的解决

终止参数选择:梯度的范数小于目标精确值

步长选择:Armijo搜索,wolfe线搜索条件

A:代码(Armijo搜索)

定义两个函数

%目标函数

function f=fun(x)

f=(x(1)+10*x(2))^2+5*(x(3)-x(4))^2+(x(2)-2*x(3))^4+10*(x(1)-x(4))^4;

%目标函数的梯度,用jacobian()函数求得

function gf=gfun(x)

gf=[ 2*x(1) + 20*x(2) + 40*(x(1) - x(4))^3, 20*x(1) + 200*x(2) + 4*(x(2) - 2*x(3))^3, 10*x(3) - 10*x(4) - 8*(x(2) - 2*x(3))^3, 10*x(4) - 10*x(3) - 40*(x(1) - x(4))^3]’;

function SDP3(fun,gfun)

syms x

x0=[3 -1 0 1]';

maxk=5000000;%最大迭代步数

rho=0.5;

sigma=0.4;

k=0;

eps=10e-5;

while(k<maxk)

    g=feval(gfun,x0);计算梯度值

    d=-g;

    if(norm(d)<eps),break;end

    m=0;mk=0;

    while(m<20)%Armoji搜索

        if(feval(fun,x0+rho^m*d)<feval(fun,x0)+sigma*rho^m*g'*d)

            mk=m;break;

        end

        m=m+1;

    end

        x0=x0+rho^mk*d;

        k=k+1;

end

x0 %最优点

 k %迭代次数

结果:

x0 =

    0.0237

   -0.0024

    0.0118

    0.0118

k =

       13624

将精度eps改为10e-6

x0 =

    0.0110

   -0.0011

    0.0055

    0.0055

k =

       62671

越来越接近实际值,但是搜索速度非常慢。

B:代码(wolfe线搜索条件)fun函数和gfun函数不变

代码同问题二的B方案一致。将代码中初始迭代点x0改为x0=[3 -1 0 1]'

结果:

速度非常慢,在进行到105416步的时候停止了计算,得到

x0 =

    0.0468

   -0.0047

    0.0233

    0.0234      这个结果离精确值差距还很大。

实验分析:

问题一用了2种步长,如果固定步长会使得搜索过程很慢,而逐一选择步长可以加快搜索过程和精度。问题二和问题三分别用Armoji搜索和wolfe搜索算步长的方法,Armoji搜索的速度要比wolfe快很多

实验三

实验目的:

使用牛顿法,编程并求解

实验过程及方案:

问题一的解决

代码:

function NTP1

syms x1 x2;

f=100*(x2-x1^2)^2+(1-x1)^2;

x0=[-1.2 1]';

eps=10e-3;

d1=jacobian(f);

d2=jacobian(d1);

d1=d1';

a=subs(d1,{x1,x2},{x0(1),x0(2)});

b=subs(d2,{x1,x2},{x0(1),x0(2)});

n=0;

while(norm(a)>eps)

    x0=x0-inv(b)*a

    a=subs(d1,{x1,x2},{x0(1),x0(2)});

    b=subs(d2,{x1,x2},{x0(1),x0(2)});

    n=n+1;

end

x0

n

结果:

x0 =

    1.0000

    1.0000

n =

     5

非常快速,只用5步就得到精度为10e-3的解。

问题二的解决

代码:

function nt

syms x1 x2 x3 x4;

f=100*(x1^2-x2)^2+(x1-1)^2+(x3-1)^2+90*(x3^2-x4)^2+10.1*((x2-1)^2+(x4-1)^2)+19.8*(x2-1)*(x4-1);

x0=[-3 -1 -3 -1]';

eps=10e-5;

d1=jacobian(f);

d2=jacobian(d1);

d1=d1';

a=subs(d1,{x1,x2,x3,x4},{x0(1),x0(2),x0(3),x0(4)});

b=subs(d2,{x1,x2,x3,x4},{x0(1),x0(2),x0(3),x0(4)});

n=0;

while(norm(a)>eps)

    x0=x0-inv(b)*a

    a=subs(d1,{x1,x2,x3,x4},{x0(1),x0(2),x0(3),x0(4)});

    b=subs(d2,{x1,x2,x3,x4},{x0(1),x0(2),x0(3),x0(4)});

    n=n+1;

end

x0

n

结果:

x0 =

   -0.9680

    0.9471

   -0.9695

    0.9512

n =

13

得到精度为10e-5的解只用了13步。

问题三的解决

代码:

function nt

syms x1 x2 x3 x4;

f=(x1+10*x2)^2+5*(x3-x4)^2+(x2-2*x3)^4+10*(x1-x4)^4;;

x0=[3 -1 0 1]';

eps=10e-20;

d1=jacobian(f);

d2=jacobian(d1);

d1=d1';

a=subs(d1,{x1,x2,x3,x4},{x0(1),x0(2),x0(3),x0(4)});

b=subs(d2,{x1,x2,x3,x4},{x0(1),x0(2),x0(3),x0(4)});

n=0;

while(norm(a)>eps)

    x0=x0-inv(b)*a

    a=subs(d1,{x1,x2,x3,x4},{x0(1),x0(2),x0(3),x0(4)});

    b=subs(d2,{x1,x2,x3,x4},{x0(1),x0(2),x0(3),x0(4)});

    n=n+1;

end

x0

n

结果:

x0 =

  1.0e-006 *

    0.1435

   -0.0144

    0.0229

    0.0229

n =

41

经过41步,得到精确度为10e-20的解。

实验分析:

牛顿法的速度较最速下降法有非常明显的改善,速度很快


实验四

实验目的:

调用MATLAB自带函数求解

实验过程及方案:

分别用fminsearch函数和fminunc函数测试,对比两个函数的结果。

P1

1、使用fminsearch函数

>> f=inline('100*(x(2)-x(1)^2)^2+(1-x(1))^2','x');

>> x0=[-1.2; 1]; ff=optimset; ff.Display='iter';

>> x=fminsearch(f,x0,ff)

Iteration   Func-count     min f(x)         Procedure

     0            1             24.2        

     1            3            20.05         initial simplex

     2            5           5.1618         expand

     3            7           4.4978         reflect

     4            9           4.4978         contract outside

   ………………………………………………………………………………

    81          151     1.12293e-009         contract inside

    82          153     1.12293e-009         contract outside

    83          155     1.12293e-009         contract inside

    84          157     1.10755e-009         contract outside

    85          159     8.17766e-010         contract inside

Optimization terminated:

 the current x satisfies the termination criteria using OPTIONS.TolX of 1.000000e-004

 and F(X) satisfies the convergence criteria using OPTIONS.TolFun of 1.000000e-004

x =

    1.0000

1.0000

总共用了85步得到结果。

2、使用fminunc函数

在刚才基础上输入

>>x=fminunc(f,[-1.2;.1],ff)

                                                       First-order

 Iteration  Func-count       f(x)        Step-size       optimality

     0           3             24.2                           216

     1           9          4.28049    0.000861873           15.2 

     2          12          4.12869              1              3 

     3          15          4.12069              1            1.5 

   ……………………………………………………………………………………

    31         123       0.00108975            0.5          0.877 

    32         126     9.14432e-005              1          0.143 

    33         129     7.27182e-006              1         0.0807 

    34         132     4.44847e-007              1          0.022 

    35         135     1.47502e-008              1        0.00272 

    36         138     2.83357e-011              1      1.91e-005 

Local minimum found.

Optimization completed because the size of the gradient is less than

the default value of the function tolerance.

<stopping criteria details>

x =

    1.0000

1.0000

只用了36步便得到正确结果,比fminsearch函数快很多。

P2

1、使用fminsearch函数

>>f=inline('100*(x(1)^2-x(2))^2+(x(1)-1)^2+(x(3)-1)^2+90*(x(3)^2-x(4))^2+10.1*((x(2)-1)^2+(x(4)-1)^2)+19.8*(x(2)-1)*(x(4)-1)','x');

>> x0=[-3;-1;-3;-1]; ff=optimset; ff.Display='iter';

>> x=fminsearch(f,x0,ff)

  314          527     1.94483e-009         contract inside

用了314步得到结果

x =

    1.0000

    1.0000

    1.0000

1.0000

2、使用fminunc函数

>>x=fminunc(f,[-3;-1;-3;-1],ff)

35         215     1.84511e-007              1        0.00339 

用35步得到结果

x =

    1.0002

    1.0004

    0.9998

0.9996

结果没有fminsearch函数精确。

P3

1、使用fminsearch函数

>>f=inline('(x(1)+10*x(2))^2+5*(x(3)-x(4))^2+(x(2)-2*x(3))^4+10*(x(1)-x(4))^4','x');

>> x0=[3;-1;0;1]; ff=optimset; ff.Display='iter';

>> x=fminsearch(f,x0,ff)

185          305     1.39059e-006         reflect

用185步得到结果

x =

    0.0094

   -0.0009

    0.0166

0.0166

与真实值还有一些差距。

norm(x-[0 0 0 0]') =0.0253

2、使用fminunc函数

>>x=fminunc(f,[3;-1;0; 1],ff)

33         170     6.38904e-009              1       0.000217

用33步得到结果

x =

    0.0015

   -0.0002

   -0.0031

   -0.0031

norm(x-[0 0 0 0]')=0.0047 比fminsearch函数得到的结果与精确值的差的范数要小。

实验分析:

fminunc函数比fminisearch函数速度更快,快很多,不过精确性上是不分伯仲的。fminisearch与fminunc这两个函数都是最优化工具箱中的,如果需要速度快些,就用fminiunc函数。

相关推荐