Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

LU分解

与えられた行列AAを単位下三角行列LLと上三角行列UUとの積で表すこと

A=LU=[1l211⋮⋱⋱ln1⋯ln,n−11][u11u12⋯u1nu22⋯u2n⋱⋮unn]A = LU = \left[\begin{array}{cccc} 1 & & & \\ l_{21} & 1 & & \\ \vdots & \ddots & \ddots & \\ l_{n 1} & \cdots & l_{n, n-1} & 1 \end{array}\right]\left[\begin{array}{cccc} u_{11} & u_{12} & \cdots & u_{1 n} \\ & u_{22} & \cdots & u_{2 n} \\ & & \ddots & \vdots \\ & & & u_{n n} \end{array}\right]

をLU分解と呼ぶ。

分解すると何が嬉しいのか?

行列式や一次方程式を少ない計算量で求められる材料としてL,UL,Uが手に入り、全体としての計算を効率化できる可能性がある。

例:連立1次方程式・逆行列

例えば様々なbbに対してAx=bAx=bを解く場合はA=LUA=LUと一旦分解して、後でL,UL,Uを使い回せばよい

様々なbbというのは、たとえばB=(b1,b2,⋯ ,bn)B=(b_1, b_2, \cdots, b_n)として行列の連立一次方程式

AX=BAX = B

を解くことができる。B=IB=I(b1=e1,b2=e2,⋯ ,bn=enb_1 = e_1, b_2 = e_2, \cdots, b_n = e_n)とすればAX=IAX=Iを解いてX=A−1X=A^{-1}を求めることができる。

計算量はLU分解にO(n3/3)O(n^3/3)かかる。そこから逆行列を計算する場合はO(2n3/3)O(2n^3/3)かかり、全体でO(n3/3+2n3/3)=O(n3)O(n^3/3 + 2n^3/3)=O(n^3)となる。これは掃き出し法と同程度だが、もとの行列が疎行列だとLUも疎行列になるので、入力が疎行列の場合も含めた計算量でいうとLU分解のほうが効率的らしい。

例:行列式

∣A∣=∣LU∣=∣L∣∣U∣(∵ 行列式の性質 ∣AB∣=∣A∣∣B∣ より )=1×∣U∣(∵L は単位下三角行列のため )=∣U∣\begin{align} |A| &= |LU|\\ &= |L| |U| \quad (\because \text{ 行列式の性質 } |AB|=|A||B| \text{ より })\\ &= 1\times |U| \quad (\because L \text{ は単位下三角行列のため })\\ &= |U| \end{align}

三角行列の行列式は対角行列の積になるため、∣L∣=1|L|=1であり∣A∣=∣U∣|A|=|U|になるし∣U∣|U|もUUの対角成分の積をとるだけでいい

計算手順(ドゥーリトル法)

LLの対角成分は1に固定し、次のような分解を仮定する

A=[10l211][u11u120u22]A = \left[\begin{array}{cc} 1 & 0 \\ l_{21} & 1 \end{array}\right] \left[\begin{array}{cc} u_{11} & u_{12} \\ 0 & u_{22} \end{array}\right]

LULUの積を計算すると

A=[u11u12l21u11l21u12+u22]A=\left[\begin{array}{ccc} u_{11} & u_{12}\\ l_{21} u_{11} & l_{21} u_{12} + u_{22} \end{array}\right]

となるため、AAの各要素との対応がとれる

a11=u11a12=u12a21=l21u11a22=l21u12+u22\begin{aligned} & a_{11}=u_{11} \\ & a_{12}=u_{12} \\ & a_{21}=l_{21} u_{11} \\ & a_{22}=l_{21} u_{12}+u_{22} \end{aligned}

これらを解いていく

一般化

もっと一般化すると次のようになる

m×nm\times n行列A=(aij)A=(a_{ij})に対して、s=min⁡(m,n)s=\min(m,n)とおき、m×sm\times sのLLとs×ns\times nのUUで分解することを考える。

L=(l1,…,ls),U=(u1T⋮usT)L = \left(\boldsymbol{l}_1, \ldots, \boldsymbol{l}_s\right), \quad U = \left(\begin{array}{c} \boldsymbol{u}_1^T \\ \vdots \\ \boldsymbol{u}_s^T \end{array}\right)

とすると

A=l1u1T+⋯+lsusTA = l_1 \boldsymbol{u}_1^T+\cdots+\boldsymbol{l}_s \boldsymbol{u}_s^T

とできるので、この表記を使っていく。

反復計算するのでA=A(1)=(aij(1))A = A(1) = (a_{ij}(1))と表記する

