7.3 群論觀點下的幾何:SymPy 的群與矩陣#
學習動機#
前兩節我們反覆說「幾何 = 群 + 不變量」。但我們至今沒有真正把群當作一個數學對象來操作:什麼叫一組變換「形成一個群」?封閉性、單位元、反元素這三條公理在變換的世界裡分別對應幾何上的什麼事實?為什麼 \(\mathcal{I}(2)\) 的部分集合,例如「繞固定點 \(O\) 的所有旋轉」會自成一個群,而「繞任意點的所有旋轉」卻不成群(缺封閉性)?
這些問題的答案,是理解愛爾蘭根綱領的地基。一旦地基打穩,所有前兩節的敘述都會從「口號」升級為「定理」:
- 「封閉性」⟺ 任何兩個允許的運動接連執行,仍在允許之列——這是「幾何」作為一門學科能自洽研究的最低門檻:你照允許的規則連續做兩個動作,不應該突然做出一個不允許的動作。
- 「單位元」⟺「什麼都不做」是允許的動作。
- 「反元素」⟺ 每個允許的動作都能被撤銷——這保證了幾何性質是「可逆判定」的:若性質 \(P\) 在 \(g\) 作用下成立,則原圖也成立。
- 「結合律」⟺ 函數複合本身自動滿足,無需另外驗證。
本節非常務實:用 SymPy 的符號矩陣當作群的元素,寫出群公理的檢驗程式,逐一驗證最重要的明星群——
- 由一個 \(2\times 2\) 旋轉矩陣族生成的 SO(2)(平面上繞原點的旋轉群)——它是第一個也是最重要的「連續群」(李群)範例;
- 全部的 \(\operatorname{O}(2)\) 、 \(\operatorname{Aff}(2)\) 、 \(\operatorname{GL}(2)\) 家族;
- 以及一些「不成群」的反例,看公理為何會破。
同時我們會觸及群論在幾何中的兩個更深的主題:
- 共軛與分類:同一共軛類的矩陣恰是「同型變換」(旋轉泊原點與繞他點;伸縮泊原軸與泊他軸),這正是 7.2 節剛體運動四類分型的代數引擎。
- 軌道與作用:群把空間切成「軌道」,Klein 幾何中的「位置等價」即軌道成員。
值得一提的是,Cayley 1858 年的定理說:「任何抽象群都同構於一個變換群。」所以「用矩陣學群」不是一個特例,而是群的標準型態——矩陣就是群的肉身。
一、群公理的矩陣版本,與 SymPy 驗證程式#
1. 定義#
集合 \(G\) 與一個二元運算 \(\cdot\) (在變換世界裡就是複合),若滿足:
- 封閉性: \(g, h \in G \Rightarrow g \cdot h \in G\) ;
- 結合律: \(\left(g\cdot h\right)\cdot k = g\cdot \left(h\cdot k\right)\) (矩陣乘法天然滿足);
- 單位元:存在 \(e \in G\) ,使 \(e\cdot g = g\cdot e = g\) ;
- 反元素:每 \(g \in G\) ,存在 \(g^{-1} \in G\) , \(g\,g^{-1} = g^{-1}g = e\) ;
則 \((G, \cdot)\) 是一個群。
2. 通用檢驗器:用 SymPy 符號矩陣驗群#
關鍵技巧:不要一點一點帶代數值,而是用符號參數構造群的一般元素,讓 SymPy 在符號層級驗證公理。以下是我們將反覆使用的工具箱:
from sympy import Matrix, symbols, eye, simplify, cos, sin, Rational
theta, phi = symbols('theta phi', real=True)
def R(theta):
"繞原點、角度 theta 的旋轉矩陣"
return Matrix([[cos(theta), -sin(theta)],
[sin(theta), cos(theta)]])
t = s = None # 佔位,使語法可讀
def compose(A, B):
"複合:先 B 後 A"
return A * B
def show_eq(A, B):
"逐元素化簡後比較矩陣是否相等"
return simplify(A - B) == Matrix.zeros(A.rows)
# ---- SO(2) 的公理檢驗(全部符號化) ----
# (1) 封閉性:R(theta) * R(phi) 仍是某角度的旋轉?
prod = simplify(R(theta) * R(phi))
print(prod) # 會顯示角度 theta+phi 的標準旋轉矩陣
print(show_eq(prod, R(theta+phi))) # True —— 封閉,而且加法公式現身!
# (2) 單位元
I2 = eye(2)
print(show_eq(R(theta) * I2, R(theta))) # True
# 且 R(0) 就是單位元:
print(show_eq(R(0), I2)) # True
# (3) 反元素:R(theta)^{-1} = R(-theta)
inv = simplify(R(theta) ** -1)
print(show_eq(inv, R(-theta))) # True
print(show_eq(R(theta) * R(-theta), I2)) # True
三個輸出 True 就是 SO(2) 是群的全套證明。注意第一條的紅利:封閉性檢驗竟順手證明了三角函數的複角公式
——這是「幾何證代數恆等式」的初範:群的封閉性就是複角公式的幾何理由(兩次轉動就是一次「總角度」的轉動)。像這類「一個代數事實在變換語言中有可視的理由」,正是 Klein 綱領帶來的心智紅利。
3. 一個「破公理」的反例,看封閉性為何不可少#
所有繞任意點的旋轉放在一起,構不構成群?構不成:封閉性破功。以兩個不同中心的 \(90°\) 旋轉相乘,會得到一個平移,而平移不是旋轉:
from sympy import Matrix, pi, Rational
def rotation_about_center(theta, c):
Rc = Matrix([[0, -1], [1, 0]]) # 以 90° 為例
# x -> Rc (x - c) + c
return Rc, c - Rc * c
Rc, t1 = rotation_about_center(pi/2, Matrix([0, 0])) # 繞原點
_, t2 = rotation_about_center(pi/2, Matrix([4, 0])) # 繞 (4,0)
# 複合:x -> Rc(Rc x + t1) + t2
M = Rc * Rc; t = Rc * t1 + t2
print(M) # [[-1, 0], [0, -1]] —— 180° 轉動分量
print(Rc * t1 + t2) # [4, -4] —— 非零平移出現了!
print(t) # [4, -4] —— 非零平移
# 結論:兩個不同中心的 90° 旋轉複合 == 180° + 平移 ≠ 任何「90° 純旋轉」
# 這不是 90° 純旋轉 ->「所有 90° 純旋轉」不封閉
(細節數值請自行運行確認;重點是複合結果含非零平移,因此不再是繞單一中心的純旋轉。)所以:
「繞原點的所有旋轉」成群(SO(2)); 「繞任意點的所有純旋轉」不成群; 「繞任意點的所有旋轉(含平移的複合)」就是全部的定向等距 \(\operatorname{SE}(2)\) ——反而成群!
從群論一看而知:「把一個最小集
加上平移」就封起來了,這正是 \(\operatorname{SE}(2)\) 之義——「允許的運動」這個概念本身,天然偏向取封閉包,所以說「幾何就是群」的法律,實際是「幾何的允許運動集必須先『閉』成群,幾何才是合法的」。
二、SymPy 的群利器:Matrix、MatrixSymbol、permutation#
在進入大規模矩陣群之前,先了解 SymPy 自帶的群相關資料結構:
sympy.Matrix:一般符號矩陣群(用於連續群,如 SO(2)、GL(2))。sympy.combinatorics.Permutation與sympy.combinatorics.PermutationGroup:離散群(用於離散群族,如三角形類對稱 \(D_3\) 、立方體旋轉群)。
from sympy.combinatorics import Permutation, PermutationGroup, Cycle
# 例子:正三角形的旋轉群 D3 用 permutation 表示
# 三個項點 0,1,2;旋轉 = (0 1 2),反射 = (1 2) 等三個
r = Permutation(Cycle(0, 1, 2))
s = Permutation(1, 2) # 反射:鏡面穿過頂點 0 的中垂軸(0 不動)
G = PermutationGroup(r, s)
print(G.order()) # 6
print([str(p) for p in G.elements]) # 群的全部 6 個元素
# 封閉性自動由群論引擎維持:
print(r**3) # (2) —— 恆等,階 3
print(r * s ** -1 in G, r * s * r**-1 in G) # True —— 封閉包內的元素
print(r * s * r**-1 == s**-1) # True —— D3 的關係式 r s r^{-1} = s^{-1}
print((r*s) in G) # True —— 群引擎自動補足封閉包的結果
在實用上:
- 對離散幾何(三角形、多面體、密鋪),
PermutationGroup是天然核武:G.order()給對稱元素個數、G.orbit(point)給軌道、G.stabilize(point)給固定群,全都是 Klein 幾何的標準工具。 - 對連續幾何(SO(2)、仿真射影),
Matrix+ 符號參數是正確工具。
本章我們主力在連續群,但在例 3 中會用一個小 PermutationGroup 做對照,以做「離散與連續」的對照。
三、SO(2):最小而最美——連續群的第一課#
1. 結構解偃#
SO(2) 的元素都在同一個形狀上:
三個關鍵事實:
- 單參數:每個元素由一個標號 \(\theta\) 完全決定。所以 SO(2) 與圓周 \(S^1\) 同構( \(\theta\) 就是圓座標):SO(2) 本身就是一個圓——群空間即幾何物件,這是李群的第一奇景。
- 交換性: \(R_\theta R_\phi = R_{\theta+\phi} = R_\phi R_\theta\) ,故 SO(2) 是交換(阿貝爾)群——平面上繞同一點的二個旋轉總可互換順序。
- 群運算退化為加法:群運算(複合)對應角座標的加法, \(\theta \mapsto \theta + \phi \pmod{2\pi}\) 。對數乘法式的操作,讓「群」這個神秘概念與中學生的加法立道對接;
2. 李群的「速度」:微分矩陣與生成元#
李群最重要的思想是「群也有切空間」。取 \(\theta = 0\) 附近展開:
這個「速度矩陣」 \(J = \begin{pmatrix} 0 & -1 \\ 1 & 0\end{pmatrix}\) 稱為 SO(2) 的李代數生成元。它滿足 \(J^2 = -I\) ,即:
也就是說:**旋轉矩陣是指數化的 \(J\) **。SymPy 對每因子打分:
from sympy import Matrix, exp, sin, cos, symbols, simplify, I
from sympy.matrices import Matrix as M
theta = symbols('theta', real=True)
J = M([[0, -1], [1, 0]]) # 李代數生成元
# (1) J^2 == -I
print(J * J) # Matrix([[-1, 0], [0, -1]])
# (2) 指數公式 exp(theta*J) == R(theta)
E = (theta*J).exp()
print(simplify(E)) # [[cos(theta), -sin(theta)], [sin(theta), cos(theta)]]
# (3) 数值版的「小轉動」近似:theta=0.1
import math
Rn = M([[math.cos(0.1), -math.sin(0.1)], [math.sin(0.1), math.cos(0.1)]])
approx = M.eye(2) + 0.1 * J # 一階近似
print((Rn - approx).norm().evalf()) # 数量级 ~5e-3 —— 小角度時近似不錯
這個「矩陣指數」 \(e^{\theta J}\) 是第 9 章微分幾何、第 10 章電腦圖學漫遊的入場券:每條平滑的變換軌跡,都是某個速度場被「指數化」後的結果。 這也是 Lie 的真本宗:把「微分方程、連續變換」與「群」縫合起來的縫線。
3. 一個非常實用的立例:群之「軌道」#
把 SO(2) 作用在點 \(P = (3, 0)\) 上,全部像的集合是什麼?半徑 3 的圓!這是 Klein 幾何說的:
點 \(P\) 在群 \(G\) 作用下的軌道 = 集合 \(\{gP \mid g \in G\}\) 。 同軌道上任何兩點,在該幾何中是「不可區分的」。
故在歐氏幾何中,單以 SO(2) 為群時,離原點半徑 \(r\) 的每個圓是一條軌道——「距原點 \(r\) 」是群不變量,也正向我們顯示:群的軌道結構在「信息」上與其不變量互為鏡像:
import math
def orbit_SO2(P, n=8):
"取 SO(2) 中均勻 n 個元素作用於 P"
px, py = P
return [( math.cos(2*math.pi*k/n)*px - math.sin(2*math.pi*k/n)*py,
math.sin(2*math.pi*k/n)*px + math.cos(2*math.pi*k/n)*py )
for k in range(n)]
pts = orbit_SO2((3, 0), n=8)
for p in pts:
print(p, math.hypot(*p)) # 都是 3.0 —— 半徑不變
軌道都是同心圓,每條軌道用一個數 \(r\) (半徑)標識,這個 \(r\) 就是不變量。「軌道 ↔ 不變量」的對偶,是所有幾何問題的元語言。
四、更多的群:O(2)、仿射群、GL(2)#
1. O(2)):SO(2) 加一面鏡子#
\(\operatorname{O}(2) = \{ R \mid R^\top R = I\}\) 由 \(\operatorname{SO}(2)\) 與一個面鏡生成:
它是 SO(2) 的「加倍版」——在群論中這叫指標為 2 的子群。它不交換:先旋轉再鏡,與先鏡再旋轉,所得一般在不同的共軛型。這個不交換性,用一對具體矩陣即可證明:
from sympy import Matrix, Rational
S = Matrix([[-1, 0], [0, 1]]) # 對 y 軸反射
R90 = Matrix([[0, -1], [1, 0]]) # 90° 旋轉
print(S * R90) # [[0, 1], [1, 0]] —— 對線 y = x 的反射
print(R90 * S) # [[0, -1], [-1, 0]] —— 對線 y = -x 的反射
兩個結果不同(分別是兩條不同對角線的鏡射)——好一個好玩的觀察:不交換性是一個具體的幾何事實,不是抽象的煩擾。
2. 仿射群 Aff(2) 與 GL(2):概念的相距#
用齊次座標可以把彷射群寫成 \(3 \times 3\) 矩陣群,群公理用同樣的檢驗器就打印:
from sympy import Matrix, symbols, eye, simplify
a, b, c, d, e, f = symbols('a b c d e f', real=True)
def affine_matrix(A, t):
M = eye(3)
M[:2, :2] = A
M[:2, 2] = t
return M
# (1) 兩個仿射矩陣之積仍是仿射矩陣(封閉性)
M1 = affine_matrix(Matrix([[a, b], [c, d]]), Matrix([e, f]))
M2 = affine_matrix(Matrix([[ Rational(1,2), 0], [0, Rational(1,3)]]),
Matrix([1, -1]))
P = simplify(M1 * M2)
print(P[2, 0], P[2, 1], P[2, 2]) # 0 0 1 —— 保有「下排不變」結構
# (2) 仿射群的反元素也是仿射矩陣
Ai = M1 ** -1
print(simplify(Ai[2, :])) # Matrix([[0, 0, 1]])
留意封閉性檢驗的深度訊息:仿射矩陣的形狀(下排 \(\begin{pmatrix} 0 & 0 & 1\end{pmatrix}\) )在乘法下維持,不會被破坏——這正是 7.2 說「仿射群 = 射影群中保無窮遠直線的矩陣群」的代數化:
群的「形狀條件」在乘法下封閉 ⟺ 幾何的「結構」在群下不變。
這條規律自 GL 到 SO 至 Klein 幾何一以貫之,值得反覆咀嚼:群的定義條件(如正交性、仿射形狀、保絕對形)經常用「乘法封閉」來驗證,而不必一點。
3. 與第 3.4 節的接軌#
在第 3.4 節我們已把線性變換組織成矩陣;本節實質是把那一群的「可見部」命名了: \(\operatorname{GL}(2)\) 。可逆 \(2\times2\) 矩陣全體是群(行列式非零,乘積非零子集)、Regular 頓群。三件事可以在 10 秒內驗完:
from sympy import Matrix, symbols, simplify
a, b, c, d, e, f, g, h = symbols('a b c d e f g h')
A = Matrix([[a, b], [c, d]]); B = Matrix([[e, f], [g, h]])
det = A.det()
print(simplify((A * B).det())) # (a d − b c)(e h − f g) —— 大小:乘法可乘
# 可逆 ⇔ det ≠ 0:所以 GL(2) 也可逆封閉
prod = simplify(A * B)
inv_prod = simplify(prod ** -1)
# 它必是 2x2 一般矩陣形式(4 參數)——換言之 GL(2) 封閉
print(inv_prod[0, 0]) # 符號式,含 (e h - f g) 等因子
五、離散群的插叙:把 Klein 幾何「算」。用 PermutationGroup#
Klein 幾何從來都是「連續」的陌生對手,但離散的對稱群在幾何中也有若房重要性(第 8 章凸包的對稱性、數值幾何的重複對稱)。用 SymPy 的 PermutationGroup,Klein 的「群 + 不變量」定理的全自動化,在一個正方形上展示:
from sympy.combinatorics import Permutation, PermutationGroup
from sympy.combinatorics import Cycle
# 正方形四項點 0,1,2,3 的旋轉(90° 每次)與反射
r = Permutation(Cycle(0, 1, 2, 3)) # 旋轉一個角
s = Permutation(1, 3) # 對角線反射(不動 0 與 2)
G = PermutationGroup(r, s) # D4
print(G.order()) # 8
print(G.is_abelian) # False —— D4 不交換
# Klein 式問題:固定某項點的群(即穩定子)有多大 ?
H = G.stabilizer(0)
print(H.order()) # 2 —— 只有恆等與一個反射
# 軌道
print(G.orbit(0)) # {0, 1, 2, 3} —— 單一軌道
註:「在歐氏平面中可把正方形隨意動到任何位置」是個很大的連續群;但「位置不動,只觀察自身的對稱」的群是離散的 D4。這兩種群層次是 Klein 幾何觀點的兩面:一邊是允許的動作集,一邊是圖形自身的自守群。 這觀點在橢圓曲線的對稱、寶石學的晶體分類、乃至第 8 章的凸包對稱性都會浮出。
六、一條整合線索:共軛型 = 變換的「形狀分類」#
最後把兩節所見的全部「型」重收拢。若 \(g\) 與 \(h\) 共軛( \(h = u g u^{-1}\) ),則 \(h\) 是把 \(g\) 「換參考系」之後的變換——尤其, \(u\) 可以是任何仿射變換(在仿射幾何中)。所以:
共軛類 = 在群允許的參考系變換下不分的類型 = Klein 意義下的「型」。
用 SymPy 對 \(2 \times 2\) 一般仿射矩陣求特徵值,即可自動得出 7.2 節的四大分型規則:
from sympy import Matrix, symbols, solve, factor
lam = symbols('lam')
s, t, u, v = symbols('s t u v')
M = Matrix([[s, t], [u, v]])
# 特徵多項式
charpoly_M = factor(M.charpoly(lam).as_expr())
print(charpoly_M)
# lam**2 - s*lam - t*u + s*v - u*t 形式(s 都包含)
# 判別式 D = trace^2 - 4 det
D = factor(M.trace()**2 - 4*M.det())
print(D)
判別式的符號分型,與 7.2 的四型一一對應:
| 判別式 | 特徵值型態 | 幾何型 |
|---|---|---|
| \(D > 0\) | 两個相異實根 | 兩個不動方向(伸縮型、滑移反射之情形也有) |
| \(D = 0\) | 重根 | 單向(純剪力型,或一段滑移) |
| \(D < 0\) | 共軛複根 = 旋轉角 | 旋轉( $ |
(在等距限制下, \(\det = \pm 1\) ,四型偕出: \(\lambda\) 實根 \(\pm1\) 兩個:平移或反射或恆等或滑移;複根 \(e^{\pm i\theta}\) :旋轉。)特徵值是變換的「身分證」,共軛不變——這是 Klein 綱領中「分類」與「不變量」的另一種根本。
七、總結與下一步#
本章三節:
- 7.1 把「幾何」的定義從公理系統改寫為「一個群 + 一組不變量」;
- 7.2 對平面最重要的四個群逐一給出矩陣型、不變量名單、以及包含階梯;
- 7.3(本節)把「群」本身當操作對象:用 SymPy 矩陣驗證公理、以符號證實封閉性、展示 SO(2) 這個最低維連續群,並用共軛與軌道接回「幾何分類」的架構。
接下來本書的旅程已在一個清晰的地圖上:
- 第 8 章(計算幾何)將聚焦「不變量」這端的實務演算法;
- 第 9 章(微分幾何)將走向「局部化群」,即被取代全域群的切空間 + 度量張量;
- 第 10 章(應用)大量用到本章的矩陣群語法(電腦圖學中每幀場景的變換,都是一個仿射—射影矩陣;機器學習中的 embedding 幾何,就是各色「群 + 不變量」設計之選擇)。
一句話總結本章:克萊因說「幾何是什麼」;本節教你看見幾何的「骨架與生命力」——在一組你可以用 SymPy 操作的矩陣裡。
習題#
7.3.1 用符號矩陣驗證 \(\operatorname{SE}(2)\) (定向等距群)的四條群公理:取 \(\begin{pmatrix} R_\theta & \mathbf{t} \\ 0 & 1 \end{pmatrix}\) 一般形(齐次 \(3\times 3\) ),檢驗封閉性、單位元、反元素(並寫出其反元素的公式),並指明結合律來自何處。
7.3.2 以下集合是否成群?逐一以 SymPy 檢驗(或指出破哪條公理):(a) 繞原點的 \(0° \le \theta \le 90°\) 的旋轉;(b) 縮放因子為整數倍的伸縮;(c) 上三角可逆矩陣 \(\begin{pmatrix} a & b \\ 0 & d \end{pmatrix}\) ;(d) 行列式為 \(1\) 的所有 \(3 \times 3\) 矩陣(即 \(\operatorname{SL}(3)\) ——驗其乘法封閉即可)。
7.3.3 用 PermutationGroup 造出正五邊形的對稱群 \(D_5\) (一個 Cycle 旋轉 + 一個反射)。求 \(|D_5|\) 、檢驗是否交換、求固定頂點 0 的子群並列出其元素。
7.3.4(SO(2) 的李代數推進)用 sympy 的 (theta*J).exp() 重新推導 \(R_\theta\) ;再對 \(3 \times 3\) 的情況照樣操作:取 \(J_z = \begin{pmatrix}0&-1&0\\1&0&0\\0&0&0\end{pmatrix}\) (繞 \(z\) 軸轉的生成元),驗證 \(\exp(\theta J_z)\) 是繞 \(z\) 軸的 \(3\) 維旋轉矩陣。這是 \(\operatorname{SO}(3)\) 的「單參數子群」。
7.3.5(挑戰)證明:矩陣群 \(G = \left\{ \begin{pmatrix} a & b \\ 0 & 1 \end{pmatrix} \mid a > 0, b \in \mathbb{R}\right\}\) 是一個群(它就是「水平縮伸 + 水平平移」之群),且它交換。用 SymPy 取帶符號的兩個一般元素驗證。此群有兩個分量(縮伸,平移),是「仿射群的一個兩參數子群」的典型——試解釋為何其幾何是「保水平線」的仿射幾何。