跳轉到

3.4 反矩陣與 Cramer 法則:何時能用、何時該用#

本節目標#

  • 理解反矩陣 \(AA^{-1}=I\) 的幾何意義:變換的還原(undo 按鈕)
  • 會用 np.linalg.inv,並對 2×2 反矩陣公式做手算對照
  • 認識 Cramer 法則:用行列式寫出解的漂亮公式,以及它為什麼「美麗但低效」
  • 說清楚為什麼實務上用 solve 而不用 inv(數值理由,第 9 章展開)
  • 認識奇異矩陣的錯誤訊息,並預告 pseudo-inverse

一、反矩陣:變換的還原鍵#

\(A\) 是一部變換機。那麼「把 \(A\) 做的破壞 完全復原」的機器存在嗎?如果存在,就叫 反矩陣 \(A^{-1}\) :

\[ A^{-1}A = A A^{-1} = I \]

幾何上:先被 \(A\) 壓扁旋轉,再被 \(A^{-1}\) 加工一次,向量回到原位 —— \(I\) 就是「什麼都不做」的變換。解方程組因此有了一個理所當然的形式:

\[ A\mathbf{x}=\mathbf{b} \;\Longrightarrow\; \mathbf{x}=A^{-1}\mathbf{b} \]

但還原鍵有存在條件:** \(A\) 不能弄丟資訊**。若 \(A\) 把整個平面壓成一條直線(奇異、 \(\det=0\) ),被擠扁的方向就無法復原 —— 你無法從一條線「還原」出整個平面。這正是:

\[ A^{-1} \text{ 存在} \iff \det(A)\neq 0 \iff \operatorname{rank}(A)=n \]

三種說法,同一件事:變換是一對一的、可逆的、滿秩的。

二、NumPy 的 inv 與 2×2 公式對照#

import numpy as np

A = np.array([[4.0, 7.0],
              [2.0, 6.0]])
A_inv = np.linalg.inv(A)
print(A_inv)
print(np.allclose(A @ A_inv, np.eye(2)))   # True

2×2 有條教科書公式:

\[ A=\begin{bmatrix} a & b \\ c & d \end{bmatrix} \;\Longrightarrow\; A^{-1}=\frac{1}{ad-bc}\begin{bmatrix} d & -b \\ -c & a \end{bmatrix} \]

口訣:主對角線互換、副對角線變號、除以行列式。手算驗證上面的例子:

\[ \det(A)=4\cdot 6-7\cdot 2=10,\qquad A^{-1}=\frac{1}{10}\begin{bmatrix} 6 & -7 \\ -2 & 4 \end{bmatrix} =\begin{bmatrix} 0.6 & -0.7 \\ -0.2 & 0.4 \end{bmatrix} \]
# 用公式手寫,對照 np.linalg.inv
a, b_, c, d = 4.0, 7.0, 2.0, 6.0
det = a * d - b_ * c
manual = np.array([[ d, -b_],
                   [-c,  a]]) / det
print(np.allclose(manual, np.linalg.inv(A)))   # True

注意公式裡那個 \(\tfrac{1}{\det}\) : \(\det\to 0\) 時反矩陣的元素爆表 —— 幾何上「壓得越扁,還原越要放大」,這是第 9 章條件數的預告。

三、Cramer 法則:用行列式寫解#

Cramer 法則說:若 \(A\) 可逆,則 \(A\mathbf{x}=\mathbf{b}\) 的每個分量都可以用 行列式的比值 寫出:

\[ x_i = \frac{\det(A_i)}{\det(A)},\qquad A_i = \text{把 } A \text{ 的第 } i \text{ 行換成 } \mathbf{b} \]

2×2 的例子( \(2x+y=3,\; x-y=0\) ):

\[ x=\frac{\begin{vmatrix} 3 & 1 \\ 0 & -1 \end{vmatrix}}{\begin{vmatrix} 2 & 1 \\ 1 & -1 \end{vmatrix}} =\frac{-3}{-3}=1,\qquad y=\frac{\begin{vmatrix} 2 & 3 \\ 1 & 0 \end{vmatrix}}{-3} =\frac{-3}{-3}=1 \]

幾何詮釋很漂亮: \(\det(A)\) 是行向量張成的平行四邊形面積;把某一行換成 \(\mathbf{b}\) ,平行四邊形會沿著「 \(\mathbf{b}\) 偏離的方向」改變面積,比值正好就是那份「配方份量」。

A = np.array([[2.0, 1.0],
              [1.0, -1.0]])
b = np.array([3.0, 0.0])

detA = np.linalg.det(A)
A1 = A.copy(); A1[:, 0] = b      # 第一行換成 b
A2 = A.copy(); A2[:, 1] = b      # 第二行換成 b
x = np.linalg.det(A1) / detA
y = np.linalg.det(A2) / detA
print(x, y)                              # 1.0 1.0
print(np.allclose([x, y], np.linalg.solve(A, b)))  # True

