1. 程式人生 > 其它 >矩陣求逆

矩陣求逆

矩陣求逆(python)

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