Julia實現數值代數中的經典算法

數值代數

Gauss消元法

對於線性方程組

{a11x1+a12x2++a1nxn=b1,a11x1+a12x2++a1nxn=b2,an1x1+an2x2++annxn=bn,\left\{\begin{aligned} a_{11}x_1 +a_{12}x_2 +&\ldots+a_{1n}x_n &= b_1,\\ a_{11}x_1 +a_{12}x_2 +&\ldots+a_{1n}x_n &= b_2,\\ &\vdots\\ a_{n1}x_1 +a_{n2}x_2 +&\ldots+a_{nn}x_n &= b_n, \end{aligned}\right.

其矩陣形式爲Ax=bAx=b,其中
A=[a11a12a1na21a22a2nan1an2ann],x=[x1x2xn],b=[b1b2bn]A=\begin{bmatrix} a_{11}&a_{12}&\ldots&a_{1n}\\ a_{21}&a_{22}&\ldots&a_{2n}\\ &&\vdots&\\ a_{n1}&a_{n2}&\ldots&a{nn}\\ \end{bmatrix}, x=\begin{bmatrix} x_1\\x_2\\\vdots\\x_n\\ \end{bmatrix}, b=\begin{bmatrix} b_1\\b_2\\\vdots\\b_n\\ \end{bmatrix}

所謂消去法,即逐次小區未知數的方法,將Ax=bAx=b化爲與原式等價的三角方程組。若化爲如下形式

[a11a12a1n0a22a2n00ann][x1x2xn]=[b1b2bn]\begin{bmatrix} a_{11}&a_{12}&\ldots&a_{1n}\\ 0&a_{22}&\ldots&a_{2n}\\ \vdots&\ldots&\vdots&\\ 0&0&\ldots&a{nn}\\ \end{bmatrix}\cdot \begin{bmatrix} x_1\\x_2\\\vdots\\x_n\\ \end{bmatrix} =\begin{bmatrix} b_1\\b_2\\\vdots\\b_n\\ \end{bmatrix}

則易得求解公式

{xn=bn/annxk=(bkj=k+1nakjxj)/akk\left\{\begin{aligned} x_n&=b_n/a_{nn}\\ x_k&=(b_k-\displaystyle\sum_{j=k+1}^na_{kj}x_j)/a_{kk} \end{aligned}\right.

在Julia中可寫爲

# Gauss消去法
# M爲n×n+1矩陣,對應Ax=b,M[:,end]爲b
function GaussElimination(M)
    M = copy(M)
    n,_ = size(M)
    # 消元過程
    for i in 1:n-1
        vMinus = M[i,:]/M[i,i]  #當前行循環所要消去的變量
        for j in i+1:n
            M[j,:] -= vMinus*M[j,i]
        end
    end
    # 回代過程
    x = zeros(n)
    for i in n:-1:1
        sumValue = sum([M[i,j]*x[j] for j in i:n])
        x[i] = (M[i,end]-sumValue)/M[i,i]
    end
    return x
end

驗證

julia> A = rand(10,10);
julia> x = rand(10);
julia> b = A*x;
julia> x1 = GaussElimination(hcat(A,b));#hcat函數爲矩陣拼接
julia> x1-x     
10-element Array{Float64,1}:
  3.3306690738754696e-15
 -1.021405182655144e-14
  5.495603971894525e-15
  5.2735593669694936e-15
 -5.10702591327572e-15
 -8.604228440844963e-15
  5.329070518200751e-15
  1.0380585280245214e-14
 -1.5836670082952642e-14
  8.659739592076221e-15

矩陣的三角分解

在Gauss消元的過程中,我們構造了一個上三角矩陣用於回代,在這個過程中,每一步操作均類似於矩陣的初等變換,而初等初等變換又可以等效爲矩陣乘法,所以這些變換矩陣之間的乘積又構成了另一個矩陣。

即高斯消元過程爲

LnL2L1M=U L_n*\ldots*L_2*L_1*M = U

其中,UU爲上三角陣,則L11L21Ln11U=ML_1^{-1}*L_2^{-1}*\ldots*L_{n-1}^{-1}*U=M,令L=L11L21Ln11L=L_1^{-1}*L_2^{-1}*\ldots*L_{n-1}^{-1},則有LU=MLU=M

通過Julia實現爲

# 生成單位矩陣
function eye(n)
    M = zeros(n,n)
    for i in 1:n
        M[i,i] = 1
    end
    return M
end

# 矩陣的LU分解
function LU(M)
    U = copy(M)
    n,_ = size(M)
    L = eye(n)
    eleMatrix = eye(n)
    # 初等變換過程
    for i in 1:n-1
        eleMatrix[i+1:end,i] = [-U[j,i]/U[i,i] for j in i+1:n]
        U = eleMatrix*U
        L = L/eleMatrix
        eleMatrix[i+1:end,i] = [0 for j in i+1:n]
    end
    return L,U
end

驗證

julia> M = rand(4,4)
julia> L,U = LU(M);

julia> L
4×4 Array{Float64,2}:
 1.0        0.0      0.0       0.0
 0.0795445  1.0      0.0       0.0
 0.686459   1.03633  1.0       0.0
 0.327521   1.27914  0.659519  1.0

julia> U
4×4 Array{Float64,2}:
 0.591548  0.102808   0.599782      0.25122
 0.0       0.51307    0.902331      0.481771
 0.0       0.0       -0.691109      0.258695
 0.0       0.0       -5.55112e-17  -0.170634

julia> L*U-M
4×4 Array{Float64,2}:
 0.0  0.0          0.0  0.0
 0.0  0.0          0.0  0.0
 0.0  0.0          0.0  0.0
 0.0  1.11022e-16  0.0  0.0

Gauss 主元素消去法

Gauss消元公式表明,akka_{kk}項不可爲0,否則將出現除零錯誤。非但如此,如果akka_{kk}是一個小量,由於計算機程序在運行過程中,其位數有限,所以可能會造成較大誤差。

julia> A =rand(4,4)*10;
julia> A[1,1] = 1e-10;
julia> x = rand(4)*10;
julia> b = A*x;
julia> x1 = GaussElimination(hcat(A,b));

julia> x1-x
4-element Array{Float64,1}:
  0.00014665020004134277
 -0.00015594355145509553
  1.9684886276571945e-6
  1.596867372199995e-5

可以看到,其最大誤差已經達到了0.0001。

爲了避免這種誤差,最直觀的想法是,在Gauss消元的過程中,使得較大元素的值儘量靠前。對於增廣矩陣B=[Ab]B=[A|b]而言,若在AA中有最大元素aija_{ij},則可以將BB的第ii行,第jj列與第一行、第一列進行交換。對於交換後的矩陣,則選取除了第一行第一列之外的子矩陣繼續進行最大值的選取與交換,直至進行到最後一行。

其Julia實現爲

# M爲n×n+1增廣矩陣,對應Ax=b,M[:,end]爲b
# 輸出爲最大元調整後的矩陣和未知數的變化順序
function allPrinciple(M)
    M = copy(M)
    n,_ = size(M)
    J = zeros(n-1)        #保存x的交換信息
    for i = 1:n-1
        pos = findmax(M[i:end,i:end-1])[2]
        ni = pos[1]+i-1; nj = pos[2]+i-1    #最大值所在位置
        J[i] = nj
        # 交換行
        rowi = M[i,:]
        M[i,:] = M[ni,:]
        M[ni,:] = rowi
        # 交換列
        colj = M[:,i]
        M[:,i] = M[:,nj]
        M[:,nj] = colj
    end
    return M,J
end

驗證

julia> include("almatrix.jl");
julia> A = rand(4,4)*10;
julia> A[1,1] = 1e-10;
julia> x = rand(4)*10;
julia> b = A*x;
julia> M = hcat(A,b)
4×5 Array{Float64,2}:
 1.0e-10  3.15827   6.67401  6.19187  91.509
 1.33812  5.68155   1.95993  9.98016  91.6819
 9.29672  1.16334   1.35398  2.7712   46.9376
 5.32787  0.445123  3.25703  1.22906  41.3079
 julia> M1,J=allPrinciple(M);
 julia> M1
4×5 Array{Float64,2}:
 9.98016  1.33812  1.95993  5.68155   91.6819
 2.7712   9.29672  1.35398  1.16334   46.9376
 6.19187  1.0e-10  6.67401  3.15827   91.509
 1.22906  5.32787  3.25703  0.445123  41.3079

可見已經實現了最大元交換,接下來可將換元過程插入到Gauss消去法中,

#全主元素消去法
function allElimitation(M)
    M,J = allPrinciple(M)       #最大主元替換
    x = GaussElimination(M)     #高斯消去法
    for i in length(J):-1:1     #未知數換位
        print(J[i])
        xi = x[J[i]]
        x[J[i]] = x[i]
        x[i] = xi
    end
    return x
end
```julia

驗證(接上面代碼)

```javascript
julia> include("almatrix.jl");
julia> x1 = GaussElimination(M);
julia> x2 = allElimitation(M);
julia> x1-x
4-element Array{Float64,1}:
 -0.00024191569586218264
 -0.0018563311857411335
 -0.00014663572230411148
  0.0011049087452414952

julia> x2-x
4-element Array{Float64,1}:
  6.661338147750939e-16
  2.1316282072803006e-14
 -8.881784197001252e-16
 -1.1546319456101628e-14

可見主元素消去法相對於原始的Gauss消去法提高了不少精度。

Gauss-Jordan消去法

Gauss消去法是一種從上到下的消元過程,即始終消去對角線下方的元素,最終使得係數矩陣變成上三角的形式。Gauss-Jordan消去法則還要消去對角線上方的元素,使得係數矩陣變成對角矩陣。

# Gauss-Jordan消去法
# M爲n×n+1增廣矩陣,對應Ax=b,M[:,end]爲b
function GaussJordan(M,maxFlag=true)
    if maxFlag
        M,J = allPrinciple(M)       #最大主元替換
    end

    n,_ = size(M)
    # Gauss消元
    for i in 1:n-1
        vMinus = M[i,:]/M[i,i]      #當前行循環所要消去的變量
        for j in i+1:n
            M[j,:] -= vMinus*M[j,i]
        end
    end

    # Jordan消元
    for i in n:-1:2
        vMinus = M[i,:]/M[i,i]
        for j in 1:i-1
            M[j,:] -= vMinus*M[j,i]
        end
    end

    # 回代
    x = [M[i,end]/M[i,i] for i in 1:n]

    if maxFlag
        for i in length(J):-1:1     #未知數換位
            print(J[i])
            xi = x[J[i]]
            x[J[i]] = x[i]
            x[i] = xi
        end
    end
    return M,x
end

追趕法

在某些偏微分方程的求解算法中,在初值條件給定的情況下會產生一個特殊的方程求解問題,其係數矩陣爲三對角矩陣Ax=fAx=f,其形式如下

[b1c1a2b2c2an1bn1cn1anbn][x1x2xn1xn]=[f1f2fn1fn]\begin{bmatrix} b_1&c_1&&& \\ a_2&b_2&c_2&&\\ &\ddots&\ddots&\\ &&a_{n-1}&b_{n-1}&c_{n-1}\\ &&&a_n&b_n \end{bmatrix} \begin{bmatrix} x_1\\x_2\\\vdots\\x_{n-1}\\x_n \end{bmatrix}= \begin{bmatrix} f_1\\f_2\\\vdots\\f_{n-1}\\f_n \end{bmatrix}

此時,對A進行LULU分解可得

A=[b1c1a2b2c2an1bn1cn1anbn]=[α1γ2α2γnαn][1β11βn11]A=\begin{bmatrix} b_1&c_1&&& \\ a_2&b_2&c_2&&\\ &\ddots&\ddots&\\ &&a_{n-1}&b_{n-1}&c_{n-1}\\ &&&a_n&b_n \end{bmatrix} =\begin{bmatrix} \alpha_1&&&\\ \gamma_2&\alpha_2&&\\ &\ddots&\ddots\\ &&\gamma_n&\alpha_n \end{bmatrix} \begin{bmatrix} 1&\beta_1&& \\ &\ddots&\ddots\\ &&1&\beta_{n-1}\\ &&&1 \end{bmatrix}

易得其變換關係爲

{b1=α1,c1=α1β1,ai=γi,bi=γiβi1+αii=2,3,,nci=αiβii=2,3,,n1\left\{\begin{aligned} b_1&=\alpha_1,\quad c_1=\alpha_1\beta_1,\\ a_i&=\gamma_i,\quad b_i = \gamma_i\beta_{i-1}+\alpha_i \quad i= 2,3,\ldots,n\\ c_i&= \alpha_i\beta_i \quad i=2,3,\ldots,n-1 \end{aligned}\right.

根據上式可得到追趕法的求解過程

Step1 計算βi\beta_i

β1=c1/b1,βi=ci/(biaiβi1)i=2,3,,n1; \beta_1=c_1/b_1,\quad \beta_i=c_i/(b_i-a_i\beta_{i-1})\quad i=2,3,\ldots,n-1;

step2 計算yy

y1=f1/b1,yi=(fiaiyi1)/(biaiβi1)i=2,3,,n y1 = f_1/b_1,\quad y_i=(f_i-a_iy_{i-1})/(b_i-a_i\beta_{i-1})\quad i=2,3,\ldots,n

step3 計算xx,即其追趕過程

xn=yn,xi=yiβixi+1,i=n1,n2,,1 x_n=y_n, \quad x_i=y_i-\beta_ix_{i+1},\quad i=n-1,n-2,\ldots,1

其Julia實現爲

# 追趕法,輸入M爲三對角矩陣,f爲向量
function chasing(M,f)
    n,_ = size(M)
    b = [M[i,i] for i in 1:n]
    c = [M[i,i+1] for i in 1:n-1]
    a = vcat(1,[M[i+1,i] for i in 1:n-1])

    # 根據遞推公式求beta
    beta = zeros(n-1)
    beta[1] = c[1]/b[1]
    for i in 2:n-1
        beta[i] = c[i]/(b[i]-a[i]*beta[i-1])
    end

    # 求解y
    y = zeros(n)
    y[1] = f[1]/b[1]
    for i in 2:n
        y[i] = (f[i]-a[i]*y[i-1])/(b[i]-a[i]*beta[i-1])
    end

    # x的追趕過程
    x = zeros(n)
    x[n] = y[n]
    for i in n-1:-1:1
        x[i] = y[i]-beta[i]*x[i+1]
    end
    
    return x
end

驗證

julia> M = zeros(5,5);
julia> for i in 1:5
       M[i,i] = rand()*10
       M[i,i+1] = rand()*3
       M[i+1,i] = rand()*3
       end          #此處會報錯哦
julia> x = rand(5);
julia> f = M*x;
julia> x1 = chasing(M,f);
julia> x1-x
5-element Array{Float64,1}:
  0.0
 -2.220446049250313e-16
  0.0
 -1.1102230246251565e-16
  0.0

Jocabi迭代法

對於方程組Ax=bAx=b

j=1naijxj=bj,i=1,2,,n \displaystyle\sum_{j=1}^na_{ij}x_j=b_j,\quad i=1,2,\ldots,n

AA爲非奇異矩陣且任意項不爲零,則將AA分裂爲A=DLUA=D-L-U,其中DD爲對角矩陣,L,UL,U分別爲對焦爲0的下三角和上三角矩陣。

將方程組中的對角項提出,則方程組變爲

xi=1aii(bij=1,jinaij) x_i=\frac{1}{a_{ii}}(b_i-\displaystyle\sum_{j=1,j\not=i}^na_{ij})

或將矩陣表達式寫爲

(L+U)xDx=bx=D1((L+U)xb)(L+U)x-Dx=b \to x=D^{-1}((L+U)x-b)

記爲

x=B0x+fx=B_0x+f

其中

B0=ID1A=D1(L+U),f=D1bB_0=I-D^{-1}A=D^{-1}(L+U),\quad f=D^{-1}b

通過迭代法求上式即可得到JacobiJacobi迭代公式

{x(0)=[x1(0),x2(0),,xn(0)]Txi(k+1)=1aii(bij=1,jinaijxj(k))\left\{\begin{aligned} x^{(0)}&=[x_1^{(0)},x_2^{(0)},\ldots,x_n^{(0)}]^T\\ x_i^{(k+1)}&=\frac{1}{a_{ii}}(b_i-\displaystyle\sum_{j=1,j\not=i}^na_{ij}x_j^{(k)}) \end{aligned}\right.

寫成矩陣形式即爲

{x(0)x(k+1)=B0x(k)+f\left\{\begin{aligned} x^{(0)}&\\ x^{(k+1)}&=B_0x^{(k)}+f \end{aligned}\right.

其Julia實現爲

## Jocobi迭代法
## n爲迭代次數
function Jacobi(M,b,n=10)
    nDim,_ = size(M)
    D = zeros(nDim,nDim)
    for i in 1:nDim
        D[i,i] = M[i,i]
    end
    B = D\(D-M)
    f = D\b

    x = f       #初始化
    for i = 1:n
        x = B*x+f
    end
    return x
end

Gauss-Seidel迭代

在Jacobi迭代中,xx被看成一個整體參與迭代,在每一次迭代的過程中,同一代的xx其內部的變量並無相互影響。

然而,如果迭代收斂,那麼新一代的xx一定比舊一代的xx更接近真實值,所以,如果將迭代過程拆分,讓新一代的計算結果實時取代舊一代的結果,那麼應該有助於加速收斂過程,此即Gauss-Seidel迭代。

如果寫出迭代公式的展開式可能會更加直觀

{x1(k+1)=1a11(b1j=1,j1na1jxj(k))x2(k+1)=1a22(b1j=1,j2na2jxj(k))xn(k+1)=1ann(b1j=1,jnnanjxj(k))\left\{\begin{aligned} x_1^{(k+1)}&=\frac{1}{a_{11}}(b_1-\displaystyle\sum_{j=1,j\not=1}^na_{1j}x_j^{(k)})\\ x_2^{(k+1)}&=\frac{1}{a_{22}}(b_1-\displaystyle\sum_{j=1,j\not=2}^na_{2j}x_j^{(k)})\\ \vdots\\ x_n^{(k+1)}&=\frac{1}{a_{nn}}(b_1-\displaystyle\sum_{j=1,j\not=n}^na_{nj}x_j^{(k)}) \end{aligned}\right.

則Gauss-Seidel迭代可寫爲

{x1(k+1)=1a11(b1a12x2(k)a13x3(k)a1nxn(k)x2(k+1)=1a11(b1a12x2(k+1)a13x3(k)a1nxn(k)xn(k+1)=1a11(b1a12x2(k+1)a13x3(k+1)a1,n1xn1(k+1)\left\{\begin{aligned} x_1^{(k+1)}&=\frac{1}{a_{11}}(b_1-a_{12}x_2^{(k)}-a_{13}x_3^{(k)}-\ldots-a_{1n}x_n^{(k)}\\ x_2^{(k+1)}&=\frac{1}{a_{11}}(b_1-a_{12}x_2^{(k+1)}-a_{13}x_3^{(k)}-\ldots-a_{1n}x_n^{(k)}\\ \vdots\\ x_n^{(k+1)}&=\frac{1}{a_{11}}(b_1-a_{12}x_2^{(k+1)}-a_{13}x_3^{(k+1)}-\ldots-a_{1,n-1}x_{n-1}^{(k+1)} \end{aligned}\right.

矩陣特徵值與特徵向量

Gerschgorin定理

A=(aij)m×n)A=(a_{ij})_{m\times n}),則AA的每一個特徵值必屬於下述圓盤之中

λaiij=1,jinaij |\lambda-a_{ii}|\leqslant\displaystyle\sum_{j=1,j\not=i}^{n}|a_{ij}|

證明 設λ\lambdaAA內任意一個特徵值,xx爲對應的特徵向量,則有

(λIA)x=0(\lambda I-A)x=0

x=(x1,x2,,xn)T0x=(x_1,x_2,\ldots,x_n)^T\not=0以及xi=maxkxk,x0|x_i|=\max_k|x_k|,x\not=0,則

(λaii)xi=j=1,jinai,jxj(\lambda-a_{ii})x_i = \displaystyle\sum_{j=1,j\not=i}^na_{i,j}x_j

又因xj/xi1|xj/xi|\leqslant1,則

λaiij=1,jinai,j|\lambda-a_{ii}| \leqslant\displaystyle\sum_{j=1,j\not=i}^n|a_{i,j}|

冪法和反冪法

冪法時一種迭代算法,所以其基本表示形式必然爲νn+1=Aνn\nu_{n+1}=A\nu_{n},即任取一非零向量ν0\nu_0,通過矩陣AA構造一向量序列

{ν1=Aν0ν2=Aν1=A2ν0νk+1=Aνk=Ak+1ν0\left\{\begin{aligned} \nu_1&=A\nu_0\\ \nu_2&=A\nu_1=A^2\nu_0\\ &\vdots\\ \nu_{k+1}&=A\nu_k=A^{k+1}\nu_0\\ &\vdots \end{aligned}\right.

若令ν0=i=1naixi,λi\nu_0=\sum^n_{i=1}a_ix_i,\quad\lambda_i爲相應的特徵向量,則

νk=Aνk1=i=1naiλikxi=λik[a1x1+i=2nai(λi/λ1)kxi\begin{aligned} \nu_k&=A\nu_{k-1}=\displaystyle\sum^n_{i=1}a_i\lambda_i^kx_i\\ &=\lambda_i^k[a_1x_1+\displaystyle\sum^n_{i=2}a_i(\lambda_i/\lambda_1)^kx_i \end{aligned}

若令λi>λi+1|\lambda_i|>|\lambda_{i+1}|,則λi/λ1<1|\lambda_i/\lambda_1|<1,則limk(λi/λ1)k=0\lim\limits_{k\to\infty}(\lambda_i/\lambda_1)^k=0。即經過無窮多次迭代之後

νka1λ1kx1\nu_k\approx a_1\lambda_1^kx_1

此即矩陣的最大特徵值所對應的特徵向量,相鄰兩次迭代特徵向量之商即爲最大特徵值。這種方法即爲冪法\textbf{冪法},與之相應地,由於其逆矩陣的特徵值變爲原矩陣的倒數,則對逆矩陣使用冪法,即可得到最小特徵向量,此方法即爲反冪法\textbf{反冪法}

# 乘冪法
function Power(M,n)
    arr = rand(size(M)[1])
    for i in 1:n-1
        arr = M*arr
        arr = arr/maximum(arr)  #對向量進行歸一化
    end
    Arr = M*arr                 
    return Arr,Arr./arr
end

驗證

julia> include("almatrix.jl");
julia> M = rand(5,5);
julia> Power(M,20)[2]
5-element Array{Float64,1}:
 2.6429750659456106         #此即最大特徵值
 2.6429750659461253
 2.6429750659454907
 2.6429750659466134
 2.642975065945339

由於向量之間點除很難得到相同的值,所以我們選擇其中一點來觀察乘冪法的收斂速度。

iki_kνk\nu_k的第ii個分量,εki\varepsilon^i_k爲第kk次迭代誤差的第ii個分量,則

ik+1ik=λ1a1x1ia1x1i+λ2a2x2ia2x2i++λna1xnia1xni=λ1a1x1i+εk+1ia1x1i+εki \frac{i_{k+1}}{i_k}=\lambda_1\frac{a_1x_1^i}{a_1x_1^i}+\lambda_2\frac{a_2x_2^i}{a_2x_2^i}+\ldots+\lambda_n\frac{a_1x_n^i}{a_1x_n^i}= \lambda_1\frac{a_1x_1^i+\varepsilon^i_{k+1}}{a_1x_1^i+\varepsilon^i_k}

根據其誤差分量的特徵可知,當主特徵值λ1\lambda_1遠大於其他特徵值時,將具備更快的收斂速度。若λ2λ1\lambda_2\approx\lambda_1,則收斂速度將會很慢。所以,如果能夠使得λ1\lambda_1與其他特徵值的差距變大,則可增快收斂速度。

對此,可以構造矩陣B=ApIB=A-pI,則其特徵值爲λip\lambda_i-p,則BB的收斂速度大於AA,因爲

λ2pλ1p<λ2λ1 |\frac{\lambda_2-p}{\lambda_1-p}|<|\frac{\lambda_2}{\lambda_1}|

通過Julia寫爲

# 加速之後的冪法
function acPower(M,n,p)
    B = M .- eye(size(M)[1])*p
    arr,val = Power(B,n)
    return arr,val.+p
end

測試

julia> x = rand(5,5);
julia> x[5,5] = 7;
julia> x[4,4] = 8;
julia> x[3,3] = 8.5;
julia> x[2,2] = 9.5;
julia> x[1,1] = 10;
julia> acPower(x,20,0)[2]
5-element Array{Float64,1}:
 11.119295564775351
 11.079539551635982
 11.058127553729367
 11.095918606361074
 11.05404344237109
 julia> acPower(x,15,5)[2]
5-element Array{Float64,1}:
 11.090309381320136
 11.094079685109394
 11.09547046795793
 11.094168499705209
 11.094043676186722

可見,在p值選5的情況下,迭代15次的結果優於未加速時迭代20次的結果。(因爲這五個值都是主特徵向量,所以這五個值越相近說明越接近真實值。)

Schmidt正交分解

αi\alpha_iRnR^n上的nn個線性無關的向量,令β1=α1α12\beta_1=\frac{\alpha_1}{\|\alpha_1\|_2},則β1\beta_1爲單位向量,再令B2=α2(α2,β1)β1β2=B2B22B_2=\alpha_2-(\alpha_2,\beta_1)\beta_1 \to \beta_2=\frac{B2}{\|B_2\|_2},則(β1,β2)=0(\beta_1,\beta_2)=0

同理,得到對任意向量組的正交化過程

α1=α1,β1=α1α12B2=α2(α2,β1)β1β2=B2B22B3=α3(α3,β1)β1(α3,β2)β2 β3=B3B32Bn=αnj=1n1(αn,βj)βjβn=BnBn2\begin{aligned} \alpha_1&=\alpha_1,\quad &\beta_1&=\frac{\alpha_1}{\|\alpha_1\|_2}\\ B_2&=\alpha_2-(\alpha_2,\beta_1)\beta_1\quad&\beta_2&=\frac{B2}{\|B_2\|_2}\\ B_3&=\alpha_3-(\alpha_3,\beta_1)\beta_1-(\alpha_3,\beta_2)\beta_2\ &\beta_3&=\frac{B_3}{\|B_3\|_2}\\ &\ldots&&\ldots\\ B_n&=\alpha_n-\displaystyle\sum_{j=1}^{n-1} (\alpha_n,\beta_j)\beta_j&\beta_n&=\frac{B_n}{\|B_n\|_2}\\ \end{aligned}

這個過程可以表示爲矩陣形式

[α1,,αn]=[β1,,βn][β12(α2,β1)(α3,β1)(αn,β1)β22(α3,β2)(αn,β1)β32(αn,β1)βn2]=QR\begin{aligned} [\alpha_1,\ldots,\alpha_n]=&[\beta_1,\ldots,\beta_n] \begin{bmatrix} \|\beta_1\|_2&(\alpha_2,\beta_1)&(\alpha_3,\beta_1)&\ldots&(\alpha_n,\beta_1)\\ &\|\beta_2\|_2&(\alpha_3,\beta_2)&\ldots&(\alpha_n,\beta_1)\\ &&\|\beta_3\|_2&\ldots&(\alpha_n,\beta_1)\\ &&&\ldots&\vdots\\ &&&&\|\beta_n\|_2 \end{bmatrix}\\ &=QR \end{aligned}

其中,Q爲正交陣,R爲上三角陣,上三角陣的對角元素即爲其特徵值。其Julia實現爲

# Schmidt正交化法,輸入爲矩陣,按每一列求其歸一化向量
function Schmidt(M)
    n,_ = size(M)
    N = zeros(n,n)
    for i = 1:n
        B = M[:,i]
        for j in 1:i-1
            B -= M[:,i]'*N[:,j]*N[:,j]
        end
        N[:,i] = B/sqrt(sum([B[j]^2 for j in 1:n]))
    end
    return N
end

驗證

julia> include("almatrix.jl");
julia> x = rand(5,5);
julia> y = Schmidt(x);
julia> for i in 1:5
       println(y[:,1]'*y[:,i])
       end
1.0000000000000002
-1.1102230246251565e-16
-3.3306690738754696e-16
-9.645062526431047e-16
-8.326672684688674e-16

Jacobi旋轉法

Jacobi法的基本思想是構造簡單、特殊的正交矩陣序列{Pk}\{P_k\},使得

A0=AAk+1=PkAkPkT,k=0,1,2,\begin{aligned} A_0=&A\\ A_{k+1}=&P_kA_kP_k^T,\quad k=0,1,2,\ldots \end{aligned}

逐漸接近對角型,從而得到A的特徵值。

對於矩陣

Pij=[1cosθsinθ1sinθcosθ1] P_{ij}=\begin{bmatrix} 1\\ &\ddots\\ &&\cos{\theta}&\ldots&\sin{\theta}\\ &&\vdots&1&\vdots\\ &&-\sin{\theta}&\ldots&\cos{\theta}\\ &&&&&\ddots\\ &&&&&&1 \end{bmatrix}

其中,對角上的cosθsinθ\cos{\theta},\sin{\theta}分別在第i,ji,j列,則該矩陣被稱爲平面旋轉矩陣。

設矩陣ARm×nA\in R^{m\times n}是對稱矩陣,記A+0=AA+0=A,對AA做一系列旋轉相似變換,得C=PTAPC=P^TAP,則ACA、C只在第i,ji,j行列的元素不同,且有如下關係

{cii=aiicos2θ+ajjsin2θaijsin2θcjj=aiisin2θ+ajjcos2θ+aijsin2θcij=12(aiiajj)sin2θ+aijcos2θcik=cki=aikcosθajksinθcjk=ckj=ajkcosθ+aiksinθ\left\{\begin{aligned} c_{ii} =& a_{ii}\cos^2\theta+a_{jj}\sin^2\theta-a_{ij}\sin2\theta\\ c_{jj} =& a_{ii}\sin^2\theta+a_{jj}\cos^2\theta+a_{ij}\sin2\theta\\ c_{ij} =& \frac{1}{2}(a_{ii}-a_{jj})\sin2\theta+a_{ij}\cos2\theta\\ c_{ik} =& c_{ki} =a_{ik}\cos\theta-a_{jk}\sin\theta\\ c_{jk} =& c_{kj} =a_{jk}\cos\theta+a_{ik}\sin\theta\\ \end{aligned}\right.

可以看到,我們可可以通過適當選取θ\theta值,使得cij=0c_{ij}=0,通過不斷選取不同的θ\theta可以逐漸使得矩陣中越來越多的元素爲零。

此時,需要滿足

tan2θ=2aijaiiajjcosθ=11+tan2θsinθ=tanθ1+tan2θ\begin{aligned} \tan2\theta=&\frac{-2a_{ij}}{a_{ii}-a_{jj}}\\ \to\cos\theta=&\frac{1}{\sqrt{1+\tan^2\theta}}\\ \to\sin\theta=&\frac{\tan\theta}{\sqrt{1+\tan^2\theta}}\\ \end{aligned}

# Jacobi旋轉法
function JacobiRot(M)
    n,_=size(M)
    E = eye(n)
    for i = 1:n
        for j = 1:n
            p2Tan = -2*M[i,j]/M[i,i]-M[j,j]
            p2Cos = 1/sqrt(1+p2Tan^2)
            p2Sin = p2Tan*p2Cos
            pCos = sqrt(p2Cos+1)/2
            pSin = p2Sin/pCos/2
            
            cii = M[i,i]*pCos^2+M[j,j]*pSin^2-M[i,j]*p2Sin
            cjj = cii+2*M[i,j]*p2Sin
            cij = (M[i,i]-M[j,j])*p2Sin/2+M[i,j]*p2Cos
            ci = [M[i,k]*pCos-M[j,k]*pSin for k in 1:n]
            cj = [M[j,k]*pCos+M[i,k]*pSin for k in 1:n]
            ci[i] = cii;ci[j]=cij
            cj[i] = cij;cj[j]=cjj

            M[i,:] = ci;M[:,i] = ci
            M[j,:] = cj;M[:,j] = cj
        end
    end
    return M
end

此外還滿足如下關係

clk=clkcil2+cjl2=ail2+ajl2cii2+cjj2+2cij2=aii2+ajj2+2aij2\begin{aligned} c_{lk} &= c_{lk}\\ c^2_{il}+c^2_{jl}&=a^2_{il}+a^2_{jl}\\ c^2_{ii}+c^2_{jj}+2c^2_{ij}&=a^2_{ii}+a^2_{jj}+2a^2_{ij}\\ \end{aligned}

:l,ki,j\quad所有等式中:l,k\not=i,j,引入記號

σ(A)=i=jnaij2,τ(A)=ijnaij2\sigma(A)=\displaystyle\sum^n_{i=j}a^2_{ij},\quad\tau(A)=\displaystyle\sum^n_{i\not=j}a^2_{ij}

則有

σ(C)=σ(A)+2aij2,τ(C)=τ(A)2aij2\sigma(C)=\sigma(A)+2a^2_{ij},\quad\tau(C)=\tau(A)-2a^2_{ij}

這說明每次Jacobi迭代雖然會使得某個元素變爲0,但也可能會讓某些爲0的元素變爲非0,在使用Jacobi旋轉法時,也應該遵循最大元優先的原則。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章