LU分解
続いて、2 行目はまず「 \(l_u_=10\) 」から「 \(l_ \cdot 5 =10\) 」となります。そこから「 \(l_=2\) 」であることが求められます。そして「 \(l_u_+u_=20\) 」から「 \(2 \cdot 6+u_=20\) 」となります。そこから「 \(u_=8\) 」であることが求められます。同じようにして「 \(l_u_+u_=23\) 」から「 \(u_=9\) 」であることが求められます。
3 行目も同じです。まず「 \(l_u_=15\) 」から「 \(l_=3\) 」であることがわかります。 続いて 「 \(l_u_+l_u_=50\) 」 から「 \(l_=4\) 」であることがわかります。最後に 「 \(l_u_+l_u_+u_=67\) 」から「 \(u_=10\) 」であることがわかります。
こうやって上から順番に解いていくことで、全ての記号の値が求められます。以上のことから、行列 \(A\) を分解したときの下方行列 \(L\) と上方行列 \(U\) が求められます。
LU分解可能な行列の条件
なおすべての正方行列で LU 分解が可能わけではありません。
ある行列が LU 分解可能なのは、すべての「主座小行列」の行列式の値が 0 ではない場合です。主座小行列とは、行列の左上に位置するすべての部分行列のことです。
この場合、次の 3 つが主座小行列になります。
これらのすべての主座小行列の行列式の値が 0 でないときのみ LU 分解が可能です。
ほぼどんな行列でも可能なPLU分解とは?
この行列をLU分解しようとしても、主座小行列の行列式の値が 0 なのでLU分解できないことに気づきます。実際に確かめてみましょう。まず、この行列の積の数値と記号の対応関係は以下の通りになります。
これを順番に解いていくだけなのですが、今回は \(u_\) が 0 なので、いきなり \(l_u_=10\) が解けないことがわかります。
このようなときに行を入れ替えることで、LU分解を可能にしてくれるのが置換行列です。たとえば、行列 \(A\) に以下の置換行列 \(P\) を左から掛けると、1 行目と 3 行目が入れ替えられます。
このように置換しておくと、主座小行列の行列式の値が 0 ではなくなるので、LU分解が可能になります。実際に解くと以下のようになります。
以上のことから、元々の行列 \(A\) は次のようにPLU分解できるということになります。
こちらの方法だと、ほとんどの行列を安定してLU分解することが可能であり、システムの安定性が増すため、プログラミング言語の Python では、PLU分解がデフォルトになっています。
PythonでLU分解
LU分解は、Python では SciyPy ライブラリの lu() 関数で実装されています。より具体的には、この関数は PLU分解を実行します。以下の通りです。
# NumPy と SciPy のインポート import numpy as np from scipy.linalg import lu # 正方行列を定義 A = np.array([ [1,2,3], [4,5,6], [7,8,9]]) print(A) [[1 2 3] [4 5 6] [7 8 9]] # PLU分解 P,L,U = lu(A) print(P) [[0. 1. 0.] [0. 0. 1.] [1. 0. 0.]] print(L) [[1. 0. 0. ] [0.14285714 1. 0. ] [0.57142857 0.5 1. ]] print(U) [[ 7.00000000e+00 8.00000000e+00 9.00000000e+00] [ 0.00000000e+00 8.57142857e-01 1.71428571e+00] [ 0.00000000e+00 0.00000000e+00 -1.58603289e-16]] # 元々の行列の再作成 B= P @ L @ U print(B) [[1. 2. 3.] [4. 5. 6.] [7. 8. 9.]]