Pythonで余因子行列を計算する

余因子行列の計算

余因子行列とは

n次正方行列に対してi行j列を取り除いた行列を考えます(minor matrixということがあります)。行列の行列式を計算し、行と列の合計が奇数の場合にはマイナスします。その行と列を取り除いた要素の行列式をいいます。ただし、このときの符号はi+jが奇数の時には-を付けます。この値を要素(i,j)に対する余因子といいます。そしてこの余因子を全ての要素に対して計算し、i行j列の要素とする行列を余因子行列(cofactor matrix)といいます。

なぜ、このような複雑な計算をする必要があるかはさておき、まずは余因子行列を計算するプログラムを作成します。

余因子行列
余因子行列

余因子行列の計算

行列の定義

4行4列の行列を定義します。ここでは2次元の配列とします。

行列の定義
  1. m_x =[[ 2, 2,-1, 1],
  2. [-1, 1, 2, 1],
  3. [ 1, 2, 0, 1],
  4. [ 2, 0, 1, 1]]

minor matrixの計算

4行4列の行列に対し、i行j列を取り除いた行列を計算する関数を作成します。

余因子の計算
  1. def minor_submatrix(m, i, j):
  2. mtrx = []
  3. for row in range(len(m)):
  4. if row != i:
  5. mtrx_rows = []
  6. for col in range(len(m[0])):
  7. if col != j:
  8. mtrx_rows.append(m[row][col])
  9. mtrx.append(mtrx_rows)
  10. return mtrx
  11. minor_submatrix(m_x,1,1)

[[2, -1, 1], [1, 0, 1], [2, 1, 1]]

図と比べると、正しく計算されたことがわかります。

行列式の計算

余因子を計算するためには、minor matrixの行列式を計算する必要があります。ここでは以前作成したdet関数を使います。

  1. import copy
  2. def d_plus(index):
  3. temp = []
  4. dim=len(index[0])+1
  5. for i in range(len(index)):
  6. for j in reversed(range(dim)):
  7. row = copy.deepcopy(index[i])
  8. row.insert(j, dim)
  9. temp.append(row)
  10. return sorted(temp)
  11. def index_m(n,index=[[1]]):
  12. if n ==1:
  13. return index
  14. else:
  15. return index_m(n-1,d_plus(index))
  16. def sgn(L):
  17. sum_of_bigger = 0
  18. for index in range(len(L)-1):
  19. for left in range(index+1, len(L)):
  20. if L[index] > L[left]:
  21. sum_of_bigger += 1
  22. if sum_of_bigger % 2 == 0:
  23. return 1
  24. else:
  25. return -1
  26. def det(m):
  27. dem = len(m)
  28. index = index_m(dem)
  29. det=0
  30. for i,row in enumerate(index):
  31. product = 1
  32. for col in range(dem):
  33. product *= m[col][row[col]-1]
  34. det += sgn(row)*product
  35. return det

かなり面倒なプログラムになりますが、4次元以上の行列となると複雑な計算をする必要があります。

余因子の計算

行列式を求めることができたら、余因子の計算はminor matrixの行列式を計算し、i+jが偶数であれば加算、奇数であれば減算するだけの簡単な計算になります。ここではcofactor関数とします。

  1. def cofactor(m,i,j):
  2. return (-1)**(i+j)*det(minor_submatrix(m_x, i, j))
  3. cofactor(m_x,1,0)

-2

余因子を計算することができました。

余因子行列の計算

cofactor関数では、元の行列の各要素にcofactor関数を適用するだけです。

  1. def cofactor_matrix(m):
  2. mtrx=[]
  3. for i in range(4):
  4. mtrx_rows=[]
  5. for j in range(4):
  6. mtrx_rows.append(cofactor(m,i,j))
  7. mtrx.append(mtrx_rows)
  8. return mtrx
  9. cofactor_matrix(m_x)

[[-3, -4, -5, 11], [-2, -2, -2, 6], [4, 6, 6, -14], [1, 0, 1, -1]]

余因子の使い途

なぜ、余因子の計算はすこし面倒ですが、面白い計算に使えます。

行列式の計算

行列式の計算は前述のとおり、かなり複雑になります。ところが、余因子を使うと次のような面白い性質があります。

余因子行列
余因子行列

3次元の行列の場合、1行目の各要素とその余因子(2行×2列)の積の和を求めると元の行列の行列式と一致します。

3次元の行列式の計算は次の式で計算します。

$a_{11}a_{22}a_{33}+a_{12}a_{23}a_{31}+a_{13}a_{21}a_{32}-a_{13}a_{22}a_{31}-a_{11}a_{23}a_{32}-a_{12}a_{21}a_{33}$

この式と図を比べると確かに計算結果は一致します。このことは4次元以上の行列にもあてはまります。このことから、再帰関数を使い行列式を計算することを考えます。この関数では前に作成したminor_submatrixを使います。

  1. def det_r(m):
  2. dim=len(m)
  3. det=0
  4. if dim==1:
  5. return m[0][0]
  6. else:
  7. for i in range(dim):
  8. det+=(-1)**i*m[0][i]* det_r(minor_submatrix(m,0,i))
  9. return det
  10. det_r(m_x)

-2

たったこれだけのプログラムで行列式を計算することができるのは驚きです。