最优化方法Python计算:正定二次型基本共轭方向算法

设目标函数
f ( x ) = 1 2 x ⊤ H x − x ⊤ b , x ∈ R n . f(\boldsymbol{x})=\frac{1}{2}\boldsymbol{x}^\top\boldsymbol{Hx}-\boldsymbol{x}^\top\boldsymbol{b},\boldsymbol{x}\in\text{ℝ}^n. f(x)=21xHxxb,xRn.
其中, H ∈ R n × n \boldsymbol{H}\in\text{ℝ}^{n\times n} HRn×n为对称正定矩阵, b ∈ R n \boldsymbol{b}\in\text{ℝ}^n bRn为一常向量。即 f ( x ) f(\boldsymbol{x}) f(x)为一二次型函数,且 ∇ f ( x ) = H x − b \nabla f(\boldsymbol{x})=\boldsymbol{Hx}-\boldsymbol{b} f(x)=Hxb ∇ 2 f ( x ) = H \nabla^2f(\boldsymbol{x})=\boldsymbol{H} 2f(x)=H。由于 H = ∇ 2 f ( x ) \boldsymbol{H}=\nabla^2f(\boldsymbol{x}) H=2f(x)正定,故 f ( x ) f(\boldsymbol{x}) f(x)有唯一的最小值点 x 0 \boldsymbol{x}_0 x0(满足 o = ∇ f ( x 0 ) = H x 0 − b \boldsymbol{o}=\nabla f(\boldsymbol{x}_0)=\boldsymbol{Hx}_0-\boldsymbol{b} o=f(x0)=Hx0b H x 0 = b \boldsymbol{Hx}_0=\boldsymbol{b} Hx0=b)。
定理1 二次型目标函数
f ( x ) = 1 2 x ⊤ H x − x ⊤ b , x ∈ R n f(\boldsymbol{x})=\frac{1}{2}\boldsymbol{x}^\top\boldsymbol{Hx}-\boldsymbol{x}^\top\boldsymbol{b},\boldsymbol{x}\in\text{ℝ}^n f(x)=21xHxxb,xRn
其中, H ∈ R n × n \boldsymbol{H}\in\text{ℝ}^{n\times n} HRn×n为正定矩阵。 d 1 , d 2 , ⋯   , d n \boldsymbol{d}_1,\boldsymbol{d}_2,\cdots,\boldsymbol{d}_n d1,d2,,dn f ( x ) f(\boldsymbol{x}) f(x)的共轭方向向量(详见博文《最优化方法Python计算:构造正定矩阵的共轭向量》),任取 x 1 ∈ R n \boldsymbol{x}_1\in\text{ℝ}^n x1Rn,对 1 ≤ k ≤ n 1\leq k\leq n 1kn α k = − ∇ f ( x k ) ⊤ d k d k ⊤ H d k \alpha_k=-\frac{\nabla f(\boldsymbol{x}_k)^\top\boldsymbol{d}_k}{\boldsymbol{d}_k^\top\boldsymbol{Hd}_k} αk=dkHdkf(xk)dk,构造迭代式
x k + 1 = x k + α k d k \boldsymbol{x}_{k+1}=\boldsymbol{x}_k+\alpha_{k}\boldsymbol{d}_{k} xk+1=xk+αkdk
则存在 1 ≤ m ≤ n + 1 1\leq m\leq n+1 1mn+1,使得 x m = x m + 1 = ⋯ = x n + 1 = x 0 \boldsymbol{x}_{m}=\boldsymbol{x}_{m+1}=\cdots=\boldsymbol{x}_{n+1}=\boldsymbol{x}_0 xm=xm+1==xn+1=x0。其中 x 0 \boldsymbol{x}_0 x0 f ( x ) f(\boldsymbol{x}) f(x)的最优解点。
利用定理1,可建立计算二次型目标函数最优解的基本共轭方向算法。下列Python函数实现该算法。

import numpy as np                          #导入numpy
from scipy.optimize import OptimizeResult   #导入OptimizeResult
def conj(x1,H,b,c,gtol=1e-5):               #基本共轭方向算法实现函数
    d=conjugation(H)                        #构造H的共轭向量组
    xk=x1                                   #初始迭代点
    gk=(np.matmul(H,xk)-b)                  #计算梯度
    k=1
    while np.linalg.norm(gk)>=gtol:         #只要梯度不为0
        ak=-np.matmul(gk,d[:,k-1])/np.matmul(np.matmul(d[:,k-1],H),d[:,k-1])
        xk+=ak*d[:,k-1]
        gk=(np.matmul(H,xk)-b)
        k+=1
    bestx=xk
    besty=(np.matmul(np.matmul(xk,H),xk)/2-np.matmul(b,xk))+c
    return OptimizeResult(fun=besty, x=bestx, nit=k)

