『Python数値計算ノート』ではアフィリエイトプログラムを利用して商品を紹介しています。

余因子と余因子行列

【Pythonで学ぶ線形代数学講座(22)】余因子と余因子行列

余因子と余因子行列

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

小行列式

$n$ 次の正方行列 $A$ について、$i$ 行目と $j$ 列目を取り除いて作った行列の行列式を $A$ の 小行列式(minor determinant)とよび、$M_{ij}$ のように表します。たとえば、
 \[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()関数を定義しておきます。

# Python_Cofactor

# In[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 を渡します。

# In[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()関数を使いましょう。

# In[3]

# すべての成分が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()を使って計算した逆行列と比較しています。

 

コメント