跳轉到

06.3 切空間與切叢#

本節目標#

  • 建立**切空間 \(T_pM\) ** 的直覺:在點 \(p\) 附近用「直線世界」近似彎曲世界。
  • 說清切向量是速度,不是位移。
  • 理解切叢(tangent bundle) 的概念:把所有點的切空間打包。
  • 學會座標表示:切向量的基底 \(\dfrac{\partial}{\partial x^i}\) 與向量場。
  • 用 SymPy diffgeom 的 base_vectors 操作切向量,並做球面切向量視覺化實驗。

直覺:在彎曲世界裡,直線只在「當下」存在#

還是地球。你站在地面上一點,指向北邊走出一步。對你來說這是「直直向前」;但從太空看,這一步其實是沿著球面稍微彎了一點。

關鍵是:「直線」只在你所在的那一點、在無限小尺度上成立。

如果讓你限制在球面上(永遠不能跳到空中),你能說的「方向」只有貼著球面的方向: irreversible南、東、西、北,或者任意貼著切的方向。所有可能的「貼著球面的方向」所構成的平面,就是你所在點的切平面——這就是你的切空間。

數學陳述:

切空間 \(T_pM\) ** 是所有在點 \(p\) 的「貼著流形方向」的集合。它是 \(\mathbb{R}^n\) 這樣的平坦向量空間,和流形本身不同維度的世界**(其實是同維度 \(n\) ,但它是向量空間,不是彎曲流形)。

切向量是「速度」,不是「位移」#

這是本節最重要的一句話。

在 \(\mathbb{R}^n\) 我們常把向量當「從 \(a\) 走到 \(b\) 的位移箭頭」。但在彎曲流形上,你不能把一個箭頭「搬到另一點」(不同的點有不同的切空間,它們之間沒有天然的連接)。

那切向量是什麼?是速度:

\[ v = \frac{d}{dt} c(t) \Big|_{t=0} \quad \text{其中 } c(0) = p \]

直覺是:有一條從 \(p\) 出發的小蟲路徑,在 \(t=0\) 的瞬間它的速度方向就是切向量。速度是無窮小的一階訊息,只看局部的第一瞬間,所以不需要知道路徑後面怎麼彎。

換個說法:

  • 位移向量:兩點之連線(在彎曲流形上,兩點間沒有「直線連線」可談)。
  • 切向量:某一點上的速度(在那一點可以談,因為小尺度就是直線)。在所謂「微分幾何」中,這是定義的核心之一。

切叢:把每個點的切空間打包#

一個流形有無窮多個點,每個點各有一個切空間:

\[ T_pM, \quad T_qM, \quad T_rM, \dots \]

把所有這些空間並起來(但記得哪一個屬於哪一點),叫做切叢:

\[ TM = \bigsqcup_{p \in M} T_pM \]

這個「叢」的直覺:像一隻刺蝟的全身刺。每一根刺(切向量)都長在特定一點;從外面看,這刺是一整套向量,每一根的出發點都不一樣。切向量的集合(每點站一根)就叫向量場(下一節細談)。

\(TM\) 的維度是 \(2n\) ( \(n\) 是流形維度,因為每個 \(T_pM\) 有 \(n\) 個方向的向量,再加上 \(n\) 個東西指定「長在哪一點」)。

切向量在座標下的表示: \(\dfrac{\partial}{\partial x^i}\)#

在座標卡 \((U, \varphi)\) 下, \(\varphi\) 把 \(U\) 上的點映到 \(\mathbb{R}^n\) 。 \(\mathbb{R}^n\) 有 \(n\) 個標準基底方向,把這些基底拉回 \(U\) ,就是 \(U\) 上切空間的基底:

\[ \left.\frac{\partial}{\partial x^1}\right|_p, \quad \left.\frac{\partial}{\partial x^2}\right|_p, \quad \dots \quad \left.\frac{\partial}{\partial x^n}\right|_p \]

其中 \(\left.\dfrac{\partial}{\partial x^1}\right|_p\) 直覺是「在 \(p\) 點沿著 \(x^1\) 座標增加的方向速度」。

任何切向量 \(v \in T_pM\) 可寫成:

\[ v = v^1 \left.\frac{\partial}{\partial x^1}\right|_p + v^2 \left.\frac{\partial}{\partial x^2}\right|_p + \dots \]

\(x^i\) 這組數 \((v^1, v^2, \dots, v^n)\) 就是切向量的座標表示。

這個記號的深意: \(\dfrac{\partial}{\partial x^i}\) 表面上是「對 \(x^i\) 求偏導的方向」,實際上也是一個操作(把它 \(f\) 吃掉,還給你 \(\frac{\partial f}{\partial x^i}\) 的值)。所以切向量不只是方向,還是一種「對函數求方向導數」的操作。這就是為什麼 \(\partial/\partial x^i\) 長得像微分算子。

向量場(vector field):在每個點放一個切向量,形成一種「連續的箭頭分布」。座標下:

\[ \vec{v}(p) = v^i(p) \frac{\partial}{\partial x^i}\Big|_p \]

