numpyやscipyの内部ではLAPACK(C/C++の線形代数ライブラリ)を使っている
LAPACKはだいたいLU分解をしている
LAPACKで連立一次方程式を解く¶
正則な係数行列をもつ連立一次方程式をLAPACKで解くには、xGESV関数(連立一次方程式を解く関数)もしくはxGETRF関数(LU分解の関数)とxGETRS関数(前進代入・後退代入を行う関数)を使えば解ける(幸谷, 2016)
xGESV関数はをについて解き、としてに代入する関数
逆行列計算の実装を覗く¶
# scipyのinv
import numpy as np
from scipy import linalg
A = np.array([
[1, 2],
[3, 4]
])
linalg.inv(A)array([[-2. , 1. ],
[ 1.5, -0.5]])numpy.linalg.inv¶
source:
import numpy as np
np.linalg.inv(A)array([[-2. , 1. ],
[ 1.5, -0.5]])scipyのLAPACK functions¶
Low-level LAPACK functions (scipy.linalg.lapack) — SciPy v1.12.0 Manual
xGESV¶
DGESV computes the solution to a real system of linear equations
A * X = B,
where A is an N-by-N matrix and X and B are N-by-NRHS matrices.
The LU decomposition with partial pivoting and row interchanges is used to factor A as
A = P * L * U,
where P is a permutation matrix, L is unit lower triangular, and U is upper triangular. The factored form of A is then used to solve the system of equations A * X = B.
from scipy.linalg.lapack import dgesv
# AX = I としてX=A^{-1}を推定する
I = np.eye(A.shape[0])
lu, piv, x, info = dgesv(A, I)xarray([[-2. , 1. ],
[ 1.5, -0.5]])xGETRF¶
LU分解をする関数。
scipy.linalg.lapack.dgetrf — SciPy v1.12.0 Manual
docs: LAPACK: dgetrf
DGETRF computes an LU factorization of a general M-by-N matrix A using partial pivoting with row interchanges. The factorization has the form
A = P * L * U
where P is a permutation matrix, L is lower triangular with unit diagonal elements (lower trapezoidal if m > n), and U is upper triangular (upper trapezoidal if m < n).
from scipy.linalg.lapack import dgetrf
lu, piv, info = dgetrf(A)luarray([[3. , 4. ],
[0.33333333, 0.66666667]])pivarray([1, 1], dtype=int32)xGETRI¶
LU分解の結果から逆行列を取得する関数
scipy.linalg.lapack.dgetri — SciPy v1.12.0 Manual
cpp docs: LAPACK: dgetri
DGETRI computes the inverse of a matrix using the LU factorization computed by DGETRF.
This method inverts U and then computes inv(A) by solving the system inv(A)*L = inv(U) for inv(A).
from scipy.linalg.lapack import dgetri
inv_a, info = dgetri(lu, piv)
inv_aarray([[-2. , 1. ],
[ 1.5, -0.5]])LAPACKはどうやって計算量を下げているのか¶
掃き出し法とLU分解+逆行列の計算は計算量的にほぼ一緒で程度らしい (『数値計算の常識』、安易に逆行列を数値計算するのはやめよう )
しかし、一般の実数行列につかえるアルゴリズムの中では最善の様子。
LUは疎行列に強いというのもある
逆行列の計算量¶
行列式を使う場合¶
を次の正方行列とする。逆行列
は、行列式の計算で、
行列式の計算量
行列式は
で、があり、各項で回を掛けるので
「行列Aのi行から、j行の定数倍を引いても、行列式の値は変わらない。」という性質を使って上三角行列に変形してから行列式を計算する。三角行列への変換は、上三角行列の行列式は対角成分の積なのでなので、全体でになる
(参考:Tech Tips: 行列式の計算)
余因子行列の計算量
余因子は「『行目と列目を除いた行列』の行列式にをかけたもの」なので、次行列の行列式を求める計算になり、
余因子行列は「余因子を成分に持つ行列を転置したもの」なので、余因子を個計算する必要がある→か?
import numpy as np
A = np.array([
[1, 2],
[3, 4]
])
np.linalg.det(A)-2.0000000000000004A[1, :] += (-3) * A[0, :]
Aarray([[ 1, 2],
[ 0, -2]])参考¶
幸谷智紀. (2016). LAPACK/BLAS 入門: Linear Algebra PACKage Basic Linear Algebra Subprograms.