目录
- 迭代法求零点
- 基本思想
- 具体做法
- 几何含义
- 重要定理
- 迭代法求解无约束优化问题
- 1. 最速下降 (SD) 法 (负梯度方法)
- 梯度和 Hesse 矩阵
- SD 法
- 一维精确线搜索
- Python 实现
- 2. Newton 法
无约束优化问题就是没有任何的约束限制的优化问题, 如求最小值 , 其中 . 求解无约束优化问题的迭代算法有最速下降 (SD) 法和 Newton 法等.
迭代法求零点
基本思想
不动点迭代:
具体做法
从一个给定的初值 出发, 计算 若 收玫, 即存在 使得 , 则由 的连续性和 可得 , 即 是 的不 动点, 也就是
几何含义
求曲线 与直线
重要定理
定理 (不动点原理, 压缩映像定理) 设 在 上连续, 且一阶导数连续, 若:
(1) 对 一切 都成立; (封闭性)
(2) 存在 , 使得 对 成立, (压缩性)
则函数 在 中有唯一的零点 , 即 存在唯一的的不动点 , s.t. .
证明思路 : 存在性: 在 上有零点.
唯一性: 用反证法, 假设存在
, 推出矛盾.
迭代法求解无约束优化问题
无约束优化问题就是没有任何的约束限制的优化问题, 如求最小值 , 其中 .
1. 最速下降 (SD) 法 (负梯度方法)
梯度和 Hesse 矩阵
SD 法
步 1: 给出 ;
步 2: 若满足终止条件 , 则迭代停止;
步 3: 计算 ;
步 4: 一维精确线搜索求 ;
步 5: , 转步 2.
其中一维精确线搜索确定最优步长的方法如下
一维精确线搜索
其中
得最速下降方法的步长
Python 实现
#最速下降法 (负梯度方法)
import numpy as np #导入numpy模块
import matplotlib.pyplot as plt #导入matplotlib.pyplot模块
from sympy import*
from scipy.interpolate import griddata
import numpy.linalg as LA
#目标函数
def nf(x1,x2):
y=1/2*(21*x1*x1+4*x2*x1+4*x1*x2+15*x2*x2)+2*x1+3*x2+10
return y
#目标函数求梯度
def ndfx(x1,x2):
fx=np.array([diff(nf(x1,x2),x1),diff(nf(x1,x2),x2)])
#分别就目标函数对x1,x2一阶偏导, array数组
# sympy.diff(func,x,n) 求导
# func是要求导的函数; x是要对其求导的变量; n是求导阶数, 缺省为1(可选)
return fx
#初始化参数
n=100 #设置最大迭代次数
x=np.zeros((n,2)) #迭代点xk
x[0,:]=[-30,100]
xk=[]
xk.append(x[0,:])
d=np.zeros((n,2)) #下降方向dk
df=np.zeros((n,2)) #梯度, 建立array数组的形式
#--------------------------------------
def main():
x1,x2=var('x1 x2') # sympy.var 将字符串变成变量
eps=1e-5 #精度要求
k=1
#设置初始迭代点:
A=np.arange(4*n).reshape(n,2,2)
fx=ndfx(x1,x2)#梯度
alpha=0.1
for i in range(n-2):
#二阶导数矩阵
#计算一阶导数值
f1x=fx[0].subs({x1:x[i][0],x2:x[i][1]})#截取xk
f2x=fx[1].subs({x1:x[i][0],x2:x[i][1]})
df[i,:]=[f1x,f2x]
b=-df[i,:].T#负梯度方向
#subs函数只能应用于sympy类型的符号函数,并非array数组类型
A[i,:,:]=[[21,4],[4,15]]#SD方法
alpha=(b*b)/(21*b[0]*b[0]+4*b[1]*b[0]+4*b[0]*b[1]+15*b[1]*b[1])#步长公式
d[i,:]=alpha*b#负梯度方向
x[i+1,:]=x[i,:]+d[i,:]
xk.append(x[i+1,:])#存储迭代点
if np.abs(x[i+1][0]-x[i][0])<eps and np.abs(x[i+1][1]-x[i][1])<eps :
break
i=i+1
print(nf(x[i][0],x[i][1]))
print('-----------------------------------')
print('最后迭代 The result is:',i)
print('最优解:x*=',x[i,:])
print('最优目标值:y=%.3f'%( nf(x[i][0],x[i][1]) ) )
#--------------------------------------
main()
plt.rc('font',size=16);plt.rc('font',family='SimHei');plt.rc('text',usetex=True)
xh0=np.arange(-100,100.1,0.1)#区域横坐标
yh0=np.arange(-100,100.1,0.1)#区域纵坐标
xh,yh=np.meshgrid(xh0,yh0)
contr=plt.contour(xh,yh,nf(xh,yh),20)
plt.clabel(contr)#等高线
plt.xlabel('$x_1$');plt.ylabel('$x_2$',rotation=90)
xk=np.reshape(xk,(1,-1))
xk=np.reshape(xk,(int(xk.size/2),2))
xtk=np.array(xk.T[0,:])
ytk=np.array(xk.T[1,:])
#print(xtk)
#print(ytk)
plt.plot(xtk,ytk,c='r',marker='H')
plt.show()
2. Newton 法
步 1: 给出 ;
步 2: 若满足终止准则 , 则输出有关信息, 停止迭代;
步 3: 由 ;
步 4: , 转步 2.
# Newton 法
import numpy as np #导入numpy模块
import matplotlib.pyplot as plt #导入matplotlib.pyplot模块
from sympy import*
from scipy.interpolate import griddata
import numpy.linalg as LA
#目标函数
def nf(x1,x2):
y=3*x1**2+3*x2**2-x1**2*x2
#y=1/2*(21*x1*x1+4*x2*x1+4*x1*x2+15*x2*x2)+2*x1+3*x2+10
return y
#目标函数求梯度 (一阶偏导)
def ndfx(x1,x2):
fx=np.zeros(2)#二维向量
fx=[diff(nf(x1,x2),x1),diff(nf(x1,x2),x2)]#分别就目标函数对x1,x2一阶偏导,列表类型
fx=np.array(fx)#转换为array数组类型
return fx
#目标函数求 Hesse 矩阵 (二阶偏导)
def ndfxx(x1,x2):
fx=ndfx(x1,x2)#梯度
fxx=[[],[]]
fxx[0]=[diff(fx[0],x1),diff(fx[0],x2)]
fxx[1]=[diff(fx[1],x1),diff(fx[1],x2)]
fxx=np.array(fxx) #转换为数组类型
return fxx
#初始化参数
n=100 #设置最大迭代次数
x=np.zeros((n,2))#迭代点xk
x[0,:]=[-2,4]#设置初始迭代点
d=np.zeros((n,2))#下降方向dk
df=np.zeros((n,2))#梯度,建立array数组的形式
A=np.arange(4*n).reshape(n,2,2)#建立array数组的形式
xk=[]
xk.append(x[0,:])
#--------------------------------------
def main():
x1,x2=var('x1 x2') #转化为sympy变量
eps=1e-6 #精度要求
fx=ndfx(x1,x2)#梯度
z1=ndfxx(x1,x2)#hesse矩阵
for i in range(n-2):
#计算一阶导数值
f1x=fx[0].subs({x1:x[i][0],x2:x[i][1]})#梯度在xk点值
f2x=fx[1].subs({x1:x[i][0],x2:x[i][1]})
df[i,:]=[f1x,f2x]
#subs函数只能应用于sympy类型的符号函数, 并非array数组类型
#为二阶导数矩阵每个元素循环赋值
z2=np.arange(4).reshape(2,2)#建立array数组的形式
for j in range(2):
for k in range(2):
z2[j][k]=z1[j][k].subs({x1:x[i][0],x2:x[i][1]})#Hesse矩阵不同分量取值
#A[i,:,:]=z1 #Gk Hesse矩阵在xk点处值
#----------------------------------
#d[i,:]=-np.dot(LA.inv(A[i,:,:]),df[i,:]) #G*d=-g
d[i,:]=-np.dot(LA.inv(z2[:,:]),df[i,:]) #G*d=-g 改成z2形式之后Newton有二阶速度
#基本newton
alpha=1.0 #全步长=1
x[i+1,:]=x[i,:]+alpha*d[i,:]
xk.append(x[i+1,:])
if LA.norm(df[i,:])<eps :
break
i=i+1
print('-----------------------------------')
print('最后迭代 The result is:',i)
print('最优解:x*=',x[i,:])
print('最优目标值:y=%.3f'%( nf(x[i][0],x[i][1]) ) )
#--------------------------------------
if __name__ == '__main__':
main()
plt.rc('font',size=16);plt.rc('font',family='SimHei');plt.rc('text',usetex=True)
xh0=np.arange(-6,6.01,0.01)#区域横坐标
yh0=np.arange(-6,6.01,0.01)#区域纵坐标
xh,yh=np.meshgrid(xh0,yh0)
contr=plt.contour(xh,yh,nf(xh,yh),20)
plt.clabel(contr)#等高线
plt.xlabel('$x1$')#x,y坐标轴
plt.ylabel('$x2$',rotation=90)
xk=np.reshape(xk,(1,-1))
xk=np.reshape(xk,(int(xk.size/2),2))
xtk=np.array(xk.T[0,:])
ytk=np.array(xk.T[1,:])
#print(xtk)
#print(ytk)
plt.plot(xtk,ytk,c='r',marker='H')
plt.show()