logo

対称行列のLDU分解 📂行列代数

対称行列のLDU分解

概要

LTL^{T} は上三角行列なので、A=LUA = LU における UUU:=DLTU:= DL^{T} に置き換えると考えればよい。一般的な LU 分解より条件が厳しくなる分、計算量は大幅に減る。

定理

可逆対称行列 AA について A=LDLTA = LDL^{T} を満たす下三角行列 LL対角行列 DD が存在する。

証明

AA可逆行列なので、A=LUA = L U を満たす下三角行列 LL上三角行列 UU が存在する。一方 A=ATA = A^{T} なので

LU=A=AT=UTLT L U = A = A^{T} = U^{T} L^{T}

LU 分解で LL は対角成分がすべて 11 である下三角行列として求められるので、detL=1\det L = 1、すなわち逆行列 L1L^{-1} が存在する。L1L^{-1} は下三角行列であり

LU=UTLT L U = U^{T} L^{T}

UU について整理すると

U=L1UTLT U = L^{-1} U^{T} L^{T}

両辺の右側に (LT)1(L^{T})^{-1} を掛けると

U(LT)1=L1UT U (L^{T})^{-1} = L^{-1} U^{T}

を得る。U(LT)1=L1UTU (L^{T})^{-1} = L^{-1} U^{T} の左辺は上三角行列、右辺は下三角行列なので

D:=U(LT)1=L1UT D: = U (L^{T})^{-1} = L^{-1} U^{T}

対角行列とわかる。これを UU について整理すると U=DLTU = DL^{T} となり、次を得る。

A=LU=LDLT A = LU = LDL^{T}

計算

さて、具体的に LLDD を計算するために次のように定義してみよう。

L:=[1000l21100l31l3210ln1ln2ln31],D:=[d110000d220000d330000dnn] L : = \begin{bmatrix} 1 & 0 & 0 & \cdots & 0 \\ l_{21} & 1 & 0 & \cdots & 0 \\ l_{31} & l_{32} & 1 & \cdots & 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ l_{n1} & l_{n2} & l_{n3} & \cdots & 1 \end{bmatrix},\quad D : = \begin{bmatrix} d_{11} & 0 & 0 & \cdots & 0 \\ 0 & d_{22} & 0 & \cdots & 0 \\ 0 & 0 & d_{33} & \cdots & 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & 0 & \cdots & d_{nn} \end{bmatrix}

A=(aij)=LDLTA = (a_{ij}) = LDL^{T} を直接計算しよう。

lij>0l_{ij} > 0 であり lii=1l_{ii} = 1 なので

aij=ν=1nliνμ=1ndνμlμjT=ν=1nliνμ=1nδνμdνμljμ=ν=1nliνdννljν=ν=1min(i,j)liνdννljν \begin{align*} a_{ij} =& \sum_{\nu = 1}^{n} l_{i \nu} \sum_{\mu = 1}^{n} d_{\nu \mu} l_{\mu j}^{T} \\ =& \sum_{\nu = 1}^{n} l_{i \nu} \sum_{\mu = 1}^{n} \delta_{\nu \mu} d_{\nu \mu} l_{ j \mu} \\ =& \sum_{\nu = 1}^{n} l_{i \nu} d_{\nu \nu} l_{ j \nu} \\ =& \sum_{\nu = 1}^{ \min (i,j) } l_{i \nu} d_{\nu \nu} l_{ j \nu} \end{align*}

まず jij \le i の場合で仮定してみよう。

aij=ν=1jliνdννljν=ν=1j1liνdννljν+lijdjjljj=ν=1j1liνdννljν+lijdjj a_{ij} = \sum_{\nu = 1}^{j} l_{i \nu} d_{\nu \nu} l_{j \nu} = \sum_{\nu = 1}^{j-1} l_{i \nu} d_{\nu \nu} l_{j \nu} + l_{ij} d_{jj} l_{jj} = \sum_{\nu = 1}^{j-1} l_{i \nu} d_{\nu \nu} l_{j \nu} + l_{ij} d_{jj}