美麗但低效:公式優雅、理論好用(證明題、符號推導的好幫手),但數值上是一場災難 —— 解 \(n\) 個未知數要算 \(n+1\) 個 \(n\times n\) 行列式,而行列式用展開算是 \(O(n!)\) 、即使聰明算法也要 \(O(n^3)\) 每個;高斯消去一次就能解完,還更穩定。 \(n=10\) 時 Cramer 已經比消去慢幾十倍, \(n=100\) 時完全是兩個世界。

四、為什麼實務用 solve 不用 inv#

「先求 \(A^{-1}\) 再乘 \(\mathbf{b}\) 」看起來直接,卻有兩個實質缺點:

  1. 多做了工:inv 是 \(O(n^3)\) 的完整計算,但 solve 只要一次分解加回代就拿到答案;若只解一組 \(\mathbf{b}\) ,inv 純屬繞路。
  2. 更不穩定:計算 \(\mathbf{x}=A^{-1}\mathbf{b}\) 多了一輪矩陣乘法,浮點誤差多累積一層;當 \(A\) 接近奇異時, \(A^{-1}\) 的元素巨大,誤差被乘得淋漓盡致。第 9 章會用條件數 \(\kappa(A)\) 把這件事說透。
n = 200
rng = np.random.default_rng(0)
A = rng.standard_normal((n, n))
b = rng.standard_normal(n)

x1 = np.linalg.solve(A, b)          # 推薦:直接解
x2 = np.linalg.inv(A) @ b           # 不推薦:繞路
print(np.abs(A @ x1 - b).max())     # 殘差更小
print(np.abs(A @ x2 - b).max())

結論成為本書守則:solve 是預設,inv 只在你真的需要「反矩陣本身」(例如反覆變換不同向量、推導公式)時才登場。

五、奇異矩陣的錯誤訊息與 pseudo-inverse 預告#

S = np.array([[1.0, 2.0],
              [2.0, 4.0]])          # 奇異:det = 0
np.linalg.inv(S)
# LinAlgError: Singular matrix
np.linalg.solve(S, np.array([1.0, 2.0]))
# LinAlgError: Singular matrix

電腦只會說「奇異」,但 3.1 節的三種命運要靠你自己分: \(\mathbf{b}\) 在像空間 → 無窮多解;不在 → 無解。

那如果矩陣 就是 奇異(或不是方陣),卻還是想要一個「盡力而為的逆」呢?偽反矩陣(Moore–Penrose pseudo-inverse) 登場:np.linalg.pinv(A) 會給出一個性質最好的「廣義逆」,把 \(\mathbf{b}\) 投影到像空間再還原 —— 它正是最小平方法(6.3 節)與 SVD(第 7 章)的地基,這裡先記一句話:

inv 只給可逆方陣;pinv 對任何矩陣都給一個「最好的近似逆」。

小結與練習#

  • \(A^{-1}\) 是變換的還原鍵,存在條件 \(\det(A)\neq 0\) (等價於滿秩、一對一)。
  • 2×2 公式:對角互換、副對角變號、除以行列式; \(\det\) 越小反矩陣越爆炸。
  • Cramer 法則 \(x_i=\det(A_i)/\det(A)\) :幾何漂亮、理論有用、數值低效 —— 不適合實際解方程。
  • 實務守則:用 np.linalg.solve,不要 inv @ b;奇異時先判斷命運,必要時轉向 pinv 與最小平方。

練習:

  1. 用 2×2 公式手算 \(\begin{bmatrix} 3 & 1 \\ 5 & 2 \end{bmatrix}^{-1}\) ,並驗證 \(AA^{-1}=I\) ,再與 np.linalg.inv 對照。
  2. 用 Cramer 法則解 \(\begin{cases}3x+2y=7\\ x+4y=9\end{cases}\) ,並畫出兩個平行四邊形( \(A\) 的行與 \(A_1\) 的行),比較面積比值與 \(x\) 。
  3. 對 \(n=50,100,200\) 的隨機矩陣,用 timeit 比較 np.linalg.solve 與 np.linalg.inv(A) @ b 的時間;另比較兩者殘差 \(\|A\mathbf{x}-\mathbf{b}\|\) 。
  4. 對本節的奇異矩陣 \(S\) 分別取 \(\mathbf{b}=(1,2)\) 與 \(\mathbf{b}=(2,4)\) ,用 3.3 節的方法判斷各自的命運,再呼叫 np.linalg.pinv(S) @ b 觀察:可達的情形它給了什麼?(其中一個答案正是零空間方向的特解。)