連立方程式を解く

先日以下の記事にしたように、LUP分解をすると正則行列𝐴に対して𝑃𝐴 = 𝐿𝑈という分解ができるのでした。𝐿は下三角行列、𝑈は上三角行列、𝑃は並べ替えの情報が入っています。

marui.hatenablog.com

これを使って連立方程式𝐴𝑥 = 𝑏を解くプログラムを作ります。LU分解のときにお世話になったサイトをふたたび参考にします。

www.hello-statisticians.com

このページの「𝑈𝑥 = 𝑦を𝑥に関して解く」の最後の式(𝑖 < 𝑛の時の𝑥𝑖の計算)の分母にある𝑢𝑖,𝑛は𝑢𝑖,𝑖じゃないといけないので、下記コードではそのようにしています。(コメントが受け付けられていないので、どうやってページの著者に連絡すればいいのやら……)

また、上記解説記事とは違い、今回はLU分解ではなくLUP分解を経由しているので、𝐴𝑥 = 𝑏 → 𝑃𝐴𝑥 = 𝑃𝑏 → 𝐿𝑈𝑥 = 𝑃𝑏 という式変形をしてから計算を開始することになります。そのため、最初に𝑃𝑏の計算(𝑃の値に従って𝑏を並べ替え)が必要になります。

(defun solve (A b)
  "Solve a system of linear equations of Ax=b for x where A is n-by-n matrix and b is a vector of length n.
Reference: https://www.hello-statisticians.com/explain-terms-cat/matrix_factorization5.html"
  (assert (/= (det A) 0) nil "Input matrix is singular.")
  (let* ((n (array-dimension A 0))
         (x (make-array n))
         (y (make-array n))
         (bb (make-array n))
         (LUP (lup-decomp A))
         (L (car LUP))
         (U (cadr LUP))
         (P (caddr LUP)))
    (loop for i from 0 below n          ;reorder b to match P
          do (loop for j from 0 below n
                   do (if (= (aref P i j) 1)
                          (setf (aref bb i) (aref b j)))))
    (setf (aref y 0) (aref bb 0))       ;set initial value
    (loop for i from 1 below n          ;forward substitution
          do (setf (aref y i)
                   (- (aref bb i)
                      (loop for j from 0 to i
                            sum (* (aref L i j) (aref y j))))))
    (setf (aref x (1- n)) (/ (aref y (1- n)) (aref U (1- n) (1- n))))
    (loop for i from (- n 2) downto 0   ;backward substitution
          do (setf (aref x i)
                   (/ (- (aref y i)
                         (loop for j from (1- n) downto i
                               sum (* (aref U i j) (aref x j))))
                      (aref U i i))))
    x))

Common LispMatlabで同じ連立方程式を解いてみましょう。

CL-USER> (solve #2A((1 2 0) (3 4 4) (5 6 3)) #(3 7 8))
#(-7/5 11/5 3/5)
>> [1 2 0 ; 3 4 4 ; 5 6 3] \ [3 ; 7 ; 8]
ans =
   -1.4000
    2.2000
    0.6000

分数か少数かの違いはあれど、同じ結果です。

(2023-11-19追記:続いて逆行列を計算しました →逆行列の計算 - 丸井綜研