SymPy:切向量與 base vectors#

sympy.diffgeom 讓你建立 \(n\) 維流形上的 CoordSystem,並取得其基底切向量。

from sympy import symbols, sin, cos, pi
from sympy.diffgeom import Manifold, Patch, CoordSystem
from sympy.diffgeom import TensorProduct, WedgeProduct

# 建立 2 維流形上的一個座標卡
m = Manifold('S2', 2)
patch = Patch('patch', m)
theta, phi = symbols('theta phi', real=True)
cs = CoordSystem('spherical', patch, [theta, phi])

# 取得座標卡的兩個基底切向量
e_theta, e_phi = cs.base_vectors()
print(e_theta, e_phi)
# => (BaseScalarField(...), BaseScalarField(...)) 或類似形式

# 任意切向量:a * e_theta + b * e_phi
a, b = symbols('a b', real=True)
v = a*e_theta + b*e_phi
print('切向量 v =', v)

# 切向量作用在函數上(「方向導數」的意義)
f = sin(theta)*cos(phi)      # 定義在流形上的一個純量函數
print('v(f) =', v.rcall(f))

rcall 是右調:把切向量 作用 在函數上,得到的是函數沿那個方向的導數(一個新函數,相當於 \(v^i \partial f / \partial x^i\) )。這是「切向量是微分算子」的程式呈現。

切向量作用純量函數#

from sympy.diffgeom import ManifoldS, PatchS, CoordSystemS
# 假設 cs 是某座標卡,e_1, e_2 是其基底切向量
# 對 f 做:v(f) = v^1 * e_1(f) + v^2 * e_2(f)
# 這是直觀的「在座標下的方向導數配合」

球面兩點切空間的方向差異#

這個實驗讓你看到:不同點的切空間不同,而且它們之間不是同一個空間。

情境設定#

  • 北極 \(\theta = 0\) , \(\phi\) 任意:切空間是一片「水平面」。
  • 赤道點 \(\theta = \pi/2\) , \(\phi = 0\) :切空間同樣是平面,但方向不同(在 \(\mathbb{R}^3\) 中看,北極那片切平面是水平的( \(z\) 方向是法向),赤道點的切平面是豎直的(沿 \(x\) 軸方向是法向))。

用 SymPy 做嚴謹計算#

from sympy import symbols, sin, cos, pi, Matrix
from sympy.diffgeom import Manifold, Patch, CoordSystem

m = Manifold('S2', 2)
patch = Patch('patch', m)

# 基底切向量 -> 用參數化算出它在 R^3 的樣子
theta, phi = symbols('theta phi', real=True)
x = sin(theta)*cos(phi)
y = sin(theta)*sin(phi)
z = cos(theta)

# 參數化對 theta 起 phi 的偏導數 = 切向量在 R^3 的模樣
partial_theta = Matrix([x.diff(theta), y.diff(theta), z.diff(theta)])
partial_phi   = Matrix([x.diff(phi),   y.diff(phi),   z.diff(phi)])

print('partial/sigma 極向量在 R^3 :', partial_theta)
print('partial phi 切向量在 R^3   :', partial_phi)

# 北極:theta=0
print('北極  partial theta :', partial_theta.subs({theta: 0}))
print('北極  partial phi   :', partial_phi.subs({theta: 0, phi: 0}))

# 赤道點:theta=pi/2, phi=0
print('赤道  partial theta :', partial_theta.subs({theta: pi/2, phi: 0}))
print('赤道  partial phi   :', partial_phi.subs({theta: pi/2, phi: 0}))

輸出你會看到:

  • 北極: \(\frac{\partial}{\partial \theta}\) 這個方向在 \(\mathbb{R}^3\) 上大概 \((1, 0, 0)\) ,但 \(\frac{\partial}{\partial \phi}\) 在北極退化成 \((0,0,0)\) (因為北極 \(\phi\) 失效)。
  • 赤道點:兩個方向都是真正的非零向量,張成一片豎直平面。

你也可以用 mermaid 加註釋想像這件事:

動手實驗#

實驗 1:球面切向量視覺化

用 matplotlib 畫出球面上的切向量場。例如在多個點各畫「向東方向」的切向量( \(\frac{\partial}{\partial \phi}\) 的方向在 \(\mathbb{R}^3\) 的樣子):

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(7, 7))
ax = fig.add_subplot(111, projection='3d')

# 畫球面(細網格)
u = np.linspace(0, np.pi, 30)
v_ = np.linspace(-np.pi, np.pi, 60)
X = np.outer(np.sin(u), np.cos(v_))
Y = np.outer(np.sin(u), np.sin(v_))
Z = np.outer(np.cos(u), np.ones_like(v_))
ax.plot_surface(X, Y, Z, alpha=0.2, color='lightblue')

# 在多個點畫「向東」的切向量(在 phi 方向的偏導)
pts = [(np.pi/6, 0), (np.pi/6, np.pi/2), (np.pi/2, 0),
       (np.pi/2, np.pi), (np.pi*5/6, np.pi/2)]
