基本行列

基本行列

基本行列

 次回記事でガウス・ジョルダンの消去法による連立方程式の求め方を学びますが、その準備として 基本行列(elementary matrices) とよばれる 3 種類の行列について説明しておきます。

置換行列

 任意の行列 $A$ に単位行列 $I$ を掛けると、$A$ が元の形を保つことはすでに学んでいます:
 
\[IA=AI=I\]
 すなわち単位行列 $I$ は恒等変換行列です。
 いま、$3\times 3$ 単位行列と、$3\times 3$ 正方行列
 
\[I=\begin{bmatrix}1&0&0\\0&1&0\\0&0&1\end{bmatrix}
,\quad A=\begin{bmatrix}a&b&c\\d&e&f\\g&h&i\end{bmatrix}\]
を考えて、$I$ の 2 行目と 3 行目を入れ替えた行列
 
\[P_{2,3}=\begin{bmatrix}1&0&0\\0&0&1\\0&1&0\end{bmatrix}\]
を定義して行列 $A$ の左側に掛けてみると、
 
\[P_{2,3\ }A=\begin{bmatrix}1&0&0\\0&0&1\\0&1&0\end{bmatrix}
\begin{bmatrix}a&b&c\\d&e&f\\g&h&i\end{bmatrix}
=\begin{bmatrix}a&b&c\\g&h&i\\d&e&f\end{bmatrix}\]
となって、$A$ の 2 行目と 3 行目を入れ替えることがわかります。

 $n\times n$ の単位行列の $i$ 行目と $j$ 行目を入れ替えた行列 $P_{i,j}$ を任意の行列 $A$ に左側から掛けると、$A$ の $i$ 行目と $j$ 行目を入れ替えます。$A$ の右側から掛けると列を交換します。

 一般に行列に作用して行または列の位置を変える行列を 置換行列 とよびます。複数回の交換をほどこす行列、すなわち一回交換の置換行列同士の積も置換行列に含まれます。

 $3\times 3$ の正方行列の置換行列は $3!=6$ 種類です。
 そのうち行を $0$ 回交換する (すなわち交換しない) 置換行列は単位行列です:
 
\[I=\begin{bmatrix}
1&0&0\\
0&1&0\\
0&0&1\end{bmatrix}\]
 行を $1$ 回交換する置換行列は $3$ 種類あります:
 
\[P_{12}=\begin{bmatrix}0&1&0\\1&0&0\\0&0&1\end{bmatrix},\quad
P_{13}=\begin{bmatrix}0&0&1\\0&1&0\\1&0&0\end{bmatrix},\quad
P_{23}=\begin{bmatrix}1&0&0\\0&0&1\\0&1&0\end{bmatrix}\]
 行を $2$ 回交換する置換行列は $2$ 種類です:
 
\[P_{23}P_{12}=\begin{bmatrix}0&1&0\\0&0&1\\1&0&0\end{bmatrix},\quad
P_{12}P_{23}=\begin{bmatrix}0&0&1\\1&0&0\\0&1&0\end{bmatrix}\]

行を定数倍する

 正方単位行列の $(i,i)$ 成分を $k$ で置き換えた行列 $C_{i,k}$ は $A$ の $i$ 行目を $k$ 倍します:
 
\[C_{1,k\ }A=\begin{bmatrix}k&0&0\\0&1&0\\0&0&1\end{bmatrix}
\begin{bmatrix}a&b&c\\d&e&f\\g&h&i\end{bmatrix}
=\begin{bmatrix}ka&kb&kc\\d&e&f\\g&h&i\end{bmatrix}\]
 $k$ 倍した行を $1/k$ 倍すれば、もとの行列に戻るので、$C_{i,k}$ の逆行列は $C_{i,1/k}$ です。
 

ある行に別の行の定数倍を加える

 正方単位行列の $(i,j)$ 成分を $k$ で置き換えた行列 $E_{i,j,k}$ は $A$ の $i$ 行目に $j$ 行目の $k$ 倍を加えます:
 
\[E_{2,1,k\ }A=\begin{bmatrix}1&0&0\\k&1&0\\0&0&1\end{bmatrix}
\begin{bmatrix}a&b&c\\d&e&f\\g&h&i\end{bmatrix}
=\begin{bmatrix}a&b&c\\d+ka&e+kb&f+kc\\g&h&i\end{bmatrix}\]
 $i$ 行目に $j$ 行目の $k$ 倍を加えたあとで $i$ 行目に $j$ 行目の $k$ 倍を引けば、もとの行列に戻ります。したがって、$E_{i,j,k}$ の逆行列は $E_{i,j,-k}$ となります。
 
\[\begin{bmatrix}1&0&0\\-k&1&0\\0&0&1\end{bmatrix}
\begin{bmatrix}a&b&c\\d+ka&e+kb&f+kc\\g&h&i\end{bmatrix}
=\begin{bmatrix}a&b&c\\d&e&f\\g&h&i\end{bmatrix}\]
 

