行列式の計算手順

当サイトではアフィリエイトプログラムを利用して商品を紹介しています。

【線形代数12】行列式の定義

前回記事で扱った $v_1w_2-v_2w_1$ は線形代数において重要な意味をもつ量であり、
 \[\mathrm{det}(\boldsymbol{v},\boldsymbol{w})=\begin{vmatrix}v_1 & w_1\\v_2 & w_2\end{vmatrix}\tag{2}\]
のように書いて 行列式 (determinant) とよびます。計算するときは対角要素の積をつくってから差をとります。大事なことなので繰り返し述べますが、$\mathrm{det}(\boldsymbol{v},\boldsymbol{w})\neq 0$ のとき、$\boldsymbol{v}$ と $\boldsymbol{w}$ は線形独立であり、この 2 つのベクトルで平面を張ることができます。

線形独立と行列式の関係を幾何学的に考えてみます。
$\mathrm{det}(\boldsymbol{v},\boldsymbol{w})$ は $\boldsymbol{v}$ と $\boldsymbol{w}$ を辺とする平行四辺形の面積を表すことが知られています。
2次元行列式 determinant の幾何学的定義
しかし、$\boldsymbol{v}$ と $\boldsymbol{w}$ が線形従属(平行)であるときは、この平行四辺形は潰れてしまって面積は $0$ になってしまいます。したがって、$\boldsymbol{v}$ と $\boldsymbol{w}$ が線形独立であることは、$\mathrm{det}(\boldsymbol{v},\boldsymbol{w})$ が $0$ 以外の値をもつことに対応します。

scipy.linalg.det()

行列式は scipy.linalg.det() を使って計算できます。

# python_determinant_1

# In[1]

import numpy as np
from scipy.linalg import det

# 配列を定義
x = np.array([[ 5, 2],
              [-3, 4]])

# 行列式を計算
det_x = det(x)

print(det_x)
# 26.0

サラスの方法

線形独立と行列式の関係は 3 次元ベクトルにも拡張できます。
3 次元空間における行列式は以下の式で与えられます。
 \[\begin{align*}\mathrm{det}(\boldsymbol{u},\boldsymbol{v},\boldsymbol{w})&=\begin{vmatrix}u_1 & v_1 & w_1\\u_2 & v_2 & w_2\\u_3 & v_3 & w_3\end{vmatrix}\\[6pt]&=u_1v_2w_3+u_2v_3w_1+u_3v_1w_2-u_1v_3w_2-u_2v_1w_3-u_2v_1w_3\end{align*}\]
