lanczos算法及C++實現(二)實對稱陣奇異值分解的QR算法


1. 基本的QR算法

我們先討論一般對陣矩陣的QR算法,再討論對稱三對角陣的QR算法

給定一個實對稱陣X,假設其特征值分解為X=PSP',其中P對正交陣,S是對角陣。求P,S的QR算法如下,其中 $Q_k$為正交陣,$R_k$為上三角陣:


$X_1=X$
for k=1,2, ...
  $X_k=Q_k*R_k$ (QR分解)
  $X_{k+1}=R_k*Q_k$
endfor
$P=Q_1*Q_2* \dots *Q_{\infty}$
$R_{\infty}$的非對角線元素置0即得S

 

用matlab代碼表示,即

function [P,S]=qreigen
A=rand(10);
A=A+A' %Symmetry real matrix, otherwise P'AP is a block upper triangle matrix
m=size(A,1);
P=eye(m);
for i=1:1000
        [Q,R]=qr(A); %QR factorization
        A=R*Q;
        P=P*Q;
end
S=diag(diag(R));
end

 

這個算法很簡單,每次迭代做一個QR分解和一個矩陣乘法。最基本的,我們用施密特正交化進行QR分解,這在上一篇lanczos算法及C++實現(一)框架及簡單實現中使用。A討論了QR方法和冪迭代方法的關系。

值得注意的是,如果矩陣X不是對稱陣,這個方法往往不能收斂到一個上三角陣,而是一個塊狀上三角陣

function [P,A]=qreigen
A=rand(10); %not symmetry
m=size(A,1);
P=eye(m);
for i=1:1000
        [Q,R]=qr(A); %QR factorization
        A=R*Q;
        P=P*Q;
end
% A is block upper triangle matrix, not upper triangle
A
end

 

 運行結果如下:

A =
4.7120   -0.6211    0.4352   -0.0450   -0.1297    0.5700   -0.3769    0.4790   -0.0754    0.2798
     0    0.0273    0.8587   -0.2188   -0.0095   -0.1913   -0.3785   -0.2142   -0.0565   -0.1236
     0   -0.9150    0.3761   -0.0914    0.0217   -0.1527    0.0317    0.4235    0.4612   -0.3284
     0   -0.0000    0.0000   -0.7400   -0.0686    0.2954    0.1561   -0.1755    0.1879   -0.2237
     0   -0.0000    0.0000   -0.0000    0.4096   -0.5238   -0.0330    0.1636    0.3090   -0.4849
     0    0.0000    0.0000   -0.0000    0.2002    0.7429    0.2064   -0.4820   -0.2602   -0.2005
     0         0         0    0.0000   -0.0000   -0.0000   -0.3812   -0.1792   -0.0188   -0.4469
     0         0         0    0.0000   -0.0000    0.0000    0.4117   -0.1513    0.1134   -0.2247
     0         0         0    0.0000   -0.0000    0.0000    0.0000    0.0000   -0.3465    0.0887
     0         0         0         0         0         0   -0.0000   -0.0000   -0.0000    0.1833

 

2. 快速QR算法

施密特正交法每次需要O(n^3)的計算,很慢。所以通常不用這個方法。一般來說,我們采用如下QR算法,該算法分成兩步:

1、利用Householder變換 (如果你對Householder變換不了解,請見附錄B),將X正交變換為上海森伯格陣(Upper Hessenburg Matrix),復雜度O(n^3)。

2、在每次迭代中,利用Givens變換 (如果你對Givens變換不了解,請見附錄C),求得上海森伯格陣的QR分解,復雜度O(n^2)。

這樣只有在迭代之前需要O(n^3)的預處理,而每次迭代只要平方復雜度,因此比施密特正交法快很多。

2.1 矩陣的上海森伯格化 Hessenburg Reduction

在這一步,對一個方陣X(不要求對稱),我們要求一個正交變換P,使得PXP'為上海森伯格矩陣,即低於對角線下一行的所有元素為0:
$PXP^T=\left(\begin{matrix}* & * & *& *& \dots \\ * & * & *& *& \dots \\ & * & *& *& \dots \\ & & *& *& \dots \\ & & & *& \dots \\ & & & & \dots \end{matrix}\right)$

如何求得這樣的P呢?基本思想如下,將矩陣X分成4塊:

$\left(\begin{matrix}x_{11} & X_{1,2:n}\\ X_{2:n,1} & X_{2:n,2:n} \end{matrix}\right)$