l1=1a11(1)(a11(1)⋮am1(1)),u1T=(a11(1),…,a1n(1))\boldsymbol{l}_1=\frac{1}{a_{11}(1)}\left(\begin{array}{c} a_{11}(1) \\ \vdots \\ a_{m 1}(1) \end{array}\right), \quad \boldsymbol{u}_1^T=\left(a_{11}(1), \ldots, a_{1 n}(1)\right)

と置くと、

A(1)−l1u1T=(00⋯00⋮A(2)0), すなわち A=l1u1T+(00⋯00⋮A(2)0)A(1)-\boldsymbol{l}_1 \boldsymbol{u}_1^T=\left(\begin{array}{c|ccc} 0 & 0 & \cdots & 0 \\ \hline 0 & & & \\ \vdots & & A(2) & \\ 0 & & & \end{array}\right), \quad \text { すなわち } A=l_1 \boldsymbol{u}_1^T+\left(\begin{array}{c|ccc} 0 & 0 & \cdots & 0 \\ \hline 0 & & & \\ \vdots & & A(2) & \\ 0 & & \end{array}\right)

となる。残ったブロック行列をA(2)A(2)としている。

ゼロじゃない要素をl(2),u(2)\boldsymbol{l}(2), \boldsymbol{u}(2)とおき、同様に

l(2)=1a11(2)(a11(2)⋮am′1(2)),u(2)T=(a11(2),…,a1n′(2))\boldsymbol{l}(2)=\frac{1}{a_{11}(2)}\left(\begin{array}{c} a_{11}(2) \\ \vdots \\ a_{m^{\prime} 1}(2) \end{array}\right), \quad \boldsymbol{u}(2)^T=\left(a_{11}(2), \ldots, a_{1 n^{\prime}}(2)\right)

とすると(ここでm′=m−1,n′=n−1m'=m-1, n'=n-1)、同様に

A(2)−l(2)u(2)T=(00⋯00⋮A(3)0)A(2)-l(2) \boldsymbol{u}(2)^T=\left(\begin{array}{c|ccc} 0 & 0 & \cdots & 0 \\ \hline 0 & & & \\ \vdots & & A(3) & \\ 0 & & & \end{array}\right)

となる。ここで

l2=(0l(2)),u2T=(0,u(2)T)\boldsymbol{l}_2=\left(\begin{array}{c} 0 \\ \boldsymbol{l}(2) \end{array}\right), \quad \boldsymbol{u}_2^T=\left(0, \boldsymbol{u}(2)^T\right)

のように頭に0をつけてサイズを戻せば

(00⋯⋯00⋮A(2)⋮0)=l2u2T+(000⋯0000⋯000⋮⋮A(3)00)\left(\begin{array}{c|cccc} 0 & 0 & \cdots & \cdots & 0 \\ \hline 0 & & & & \\ \vdots & & A(2) & & \\ \vdots & & & & \\ 0 & & & & \end{array}\right)=l_2 \boldsymbol{u}_2^T+\left(\begin{array}{cc|ccc} 0 & 0 & 0 & \cdots & 0 \\ 0 & 0 & 0 & \cdots & 0 \\ \hline 0 & 0 & & & \\ \vdots & \vdots & & A(3) & \\ 0 & 0 & & \end{array}\right)

から

A=l1u1T+l2u2T+(000⋯0000⋯000⋮⋮A(3)00)A=l_1 \boldsymbol{u}_1^T+\boldsymbol{l}_2 \boldsymbol{u}_2^T+\left(\begin{array}{cc|ccc} 0 & 0 & 0 & \cdots & 0 \\ 0 & 0 & 0 & \cdots & 0 \\ \hline 0 & 0 & & & \\ \vdots & \vdots & & A(3) & \\ 0 & 0 & & & \end{array}\right)

となる。

これを何度も繰り返していくと、最後は残る行列がゼロ行列になる

A=l1u1T+⋯+lsusT+OA=l_1 \boldsymbol{u}_1^T+\cdots+\boldsymbol{l}_s \boldsymbol{u}_s^T+O

そうしたら

L=(l1,…,ls),U=(u1T⋮usT)L = \left(\boldsymbol{l}_1, \ldots, \boldsymbol{l}_s\right), \quad U = \left(\begin{array}{c} \boldsymbol{u}_1^T \\ \vdots \\ \boldsymbol{u}_s^T \end{array}\right)

のように行列L,UL,Uを作ればよい

pythonの例