こんな式を覚えられるわけないので、以下の図に示すように行列式のを二つ重ねて、対角線上の積をつくって合計します。
Python サラスの方法 (Sarrus' rule)
ただし、左上から右下にとる積はプラス、右上から左下にとる積はマイナスの符号をつけて計算します。この計算法を サラスの方法 (Sarrus’ rule) とよびます。

3次元ベクトルの線形結合

3 次元のベクトルで作られる行列式は、3 つのベクトルが作る立体の体積を表します。
3次元行列式 determinant の幾何学的意味
3 つのベクトルが同じ平面内にあるとき (線形従属の関係にあるとき) には、立体は潰れてしまって体積は $0$ になります。$\boldsymbol{u},\ \boldsymbol{v},\ \boldsymbol{w}$ で空間を張ることができる (線形独立の関係にある) のは、行列式の値が $0$ 以外の値をとるときです。

行列式の計算手順

 実際に行列式を計算するときは、サラスの方法を使う前に、明らかに行列式が $0$ にならないかを確認します。たとえば、
 \[\mathrm{det}A=\begin{vmatrix}2 & 4 & 5\\1 & 2 & 5\\4 & 8 & 3\end{vmatrix}\]
という行列式は、2 列目のベクトルが 1 列目のベクトルの 2 倍になっています。つまり平行なベクトルが含まれているので、この行列式は計算するまでもなく $\mathrm{det}A=0$ だとわかります。
 
あるベクトルの成分に共通の約数があれば行列式の外に出します(詳しくは次回記事 行列式の線形性 で扱います)。すなわち成分の最大公約数を見つけます。たとえば、
 \[\mathrm{det}B=\begin{vmatrix}1 & 5 & 12\\7 & 0 & 16\\9 & 5 & 8\end{vmatrix}\]
の 2 列目の最大公約数は $5$, 3 列目の成分の最大公約数は $4$ なので、この行列式は
 \[\mathrm{det}B=4\cdot 5\begin{vmatrix}1 & 1 & 3\\7 & 0 & 4\\9 & 1 & 2\end{vmatrix}=20\times 39=780\]
のように計算できます。

n次元ベクトルの線形結合

2 次元と 3 次元で展開された議論はそのまま $n$ 次元空間に拡張されます。
$n$ 組の $n$ 次元ベクトルが $n$ 次元空間を張るための条件は、互いに線形独立の関係にあること、すなわち、$n$ 組の $n$ 次元ベクトルから作られた行列式が $0$ 以外の値をとることです。
次元が増えると、もはや紙の上での計算では手に負えなくなるので、コンピュータの力を借りることになります。scipy.linalg.det() を使って、10 次元の行列式の値を計算してみましょう。各成分は np.random.randint() を使って 0 ~ 9 の範囲で無作為に決定します。

# python_determinant_2

# In[1]

import numpy as np
from scipy.linalg import det

# 乱数シードを設定
np.random.seed(10)

# 10次元ベクトルを10個格納した2次元配列
# [[5 0 3 3 7 9 3 5 2 4]
#  [7 6 8 8 1 6 7 7 8 1]
#  [5 9 8 9 4 3 0 3 5 0]
#  [2 3 8 1 3 3 3 7 0 1]
#  [9 9 0 4 7 3 2 7 2 0]
#  [0 4 5 5 6 8 4 1 4 9]
#  [8 1 1 7 9 9 3 6 7 2]
#  [0 3 5 9 4 4 6 4 4 3]
#  [4 4 8 4 3 7 5 5 0 1]
#  [5 9 3 0 5 0 1 2 4 2]]
x = np.random.randint(0, 10, (10, 10))

# 行列式の値を計算
det_x = det(x)

print("{:.3e}".format(det_x))
# 5.825e+07

$5.825\times 10^7$ という大きな桁の数が表示されました。
言うまでもなく、上のコードで設定したベクトルは互いに線形独立です。
次元が大きい場合、ランダムに成分を決めても、線形従属なベクトルの組は滅多に出現しないようです。行列式の値はプラス側にもマイナス側にも大きく振れます。上のコードで seed を 10 に設定すると $-2.982\times 10^8$ となります。
 
同じように、3 次元で 0 ~ 9 の範囲のランダム成分をもつ行列式を 10 万個つくって、そのうち何個が 0 になるか調べてみました。

# In[2]

# 乱数シードを設定
np.random.seed(0)

# カウント数の初期値
ct = 0

# 無作為な3次元行列式を10万個作成して値を計算
for k in range(10**5):
    x = np.random.randint(0, 10, (3, 3))
    if det(x) == 0:
        ct += 1
        
print("行列式が0になった個数:{}".format(ct))
# 行列式が0になった個数:1785

結果は 1785 個です。seed を変えて計算しても、概ね 1700 個前後でした。おおよそ 100 個のうち 2 個程度が線形従属の関係にあるベクトルの組となります。

行列式の展開

行列式を計算する別の手段として、行展開(または列展開)があります。たとえば、3 次元行列式は以下のように展開できることが知られています。
 \[\begin{align*}\begin{vmatrix}u_1 & v_1 & w_1\\u_2 & v_2 & w_2\\u_3 & v_3 & w_3\end{vmatrix}&=u_1\begin{vmatrix}v_2 & w_2 \\ v_3 & w_3\end{vmatrix}-v_1\begin{vmatrix}u_2 & w_2 \\ u_3 & w_3\end{vmatrix}+w_1\begin{vmatrix}u_2 & v_2 \\ u_3 & v_3\end{vmatrix}\end{align*}\]
各項は次のような手順で作られます。
 
Python 行列式の展開 (expand determinant)
符号は +, -, + のように交互に並べます。上の例では 1 行目を使いましたが、係数はどの行または列を選んでも構いません。大きなサイズの行列式についても、同じように次元を 1 つ下げた行列式を使って展開できるので、展開を繰り返すことによって最終的には 2 次元行列式の計算に帰着できます。

コメント

  1. あとりえこばと より:

    【AI連載小説】科学とコードの交差点(64)
    「ライブラリなしで行列式を計算してみよう」
     
    開誠(サークルの部屋で、ホワイトボードを指しながら):「今日はライブラリを使わずにPythonで行列式を計算する方法について考えてみよう」
    美純:「でも、Pythonって元々数値計算が得意な言語だし、NumPyを使わないのは少し非効率じゃない?」
    開誠:「その通りだけど、手計算的なアプローチを考えることで、数学的な理解が深まることもあるからね」
    明信:「じゃあ、どんな手計算的な方法があるんだ?」
    開誠:「例えば、余因子展開を使う方法がある。これは再帰的なアプローチで行列を小さな部分行列に分割していく手法だ」
    美純:「具体的なコードを見せてくれる?」

    開誠がPythonコードを書きながら説明します。

    明信:「なるほど、再帰的に部分行列の行列式を計算していくんだ」
    開誠:「そうだ。これが手計算的なアプローチの一例だ。ただし、実際には大きな行列になると計算コストが高くなるから、通常はライブラリを使った方が効率的だね」