然后用Householder變換,將左下的一列變為只有一個非零元素:

$P_1 X_{2:n,1} = v_1 \mathbf e_1=\left(\begin{matrix}v_1\\ 0 \\ 0 \\ \dots \end{matrix}\right)$
其中$P_1=I-2u*u^T$是一個正交矩陣,

$u=\frac{X_{2:n,1}-\|X_{2:n,1}\|\mathbf e_1}{\left\|X_{2:n,1}-\|X_{2:n,1}\|\mathbf e_1\right\|}$

$ \mathbf e_i$是一個除第i個分量為1以外,其他分量為0的向量。P1的具體求法,參見附錄B

這樣我們有

$\left(\begin{matrix}1 & 0 \\ 0 & P_1 \end{matrix}\right) X \left(\begin{matrix}1 & 0 \\ 0 & P^T_1 \end{matrix}\right) = \left(\begin{matrix}x_{11} & X^*_{1,2:n} \\ v_1\mathbf e_1 & X^*_{2:n,2:n} \end{matrix}\right) $

類似的,我們可以構造$\left(\begin{matrix}1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & P_2\end{matrix}\right)$等共n-1個矩陣,使得X正交相似於一個上海森伯格矩陣。

值得一提的是,如果X是一個對稱陣,那么根據對稱性,X正交相似於一個三對角陣。

2.2 上海森伯矩陣的QR分解

首先,如果H是一個上海森伯格陣,其QR分解為H=QR,那么RQ也是一個上海森伯格陣。證明省略。

這就是說,如果我們有一個對海森伯格陣的快速QR算法,那么在每次迭代中我們可以反復使用該算法。

我們采用Givens變換來進行QR分解。對於n階上海森伯格陣H,從上到下對每相鄰的兩行使用Given變換,每次變換都消去對角線下方的一個元素。共n-1次變換。由於Givens變換是正交變換,那么這n-1次變換的乘積也是正交變換,變換后,
\(G^T_{n-1}*\dots *G^T_1 H\) 變成了上三角陣。其中\(G^T_i\)是第i次Givens行變換的矩陣表示。
根據QR算法,我們需要求RQ。因此在對H進行n-1次行變換后,再從左到右對每相鄰的兩列使用對應的Given變換的逆變換,同樣一共也是n-1次變換:
\(RQ=G^T_{n-1}*\dots *G^T_1 H G_1*\dots *G_{n-1}\),這樣我們就完成了一次迭代。

這個過程可以用下圖表示:

QR分解過程,$G_{n-1}^T*\dots*G_1^TH=R$,其中紅框代表當前需要考慮的H中的元素,這些元素將被更新。注意每次Givens變換將一個對角線下的元素變成0.

而R*Q的過程如下:

其中

$c_i=\frac{H(i)_{i,i}}{\sqrt{H(i)^2_{i,i}+H(i)^2_{i+1,i}}}$

$s_i=\frac{H(i)_{i+1,i}}{\sqrt{H(i)^2_{i,i}+H(i)^2_{i+1,i}}}$

$H(i)=G^T_{i-1}*\dots*G_1^TH$

將這個過程中所有產生的G乘起來就得到了H的特征向量。我們可以看到,每次迭代只需要O(n^2)的計算量,比施密特正交化快多了。

2.3 三對角陣的特征值分解

在lanczos方法中,我們得到的是一個對稱三對角陣,是上海森伯格陣的特例。因此可以用上面所述方法計算特征值。值得注意的是,這里可以利用三對角陣的特性加速計算,在求第一個行變換G'1H的時候,可以只考慮H左上的2*3的小陣,而不是整個前兩行。而接下來的每次行變換也只需考慮H的2*3的子陣。在列變換中,每次只需考慮H的3*2的子陣即可。這樣一次QR迭代的復雜度只有O(n)了。

2.4 通過平移(shifts)和deflation加速上海森伯格矩陣的特征值分解

由於QR算法的收斂速度取決於特征值之間的差異,差別越大,QR收斂越快。這和冪迭代算法是一致的。那么怎么加快特征值之間的差異呢?通常的做法就是平移。

假設H有兩個特征值$\lambda_1>\lambda_2\ge0$,那么QR迭代的速度為 $\left(\frac{\lambda_2}{\lambda_1}\right)^k$。假如$\delta$滿足$\lambda_1>\lambda_2\ge\delta\ge0$,那么矩陣$H^*=H-\delta I$和H有相同的特征向量,其特征值為$\lambda_1-\delta>\lambda_2-\delta\ge0$,而求H^*的特征向量會很快,其收斂速度為$\left(\frac{\lambda_2-\delta}{\lambda_1-\delta}\right)^k$