l1=array([1., 3.]), u1=array([1, 2])
array([[1., 2.], [3., 6.]])
array([[ 0., 0.], [ 0., -2.]])
l2_=array([1.]), u2_=array([-2.])
array([[0.]])
array([[1., 2.], [3., 4.]])
array([[1., 0.], [3., 1.]])
array([[ 1., 2.], [ 0., -2.]])
array([[1., 2.], [3., 4.]])

行列式をLU分解で求める


|A| = -2.0
|L||U| = -2.0
Uの対角成分の積 = -2.0

連立一次方程式をLU分解で解く

連立一次方程式

Ax=bAx = b

に対し、LU分解すると

Ax=LUx=bAx = LUx = b

であり、変数yyを

Ux=yUx=y

とおき代入すると

Ly=bLy = b

になることから変数yyを求める。

Ly=bLy = b(前進代入)は

y1:=b1y2:=b2−l21y1⋮yn−1:=bn−1−∑j=1n−2ln−1,jyjyn:=bn−∑j=1n−1lnjyj\begin{aligned} & y_1:=b_1 \\ & y_2:=b_2-l_{21} y_1 \\ & \vdots \\ & y_{n-1}:=b_{n-1}-\sum_{j=1}^{n-2} l_{n-1, j} y_j \\ & y_n:=b_n-\sum_{j=1}^{n-1} l_{n j} y_j \end{aligned}

Ux=yUx = y(後退代入)は

xn:=ynunnxn−1:=yn−1−un−1,nxnun−1,n−1⋮x2:=y2−∑j=3nu2jxju22x1:=y1−∑j=2nu1jxju11\begin{aligned} & x_n:=\frac{y_n}{u_{n n}} \\ & x_{n-1}:=\frac{y_{n-1}-u_{n-1, n} x_n}{u_{n-1, n-1}}\\ & \vdots\\ & x_2:=\frac{y_2-\sum_{j=3}^n u_{2 j} x_j}{u_{22}} \\ & x_1:=\frac{y_1-\sum_{j=2}^n u_{1 j} x_j}{u_{11}} \end{aligned}

という計算

xGETRS

前進代入・後退代入を行うのがLAPACKのxGETRSサブルーチン

(array([0. , 0.5]), 0)
array([ 1., -1.])
array([0. , 0.5])
array([1., 2.])

逆行列

A−1=U−1L−1A^{-1} = U^{-1} L^{-1}

あるいはAx=bAx=bのxxを求める操作をnn回繰り返す

array([[-2. , 1. ], [ 1.5, -0.5]])
array([[-2. , 1. ], [ 1.5, -0.5]])

Ax=bAx=bのxxを求める操作をnn回繰り返す

array([[0., 1.], [1., 0.]])
array([[1. , 0. ], [0.33333333, 1. ]])
array([[3. , 4. ], [0. , 0.66666667]])
array([[1., 2.], [3., 4.]])

置換行列PPつきの分解はPA=LUPA=LUとなる。

Ax=bAx = bは2つの方程式Ly=Pb,Ux=yLy=Pb, Ux=yと同値。

L(Ux)=P−1bL(Ux) = P^{-1} b

となり、並べ替えをもとに戻したb=P−1bb = P^{-1} bを使ってやればいい

Ly=bLy = b(前進代入)は

yi=bi−∑j=1i−1lijyjy_i = b_i - \sum^{i-1}_{j=1} l_{ij} y_j

このyyは枢軸選択つきの前進消去で得られる(b1(1),⋯ ,bn(n))⊤\left(b_1^{(1)}, \cdots, b_n^{(n)}\right)^{\top}に等しい

Ux=yUx = y(後退代入)は消去法と同じく

xi=1uii(bi(i)−∑j=i+1nuijxj)(i=n,n−1,⋯ ,1)x_i=\frac{1}{u_{i i}}\left(b_i^{(i)}-\sum_{j=i+1}^n u_{i j} x_j\right) \quad(i=n, n-1, \cdots, 1)

で解ける

array([14, 32, 23])
array([23., 14., 32.])
array([23. , 10.71428571, 13.5 ])
array([1., 2., 3.])

逆行列を解く

I=(e1,⋯ ,en)I=(e_1, \cdots, e_n)として

AX=IAX=I

を解く

array([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]])
array([[-1.778, 0.889, -0.111], [ 1.556, -0.778, 0.222], [-0.111, 0.222, -0.111]])
array([[-1.778, 0.889, -0.111], [ 1.556, -0.778, 0.222], [-0.111, 0.222, -0.111]])

参考文献

  • ドゥーリトル法:LU分解 - Wikipedia

  • 一般化した計算手順:『プログラミングのための線形代数』