跳轉到

7.3 群論觀點下的幾何:SymPy 的群與矩陣#

學習動機#

前兩節我們反覆說「幾何 = 群 + 不變量」。但我們至今沒有真正把群當作一個數學對象來操作:什麼叫一組變換「形成一個群」?封閉性、單位元、反元素這三條公理在變換的世界裡分別對應幾何上的什麼事實?為什麼 \(\mathcal{I}(2)\) 的部分集合,例如「繞固定點 \(O\) 的所有旋轉」會自成一個群,而「繞任意點的所有旋轉」卻不成群(缺封閉性)?

這些問題的答案,是理解愛爾蘭根綱領的地基。一旦地基打穩,所有前兩節的敘述都會從「口號」升級為「定理」:

  • 「封閉性」⟺ 任何兩個允許的運動接連執行,仍在允許之列——這是「幾何」作為一門學科能自洽研究的最低門檻:你照允許的規則連續做兩個動作,不應該突然做出一個不允許的動作。
  • 「單位元」⟺「什麼都不做」是允許的動作。
  • 「反元素」⟺ 每個允許的動作都能被撤銷——這保證了幾何性質是「可逆判定」的:若性質 \(P\) 在 \(g\) 作用下成立,則原圖也成立。
  • 「結合律」⟺ 函數複合本身自動滿足,無需另外驗證。

本節非常務實:用 SymPy 的符號矩陣當作群的元素,寫出群公理的檢驗程式,逐一驗證最重要的明星群——

  1. 由一個 \(2\times 2\) 旋轉矩陣族生成的 SO(2)(平面上繞原點的旋轉群)——它是第一個也是最重要的「連續群」(李群)範例;
  2. 全部的 \(\operatorname{O}(2)\) 、 \(\operatorname{Aff}(2)\) 、 \(\operatorname{GL}(2)\) 家族;
  3. 以及一些「不成群」的反例,看公理為何會破。

同時我們會觸及群論在幾何中的兩個更深的主題:

  • 共軛與分類:同一共軛類的矩陣恰是「同型變換」(旋轉泊原點與繞他點;伸縮泊原軸與泊他軸),這正是 7.2 節剛體運動四類分型的代數引擎。
  • 軌道與作用:群把空間切成「軌道」,Klein 幾何中的「位置等價」即軌道成員。

值得一提的是,Cayley 1858 年的定理說:「任何抽象群都同構於一個變換群。」所以「用矩陣學群」不是一個特例,而是群的標準型態——矩陣就是群的肉身。

一、群公理的矩陣版本,與 SymPy 驗證程式#

1. 定義#

集合 \(G\) 與一個二元運算 \(\cdot\) (在變換世界裡就是複合),若滿足:

  1. 封閉性: \(g, h \in G \Rightarrow g \cdot h \in G\) ;
  2. 結合律: \(\left(g\cdot h\right)\cdot k = g\cdot \left(h\cdot k\right)\) (矩陣乘法天然滿足);
  3. 單位元:存在 \(e \in G\) ,使 \(e\cdot g = g\cdot e = g\) ;
  4. 反元素:每 \(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) 是群的全套證明。注意第一條的紅利:封閉性檢驗竟順手證明了三角函數的複角公式

\[ \begin{pmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta\end{pmatrix} \begin{pmatrix} \cos\phi & -\sin\phi \\ \sin\phi & \cos\phi\end{pmatrix} = \begin{pmatrix}\cos(\theta + \phi) & -\sin(\theta+\phi) \\ \sin(\theta+\phi) & \cos(\theta+\phi)\end{pmatrix} \]

——這是「幾何證代數恆等式」的初範:群的封閉性就是複角公式的幾何理由(兩次轉動就是一次「總角度」的轉動)。像這類「一個代數事實在變換語言中有可視的理由」,正是 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)\) ——反而成群!

從群論一看而知:「把一個最小集

\[ \{ \text{繞原點旋轉}\} \]

加上平移」就封起來了,這正是 \(\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) 的元素都在同一個形狀上:

\[ R_\theta = \begin{pmatrix}\cos\theta & -\sin\theta \\ \sin\theta & \cos\theta\end{pmatrix}, \quad \theta \in \mathbb{R} \]

三個關鍵事實:

  1. 單參數:每個元素由一個標號 \(\theta\) 完全決定。所以 SO(2) 與圓周 \(S^1\) 同構( \(\theta\) 就是圓座標):SO(2) 本身就是一個圓——群空間即幾何物件,這是李群的第一奇景。
  2. 交換性: \(R_\theta R_\phi = R_{\theta+\phi} = R_\phi R_\theta\) ,故 SO(2) 是交換(阿貝爾)群——平面上繞同一點的二個旋轉總可互換順序。
  3. 群運算退化為加法:群運算(複合)對應角座標的加法, \(\theta \mapsto \theta + \phi \pmod{2\pi}\) 。對數乘法式的操作,讓「群」這個神秘概念與中學生的加法立道對接;

2. 李群的「速度」:微分矩陣與生成元#

李群最重要的思想是「群也有切空間」。取 \(\theta = 0\) 附近展開:

\[ R_{\theta} = I + \theta \begin{pmatrix} 0 & -1 \\ 1 & 0 \end{pmatrix} + O(\theta^2) \]

這個「速度矩陣」 \(J = \begin{pmatrix} 0 & -1 \\ 1 & 0\end{pmatrix}\) 稱為 SO(2) 的李代數生成元。它滿足 \(J^2 = -I\) ,即:

\[ e^{\theta J} = \cos\theta \, I + \sin\theta \, J = R_\theta . \]

也就是說:**旋轉矩陣是指數化的 \(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)\) 與一個面鏡生成:

\[ \operatorname{O}(2) = \operatorname{SO}(2) \;\cup\; \operatorname{SO}(2)\cdot S \]

它是 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 取帶符號的兩個一般元素驗證。此群有兩個分量(縮伸,平移),是「仿射群的一個兩參數子群」的典型——試解釋為何其幾何是「保水平線」的仿射幾何。