基於這樣的觀察,在求海森伯格矩陣的特征值時,每次迭代我們進行如下QR分解

  $H-\delta I=QR$ (QR分解)
  $H=RQ+\delta I$
顯然,這樣的QR分解不改變H的特征向量,但是如果選取合適的 $\delta$收斂速度要快很多。特別地,如果$\delta$恰好取到某個的特征值時,那么一次迭代即可就可確定該特征值。見文獻https://www.math.kth.se/na/SF2524/matber15/qrmethod.pdf中的lemma 2.3.2。事實上我們沒那么幸運,但可以用每次迭代中,H對角線上的元素可以看作是特征值的估計。所以每次計算完RQ后,取對角線上固定某個位置的元素(比如始終取第1個)作為$\delta$。但如果矩陣存在一對特征值互為相反數,那么這種方法不能收斂。比如矩陣 $\left(\begin{matrix}0 & 1\\1 & 0\end{matrix}\right)$,因此更好的做法是Wilkinson shift,取H對角線上的2*2的方陣的特征值作為$\delta$。此外對復矩陣還有雙位移方法(Double shift),這里不作詳細的討論,有興趣的讀者可以參考http://people.inf.ethz.ch/arbenz/ewp/Lnotes/chapter4.pdf


那么這樣只能加速計算某個特征值,比如始終取對角線上的最后一個則加快了求解最小特征值的速度。如何加速求解其他特征值的速度呢?這里就用到了deflation。

抱歉我不知道怎么翻譯這個詞deflation,因此就用英文了。

Deflation是指在迭代過程中,如果對角線上某個位置的下一行幾乎為0的時候,說明該位置上的值很接近於特征值了,此時將改位置所對應的行和列從矩陣中刨去,對剩下的矩陣進行計算。

一般的步驟如下,取對角線最右下的元素做deflation,直到該元素左邊的元素幾乎為0時,這時最小特征值已經求出,將最后一行一列去掉,對剩下的矩陣繼續計算。如此反復,deflate n-1次之后,所有特征值全部求出。

2.5 QR算法的C++實現

最后,附上我的QR算法的C++實現。這個算法實現了這篇文章中的所有內容,包括實對稱陣到上海森伯格陣的轉化(hessenburgReduction函數),上海森伯格陣特征值分解的QR算法(QRHessenberg函數),三對角陣的特征值分解的QR算法(QRTridiagonal函數),每個QR算法中都用了shift和deflation加速,采用的是Wilkinson shift。在Lanczos算法中,只有QRTridiagonal函數被調用。當然如果不用lanczos方法三對角化,也可以通過hessenburgReduction函數和QRHessenberg函數來進行QR迭代求解特征值分解。具體代碼參見lanczos算法及C++實現(〇)C++代碼

3. 參考文獻

https://www.math.kth.se/na/SF2524/matber15/qrmethod.pdf

http://people.inf.ethz.ch/arbenz/ewp/Lnotes/chapter4.pdf

 

附錄

附錄 A QR算法等價於並行冪迭代算法(Simultaneous Iteration)

QR算法實際上等價於並行冪迭代算法 (Simultaneous Iteration)。在冪迭代中,如果我們用一組線性獨立的向量而不是一個向量與X反復相乘,則最終得到的將是一組線性獨立的向量,對其正交化后,可以 得到X的特征向量。但實際上由於冪迭代的性質,這些向量快速的收斂到主特征向量,而其他的特征向量被快速丟棄。為了保留較小特征向量的成分,每次與X相乘 后,都做一次正交化,那么這樣最終這些向量將收斂到X的不同的特征向量。如果一開始選取的一組向量是單位陣,那么這種並行的冪迭代算法,實際上就是QR算 法。為什么這么說呢?我們可以看到,第一迭代,這組向量相乘X,得到X,然后正交化。而正交化實際上就是QR分解:$X=Q_1*R_1$,接着第二次迭代,我們用X乘$Q_1$並正交化:$X*Q_1=Q_2*R_2$,如此我們得到

\(X=Q_1R_1\)

\(XQ_1=Q_2R_2\)

\(XQ_2=Q_3R_3\)

...

比較一下QR算法

\(X=Q_1R_1\)

\(R_1Q_1=Q_2R_2\)

\(R_2Q_2=Q_3R_3\)

