2、牛顿法和最速下降法只能求解无约束优化,有约束的非线性规划有哪些求解方法?

Python013

2、牛顿法和最速下降法只能求解无约束优化,有约束的非线性规划有哪些求解方法?,第1张

Data Mining

无约束最优化方法

梯度的方向与等值面垂直,并且指向函数值提升的方向。

二次收敛是指一个算法用于具有正定二次型函数时,在有限步可达到它的极小点。二次收敛与二阶收敛没有尽然联系,更不是一回事,二次收敛往往具有超线性以上的收敛性。一阶收敛不一定是线性收敛。

解释一下什么叫正定二次型函数:

n阶实对称矩阵Q,对于任意的非0向量X,如果有XTQX>0,则称Q是正定矩阵。

对称矩阵Q为正定的充要条件是:Q的特征值全为正。

二次函数,若Q是正定的,则称f(X)为正定二次函数。

黄金分割法

黄金分割法适用于任何单峰函数求极小值问题。

求函数在[a,b]上的极小点,我们在[a,b]内取两点c,d,使得a<c<d<b。并且有

1)如果f(c)<f(d),则最小点出现在[a,d]上,因此[a,d]成为下一次的搜索区间。

2)如果f(c)>f(d),则[c,b]成为下一次的搜索区间。

假如确定了[a,d]是新的搜索区间,我们并不希望在[a,d]上重新找两个新的点使之满足(1)式,而是利用已经抗找到有c点,再找一个e点,使满足:

可以解得r=0.382,而黄金分割点是0.618。

练习:求函数f(x)=x*x-10*x+36在[1,10]上的极小值。

+ View Code

最速下降法

泰勒级数告诉我们:

其中Δx可正可负,但必须充分接近于0。

X沿D方向移动步长a后,变为X+aD。由泰勒展开式:

目标函数:

a确定的情况下即最小化:

向量的内积何时最小?当然是两向量方向相反时。所以X移动的方向应该和梯度的方向相反。

接下来的问题是步长a应该怎么定才能使迭代的次数最少?

若f(X)具有二阶连续偏导,由泰勒展开式可得:

H是f(X)的Hesse矩阵。

可得最优步长:

g是f(X)的梯度矩阵。

此时:

可见最速下降法中最优步长不仅与梯度有关,而且与Hesse矩阵有关。

练习:求函数f(x1,x2)=x1*x1+4*x2*x2在极小点,以初始点X0=(1,1)T。

+ View Code

梯度下降法开始的几步搜索,目标函数下降较快,但接近极值点时,收敛速度就比较慢了,特别是当椭圆比较扁平时,收敛速度就更慢了。

另外最速下降法是以函数的一次近似提出的,如果要考虑二次近似,就有牛顿迭代法。

牛顿迭代法

在点Xk处对目标函数按Taylar展开:

可见X的搜索方向是,函数值要在此方向上下降,就需要它与梯度的方向相反,即。所以要求在每一个迭代点上Hesse矩阵必须是正定的。

练习:求的极小点,初始点取X=(0,3)。

+ View Code

牛顿法是二次收敛的,并且收敛阶数是2。一般目标函数在最优点附近呈现为二次函数,于是可以想像最优点附近用牛顿迭代法收敛是比较快的。而在开始搜索的几步,我们用梯度下降法收敛是比较快的。将两个方法融合起来可以达到满意的效果。

收敛快是牛顿迭代法最大的优点,但也有致命的缺点:Hesse矩阵及其逆的求解计算量大,更何况在某个迭代点Xk处Hesse矩阵的逆可能根本就不存在(即Hesse矩阵奇异),这样无法求得Xk+1。

拟牛顿法

Hesse矩阵在拟牛顿法中是不计算的,拟牛顿法是构造与Hesse矩阵相似的正定矩阵,这个构造方法,使用了目标函数的梯度(一阶导数)信息和两个点的“位移”(Xk-Xk-1)来实现。有人会说,是不是用Hesse矩阵的近似矩阵来代替Hesse矩阵,会导致求解效果变差呢?事实上,效果反而通常会变好。

拟牛顿法与牛顿法的迭代过程一样,仅仅是各个Hesse矩阵的求解方法不一样。

在远离极小值点处,Hesse矩阵一般不能保证正定,使得目标函数值不降反升。而拟牛顿法可以使目标函数值沿下降方向走下去,并且到了最后,在极小值点附近,可使构造出来的矩阵与Hesse矩阵“很像”了,这样,拟牛顿法也会具有牛顿法的二阶收敛性。

对目标函数f(X)做二阶泰勒展开:

两边对X求导

当X=Xi时,有

这里我们用Hi来代表在点Xi处的Hesse矩阵的逆,则

(5)式就是拟牛顿方程。

下面给出拟牛顿法中的一种--DFP法。

我们希望Hi+1在Hi的基础上加一个修正来得到:

给定Ei的一种形式:

m和n均为实数,v和w均为N维向量。

(6)(7)联合起来代入(5)可得:

下面再给一种拟牛顿法--BFGS算法。

(8)式中黑色的部分就是DFP算法,红色部分是BFGS比DFP多出来的部分。

BFGS算法不仅具有二次收敛性,而且只有初始矩阵对称正定,则BFGS修正公式所产生的矩阵Hk也是对称正定的,且Hk不易变为奇异,因此BFGS比DFP具有更好的数值稳定性。

