1. 矩陣求逆原理介紹
矩陣求逆的原理有很多,此處僅介紹兩種:利用伴隨矩陣 和 利用行變換
前者具有較好的精度,后者具有較好的計算速率
1.1 利用伴隨矩陣求逆
(1) 代數余子式
一個 \(n \times n\) 矩陣 \(A\),\(A\) 在 \((i,j)\) 處的代數余子式為 \(A\) 去掉第 \(i\) 行和第 \(j\) 列后剩下的矩陣的行列式的值再乘上 \((-1)^{i+j}\)
(2) 伴隨矩陣
一個 \(n \times n\) 矩陣 \(A\),\(A\) 的伴隨矩陣 \(C_A\) 為一個 \(n \times n\) 矩陣,\(C_A\) 在 \((i,j)\) 處的值為 \(A\) 在 \((i,j)\) 處的代數余子式
(3) 轉置矩陣
一個 \(n \times n\) 矩陣 \(A\),\(A\) 的轉置矩陣 \(A^T\) 為一個 \(n \times n\) 矩陣,\(A^T\) 在 \((i,j)\) 處的值為 \(A\) 在 \((j,i)\) 處的值
(4) 逆矩陣
一個 \(n \times n\) 矩陣 \(A\),\(A\) 的逆矩陣 \(A^{-1}\) 為 \(\frac{1}{d} \cdot (C_A)^T\)。其中 d 是矩陣 \(A\) 的行列式,\(C_A\) 是 \(A\) 的伴隨矩陣,\((C_A)^T\) 是 \(C_A\) 的轉置矩陣
1.2 利用高斯行變換
一個 \(n \times n\) 的矩陣 \(A\),構造一個 \(n \times n\) 的單位陣作為其擴展矩陣,拼接后成為一個 \(n \times 2n\) 的矩陣 \([A_{n \times n}|I_{n \times n}]\)
再通過初等行變換,將上述矩陣轉變為 \([I_{n \times n}|P_{n \times n}]\) 的形式,則有 \(A^{-1} = P\)
2. 矩陣行列式
2.1 使用余子式
對於 \(n \times n\) 的矩陣 \(A\),其行列式 \(det(A)\) 的值等於 任意一行的元素 依次乘以 對應位置的余子式 的結果之和
2.2 利用行變換
通過初等行變換將矩陣變成對角矩陣(除了對角線之外其它元素均為 0 的矩陣),對角線元素的乘積即為行列式的值
3. 矩陣求逆代碼(python)
兩種求逆方法各有優劣,利用伴隨矩陣的方法在對整數矩陣求逆時精度更好,會損失精度的除法運算只在最后一步中使用;利用高斯行變換求解時可能會因為行變換的除法而損失一定的精度
但就時間復雜度來說,伴隨矩陣所消耗的時間復雜度遠大於使用高斯行變換的方式
3.1 利用伴隨矩陣
def _determinant(matrix):
"""遞歸計算矩陣行列式"""
if len(matrix) == 1:
return matrix[0][0]
else:
d = 0
matrix_row, matrix_col = len(matrix), len(matrix[0])
for col in range(matrix_col):
# 刪去第 0 行 col 列
m = [[matrix[i][j] for j in range(matrix_col) if j != col] for i in range(matrix_row) if i != 0]
d = d + (-1) ** (col & 1) * matrix[0][col] * _determinant(m)
return d
def _cofactor(matrix):
"""計算伴隨矩陣"""
matrix_row, matrix_col = len(matrix), len(matrix[0])
res = [[0 for _ in range(matrix_col)] for _ in range(matrix_row)]
for row in range(matrix_row):
for col in range(matrix_col):
# 刪去第 i 行 j 列
m = [[matrix[i][j] for j in range(matrix_col) if j != col] for i in range(matrix_row) if i != row]
# 計算余子式
res[row][col] = (-1) ** ((row + col) & 1) * _determinant(m)
return res
def _traverse(matrix):
"""矩陣轉置"""
return [[matrix[col][row] for col in range(len(matrix[0]))] for row in range(len(matrix))]
def inverse(matrix):
d = _determinant(matrix) # 行列式
if d == 0: # 行列式等於0,不存在逆矩陣
return None
else:
cofactor = _cofactor(matrix) # 獲取伴隨矩陣
res = _traverse(cofactor) # 伴隨矩陣的轉置
# 將每個元素都除以 d
for row in range(len(res)):
for col in range(len(res[0])):
res[row][col] = res[row][col] / d
return res
3.2 利用高斯行變換
def inverse(matrix):
row, col = len(matrix), len(matrix[0]) # 矩陣的行列
t_matrix = [[matrix[r][c] for c in range(col)] for r in range(row)]
e_matrix = [[0 if c != r else 1 for c in range(col)] for r in range(row)] # 擴展矩陣
for i in range(row):
# 尋找第i列不為0的行
for r in range(i, row):
if t_matrix[r][i] != 0:
if i != r:
t_matrix[i], t_matrix[r] = t_matrix[r], t_matrix[i]
e_matrix[i], e_matrix[r] = e_matrix[r], e_matrix[i]
break
else: # 找不到對應的行,沒有逆矩陣
return None
# 對當前行的變換
temp = t_matrix[i][i]
for c in range(col):
t_matrix[i][c] /= temp
e_matrix[i][c] /= temp
# 對其它行的變換
for r in range(row):
if r != i:
temp = t_matrix[r][i]
for c in range(col):
e_matrix[r][c] = e_matrix[r][c] - e_matrix[i][c] * temp
t_matrix[r][c] = t_matrix[r][c] - t_matrix[i][c] * temp
return e_matrix
4. 最后
上文提過,利用伴隨矩陣求逆的方式會消耗極大的時間,在求解 6 階以上的矩陣的時候就已經開始明顯變慢;而行變換的方式會產生精度問題,在求解高階矩陣的逆矩陣是很可能會由於精度產生錯誤
例如求解如下矩陣的逆矩陣:
m = [[7, 18, 16, 9, 13],
[21, 0, 21, 1, 22],
[1, 20, 11, 2, 17],
[1, 0, 14, 20, 5],
[10, 13, 11, 22, 5]]
這是一個 5 階矩陣,當使用行變換求解時就會由於除法精度問題而產生錯誤
為了避免精度的問題,可以采用 python 的分數庫 Fraction 來計算除法,或者使用其它的求逆方法(例如 QR 分解)