ここで i=j=ki = j = k の場合

akk=ν=1k1lkνdννlkν+dkkdkk a_{kk} = \sum_{\nu = 1}^{k-1} l_{k \nu} d_{\nu \nu} l_{k \nu} + d_{kk} d_{kk}

について整理すると

dkk=akkν=1k1dννlkν2 d_{kk} = a_{kk} - \sum_{\nu = 1}^{k-1} d_{\nu \nu} l_{k \nu}^2

逆に j=kj = k であり i=k+1,,ni = k+1, \cdots , n とすると

aik=ν=1k1liνdννlkν+likdkk a_{ik} = \sum_{\nu = 1}^{k-1} l_{i \nu} d_{\nu \nu} l_{k \nu} + l_{ik} d_{kk}

likl_{ik} について整理すると

lik=1dkk{aikν=1k1liνdννlkν} l_{ik} = {{1} \over {d_{kk}}} \left\{ a_{ik} - \sum_{\nu = 1}^{k-1} l_{i \nu} d_{\nu \nu} l_{k \nu} \right\}

アルゴリズム

(aij)Rn×n(a_{ij}) \in \mathbb{R}^{n \times n} が可逆対称行列としよう。

**Step 1. k=1k = 1

d11=a11d_{11} = a_{11} を代入して li1=1d11ai1\displaystyle l_{i1} = {{1} \over {d_{11}}} a_{i1} を計算する。


**Step 2. k=2,3,,n1k = 2, 3, \cdots , n-1

  • Step 2-1. 次を計算する。 dkk=akkν=1k1dννlkν2 d_{kk} = a_{kk} - \sum_{\nu = 1}^{k-1} d_{\nu \nu} l_{k \nu}^2

  • **Step 2-2. i=k+1,k+2,,n1i = k+1 , k+2 , \cdots , n-1 について次を計算する。 lik=1dkk{aikν=1k1liνdννlkν} l_{ik} = {{1} \over {d_{kk}}} \left\{ a_{ik} - \sum_{\nu = 1}^{k-1} l_{i \nu} d_{\nu \nu} l_{k \nu} \right\}


**Step 3. k=nk = n について次を計算する。 dnn=annν=1n1dννlnν2 d_{nn} = a_{nn} - \sum_{\nu = 1}^{n-1} d_{\nu \nu} l_{n \nu}^2


  • 手計算では複雑に見えたが、アルゴリズムとして整理すれば計算量は大幅に減少したことが分かる。常に DD の対角成分を先に求め、次に LL の値を列単位で求めていくことを覚えておこう。

コード

さて、LU 分解で行ったのと同じ例を使って LDU 分解を実際に試してみよう。

5A1AC6BB2.png

以下のコードは上記のアルゴリズムを R で実際に実装したものだ。

B <- matrix(c(2,1,0,1,2,1,0,1,2), ncol= 3); B
 
LDU<-function(A)
{
  n=length(A[,1])
  L<-diag(1,n)
  D<-diag(0,n)
  
  k=1
  D[1,1] = A[1,1]
  L[,1] = A[,1]/D[1,1]
 
  for(k in 2:(n-1))
  {
    D[k,k] = A[k,k] - sum(diag(D)[1:(k-1)]*L[k,1:(k-1)]^2)
    for(i in (k+1):n)
    {
      L[i,k] = ( A[i,k] - sum(L[i,1:(k-1)]*diag(D)[1:(k-1)]*L[k,1:(k-1)]) )/D[k,k]
    }
  }
  
  D[n,n] = A[n,n] - sum(diag(D)[1:(n-1)]*L[n,1:(n-1)]^2)
 
  return(list(L=L, D=D))
}
 
LDU(B)
LDU(B)$L%*%LDU(B)$D%*%t(LDU(B)$L)

実行結果は次の通りだ。 20171128\_143203.png

R には LDU 分解が実装されていないため、結果を確認しただけだが、正確に分解されていることが分かる。

BB のサイズがそれほど大きくなく、計算もそれなりにできるので、疑わしい場合は直接手計算しても良い。