余因子と余因子行列

余因子と余因子行列

余因子と余因子行列

 すでに $2\times 2$ の逆行列については学んでいますが、サイズの大きな行列の逆行列を求めることは簡単なことではありません。一般に逆行列を求める手順として、「掃き出し法」と「余因子行列を用いる方法」があります。この記事では余因子行列について解説します。

小行列式

 $n$ 次の正方行列 $A$ について、$i$ 行目と $j$ 列目を取り除いて作った行列式を $A$ の 小行列式 (minor determinant) とよび、$M_{ij}$ のように表します。

 Aの余因子 (cofactor)

 たとえば、
 
\[A=\begin{bmatrix}
2&7&3\\5&0&9\\3&1&4\end{bmatrix}\tag{1}\]
の小行列式 $M_{12}$ は
 
\[M_{12}=\begin{vmatrix}
5&9\\3&4\end{vmatrix}=-7\tag{2}\]
となります。
 

余因子

 小行列式 $M_{ij}$ に $(-1)^{i+j}$ を掛けた値を $A$ の 余因子 (cofactor) とよび、$A_{ij}$ で表します。
 
\[A_{ij}=(-1)^{i+j}M_{ij}\tag{3}\]
 $i+j$ が偶数のときは $(-1)^{i+j}=1$ なので、余因子は小行列式と同じ値をもちます。
 $i+j$ が奇数のときは $(-1)^{i+j}=-1$ なので、余因子は小行列式の符号を反転させた値となります。
 

cofactor()

 NumPy で余因子と小行列式を求める cofactor()関数を定義しておきます。

# リストSLA029-1

import numpy as np

# 余因子または小行列式を求める関数
def cofactor(a, i, j, minor = False):
    x = np.delete(a, i, axis = 0)
    x = np.delete(x, j, axis = 1)
    if minor == False:
        a_ij = (-1)**(i + j) * np.linalg.det(x)
    else:
        a_ij = np.linalg.det(x)
    return a_ij

 この関数はデフォルトで a の余因子を返すようになっています。
 引数 minor に True を指定すると小行列式を返します。
 引数 i, j には、それぞれ消去する行と列を渡しますが、NumPy のインデックスの数え方に合わせているので、たとえば 1 行目と 2 列目を消去する場合は、i = 0, j = 1 を渡します。

# リストSLA029-2

# 行列aを定義
a = np.array([[2, 7, 3],
              [5, 0, 9],
              [3, 1, 4]])

# 0行目と1列目を取り除いた小行列式
m_ij = cofactor(a, 0, 1, minor = True)

# 0行目と1列目を取り除いた余因子
a_ij = cofactor(a, 0, 1)

print("m_ij = {:.3f}".format(m_ij))
print("a_ij = {:.3f}".format(a_ij))
m_ij = -7.000
a_ij = 7.000

 

余因子行列と逆行列

 $A$ の余因子 $A_{ij}$ を $(j,i)$ 成分にもつ行列 $\tilde{A}$ を余因子行列とよびます。
 
\[\tilde{A}=\begin{bmatrix}
A_{11}&A_{21} &\cdots &A_{n1}\\
A_{12}&A_{22} &\cdots &A_{n2}\\
\vdots & \vdots &\ddots &\vdots\\
A_{1n}&A_{2n} &\cdots &A_{nn}
\end{bmatrix}\tag{4}\]
 証明は省略しますが、$A$ の逆行列 $A^{-1}$ は余因子行列によって、
 
\[A^{-1}=\frac{1}{\mathrm{det}A}\tilde{A}\tag{5}\]
で与えられます。(1) で定義した行列
 
\[A=\begin{bmatrix}
2&7&3\\5&0&9\\3&1&4\end{bmatrix}\tag{1}\]
の逆行列を求めてみましょう。手計算だとうんざりすると思うので、先ほど定義した cofactor()関数を使いましょう。

# リストSLA029-3

# 行列aを定義
a = np.array([[2, 7, 3],
              [5, 0, 9],
              [3, 1, 4]])

# すべての成分が0の3×3行列を生成
a_ij = np.zeros((3, 3))

# 余因子行列を生成
for i in range(3):
    for j in range(3):
        a_ij[j, i] = cofactor(a, i, j)

# 余因子行列を使って逆行列を計算
a_inv_1 = a_ij / np.linalg.det(a)

# NumPyの関数を使って逆行列を計算
a_inv_2 = np.linalg.inv(a)

print("aの余因子行列\n{}\n".format(a_ij))
print("余因子行列を使って計算した逆行列\n{}\n".format(a_inv_1))
print("numpy.linalg.inv()を使って計算した逆行列\n{}".format(a_inv_2))
aの余因子行列
[[ -9. -25.  63.]
 [  7.  -1.  -3.]
 [  5.  19. -35.]]

余因子行列を使って計算した逆行列
[[-0.19565217 -0.54347826  1.36956522]
 [ 0.15217391 -0.02173913 -0.06521739]
 [ 0.10869565  0.41304348 -0.76086957]]

numpy.linalg.inv()を使って計算した逆行列
[[-0.19565217 -0.54347826  1.36956522]
 [ 0.15217391 -0.02173913 -0.06521739]
 [ 0.10869565  0.41304348 -0.76086957]]

 コードの記述ミスがないように、numpy.linalg.inv()を使って計算した逆行列と比較しています。