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 分解)