ガウスの消去法 (Gauss elimination)、 ガウス=ジョルダンの消去法 (Gauss-Jordan elimination)、あるいは 掃き出し法 と呼ばれる方法。
n n n 個の未知数 x j ( j = 1 , ⋯ , n ) x_j(j=1, \cdots, n) x j ( j = 1 , ⋯ , n ) と n n n 個の方程式からなる連立 1 次方程式
∑ j = 1 n a i j x j = b i ( i = 1 , ⋯ , n ) \sum_{j=1}^n a_{i j} x_j=b_i \quad(i=1, \cdots, n) j = 1 ∑ n a ij x j = b i ( i = 1 , ⋯ , n ) について考える。
連立1次方程式を
Undefined control sequence: \DeclareMathOperator at position 57: …{#1}}
% 演算子の定義
\̲D̲e̲c̲l̲a̲r̲e̲M̲a̲t̲h̲O̲p̲e̲r̲a̲t̲o̲r̲{\im}{ \text{Im…
% 太字のalias
\newcommand{\b}[1]{\boldsymbol{#1}}
% 演算子の定義
\DeclareMathOperator{\im}{ \text{Im} }
\DeclareMathOperator{\rank}{ \text{rank} }
\DeclareMathOperator{\span}{ \text{Span} }
\DeclareMathOperator{\Ker}{ \text{Ker} }
%
\begin{align}
& a_{11}^{(1)} x_1+a_{12}^{(1)} x_2+\cdots+a_{1 n}^{(1)} x_n=b_1^{(1)}\\
& a_{21}^{(1)} x_1+a_{22}^{(1)} x_2+\cdots+a_{2 n}^{(1)} x_n=b_2^{(1)}\\
&\quad \vdots\\
& a_{n 1}^{(1)} x_1+a_{n 2}^{(1)} x_2+\cdots+a_{n n}^{(1)} x_n=b_n^{(1)} \\
\end{align}の形に書く。
Gaussの消去法では、前進消去と後退代入という操作によって方程式を解く。
前進消去 ¶ (1) 1番目の未知数x 1 x_1 x 1 に着目し、2~n n n 番目の方程式から消去する。
i = 2 , ⋯ , n i=2,\cdots,n i = 2 , ⋯ , n について、i i i 番目の式から1番目の式のm i 1 = a i 1 ( 1 ) / a 11 ( 1 ) m_{i1} = a_{i1}^{(1)} / a_{11}^{(1)} m i 1 = a i 1 ( 1 ) / a 11 ( 1 ) 倍を引けばよい(a 11 ( 1 ) ≠ 0 a_{11}^{(1)}\neq 0 a 11 ( 1 ) = 0 と仮定しておく)
この操作のあとの連立1次方程式は、
a i j ( 2 ) = a i j ( 1 ) − m i 1 a 1 j ( 1 ) ( i = 2 , ⋯ , n ; j = 2 , ⋯ , n ) b i ( 2 ) = b i ( 1 ) − m i 1 b 1 ( 1 ) ( i = 2 , ⋯ , n ) \begin{align}
a_{i j}^{(2)}=a_{i j}^{(1)}-m_{i 1} a_{1 j}^{(1)} & \quad(i=2, \cdots, n ; j=2, \cdots, n) \\
b_i^{(2)}=b_i^{(1)}-m_{i 1} b_1^{(1)} & \quad (i=2, \cdots, n)
\end{align} a ij ( 2 ) = a ij ( 1 ) − m i 1 a 1 j ( 1 ) b i ( 2 ) = b i ( 1 ) − m i 1 b 1 ( 1 ) ( i = 2 , ⋯ , n ; j = 2 , ⋯ , n ) ( i = 2 , ⋯ , n ) とおくと、
a 11 ( 1 ) x 1 + a 12 ( 1 ) x 2 + ⋯ + a 1 n ( 1 ) x n = b 1 ( 1 ) a 22 ( 2 ) x 2 + ⋯ + a 2 n ( 2 ) x n = b 2 ( 2 ) ⋮ a n 2 ( 2 ) x 2 + ⋯ + a n n ( 2 ) x n = b n ( 2 ) \begin{aligned}
a_{11}^{(1)} x_1+a_{12}^{(1)} x_2+\cdots+a_{1 n}^{(1)} x_n=b_1^{(1)}&\\
a_{22}^{(2)} x_2+\cdots+a_{2 n}^{(2)} x_n=b_2^{(2)}&\\
\vdots \quad &\\
a_{n 2}^{(2)} x_2+\cdots+a_{n n}^{(2)} x_n=b_n^{(2)}&\\
\end{aligned} a 11 ( 1 ) x 1 + a 12 ( 1 ) x 2 + ⋯ + a 1 n ( 1 ) x n = b 1 ( 1 ) a 22 ( 2 ) x 2 + ⋯ + a 2 n ( 2 ) x n = b 2 ( 2 ) ⋮ a n 2 ( 2 ) x 2 + ⋯ + a nn ( 2 ) x n = b n ( 2 ) となる。
この消去操作において着目した行列要素の位置 ( 1 , 1 ) (1,1) ( 1 , 1 ) を 枢軸 (pivot)、その要素a 11 ( 1 ) a_{11}^{(1)} a 11 ( 1 ) を 枢軸要素 、 m i 1 m_{i1} m i 1 を 乗数 と呼ぶ。
(2) 2番目の未知数x 2 x_2 x 2 に着目し、3~n n n 番目の方程式から消去する。
以下、このような操作をn − 1 n-1 n − 1 回まで繰り返す。そして以下を得る
a 11 ( 1 ) x 1 + a 12 ( 1 ) x 2 + a 13 ( 1 ) x 3 + ⋯ + a 1 n ( 1 ) x n = b 1 ( 1 ) a 22 ( 2 ) x 2 + a 23 ( 2 ) x 3 + ⋯ + a 2 n ( 2 ) x n = b 2 ( 2 ) a 33 ( 3 ) x 3 + ⋯ + a 3 n ( 3 ) x n = b 3 ( 3 ) ⋱ ⋮ ⋮ a n n ( n ) x n = b n ( n ) \begin{aligned}
a_{11}^{(1)} x_1+a_{12}^{(1)} x_2+a_{13}^{(1)} x_3+\cdots+a_{1 n}^{(1)} x_n =b_1^{(1)}&\\
a_{22}^{(2)} x_2+a_{23}^{(2)} x_3+\cdots+a_{2 n}^{(2)} x_n=b_2^{(2)}&\\
a_{33}^{(3)} x_3+\cdots+a_{3 n}^{(3)} x_n=b_3^{(3)}&\\
\ddots \quad \quad \vdots \quad \quad \vdots \quad&\\
a_{n n}^{(n)} x_n=b_n^{(n)} &\\
\end{aligned} a 11 ( 1 ) x 1 + a 12 ( 1 ) x 2 + a 13 ( 1 ) x 3 + ⋯ + a 1 n ( 1 ) x n = b 1 ( 1 ) a 22 ( 2 ) x 2 + a 23 ( 2 ) x 3 + ⋯ + a 2 n ( 2 ) x n = b 2 ( 2 ) a 33 ( 3 ) x 3 + ⋯ + a 3 n ( 3 ) x n = b 3 ( 3 ) ⋱ ⋮ ⋮ a nn ( n ) x n = b n ( n ) ただし、a 11 ( 1 ) ≠ 0 , a 22 ( 2 ) ≠ 0 , ⋯ , a n n ( n ) ≠ 0 a_{11}^{(1)} \neq 0, \quad a_{22}^{(2)} \neq 0, \quad \cdots, \quad a_{n n}^{(n)} \neq 0 a 11 ( 1 ) = 0 , a 22 ( 2 ) = 0 , ⋯ , a nn ( n ) = 0 と仮定している。
後退代入 ¶ x n x_n x n については、
a n n ( n ) x n = b n ( n ) a_{n n}^{(n)} x_n=b_n^{(n)} a nn ( n ) x n = b n ( n ) なので、
x n = b n ( n ) a n n ( n ) x_n = \frac{ b_n^{(n)} }{ a_{n n}^{(n)} } x n = a nn ( n ) b n ( n ) として解が求まる。
x n − 1 x_{n-1} x n − 1 については
a n − 1 , n − 1 ( n − 1 ) x n − 1 + a n n ( n − 1 ) x n = b n − 1 ( n − 1 ) a_{n-1, n-1}^{(n-1)} x_{n-1} + a_{n n}^{(n-1)} x_n = b_{n-1}^{(n-1)} a n − 1 , n − 1 ( n − 1 ) x n − 1 + a nn ( n − 1 ) x n = b n − 1 ( n − 1 ) となっているので
x n − 1 = 1 a n − 1 , n − 1 ( n − 1 ) ( b n − 1 ( n − 1 ) − a n n ( n − 1 ) x n ) x_{n-1} = \frac{1}{a_{n-1, n-1}^{(n-1)}} (b_{n-1}^{(n-1)} - a_{n n}^{(n-1)} x_n ) x n − 1 = a n − 1 , n − 1 ( n − 1 ) 1 ( b n − 1 ( n − 1 ) − a nn ( n − 1 ) x n ) として解が求まる。
これを一般化すると、解は
x i = 1 a i i ( i ) ( b i ( i ) − ∑ j = i + 1 n a i j ( i ) x j ) ( i = n , n − 1 , ⋯ , 1 ) x_i=\frac{1}{a_{i i}^{(i)}}\left(b_i^{(i)}-\sum_{j=i+1}^n a_{i j}^{(i)} x_j\right) \quad(i=n, n-1, \cdots, 1) x i = a ii ( i ) 1 ( b i ( i ) − j = i + 1 ∑ n a ij ( i ) x j ) ( i = n , n − 1 , ⋯ , 1 ) によって求まる。これを 後退代入 と呼ぶ。
# データの作成
import numpy as np
A = np.array([
[1,2,3],
[4,5,6],
[7,8,0],
])
x_true = np.array([1, 2, 3])
b = A @ x_true
def forward_elimination(A, b):
# 前進消去
n = len(b)
for k in range(n):
for i in range(k + 1, n):
m = A[i,k] / A[k,k]
# numpyのベクトル演算に頼っているが、本来はここもA[i,]の各j要素にわたってfor j in range(n)が必要 → 計算量はO(n^3)
A[i,k:] = A[i,k:] - m * A[k,k:]
b[i] = b[i] - m * b[k]
# print(f"{i=}, {j=}, {m=}")
# print(A)
return A, b
A, b = forward_elimination(A, b)
print(f"{A=}")
print(f"{b=}")
A=array([[-1.0000e-03, 6.0000e+00],
[ 0.0000e+00, 1.8005e+04]])
b=array([6.0010e+00, 1.8005e+04])
def backward_substitution(A, b):
# 後退代入
n = len(b)
x = np.zeros(shape=(n,))
for i in range(n-1, -1, -1):
x[i] = (1 / A[i,i]) * (b[i] - A[i,i+1:] @ x[i+1:])
return x
x = backward_substitution(A, b)
print(f"{x=}")消去法が使える行列 ¶ 以下の条件のいずれかを満たす行列A A A は、a 11 ( 1 ) ≠ 0 , a 22 ( 2 ) ≠ 0 , ⋯ , a n n ( n ) ≠ 0 a_{11}^{(1)} \neq 0, \quad a_{22}^{(2)} \neq 0, \quad \cdots, \quad a_{n n}^{(n)} \neq 0 a 11 ( 1 ) = 0 , a 22 ( 2 ) = 0 , ⋯ , a nn ( n ) = 0 を満たし、消去法が適用可能
行方向に一般化狭義優対角.
列方向に一般化狭義優対角.
(正則な) M \mathrm{M} M 行列.
対称部分が正定値: x ⊤ A x = 1 2 x ⊤ ( A + A ⊤ ) x > 0 ( ∀ x ≠ 0 ) \boldsymbol{x}^{\top} A \boldsymbol{x}=\frac{1}{2} \boldsymbol{x}^{\top}\left(A+A^{\top}\right) \boldsymbol{x}>0 \quad(\forall \boldsymbol{x} \neq \mathbf{0}) x ⊤ A x = 2 1 x ⊤ ( A + A ⊤ ) x > 0 ( ∀ x = 0 ) .
各行において, 対角要素の絶対値が非対角要素の絶対値の和に比べて大きい 行列, すなわち,
∣ a i i ∣ ≥ ∑ j ≠ i ∣ a i j ∣ , ( 1 ≤ i ≤ n ) \left|a_{i i}\right| \geq \sum_{j \neq i}\left|a_{i j}\right|
, \quad (1 \leq i \leq n) ∣ a ii ∣ ≥ j = i ∑ ∣ a ij ∣ , ( 1 ≤ i ≤ n ) を満たす行列 A A A を(行方向の) 狭義優対角行列 と呼ぶ.
また、正の実数d 1 , ⋯ , d n d_1, \cdots, d_n d 1 , ⋯ , d n に対して
∣ a i i ∣ d i > ∑ j ≠ i ∣ a i j ∣ d j ( i = 1 , ⋯ , n ) \left|a_{i i}\right| d_i>\sum_{j \neq i}\left|a_{i j}\right| d_j \quad(i=1, \cdots, n) ∣ a ii ∣ d i > j = i ∑ ∣ a ij ∣ d j ( i = 1 , ⋯ , n ) が成り立つとき, A A A を(行方向の) 一般化狭義優対角行列 と呼ぶ
枢軸選択 ¶ 枢軸要素a k k ( k ) a_{kk}^{(k)} a kk ( k ) が0になると次の段に進めなくなるし、0に近い値だと誤差の拡大が起きて精度の良い解が得られない。
第k k k 段の消去の前に、k k k 番目以降の方程式を入れ替えて、枢軸要素の絶対値∣ a k k ( k ) ∣ |a_{kk}^{(k)}| ∣ a kk ( k ) ∣ がそれより下の位置にある要素の絶対値∣ a i k ( k ) ∣ ( k ≤ i ≤ n ) |a_{ik}^{(k)}| (k\leq i \leq n) ∣ a ik ( k ) ∣ ( k ≤ i ≤ n ) の中で最大になるようにすることができる。この操作を 枢軸選択 (pivoting) あるいは 部分枢軸選択 (partial pivoting) と呼ぶ。
import numpy as np
A = np.array([
[-0.001, 6],
[3, 5],
])
x_true = np.array([-1, 1])
b = A @ x_true
print(f"{b=}")A, b = forward_elimination(A, b)
print(f"{A=}")
print(f"{b=}")
x = backward_substitution(A, b)
print(f"{x=}")A=array([[-1.0000e-03, 6.0000e+00],
[ 0.0000e+00, 1.8005e+04]])
b=array([6.0010e+00, 1.8005e+04])
x=array([-1., 1.])
スケーリング ¶ 各方程式にゼロでない定数を掛けることをスケーリングと呼ぶ。
数学的には解は不変のはずだが、枢軸選択の結果はスケーリングに依存してしまう問題がある。