设r是的根,选取作为r的初始近似值,过点做曲线的切线L,L的方程为,求出L与x轴交点的横坐标,称x1为r的一次近似值。过点做曲线的切线,并求该切线与x轴交点的横坐标,称为r的二次近似值。重复以上过程,得r的近似值序列,其中,称为r的次近似值,上式称为牛顿迭代公式。

用牛顿迭代法解非线性方程,是把非线性方程线性化的一种近似方法。把在点的某邻域内展开成泰勒级数,取其线性部分(即泰勒展开的前两项),并令其等于0,即,以此作为非线性方程的近似方程,若,则其解为, 这样,得到牛顿迭代法的一个迭代关系式:。

已经证明,如果是连续的,并且待求的零点是孤立的,那么在零点周围存在一个区域,只要初始值位于这个邻近区域内,那么牛顿法必定收敛。 并且,如果不为0, 那么牛顿法将具有平方收敛的性能. 粗略的说,这意味着每迭代一次,牛顿法结果的有效数字将增加一倍。

军人在进攻时常采用交替掩护进攻的方式,若在数轴上的点表示A,B两人的位置,规定在前面的数大于后面的数,则是A>B,B>A交替出现。但现在假设军中有一个胆小鬼,同时大家又都很照顾他,每次冲锋都是让他跟在后面,每当前面的人占据一个新的位置,就把位置交给他,然后其他人再往前占领新的位置。也就是A始终在B的前面,A向前迈进,B跟上,A把自己的位置交给B(即执行B = A),然后A 再前进占领新的位置,B再跟上,直到占领所有的阵地,前进结束。像这种两个数一前一后逐步向某个位置逼近的方法称为迭代法。

迭代法也称辗转法,是一种不断用变量的旧值递推新值的过程,跟迭代法相对应的是直接法(或者称为一次解法),即一次性解决问题。迭代算法是用计算机解决问题的一种基本方法。它利用计算机运算速度快、适合做重复性操作的特点,让计算机对一组指令(或一定步骤)重复执行,在每次执行这组指令(或这些步骤)时,都从变量的原值推出它的一个新值。

利用迭代算法解决问题,需要做好以下三个方面的工作:

一、确定迭代变量

在可以用迭代算法解决的问题中,至少存在一个可直接或间接地不断由旧值递推出新值的变量,这个变量就是迭代变量。

二、建立迭代关系式

所谓迭代关系式,指如何从变量的前一个值推出其下一个值的公式(或关系)。迭代关系式的建立是解决迭代问题的关键,通常可以使用递推或倒推的方法来完成。

三、对迭代过程进行控制

在什么时候结束迭代过程?这是编写迭代程序必须考虑的问题。不能让迭代过程无休止地执行下去。迭代过程的控制通常可分为两种情况:一种是所需的迭代次数是个确定的值,可以计算出来;另一种是所需的迭代次数无法确定。对于前一种情况,可以构建一个固定次数的循环来实现对迭代过程的控制;对于后一种情况,需要进一步分析得出可用来结束迭代过程的条件。

牛顿迭代法是一种常用的计算方法,这个大学大三应该学过。

具体为:设r是f(x) = 0的根,选取x0作为r初始近似值,过点(x0,f(x0))做曲线y = f(x)的切线L,L的方程为y = f(x0)+f'(x0)(x-x0),求出L与x轴交点的横坐标 x1 = x0-f(x0)/f'(x0),称x1为r的一次近似值。过点(x1,f(x1))做曲线y = f(x)的切线,并求该切线与x轴交点的横坐标 x2 = x1-f(x1)/f'(x1),称x2为r的二次近似值。重复以上过程,得r的近似值序列,其中x(n+1)=x(n)-f(x(n))/f'(x(n)),称为r的n+1次近似值,上式称为牛顿迭代公式。

你把这段文字认真仔细慢慢读一遍,把给的方程式写出来,然后照这个在纸上画出图形,就会明白牛顿迭代法的概要了。

你讲的xopint?root?float?这些都是自己定义的函数。float是c语言中定义浮点型变量的写法。

#include <iostream>

#include <math.h>

void main()

{

float f(float)

float xpoint(float,float)

float root(float,float)

float x,x1,x2,f1,f2

do

{

printf("输入x1,x2\n\n")

scanf("%f%f",&x1,&x2)

f1=f(x1)

f2=f(x2)

}while(f1*f2>0)

x=root(x1,x2)

printf("方程在1.5附近的根为:%f\n\n",x)

}

float f(float x)//定义一个f函数,返回值y

{

float y

y=2*x*x*x-4*x*x+3*x-6

return(y)

}

float xpoint(float x1,float x2)//定义一个带返回值的函数即y,也就是求y的函数,main()中调用

{

float y

y=(x1*f(x2)-x2*f(x1))/(f(x2)-f(x1))

return(y)

}

float root(float x1,float x2)//这也是定义一个函数,是求根的函数,利用了上面自己定义的函数

{

float x,y,y1

y1=f(x1)

do

{

x=xpoint(x1,x2)

y=f(x)

if(y*y1>0)

{

y1=y

x1=x

}

else

x2=x

}while(fabs(y)>1e-4)

return(x)

}

建议你看看c 语言教程,上面讲得很详细噢。