程序的第3~15行定义实现基本共轭方向法的conj函数,参数x1表示初始迭代点 x 1 \boldsymbol{x}_1 x1,H、b和c分别表示二次型函数
f ( x ) = 1 2 x ⊤ H x − x ⊤ b + c f(\boldsymbol{x})=\frac{1}{2}\boldsymbol{x}^\top\boldsymbol{Hx}-\boldsymbol{x}^\top\boldsymbol{b}+c f(x)=21xHxxb+c
中的矩阵 H \boldsymbol{H} H、向量 b \boldsymbol{b} b和常数 c c c,gtol表示容错误差 ε \varepsilon ε,缺省值为 1 0 − 5 10^{-5} 105
第4~7行执行初始化操作:第4行调用博文《最优化方法Python计算:构造正定矩阵的共轭向量》中定义的构造正定矩阵共轭向量组的函数conjugation,构造 H \boldsymbol{H} H的共轭向量组
d 1 , d 2 , ⋯   , d n \boldsymbol{d}_1,\boldsymbol{d}_2,\cdots,\boldsymbol{d}_n d1,d2,,dn
存储于d。第5行设置迭代点xk初始化为x1。第6行计算目标函数的当前梯度
g 1 = H x 1 − b \boldsymbol{g}_1=\boldsymbol{Hx}_1-\boldsymbol{b} g1=Hx1b
赋予gk。第7行将迭代次数k初始化为1。\par
第8~12行的while循环作迭代操作:第9行计算
α k = − g k ⊤ d k d k ⊤ H d k \alpha_k=-\frac{\boldsymbol{g}_k^\top\boldsymbol{d}_k}{\boldsymbol{d}_k^\top\boldsymbol{Hd}_k} αk=dkHdkgkdk
赋予ak。第10行用
x k + α k d k \boldsymbol{x}_k+\alpha_k\boldsymbol{d}_k xk+αkdk
更新xk。第11行用xk更新梯度gk。第12行迭代次数k自增1。循环往复,直至条件
∥ g ( x k ) ∥ < 1 0 − 5 \lVert\boldsymbol{g}(\boldsymbol{x}_k)\rVert<10^{-5} g(xk)∥<105
g ( x k ) \boldsymbol{g}(\boldsymbol{x}_k) g(xk)近似为 o \boldsymbol{o} o)成立。需要注意的是于Python数组的下标是从0开始编码的,故在第9、10行中k作为数组下标时表示为k-1。
第13~15行用 f ( x k ) f(\boldsymbol{x}_k) f(xk) x k \boldsymbol{x}_k xk k k k构造OptimizeResult(第2行导入)对象,并返回。
例1 用函数conj计算正定二次型函数 f ( x ) = 3 2 x 1 2 + 2 x 2 2 + 3 2 x 3 2 + x 1 x 3 + 2 x 2 x 3 − 3 x 1 − x 3 f(\boldsymbol{x})=\frac{3}{2}x_1^2+2x_2^2+\frac{3}{2}x_3^2+x_1x_3+2x_2x_3-3x_1-x_3 f(x)=23x12+2x22+23x32+x1x3+2x2x33x1x3的最优解。给定初始点 x 1 = ( 0 0 0 ) \boldsymbol{x}_1=\begin{pmatrix}0\\0\\0\end{pmatrix} x1= 000 ,容错误差 ε = 1 0 − 5 \varepsilon=10^{-5} ε=105
f ( x ) f(\boldsymbol{x}) f(x)的矩阵形式 f ( x ) = 1 2 x ⊤ H x − x ⊤ b + c f(\boldsymbol{x})=\frac{1}{2}\boldsymbol{x}^\top\boldsymbol{Hx}-\boldsymbol{x}^\top\boldsymbol{b}+c f(x)=21xHxxb+c中, H = ( 3 0 1 0 4 2 1 2 3 ) \boldsymbol{H}=\begin{pmatrix}3&0&1\\0&4&2\\1&2&3\end{pmatrix} H= 301042123 b = ( 3 0 1 ) \boldsymbol{b}=\begin{pmatrix}3\\0\\1\end{pmatrix} b= 301 c = 0 c=0 c=0。下列代码完成计算。

import numpy as np                          #导入numpy
H=np.array([[3,0,1],                        #设置Hesse阵
            [0,4,2],
            [1,2,3]],dtype='float')
b=np.array([3,0,1],dtype='float')           #设置向量
x=np.array([0,0,0],dtype='float')           #设置初始点
c=0                                         #设置常量
print(conj(x,H,b,c))                        #计算并输出最优解

借助代码内部的注释信息,不难理解本程序。需要注意的是,由于给定的容错误差为 ε = 1 0 − 5 \varepsilon=10^{-5} ε=105,故调用conj时使用参数gtol的缺省值。运行程序,输出

 fun: -1.5
 nit: 2
   x: array([1., 0., 0.])

这意味着在 ε = 1 0 − 5 \varepsilon=10^{-5} ε=105的容错误差下,迭代2次即算得 f ( x ) f(\boldsymbol{x}) f(x)的最优解 x 0 = ( 1 0 0 ) \boldsymbol{x}_0=\begin{pmatrix}1\\0\\0\end{pmatrix} x0= 100

你可能感兴趣的:(最优化方法,python,最优化方法)