基本行列の実装

 今後の記事で基本行列の積を計算することがあるので、3 種の基本行列を Python で実装しておきます。

# SLA_039-1

import numpy as np

# i行とj行の交換
def matrix_p(n, i=1, j=1):
    arr = np.eye(n)
    arr[[i-1, j-1]] = arr[[j-1, i-1]]
    return arr

# i行の定数倍
def matrix_c(n, i=1, k=1):
    arr = np.eye(n)
    arr[i-1, i-1] = k
    return arr

# i行にj行の定数倍を加える
def matrix_e(n, i=1, j=1, k=1):
    arr = np.eye(n)
    arr[i-1, j-1] = k
    return arr

 numpy.eye() で指定した大きさの単位行列を生成して、必要な成分を書き換えます。
 matrix_p() の内部に記述されている

arr[[i-1, j-1]] = arr[[j-1, i-1]]

の意味については記事の後半を参照してください。

 定義した関数を使って 4 × 4 の基本行列を生成してみましょう。

2行目と3行目を入れ替える行列:

# SLA_039-2

p = matrix_p(4, 2, 3)

print(p)
[[1. 0. 0. 0.]
 [0. 0. 1. 0.]
 [0. 1. 0. 0.]
 [0. 0. 0. 1.]]

3行目を5倍する行列:

# SLA_039-3

c = matrix_c(4, 3, 5)

print(c)
[[1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 5. 0.]
 [0. 0. 0. 1.]]

3行目に1行目の2倍を加える行列:

# SLA_039-4

e = matrix_e(4, 3, 1, 2)

print(e)
[[1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [2. 0. 1. 0.]
 [0. 0. 0. 1.]]

 コード SLA_039 の基本行列は、今後の記事で線形代数の定理を確認するために定義しています。一般に、NumPy で行を操作する場合、配列の行にアクセスして書き換えます。たとえば「 3 行目に 1 行目の 5 倍を加える」という操作は次のように記述します。

# SLA_039-5

# [[1 2 3]
#  [4 5 6]
#  [7 8 9]]
x = np.arange(1, 10).reshape(3,3)

# xの3行目に1行目の5倍を加える
x[2, :] = x[2, :] + 5 * x[0, :]

print(x)
[[ 1  2  3]
 [ 4  5  6]
 [12 18 24]]

 行の交換については以下の節を参照してください。
 

線型代数入門 (基礎数学)

中古価格
¥864から
(2019/10/24 15:44時点)

配列の行を入れ替える

 NumPy で 配列の行を入れ替える方法 を解説します。
 最初に 3×3 の 2 次元配列を作成しておきます。

# SWP-1

import numpy as np

x = np.arange(1, 10).reshape(3, 3)

print(x)
[[1 2 3]
 [4 5 6]
 [7 8 9]]

 NumPy ではファンシーインデックス (インデックスリストを渡して複数要素に同時アクセスする手法) を使って特定の行にアクセスできます。たとえば、x[[1, 2]] は 1 行目と 2 行目を縦積みした配列を取得します。

# SWP-2

print(x[[1, 2]])
[[4 5 6]
 [7 8 9]]

 x[[2, 1]] は 2 行目と 1 行目を取得します。

# SWP-3

print(x[[2, 1]])
[[7 8 9]
 [4 5 6]]

 ファンシーインデックスはメモリへの直接アクセスなので、x[[1, 2]] に x[[2, 1]] を代入すると、結果として 1 行目と 2 行目が交換されることになります (もとの配列が変更されます)。

# SWP-4

x[[1, 2]] = x[[2, 1]]

print(x)
[[1 2 3]
 [7 8 9]
 [4 5 6]]

 一般に、x[[i, j]] = x[[j, i]] という記述で i 行と j 行を入れ替えられます。

def swap_rows(x, i, j):
    x[[i, j]] = x[[j, i]]

 とはいえ、場合によっては元の配列を変更したくないと思うかもしれません。以下に定義する swap_rows()関数 は、受け取った配列のコピーを作成して行を入れ替えます。

# SWP-5

def swap_rows(x, i, j):
    a = x.copy()
    a[[i, j]] = a[[j, i]]
    return a

 swap_rows() の動作を確認するために、新しい 2 次元配列 y を作成しておきます。

# SWP-6

# 乱数生成器のシードを0に固定
np.random.seed(0)

# 要素をランダムに決定して配列を生成
y = np.random.randint(0, 10, (5, 5))

print(y)
[[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]]

 y を swap_rows() に渡して 2 行目と 4 行目を入れ替えます。

# SWP-7

# yの2行目と4行目を交換
sy = swap_rows(y, 1, 3)

print(sy)
[[5 0 3 3 7]
 [6 7 7 8 1]
 [7 6 8 8 1]
 [9 3 5 2 4]
 [5 9 8 9 4]]

 [参考文献] 世界標準MIT教科書 ストラング線形代数イントロダクション