正定値行列のコレスキー分解
📂行列代数正定値行列のコレスキー分解
概要
可逆行列から対角行列への条件が強化され、LDU分解ができたように、正定値行列への条件強化で、より効率的な行列分解であるコレスキー分解cholesky decompositionができる。
ビルドアップ
m×m 正定値行列 A:=[a11wwTK]>0 を考えると、a11 は正の数であり、w∈Rm−1 且つ K∈R(m−1)×(m−1) だ。もし a11≤0 ならば、e1=(1,0,⋯,0) に対して、e1TAe1=a11≤0 なので、A は正定値になれない。一方で、任意のベクトル0=x∈Rm−1 について
xTKx=[0xT][a11wwTK][0x]>0
となるので、K>0 だ。便宜上 a11=1 と置くと、
A0:=[1wwTK]=[1w0I][100K−wwT][10wTI]
と表せる。ここで、L1:=[1wwTK] は上三角行列、A1:=[100K−wwT] は正定値なので、K−wwT>0 だ。したがって、このプロセス An−1=LnAnLnT を n=m まで繰り返すと、
A0=L1⋯LmImLmT⋯L1T
のように表せる。
一般化
今、a11>0 の場合について一般化してみよう。A:=A0 とすると、
A0==[a11wwTK][a1100I][1a111wa111wTK][a1100I]
[1a111wa111wTK]はa11=1 の場合で扱った形なので、
[1a111wa111wTK]=[1a111w0I][100K−a11wwT][10a111wTI]
L1:=[a1100I][1a111w0I]
そして、
A1:=[100K−a11wwT]
と置くと、
A0==[a1100I][1a111w0I][100K−a11wwT][10a111wI][a1100I]L1A1L1T
同様にプロセス An−1=LnAnLnT を n=m まで繰り返すと、
A0=L1⋯LmImLmT⋯L1T
が得られる。L1,L2,⋯Lm は下三角行列であり、その積L:=LmLm−1⋯L1 も下三角行列であり、A0=A=LLT と表される。
こうして、下三角行列 L だけで A=LLT を表すことが、コレスキー分解と言われる。正定値という条件はかなり強力だが、その分解は驚くほど単純で、非常に少ない計算で求めることができる。これから具体的に、
L:=l11l21l31⋮ln10l22l32⋮ln200l33⋮ln3⋯⋯⋯⋱⋯000⋮lnn
を見つけるために、A=(aij)=LLT を直接計算してみよう。対角成分より後は計算する必要がないので、
aij=s=1∑nlislsjT=s=1∑min(i,j)lisljs
i=j=k ならば、
akk=s=1∑k−1lks2+lkk2lkk=akk−s=1∑k−1lks2
j=k ならば、i=k+1,⋯,n について、
aik=s=1∑k−1lislks+liklkklik=lkk1(aik−s=1∑k−1lislks)
アルゴリズム
(aij)∈Rn×n が正定値行列だとする。
ステップ1. k=1
d11=a11 を代入して、li1=d111ai1 を計算する。
ステップ2. k=2,3,⋯,n−1 に対して、以下を計算する。
ステップ2-1.
lkk=akk−s=1∑k−1lks2
ステップ2-2. i=k+1,k+2,⋯,n−1 に対して、以下を計算する。
lik=lkk1(aik−s=1∑k−1lislks)
ステップ3. k=n に対して、以下を計算する。
lnn=ann−s=1∑n−1lns2
- LU分解やLDU分解と比べて、計算量が目に見えて減ったのを確認できる。さらに、行なっている計算も複雑ではなく、内積やノルムを求めるのに似ていることに注目しよう。
コード
さあ、実際にコレスキー分解を試してみよう。

以下のコードは、上記アルゴリズムをRで実装したものである。
B <- matrix(c(2,1,0,1,2,1,0,1,2), ncol= 3); B
Cholesky<-function(A){
n=length(A[,1])
L<-diag(0,n)
k=1
L[1,1] = sqrt(A[1,1])
L[,1] = A[,1]/L[1,1]
for(k in 2:(n-1)) {
L[k,k] = sqrt(A[k,k] - sum(L[k,1:(k-1)])^2 )
for(i in (k+1):n) {
L[i,k] = ( A[i,k] - sum( L[i,1:(k-1)] * L[k,1:(k-1)] ) )/L[k,k]
}
}
L[n,n] = sqrt( A[n,n] - sum(L[n,1:(n-1)]^2) )
return(list(L=L))
}
Cholesky(B)
t(chol(B))
実行結果は以下の通り。

Rに内蔵されているコレスキー分解の結果と比較して、正確に一致していることが確認できる。