for th, ph in pts:
    # 求點座標
    px = np.sin(th)*np.cos(ph)
    py = np.sin(th)*np.sin(ph)
    pz = np.cos(th)
    # 向東方向 = d/d phi 在 (th, ph) 的值 = (-sin(th)*sin(ph), sin(th)*cos(ph), 0)
    dx = -np.sin(th)*np.sin(ph)
    dy =  np.sin(th)*np.cos(ph)
    dz = 0.0
    ax.quiver(px, py, pz, dx, dy, dz, color='red', length=0.3, normalize=True)

ax.set_xlabel('x'), ax.set_ylabel('y'), ax.set_zlabel('z')
ax.set_title('球面上的向東切向量場')
plt.show()

觀察:紅色箭頭都貼著球面(與該點法向量垂直),沒有一根指向空中。這就是「切」的意義。

實驗 2:確認切向量與法向量垂直

在任一點,球面的法向量就是位置向量 \((x, y, z)\) 。請寫程式驗證:

\[ \frac{\partial}{\partial \theta}(x,y,z) \cdot (x,y,z) = 0, \quad \frac{\partial}{\partial \phi}(x,y,z) \cdot (x,y,z) = 0 \]

用 SymPy 符號運算:

from sympy import symbols, sin, cos, Matrix, simplify

theta, phi = symbols('theta phi', real=True)
r = Matrix([sin(theta)*cos(phi), sin(theta)*sin(phi), cos(theta)])
pt = r.diff(theta)
pp = r.diff(phi)
print('partial_theta dot r =', simplify(pt.dot(r)))   # 應為 0
print('partial_phi   dot r =', simplify(pp.dot(r)))   # 應為 0

這說明切向量在球面上(垂直於法向),它們的確是「速度」的方向。

實驗 3:用 base_vectors 表示任一切向量

在 SymPy 中:定義一個切向量 \(v = 3 e_\theta - 2 e_\phi\) ,然後叫做 rcall 的動作讓它作用在 \(f = \theta^2 + \phi\) 上,確認得到的值是 \(3 \cdot 2\theta - 2\) ,在 \(\theta = \pi/4\) 時:

from sympy import symbols, sin, cos, pi, Rational
from sympy.diffgeom import Manifold, Patch, CoordSystem

m = Manifold('S2', 2)
patch = Patch('patch', m)
theta, phi = symbols('theta phi', real=True)
cs = CoordSystem('spherical', patch, [theta, phi])
e_th, e_ph = cs.base_vectors()

v = 3*e_th - 2*e_ph
f = theta**2 + phi
print('v 在 theta=pi/4 的作用值:', v.rcall(f).subs({theta: pi/4}))
# 手算:3 * 2*(pi/4) - 2 = 3*pi/2 - 2

實驗 4:莫比烏斯帶的切向量方向不連續

有趣的反思:莫比烏斯帶上沿著中央線的切向量場,走一圈回到原點時,方向會翻轉。請你想像並寫一段文字,說明這和「不可定向」的直接關聯。(提示:一個「定義良好」的向量場,在穿越座標卡邊界時應該連續;如果 transition map 的 sign 變化導致向量反向,就無法定義一致的方向。)

小結與練習#

  • **切空間 \(T_pM\) **:在點 \(p\) 的平坦向量空間,容納所有貼著流形的方向。
  • 切向量是速度,不是位移:定義依賴於「路徑的速度」,不是兩點連線。
  • **切叢 \(TM\) **:把所有切空間打包,維度為 \(2n\) ;一個切向量的分配就是向量場。
  • 座標表示:基底是 \(\frac{\partial}{\partial x^i}\) ,座標是 \((v^1, \dots, v^n)\) ,且切向量也可作為微分算子。
  • SymPy diffgeom 中 base_vectors 給出基底,rcall 呈現切向量的「微分算子」本性。

練習:

  1. 請解釋:在切空間 \(T_pM\) 中「兩個向量相加」有意義,但在不同點 \(p \neq q\) 的切向量「直接相加」原則上沒有意義。為什麼?
  2. 在圓 \(S^1\) 上,取角度參數 \(\theta\) ,基底切向量是 \(\frac{d}{d\theta}\) 。請說明它的大小不一定是 1(如果圓的另一個參數是弧長 \(s = R\theta\) ,那 \(\frac{d}{ds}\) 的大小才會是 1)。這也提醒你座標表示在不同座標下可以差一個常數因子。
  3. 在 SymPy 中驗證:對環面參數化 \(x = (2+\cos v)\cos u\) 、 \(y=(2+\cos v)\sin u\) 、 \(z=\sin v\) ,兩個基底切向量 \(\partial/\partial u\) 與 \(\partial/\partial v\) 均與法向量垂直(dot product 為 0)。
  4. 「貼著球面向東走」在赤道、在北極、在南極呈現的形狀不盡相同。請用 mermaid 或金思賀的圖說明 切向量場沿緯度圈在不同緯度觀察的差異。
  5. 用 matplotlib 畫出莫比烏斯帶的一個切向量場,並觀察是否會在帶子交陪處出現方向翻轉。