...

用數學歸納法可以證明QR算法中的
\(R_k\)
和並行冪迭代中的
\(R_k\)
相同。因為當k=1時,顯然成立,當k=2時
並行冪迭代中
\(Q_1R_1Q_1=Q_2R_2\)
而QR算法中
\(R_1Q_1=Q_2R_2\)
由於
\(Q_1\)
是正交陣,一個矩陣在進行行正交變換(左乘正交陣)后,其QR分解中的R不變。因此兩者的
\(R_2\)相同

以此類推。可以證明兩個算法中所有的
\(R_k\)相同

然后,我們可以得到在並行冪迭代中,

\(Q_k=X^k*R_k^{-1}*R_{k-1}^{-1}*\dots*R_1^{-1}\)

而QR算法中

\(Q_k=R_{k-1}*\dots*R_1*X*R_k^{-1}*R_{k-1}^{-1}*\dots*R_1^{-1}\)

於是,可以得到兩個算法中
\(Q_k\)的聯系:

\(Q^{\mathrm{Simultaneous Iteration}}_k=Q_1^{QR}*\dots*Q_k^{QR}\)

 

附錄 B Householder變換

又名Householder Reflections,顧名思義,是一種鏡像變換。如圖,假設給定一個點x和一個過原點的平面(虛線),平面用一個垂直於它的單位向量v表示,那么對x的Householder變換就是求x關於平面v的鏡像點x'。現在我們來看怎么計算x'

首先$0$指向$x$的向量在向量$v$上的投影為 $v*v^Tx$ ,在平面v上的投影為$x-v*v^Tx$。所以其鏡像點x'的坐標為$x-2v*v^Tx = (I-2vv^T)x$

這里矩陣$I-2vv^T$就是一個householder矩陣,是一個對稱的正交矩陣,有兩個特征值,1和-1

 

現在我們考慮如何利用householder變換將一個向量變x成只有一個非0元素的向量,如下圖所示

關鍵就是求那個平面,即v向量。由圖可得出x-x'平行於v,因此我們有

$v=\frac{u}{\|u\|}$

其中

$u=x-\left(\begin{matrix} \|x\| \\ 0 \\0 \\0 \\ \dots\end{matrix}\right)$

 

附錄 C Givens變換

又名Givens旋轉,顧名思義,是對一個向量進行旋轉變換,不改變向量的長度,因此是一個正交變換,其逆變換就是反方向旋轉回去。

如圖所示,我們考慮一個二維向量$v=\left(\begin{matrix}a\\b\end{matrix}\right)$,將它逆時針旋轉$\theta$角度后,求所得到的坐標。


這里我們可以將向量重新表示為\(v=|v|\left(\begin{matrix}cos(\alpha)\\sin(\alpha)\end{matrix}\right)\),其中\(\alpha\)是向量v與x坐標軸的夾角。


這樣變換后的坐標為

$w=|v|\left(\begin{matrix}cos(\alpha+\theta)\\sin(\alpha+\theta)\end{matrix}\right)$

     $=|v|\left(\begin{matrix}cos(\alpha)cos(\theta)-sin(\alpha)sin(\theta)\\sin(\alpha)cos(\theta) + sin(\theta)cos(\alpha)\end{matrix}\right)$

     $= \left(\begin{matrix}cos(\theta) & -sin(\theta)\\sin(\theta) & cos(\theta)\end{matrix}\right)*|v|\left(\begin{matrix}cos(\alpha)\\sin(\alpha)\end{matrix}\right) $

     $= \left(\begin{matrix}cos(\theta) & -sin(\theta)\\sin(\theta) & cos(\theta)\end{matrix}\right)v$

 

其中$G= \left(\begin{matrix}cos(\theta) & -sin(\theta)\\sin(\theta) & cos(\theta)\end{matrix}\right)$為Givens變換矩陣,是一個正交陣,其逆陣為

 

$G^T= \left(\begin{matrix}cos(\theta) & sin(\theta)\\-sin(\theta) & cos(\theta)\end{matrix}\right)$

 

本文屬作者原創,轉載請注明出處:

http://www.cnblogs.com/qxred/p/qralgorithm.html

 

本系列目錄:

lanczos算法及C++實現(〇)C++代碼

lanczos算法及C++實現(一)框架及簡單實現

lanczos算法及C++實現(二)實對稱陣奇異值分解的QR算法

lanczos算法及C++實現(三)實對稱三對角陣特征值分解的分治算法

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM