coordinate-system 7.0.0__cp313-cp313-win_amd64.whl → 7.0.2__cp313-cp313-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,33 +1,34 @@
1
- """
2
- 傅里叶标架场与希尔伯特空间谱几何 (Fourier Frame Field & Hilbert Space Spectral Geometry)
3
- ================================================================================
4
-
5
- 基于希尔伯特空间的傅里叶标架与谱分析框架。
6
-
7
- 核心思想:
8
- - 傅里叶标架 = FourierFrame * e^{iθ} (相位旋转,傅里叶变换)
9
- - 共形变换 = FourierFrame * λ (λ ∈ ℝ⁺, 缩放)
10
- - 内禀梯度算子 G_μ = d/dx^μ log FourierFrame(x)
11
- - 曲率 R_{μν} = [G_μ, G_ν]
12
- - Berry相位 γ = ∮ G_μ dx^μ (几何相位,平行输运)
13
- - 陈数 c₁ = (1/2π) ∬ R_{μν} dS (拓扑不变量)
14
-
15
- 数学框架:
16
- - 希尔伯特空间:L²(M) 上的傅里叶分析
17
- - 谱理论:拉普拉斯算子的本征值问题
18
- - 纤维丛理论:FourierFrame 作为标架丛的局部截面
19
- - 李群李代数:内禀梯度算子构成李代数
20
- - 热核展开:几何不变量的提取
21
-
22
- 群论对应:
23
- - FourierFrame ↔ GL(1,ℂ) = ℂ× = U(1) × ℝ⁺
24
- - Phase e^{iθ} ↔ U(1) (单位圆)
25
- - Magnitude |Q| ↔ ℝ⁺ (正实缩放)
26
-
27
- Author: Quantum Frame Theory
28
- Date: 2025-12-04
29
- Version: 6.0.3
30
- """
1
+ """
2
+ Fourier Frame Field and Hilbert Space Spectral Geometry
3
+ =======================================================
4
+
5
+ A FourierFrame-based spectral geometry framework on Hilbert spaces.
6
+
7
+ Core ideas:
8
+ - Fourier frame = FourierFrame * e^{iθ} (phase rotation / Fourier transform)
9
+ - Conformal transform = FourierFrame * λ, λ ∈ ℝ⁺ (scaling)
10
+ - Intrinsic gradient operator G_μ = d/dx^μ log FourierFrame(x)
11
+ - Curvature R_{μν} = [G_μ, G_ν]
12
+ - Berry phase γ = ∮ G_μ dx^μ (geometric phase / parallel transport)
13
+ - Chern number c₁ = (1/2π) ∬ R_{μν} dS (topological invariant)
14
+
15
+ Mathematical framework:
16
+ - Hilbert space: Fourier analysis on L²(M)
17
+ - Spectral theory: Laplacian eigenvalue problems
18
+ - Fiber bundles: FourierFrame as a local section of the frame bundle
19
+ - Lie groups/algebras: intrinsic gradient operator forms a Lie algebra
20
+ - Heat kernel expansion: extraction of geometric invariants
21
+
22
+ Group correspondence:
23
+ - FourierFrame ↔ GL(1,ℂ) = ℂ× = U(1) × ℝ⁺
24
+ - Phase e^{iθ} ↔ U(1) (unit circle)
25
+ - Magnitude |Q| ↔ ℝ⁺ (positive scaling)
26
+
27
+ **Authors:** Pan Guojun
28
+ Date: 2025-12-04
29
+ Version: 6.0.3
30
+ **DOI:** https://doi.org/10.5281/zenodo.14435613
31
+ """
31
32
 
32
33
  __version__ = '6.0.3'
33
34
 
@@ -36,22 +37,22 @@ from typing import List, Tuple, Dict, Optional, Union, Any, Callable
36
37
  from dataclasses import dataclass
37
38
  import warnings
38
39
 
39
- # 导入坐标系统
40
+ # Import coordinate system types
40
41
  try:
41
42
  from .coordinate_system import coord3, vec3, quat
42
43
  except ImportError:
43
44
  try:
44
45
  from coordinate_system import coord3, vec3, quat
45
46
  except ImportError:
46
- # 延迟导入,允许独立使用
47
+ # Lazy import for standalone usage
47
48
  coord3 = None
48
49
  vec3 = None
49
50
  quat = None
50
51
 
51
- # 物理常数
52
- HBAR = 1.0 # 约化普朗克常数(自然单位)
52
+ # Physical constants
53
+ HBAR = 1.0 # Reduced Planck constant (natural units)
53
54
 
54
- # GPU 可用性检查
55
+ # GPU availability check
55
56
  try:
56
57
  import cupy as cp
57
58
  import cupyx.scipy.fft as cufft
@@ -62,66 +63,60 @@ except ImportError:
62
63
  cufft = None
63
64
 
64
65
 
65
- # ============================================================
66
- # 傅里叶标架代数 (Fourier Frame Algebra)
67
- # ============================================================
68
-
69
- class FourierFrame:
70
- """
71
- 傅里叶标架 - 希尔伯特空间上的频谱分析核心对象
72
-
73
- 数学结构:
74
- -----------
75
- FourierFrame 对应 GL(1,ℂ) = ℂ× = U(1) × ℝ⁺ 群
76
-
77
- - Q ℂ× (非零复数)
78
- - Q = |Q| · e^{iθ}
79
- - Phase e^{iθ}U(1): 傅里叶变换(相位旋转)
80
- - Magnitude |Q| ∈ ℝ⁺: 共形变换(缩放)
81
-
82
- 核心属性:
83
- ----------
84
- - base_coord: 基础坐标系 (coord3 对象)
85
- - Q: 复标度因子 Q ∈ ℂ×,编码相位与缩放
86
-
87
- 关键变换:
88
- ----------
89
- - FourierFrame * e^{iθ} = 傅里叶变换 (θ=π/2 为标准 90° 旋转)
90
- - FourierFrame * λ = 共形变换 (λ ∈ ℝ⁺,纯缩放)
91
- - FourierFrame * FourierFrame = 标架复合
92
-
93
- 希尔伯特空间意义:
94
- -----------------
95
- - L²(M) 空间上的傅里叶基
96
- - 内禀梯度算子 G_μ = d/dx^μ log Q(x)
97
- - 谱分解:Δφ_n = -λ_n φ_n
98
- - 热核:K(x,y,t) = Σ_n e^{-λ_n t} φ_n(x) φ_n*(y)
99
-
100
- 几何意义:
101
- ----------
102
- - 作为标架丛 F(M) 的局部截面
103
- - 内禀梯度算子 G_μ 描述局部旋转
104
- - 曲率 R_{μν} = [G_μ, G_ν] 描述非交换性
105
- - Berry 相位 γ = G_μ dx^μ (平行输运)
106
-
107
- 与 U3Frame 的关系:
108
- ------------------
109
- - FourierFrame: GL(1,ℂ) 群,1个复数自由度
110
- - U3Frame: U(3) 群,9个实自由度
111
- - U(3) ⊃ U(1) as global phase subgroup
112
- """
113
-
114
- def __init__(self, base_coord=None, q_factor=1.0+0j):
115
- """
116
- 初始化傅里叶标架
117
-
118
- Args:
119
- base_coord: 基础坐标系 (coord3 对象),None 时使用单位标架
120
- q_factor: 复标度因子 Q ∈ ℂ× = GL(1,ℂ)
121
- Q = |Q| · e^{iθ}
122
- - 相位 e^{iθ}: 傅里叶变换
123
- - 模 |Q|: 共形缩放
124
- """
66
+ # ============================================================
67
+ # Fourier Frame Algebra
68
+ # ============================================================
69
+
70
+ class FourierFrame:
71
+ """
72
+ FourierFrame: core spectral-geometry object on Hilbert space.
73
+
74
+ Mathematical structure:
75
+ FourierFrame ↔ GL(1,ℂ) = ℂ× = U(1) × ℝ⁺
76
+
77
+ - Q ∈ ℂ× (nonzero complex)
78
+ - Q = |Q| · e^{iθ}
79
+ - Phase e^{iθ} ∈ U(1): Fourier transform (phase rotation)
80
+ - Magnitude |Q|ℝ⁺: conformal scaling
81
+
82
+ Key properties:
83
+ - base_coord: underlying coord3 frame (optional)
84
+ - Q: complex scale factor encoding phase and magnitude
85
+
86
+ Key transforms:
87
+ - FourierFrame * e^{iθ} = Fourier transform (θ = π/2 is the standard 90°)
88
+ - FourierFrame * λ = conformal transform (λ ∈ ℝ⁺)
89
+ - FourierFrame * FourierFrame = frame composition
90
+
91
+ Hilbert-space meaning:
92
+ - Fourier basis on L²(M)
93
+ - Intrinsic gradient G_μ = d/dx^μ log Q(x)
94
+ - Spectrum: Δφ_n = -λ_n φ_n
95
+ - Heat kernel: K(x,y,t) = Σ_n e^{-λ_n t} φ_n(x) φ_n*(y)
96
+
97
+ Geometric meaning:
98
+ - Local section of the frame bundle F(M)
99
+ - G_μ describes local rotation
100
+ - Curvature R_{μν} = [G_μ, G_ν]
101
+ - Berry phase γ = ∮ G_μ dx^μ (parallel transport)
102
+
103
+ Relation to U3Frame:
104
+ - FourierFrame: GL(1,ℂ), one complex DOF
105
+ - U3Frame: U(3), nine real DOF
106
+ - U(3) U(1) as global phase subgroup
107
+ """
108
+
109
+ def __init__(self, base_coord=None, q_factor=1.0+0j):
110
+ """
111
+ Initialize a FourierFrame.
112
+
113
+ Args:
114
+ base_coord: base coordinate frame (coord3), or identity if None
115
+ q_factor: complex scale factor Q ∈ ℂ× = GL(1,ℂ)
116
+ Q = |Q| · e^{iθ}
117
+ - phase e^{iθ}: Fourier transform
118
+ - magnitude |Q|: conformal scaling
119
+ """
125
120
  if base_coord is None:
126
121
  if coord3 is not None:
127
122
  self.base = coord3.identity()
@@ -130,283 +125,282 @@ class FourierFrame:
130
125
  else:
131
126
  self.base = base_coord
132
127
 
133
- self.Q = complex(q_factor) # 确保是复数
134
- self.dim = 3
135
-
136
- # -------------------- 复标架属性 --------------------
137
-
138
- @property
139
- def o(self):
140
- """复位置向量"""
141
- if self.base is None:
142
- return None
143
- o_base = self.base.o
144
- # 复扩展:实部为原位置,虚部编码相位信息
145
- return vec3(
146
- o_base.x * self.Q.real + 1j * o_base.x * self.Q.imag,
147
- o_base.y * self.Q.real + 1j * o_base.y * self.Q.imag,
148
- o_base.z * self.Q.real + 1j * o_base.z * self.Q.imag
128
+ self.Q = complex(q_factor) # Ensure complex
129
+ self.dim = 3
130
+
131
+ # -------------------- Complex frame properties --------------------
132
+
133
+ @property
134
+ def o(self):
135
+ """Complex position vector."""
136
+ if self.base is None:
137
+ return None
138
+ o_base = self.base.o
139
+ # Complex extension: real part is position, imaginary part encodes phase
140
+ return vec3(
141
+ o_base.x * self.Q.real + 1j * o_base.x * self.Q.imag,
142
+ o_base.y * self.Q.real + 1j * o_base.y * self.Q.imag,
143
+ o_base.z * self.Q.real + 1j * o_base.z * self.Q.imag
149
144
  ) if vec3 else None
150
145
 
151
- @property
152
- def s(self):
153
- """复缩放向量: s_Q = s_base · Q"""
154
- if self.base is None:
155
- return None
156
- s_base = self.base.s
146
+ @property
147
+ def s(self):
148
+ """Complex scale vector: s_Q = s_base · Q."""
149
+ if self.base is None:
150
+ return None
151
+ s_base = self.base.s
157
152
  return vec3(
158
153
  s_base.x * self.Q.real + 1j * s_base.x * self.Q.imag,
159
154
  s_base.y * self.Q.real + 1j * s_base.y * self.Q.imag,
160
155
  s_base.z * self.Q.real + 1j * s_base.z * self.Q.imag
161
156
  ) if vec3 else None
162
157
 
163
- @property
164
- def phase(self):
165
- """相位 arg(Q)"""
166
- return np.angle(self.Q)
167
-
168
- @property
169
- def magnitude(self):
170
- """ |Q|"""
171
- return np.abs(self.Q)
158
+ @property
159
+ def phase(self):
160
+ """Phase arg(Q)."""
161
+ return np.angle(self.Q)
162
+
163
+ @property
164
+ def magnitude(self):
165
+ """Magnitude |Q|."""
166
+ return np.abs(self.Q)
167
+
168
+ @property
169
+ def det(self):
170
+ """
171
+ Determinant: Det(Frame).
172
+
173
+ Used in the path-integral measure ∫ Dφ · Det[Frame] · exp(iS/ħ).
174
+ """
175
+ if self.base is None:
176
+ return self.Q ** 3 # 3D frame
177
+ s = self.base.s
178
+ det_s = s.x * s.y * s.z
179
+ return det_s * (self.Q ** 3)
180
+
181
+ # -------------------- Frame operations --------------------
182
+
183
+ def __mul__(self, other):
184
+ """
185
+ Frame multiplication: core transform operator.
186
+
187
+ Supports:
188
+ - Frame * complex: phase rotation / scaling (Fourier / conformal transform)
189
+ - Frame * Frame: frame composition
190
+ - Frame * vec3: vector transform
191
+ """
192
+ if isinstance(other, (int, float, complex)):
193
+ # Scalar multiplication: Fourier / conformal transform
194
+ new_Q = self.Q * other
195
+ return FourierFrame(self.base, new_Q)
196
+
197
+ elif isinstance(other, FourierFrame):
198
+ # Frame composition
199
+ if self.base is not None and other.base is not None:
200
+ new_base = self.base * other.base
201
+ else:
202
+ new_base = self.base or other.base
203
+ new_Q = self.Q * other.Q
204
+ return FourierFrame(new_base, new_Q)
205
+
206
+ elif vec3 is not None and isinstance(other, vec3):
207
+ # Vector transform
208
+ return vec3(
209
+ other.x * self.Q.real,
210
+ other.y * self.Q.real,
211
+ other.z * self.Q.real
212
+ )
172
213
 
173
- @property
174
- def det(self):
175
- """
176
- 行列式: Det(Frame)
177
-
178
- 用于路径积分测度 ∫ Dφ · Det[Frame] · exp(iS/ħ)
179
- """
180
- if self.base is None:
181
- return self.Q ** 3 # 3维标架
182
- s = self.base.s
183
- det_s = s.x * s.y * s.z
184
- return det_s * (self.Q ** 3)
185
-
186
- # -------------------- 标架运算 --------------------
187
-
188
- def __mul__(self, other):
189
- """
190
- 标架乘法 - 核心变换操作
191
-
192
- 支持:
193
- - Frame * complex: 相位旋转/缩放 (傅里叶/共形变换)
194
- - Frame * Frame: 标架复合 (路径积分复合)
195
- - Frame * vec3: 向量变换
196
- """
197
- if isinstance(other, (int, float, complex)):
198
- # 标量乘法实现傅里叶/共形变换
199
- new_Q = self.Q * other
200
- return FourierFrame(self.base, new_Q)
201
-
202
- elif isinstance(other, FourierFrame):
203
- # 标架复合
204
- if self.base is not None and other.base is not None:
205
- new_base = self.base * other.base
206
- else:
207
- new_base = self.base or other.base
208
- new_Q = self.Q * other.Q
209
- return FourierFrame(new_base, new_Q)
210
-
211
- elif vec3 is not None and isinstance(other, vec3):
212
- # 向量变换
213
- return vec3(
214
- other.x * self.Q.real,
215
- other.y * self.Q.real,
216
- other.z * self.Q.real
217
- )
218
-
219
- return NotImplemented
220
-
221
- def __rmul__(self, other):
222
- """右乘法"""
223
- return self.__mul__(other)
224
-
225
- def __truediv__(self, other):
226
- """标架除法 - 逆变换"""
227
- if isinstance(other, (int, float, complex)):
228
- return FourierFrame(self.base, self.Q / other)
229
- elif isinstance(other, FourierFrame):
230
- if self.base is not None and other.base is not None:
231
- new_base = self.base / other.base
232
- else:
233
- new_base = self.base
234
- return FourierFrame(new_base, self.Q / other.Q)
235
- return NotImplemented
236
-
237
- def __pow__(self, n):
238
- """幂运算: 对应多次变换"""
239
- if isinstance(n, (int, float, complex)):
240
- return FourierFrame(self.base, self.Q ** n)
241
214
  return NotImplemented
242
215
 
243
- def __eq__(self, other):
244
- """相等比较"""
245
- if not isinstance(other, FourierFrame):
246
- return False
247
- return np.isclose(self.Q, other.Q)
216
+ def __rmul__(self, other):
217
+ """Right multiplication."""
218
+ return self.__mul__(other)
219
+
220
+ def __truediv__(self, other):
221
+ """Frame division (inverse transform)."""
222
+ if isinstance(other, (int, float, complex)):
223
+ return FourierFrame(self.base, self.Q / other)
224
+ elif isinstance(other, FourierFrame):
225
+ if self.base is not None and other.base is not None:
226
+ new_base = self.base / other.base
227
+ else:
228
+ new_base = self.base
229
+ return FourierFrame(new_base, self.Q / other.Q)
230
+ return NotImplemented
231
+
232
+ def __pow__(self, n):
233
+ """Power operator for repeated transforms."""
234
+ if isinstance(n, (int, float, complex)):
235
+ return FourierFrame(self.base, self.Q ** n)
236
+ return NotImplemented
237
+
238
+ def __eq__(self, other):
239
+ """Equality check."""
240
+ if not isinstance(other, FourierFrame):
241
+ return False
242
+ return np.isclose(self.Q, other.Q)
248
243
 
249
244
  def __repr__(self):
250
245
  if self.base is not None:
251
246
  return f"FourierFrame(Q={self.Q:.4f}, o={self.base.o})"
252
247
  return f"FourierFrame(Q={self.Q:.4f})"
253
248
 
254
- # -------------------- 傅里叶变换 --------------------
255
-
256
- def fourier_transform(self, theta: float = np.pi/2) -> 'FourierFrame':
257
- """
258
- 傅里叶变换: F_θ[FourierFrame] = FourierFrame · e^{iθ}
259
-
260
- Args:
261
- theta: 旋转角度,π/2 为标准傅里叶变换
262
-
263
- Returns:
264
- 变换后的 FourierFrame
265
-
266
- 性质:
267
- - F^4 = I (四次变换回到自身)
268
- - F^2 = P (宇称变换)
269
- """
270
- ft_factor = np.exp(1j * theta)
271
- return self * ft_factor
272
-
273
- def inverse_fourier_transform(self, theta: float = np.pi/2) -> 'FourierFrame':
274
- """逆傅里叶变换: F^{-1} = F_{-θ}"""
275
- return self.fourier_transform(-theta)
276
-
277
- def conformal_transform(self, lambda_factor: float) -> 'FourierFrame':
278
- """
279
- 共形变换: FourierFrame → FourierFrame · λ, λ ∈ ℝ⁺
280
-
281
- 实现缩放变换,保持角度不变
282
- """
283
- return self * lambda_factor
284
-
285
- # -------------------- 经典几何演化 --------------------
286
-
287
- def diffusion_evolution(self, t: float, kappa: float = 1.0) -> 'FourierFrame':
288
- """
289
- 扩散演化算子: e^{tΔ} FourierFrame
290
-
291
- 这是经典热方程 ∂u/∂t = κΔu 的解算子,其中:
292
- - Δ 是拉普拉斯算子(几何扩散算子)
293
- - t 是时间参数(实时间,非虚时间)
294
- - κ 是扩散系数
295
-
296
- 数学形式:
297
- FourierFrame(x, t) = e^{tκΔ} FourierFrame(x, 0)
298
- = FourierFrame₀ · e^{-tκ|k|²} (动量空间)
299
-
300
- 物理意义:
301
- - 描述几何信息在流形上的扩散过程
302
- - 热核作为基本解:K(x,y,t) = (4πκt)^{-d/2} e^{-|x-y|²/(4κt)}
303
- - 谱几何中的核心工具,用于提取流形的几何不变量
304
-
305
- 注意:这是**经典几何**的扩散过程,与量子力学的虚时间演化
306
- 在形式上类似,但物理意义完全不同。
307
-
308
- Args:
309
- t: 扩散时间(必须 > 0
310
- kappa: 扩散系数(默认1.0)
311
-
312
- Returns:
313
- 扩散演化后的FourierFrame
314
-
315
- 局限性:
316
- - 简化实现:仅对标度因子Q进行扩散
317
- - 完整实现需要在标架场上定义拉普拉斯算子
318
- - 数值实现受网格分辨率限制
319
- """
320
- if t < 0:
321
- raise ValueError("扩散时间t必须非负")
322
-
323
- # 简化模型:对Q因子进行衰减(高频抑制)
324
- # 完整实现需要在标架场的频谱表示中进行
325
- decay_factor = np.exp(-kappa * t * np.abs(self.Q)**2)
326
- evolved_Q = self.Q * decay_factor
249
+ # -------------------- Fourier transform --------------------
250
+
251
+ def fourier_transform(self, theta: float = np.pi/2) -> 'FourierFrame':
252
+ """
253
+ Fourier transform: F_θ[FourierFrame] = FourierFrame · e^{iθ}.
254
+
255
+ Args:
256
+ theta: rotation angle, π/2 is the standard Fourier transform
257
+
258
+ Returns:
259
+ Transformed FourierFrame.
260
+
261
+ Properties:
262
+ - F^4 = I (four transforms return to identity)
263
+ - F^2 = P (parity)
264
+ """
265
+ ft_factor = np.exp(1j * theta)
266
+ return self * ft_factor
267
+
268
+ def inverse_fourier_transform(self, theta: float = np.pi/2) -> 'FourierFrame':
269
+ """Inverse Fourier transform: F^{-1} = F_{-θ}."""
270
+ return self.fourier_transform(-theta)
271
+
272
+ def conformal_transform(self, lambda_factor: float) -> 'FourierFrame':
273
+ """
274
+ Conformal transform: FourierFrame → FourierFrame · λ, λ ∈ ℝ⁺.
275
+
276
+ Implements scaling while preserving angles.
277
+ """
278
+ return self * lambda_factor
279
+
280
+ # -------------------- Classical geometric evolution --------------------
281
+
282
+ def diffusion_evolution(self, t: float, kappa: float = 1.0) -> 'FourierFrame':
283
+ """
284
+ Diffusion evolution operator: e^{tΔ} FourierFrame.
285
+
286
+ This is the solution operator of the classical heat equation ∂u/∂t = κΔu:
287
+ - Δ is the Laplacian (geometric diffusion operator)
288
+ - t is time (real time, not imaginary)
289
+ - κ is the diffusion coefficient
290
+
291
+ Form:
292
+ FourierFrame(x, t) = e^{tκΔ} FourierFrame(x, 0)
293
+ = FourierFrame₀ · e^{-tκ|k|²} (momentum space)
294
+
295
+ Notes:
296
+ - Describes diffusion of geometric information over the manifold
297
+ - Heat kernel K(x,y,t) = (4πκt)^{-d/2} e^{-|x-y|²/(4κt)}
298
+ - Core tool in spectral geometry for extracting invariants
299
+
300
+ This is a classical diffusion process (not quantum imaginary-time evolution).
301
+
302
+ Args:
303
+ t: diffusion time (must be > 0)
304
+ kappa: diffusion coefficient (default 1.0)
305
+
306
+ Returns:
307
+ Diffused FourierFrame.
308
+
309
+ Limitations:
310
+ - Simplified: only the Q factor is diffused
311
+ - Full implementation requires a Laplacian on the frame field
312
+ - Numerical results depend on grid resolution
313
+ """
314
+ if t < 0:
315
+ raise ValueError("Diffusion time t must be non-negative")
316
+
317
+ # Simplified model: decay Q factor (high-frequency suppression)
318
+ # Full implementation uses spectral representation of the frame field
319
+ decay_factor = np.exp(-kappa * t * np.abs(self.Q)**2)
320
+ evolved_Q = self.Q * decay_factor
327
321
 
328
322
  return FourierFrame(self.base, evolved_Q)
329
323
 
330
324
  @staticmethod
331
- def laplacian_from_field(frame_field: List[List['FourierFrame']],
332
- i: int, j: int) -> complex:
333
- """
334
- 从离散标架场计算拉普拉斯算子
335
-
336
- Δ log FourierFrame ≈ (∇² log FourierFrame)
337
- = ∂²/∂x² log Q + ∂²/∂y² log Q
338
-
339
- Args:
340
- frame_field: 离散标架场
341
- i, j: 网格位置
342
-
343
- Returns:
344
- 拉普拉斯算子作用结果(复数)
345
-
346
- 数学细节:
347
- 使用五点差分模板计算二阶导数:
348
- Δf ≈ [f(i+1,j) + f(i-1,j) + f(i,j+1) + f(i,j-1) - 4f(i,j)] / h²
349
- """
350
- ny, nx = len(frame_field), len(frame_field[0])
325
+ def laplacian_from_field(frame_field: List[List['FourierFrame']],
326
+ i: int, j: int) -> complex:
327
+ """
328
+ Compute the Laplacian from a discrete frame field.
329
+
330
+ Δ log FourierFrame ≈ (∇² log FourierFrame)
331
+ = ∂²/∂x² log Q + ∂²/∂y² log Q
332
+
333
+ Args:
334
+ frame_field: discrete frame field
335
+ i, j: grid indices
336
+
337
+ Returns:
338
+ Laplacian result (complex).
339
+
340
+ Numerical details:
341
+ Use a 5-point stencil for second derivatives:
342
+ Δf ≈ [f(i+1,j) + f(i-1,j) + f(i,j+1) + f(i,j-1) - 4f(i,j)] / h²
343
+ """
344
+ ny, nx = len(frame_field), len(frame_field[0])
351
345
 
352
346
  if i <= 0 or i >= ny - 1 or j <= 0 or j >= nx - 1:
353
347
  return 0.0 + 0j
354
348
 
355
- # 中心点
356
- log_Q_center = np.log(frame_field[i][j].Q)
357
-
358
- # 四个邻居
359
- log_Q_xp = np.log(frame_field[i][j+1].Q)
360
- log_Q_xm = np.log(frame_field[i][j-1].Q)
361
- log_Q_yp = np.log(frame_field[i+1][j].Q)
362
- log_Q_ym = np.log(frame_field[i-1][j].Q)
363
-
364
- # 五点拉普拉斯模板(假设网格间距h=1
365
- laplacian = (log_Q_xp + log_Q_xm + log_Q_yp + log_Q_ym - 4*log_Q_center)
349
+ # Center point
350
+ log_Q_center = np.log(frame_field[i][j].Q)
351
+
352
+ # Four neighbors
353
+ log_Q_xp = np.log(frame_field[i][j+1].Q)
354
+ log_Q_xm = np.log(frame_field[i][j-1].Q)
355
+ log_Q_yp = np.log(frame_field[i+1][j].Q)
356
+ log_Q_ym = np.log(frame_field[i-1][j].Q)
357
+
358
+ # 5-point Laplacian stencil (assume grid spacing h=1)
359
+ laplacian = (log_Q_xp + log_Q_xm + log_Q_yp + log_Q_ym - 4*log_Q_center)
366
360
 
367
361
  return laplacian
368
362
 
369
- # -------------------- 谱变换 --------------------
363
+ # -------------------- Spectral transform --------------------
370
364
 
371
365
  @staticmethod
372
- def spectral_transform_2d(field: np.ndarray, hbar: float = HBAR) -> np.ndarray:
373
- """
374
- 二维谱变换:位置空间动量空间
375
-
376
- 数学形式:
377
- ψ̃(k) = ∫ e^{ikx/ħ} ψ(x) dx / √(2πħ)
378
-
379
- Args:
380
- field: 输入场,形状 [ny, nx, ...] [ny, nx]
381
- hbar: 约化普朗克常数
382
-
383
- Returns:
384
- 动量空间谱
385
- """
386
- # 确定 FFT 的轴
387
- if field.ndim >= 2:
388
- axes = (0, 1)
389
- else:
390
- axes = None
391
-
392
- spectrum = np.fft.fft2(field, axes=axes)
393
-
394
- # 量子力学归一化
395
- normalization = 1.0 / np.sqrt(2 * np.pi * hbar)
396
- return spectrum * normalization
366
+ def spectral_transform_2d(field: np.ndarray, hbar: float = HBAR) -> np.ndarray:
367
+ """
368
+ 2D spectral transform: position space momentum space.
369
+
370
+ Form:
371
+ ψ̃(k) = ∫ e^{ikx/ħ} ψ(x) dx / √(2πħ)
372
+
373
+ Args:
374
+ field: input field, shape [ny, nx, ...] or [ny, nx]
375
+ hbar: reduced Planck constant
376
+
377
+ Returns:
378
+ Momentum-space spectrum.
379
+ """
380
+ # FFT axes
381
+ if field.ndim >= 2:
382
+ axes = (0, 1)
383
+ else:
384
+ axes = None
385
+
386
+ spectrum = np.fft.fft2(field, axes=axes)
387
+
388
+ # Quantum normalization
389
+ normalization = 1.0 / np.sqrt(2 * np.pi * hbar)
390
+ return spectrum * normalization
397
391
 
398
392
  @staticmethod
399
- def inverse_spectral_transform_2d(spectrum: np.ndarray, hbar: float = HBAR) -> np.ndarray:
400
- """
401
- 二维逆谱变换:动量空间位置空间
402
-
403
- Args:
404
- spectrum: 动量空间谱
405
- hbar: 约化普朗克常数
406
-
407
- Returns:
408
- 位置空间场
409
- """
393
+ def inverse_spectral_transform_2d(spectrum: np.ndarray, hbar: float = HBAR) -> np.ndarray:
394
+ """
395
+ 2D inverse spectral transform: momentum space position space.
396
+
397
+ Args:
398
+ spectrum: momentum-space spectrum
399
+ hbar: reduced Planck constant
400
+
401
+ Returns:
402
+ Position-space field.
403
+ """
410
404
  if spectrum.ndim >= 2:
411
405
  axes = (0, 1)
412
406
  else:
@@ -416,10 +410,10 @@ class FourierFrame:
416
410
  return np.fft.ifft2(spectrum * denormalization, axes=axes).real
417
411
 
418
412
  @staticmethod
419
- def spectral_transform_2d_gpu(field: np.ndarray, hbar: float = HBAR) -> np.ndarray:
420
- """GPU 加速的二维谱变换"""
421
- if not GPU_AVAILABLE:
422
- raise RuntimeError("CuPy 不可用,无法使用 GPU 加速")
413
+ def spectral_transform_2d_gpu(field: np.ndarray, hbar: float = HBAR) -> np.ndarray:
414
+ """GPU-accelerated 2D spectral transform."""
415
+ if not GPU_AVAILABLE:
416
+ raise RuntimeError("CuPy is unavailable; GPU acceleration not supported")
423
417
 
424
418
  field_gpu = cp.asarray(field)
425
419
  spectrum_gpu = cufft.fft2(field_gpu, axes=(0, 1))
@@ -428,41 +422,41 @@ class FourierFrame:
428
422
  return cp.asnumpy(spectrum_gpu)
429
423
 
430
424
  @classmethod
431
- def from_coord_field(cls, coord_field: List[List], hbar: float = HBAR) -> 'FourierFrameSpectrum':
432
- """
433
- 从坐标场创建谱表示
434
-
435
- 将坐标场的各分量进行谱变换
436
-
437
- Args:
438
- coord_field: 二维坐标场列表 [[coord3, ...], ...]
439
- hbar: 约化普朗克常数
440
-
441
- Returns:
442
- FourierFrameSpectrum 对象
443
- """
444
- ny = len(coord_field)
445
- nx = len(coord_field[0]) if ny > 0 else 0
446
-
447
- # 提取场分量
448
- tensor_field = np.zeros((ny, nx, 12), dtype=np.float64)
449
- for i in range(ny):
450
- for j in range(nx):
425
+ def from_coord_field(cls, coord_field: List[List], hbar: float = HBAR) -> 'FourierFrameSpectrum':
426
+ """
427
+ Create a spectral representation from a coordinate field.
428
+
429
+ Applies spectral transforms to each component of the coordinate field.
430
+
431
+ Args:
432
+ coord_field: 2D coordinate field list [[coord3, ...], ...]
433
+ hbar: reduced Planck constant
434
+
435
+ Returns:
436
+ FourierFrameSpectrum object.
437
+ """
438
+ ny = len(coord_field)
439
+ nx = len(coord_field[0]) if ny > 0 else 0
440
+
441
+ # Extract field components
442
+ tensor_field = np.zeros((ny, nx, 12), dtype=np.float64)
443
+ for i in range(ny):
444
+ for j in range(nx):
451
445
  coord = coord_field[i][j]
452
446
  tensor_field[i, j, 0:3] = [coord.o.x, coord.o.y, coord.o.z]
453
447
  tensor_field[i, j, 3:6] = [coord.ux.x, coord.ux.y, coord.ux.z]
454
448
  tensor_field[i, j, 6:9] = [coord.uy.x, coord.uy.y, coord.uy.z]
455
449
  tensor_field[i, j, 9:12] = [coord.uz.x, coord.uz.y, coord.uz.z]
456
450
 
457
- # 谱变换各分量
458
- origin_spectrum = cls.spectral_transform_2d(tensor_field[..., 0:3], hbar)
459
- ux_spectrum = cls.spectral_transform_2d(tensor_field[..., 3:6], hbar)
460
- uy_spectrum = cls.spectral_transform_2d(tensor_field[..., 6:9], hbar)
461
- uz_spectrum = cls.spectral_transform_2d(tensor_field[..., 9:12], hbar)
462
-
463
- # 动量网格
464
- kx = 2 * np.pi * np.fft.fftfreq(nx) / hbar
465
- ky = 2 * np.pi * np.fft.fftfreq(ny) / hbar
451
+ # Spectral transform per component
452
+ origin_spectrum = cls.spectral_transform_2d(tensor_field[..., 0:3], hbar)
453
+ ux_spectrum = cls.spectral_transform_2d(tensor_field[..., 3:6], hbar)
454
+ uy_spectrum = cls.spectral_transform_2d(tensor_field[..., 6:9], hbar)
455
+ uz_spectrum = cls.spectral_transform_2d(tensor_field[..., 9:12], hbar)
456
+
457
+ # Momentum grid
458
+ kx = 2 * np.pi * np.fft.fftfreq(nx) / hbar
459
+ ky = 2 * np.pi * np.fft.fftfreq(ny) / hbar
466
460
 
467
461
  return FourierFrameSpectrum(
468
462
  ux_spectrum=ux_spectrum,
@@ -475,89 +469,89 @@ class FourierFrame:
475
469
 
476
470
 
477
471
  # ============================================================
478
- # 内禀梯度算子 (Intrinsic Gradient Operator)
472
+ # Intrinsic Gradient Operator
479
473
  # ============================================================
480
474
 
481
- class IntrinsicGradient:
482
- """
483
- 内禀梯度算子 G_μ = d/dx^μ log FourierFrame(x)
484
-
485
- 几何意义(经典谱几何视角):
486
- - 描述标架的局部旋转速率(协变导数的对数形式)
487
- - 对应黎曼几何中的联络1-形式
488
- - 非交换性 [G_μ, G_ν] 直接给出曲率张量
489
-
490
- 数学性质:
491
- - δFourierFrame = G_μ FourierFrame δx^μ (无穷小变换)
492
- - [G_μ, G_ν] = R_{μν} (曲率2-形式)
493
- - γ = ∮ G_μ dx^μ (几何相位 - parallel transport
494
- - Δ = ∇² = ∂_μ ∂^μ (拉普拉斯算子)
495
-
496
- 与量子理论的关系:
497
- - 形式上类似规范场论中的联络,但这里是**纯几何对象**
498
- - Berry相位在这里是经典几何相位(平行输运),非量子效应
499
- - 该理论完全在经典微分几何框架内
500
- """
501
-
502
- def __init__(self, frame_field: Union[Callable, List[List['FourierFrame']]]):
503
- """
504
- 初始化内禀梯度算子
505
-
506
- Args:
507
- frame_field: 标架场,可以是函数或离散场
508
- """
475
+ class IntrinsicGradient:
476
+ """
477
+ Intrinsic gradient operator G_μ = d/dx^μ log FourierFrame(x).
478
+
479
+ Geometric meaning (classical spectral geometry):
480
+ - Describes the local rotation rate of the frame (logarithmic covariant derivative)
481
+ - Corresponds to the connection 1-form in Riemannian geometry
482
+ - Non-commutativity [G_μ, G_ν] yields curvature
483
+
484
+ Properties:
485
+ - δFourierFrame = G_μ FourierFrame δx^μ (infinitesimal transform)
486
+ - [G_μ, G_ν] = R_{μν} (curvature 2-form)
487
+ - γ = ∮ G_μ dx^μ (geometric phase / parallel transport)
488
+ - Δ = ∇² = ∂_μ ∂^μ (Laplacian)
489
+
490
+ Relation to quantum theory:
491
+ - Formally resembles a gauge connection, but here it is purely geometric
492
+ - Berry phase here is a classical geometric phase, not a quantum effect
493
+ - The framework stays within classical differential geometry
494
+ """
495
+
496
+ def __init__(self, frame_field: Union[Callable, List[List['FourierFrame']]]):
497
+ """
498
+ Initialize the intrinsic gradient operator.
499
+
500
+ Args:
501
+ frame_field: frame field, either a function or a discrete field
502
+ """
509
503
  self.frame_field = frame_field
510
504
  self.is_discrete = isinstance(frame_field, list)
511
505
 
512
- def compute_at(self, position: Union[Tuple, int],
513
- direction: int, delta: float = 1e-5) -> complex:
514
- """
515
- 计算指定位置和方向的内禀梯度
516
-
517
- Args:
518
- position: 位置坐标 (连续) 或索引 (离散)
519
- direction: 方向索引 (0=x, 1=y, 2=z)
520
- delta: 有限差分步长
521
-
522
- Returns:
523
- G_μ 的复数值
524
- """
506
+ def compute_at(self, position: Union[Tuple, int],
507
+ direction: int, delta: float = 1e-5) -> complex:
508
+ """
509
+ Compute the intrinsic gradient at a given position and direction.
510
+
511
+ Args:
512
+ position: coordinates (continuous) or indices (discrete)
513
+ direction: direction index (0=x, 1=y, 2=z)
514
+ delta: finite-difference step size
515
+
516
+ Returns:
517
+ Complex value of G_μ.
518
+ """
525
519
  if self.is_discrete:
526
520
  return self._compute_discrete(position, direction)
527
521
  else:
528
522
  return self._compute_continuous(position, direction, delta)
529
523
 
530
- def _compute_discrete(self, idx: Tuple[int, int], direction: int) -> complex:
531
- """离散场的内禀梯度"""
532
- i, j = idx
533
- ny, nx = len(self.frame_field), len(self.frame_field[0])
534
-
535
- # 中心差分
536
- if direction == 0: # x方向
537
- if j + 1 < nx and j - 1 >= 0:
538
- frame_forward = self.frame_field[i][j + 1]
539
- frame_backward = self.frame_field[i][j - 1]
540
- frame_center = self.frame_field[i][j]
524
+ def _compute_discrete(self, idx: Tuple[int, int], direction: int) -> complex:
525
+ """Intrinsic gradient for a discrete field."""
526
+ i, j = idx
527
+ ny, nx = len(self.frame_field), len(self.frame_field[0])
528
+
529
+ # Central difference
530
+ if direction == 0: # x direction
531
+ if j + 1 < nx and j - 1 >= 0:
532
+ frame_forward = self.frame_field[i][j + 1]
533
+ frame_backward = self.frame_field[i][j - 1]
534
+ frame_center = self.frame_field[i][j]
541
535
 
542
536
  # G_x ≈ (log Q_{j+1} - log Q_{j-1}) / 2
543
537
  return (np.log(frame_forward.Q) - np.log(frame_backward.Q)) / 2.0
544
538
 
545
- elif direction == 1: # y方向
546
- if i + 1 < ny and i - 1 >= 0:
547
- frame_forward = self.frame_field[i + 1][j]
548
- frame_backward = self.frame_field[i - 1][j]
539
+ elif direction == 1: # y direction
540
+ if i + 1 < ny and i - 1 >= 0:
541
+ frame_forward = self.frame_field[i + 1][j]
542
+ frame_backward = self.frame_field[i - 1][j]
549
543
 
550
544
  return (np.log(frame_forward.Q) - np.log(frame_backward.Q)) / 2.0
551
545
 
552
546
  return 0.0 + 0j
553
547
 
554
- def _compute_continuous(self, pos: Tuple, direction: int, delta: float) -> complex:
555
- """连续场的内禀梯度"""
556
- pos_list = list(pos)
557
-
558
- # 前向和后向位置
559
- pos_forward = pos_list.copy()
560
- pos_backward = pos_list.copy()
548
+ def _compute_continuous(self, pos: Tuple, direction: int, delta: float) -> complex:
549
+ """Intrinsic gradient for a continuous field."""
550
+ pos_list = list(pos)
551
+
552
+ # Forward and backward positions
553
+ pos_forward = pos_list.copy()
554
+ pos_backward = pos_list.copy()
561
555
  pos_forward[direction] += delta
562
556
  pos_backward[direction] -= delta
563
557
 
@@ -567,136 +561,136 @@ class IntrinsicGradient:
567
561
  # G_μ = d/dx^μ log Frame
568
562
  return (np.log(frame_forward.Q) - np.log(frame_backward.Q)) / (2 * delta)
569
563
 
570
- def commutator(self, pos: Union[Tuple, int],
571
- dir1: int, dir2: int, delta: float = 1e-5) -> complex:
572
- """
573
- 计算李括号 [G_μ, G_ν] = 曲率 R_{μν}
574
-
575
- Args:
576
- pos: 位置
577
- dir1, dir2: 两个方向索引
578
- delta: 有限差分步长
579
-
580
- Returns:
581
- 曲率分量 R_{μν}
582
- """
583
- G_mu = self.compute_at(pos, dir1, delta)
584
- G_nu = self.compute_at(pos, dir2, delta)
585
-
586
- # 简化版本:[G_μ, G_ν] ≈ G_μ G_ν - G_ν G_μ
587
- # 对于阿贝尔情况(标量Q),交换子为0
588
- # 完整实现需要考虑标架场的非阿贝尔结构
589
- return G_mu * G_nu - G_nu * G_mu
590
-
591
- def laplacian(self, position: Union[Tuple[int, int], int]) -> complex:
592
- """
593
- 拉普拉斯算子 Δ = ∇² = ∂²/∂x² + ∂²/∂y²
594
-
595
- 作用于 log FourierFrame
596
- Δ log FourierFrame = ∂²/∂x² log Q + ∂²/∂y² log Q
597
-
598
- 这是谱几何的核心算子,其本征值问题:
599
- Δφ_n = -λ_n φ_n
600
-
601
- 定义了流形的谱(spectrum),从而编码几何信息。
602
-
603
- Args:
604
- position: 网格位置 (i, j) 或索引
605
-
606
- Returns:
607
- 拉普拉斯算子作用结果
608
-
609
- 数学背景:
610
- - 拉普拉斯算子是黎曼流形上的自然微分算子
611
- - 其谱{λ_n}包含流形的几何不变量(Weyl律、热核展开)
612
- - "Can one hear the shape of a drum?" - Kac's问题
613
- """
614
- if not self.is_discrete:
615
- raise NotImplementedError("连续场的拉普拉斯算子需要额外实现")
616
-
617
- if isinstance(position, int):
618
- # 1D情况(简化)
619
- return 0.0 + 0j
620
-
621
- # 使用FourierFrame的静态方法
622
- return FourierFrame.laplacian_from_field(self.frame_field, position[0], position[1])
564
+ def commutator(self, pos: Union[Tuple, int],
565
+ dir1: int, dir2: int, delta: float = 1e-5) -> complex:
566
+ """
567
+ Compute the commutator [G_μ, G_ν] = curvature R_{μν}.
568
+
569
+ Args:
570
+ pos: position
571
+ dir1, dir2: direction indices
572
+ delta: finite-difference step
573
+
574
+ Returns:
575
+ Curvature component R_{μν}.
576
+ """
577
+ G_mu = self.compute_at(pos, dir1, delta)
578
+ G_nu = self.compute_at(pos, dir2, delta)
579
+
580
+ # Simplified: [G_μ, G_ν] ≈ G_μ G_ν - G_ν G_μ
581
+ # For Abelian case (scalar Q), the commutator is zero
582
+ # Full implementation must consider non-Abelian frame structure
583
+ return G_mu * G_nu - G_nu * G_mu
584
+
585
+ def laplacian(self, position: Union[Tuple[int, int], int]) -> complex:
586
+ """
587
+ Laplacian Δ = ∇² = ∂²/∂x² + ∂²/∂y².
588
+
589
+ Applied to log FourierFrame:
590
+ Δ log FourierFrame = ∂²/∂x² log Q + ∂²/∂y² log Q
591
+
592
+ This is the core operator in spectral geometry, with eigenvalue problem:
593
+ Δφ_n = -λ_n φ_n
594
+
595
+ The spectrum encodes geometric information of the manifold.
596
+
597
+ Args:
598
+ position: grid indices (i, j) or index
599
+
600
+ Returns:
601
+ Laplacian result.
602
+
603
+ Background:
604
+ - The Laplacian is a natural differential operator on a Riemannian manifold
605
+ - Its spectrum {λ_n} contains geometric invariants (Weyl law, heat kernel expansion)
606
+ - "Can one hear the shape of a drum?" - Kac's question
607
+ """
608
+ if not self.is_discrete:
609
+ raise NotImplementedError("Laplacian for continuous fields requires additional implementation")
610
+
611
+ if isinstance(position, int):
612
+ # 1D case (simplified)
613
+ return 0.0 + 0j
614
+
615
+ # Use FourierFrame static method
616
+ return FourierFrame.laplacian_from_field(self.frame_field, position[0], position[1])
623
617
 
624
618
 
625
619
  # ============================================================
626
- # 曲率计算 (Curvature from Frames)
620
+ # Curvature from Frames
627
621
  # ============================================================
628
622
 
629
- class CurvatureFromFrame:
630
- """
631
- 从标架场计算曲率
632
-
633
- 核心公式:
634
- - R_{μν} = [G_μ, G_ν] = ∂_μ G_ν - ∂_ν G_μ - [G_μ, G_ν]
635
- - 高斯曲率 K = -⟨[G_u, G_v] e_v, e_u⟩ / √det(g)
636
- - 平均曲率 H = (1/2) Tr(R)
637
- """
638
-
639
- def __init__(self, frame_field: List[List['FourierFrame']]):
640
- """
641
- 初始化曲率计算器
642
-
643
- Args:
644
- frame_field: 离散标架场
645
- """
623
+ class CurvatureFromFrame:
624
+ """
625
+ Compute curvature from a frame field.
626
+
627
+ Core formulas:
628
+ - R_{μν} = [G_μ, G_ν] = ∂_μ G_ν - ∂_ν G_μ - [G_μ, G_ν]
629
+ - Gaussian curvature K = -⟨[G_u, G_v] e_v, e_u⟩ / √det(g)
630
+ - Mean curvature H = (1/2) Tr(R)
631
+ """
632
+
633
+ def __init__(self, frame_field: List[List['FourierFrame']]):
634
+ """
635
+ Initialize curvature calculator.
636
+
637
+ Args:
638
+ frame_field: discrete frame field
639
+ """
646
640
  self.frame_field = frame_field
647
641
  self.gradient_op = IntrinsicGradient(frame_field)
648
642
  self.ny = len(frame_field)
649
643
  self.nx = len(frame_field[0]) if self.ny > 0 else 0
650
644
 
651
- def gaussian_curvature(self, i: int, j: int) -> float:
652
- """
653
- 计算高斯曲率
654
-
655
- K = -⟨[G_u, G_v] e_v, e_u⟩ / √det(g)
656
-
657
- Args:
658
- i, j: 网格索引
659
-
660
- Returns:
661
- 高斯曲率值
662
- """
663
- # 计算李括号 [G_x, G_y]
664
- R_xy = self.gradient_op.commutator((i, j), 0, 1)
665
-
666
- # 简化版本:K ≈ -Im(R_xy) (对于复标架)
667
- # 完整实现需要计算度量张量
668
- return -R_xy.imag
669
-
670
- def mean_curvature(self, i: int, j: int) -> float:
671
- """
672
- 计算平均曲率
673
-
674
- H = (1/2) Tr(R)
675
-
676
- Args:
677
- i, j: 网格索引
678
-
679
- Returns:
680
- 平均曲率值
681
- """
682
- # 简化实现
683
- R_xx = self.gradient_op.commutator((i, j), 0, 0)
684
- R_yy = self.gradient_op.commutator((i, j), 1, 1)
645
+ def gaussian_curvature(self, i: int, j: int) -> float:
646
+ """
647
+ Compute Gaussian curvature.
648
+
649
+ K = -⟨[G_u, G_v] e_v, e_u⟩ / √det(g)
650
+
651
+ Args:
652
+ i, j: grid indices
653
+
654
+ Returns:
655
+ Gaussian curvature value.
656
+ """
657
+ # Commutator [G_x, G_y]
658
+ R_xy = self.gradient_op.commutator((i, j), 0, 1)
659
+
660
+ # Simplified: K ≈ -Im(R_xy) for complex frames
661
+ # Full implementation should compute the metric tensor
662
+ return -R_xy.imag
663
+
664
+ def mean_curvature(self, i: int, j: int) -> float:
665
+ """
666
+ Compute mean curvature.
667
+
668
+ H = (1/2) Tr(R)
669
+
670
+ Args:
671
+ i, j: grid indices
672
+
673
+ Returns:
674
+ Mean curvature value.
675
+ """
676
+ # Simplified implementation
677
+ R_xx = self.gradient_op.commutator((i, j), 0, 0)
678
+ R_yy = self.gradient_op.commutator((i, j), 1, 1)
685
679
 
686
680
  return 0.5 * (R_xx.real + R_yy.real)
687
681
 
688
- def riemann_curvature_tensor(self, i: int, j: int) -> np.ndarray:
689
- """
690
- 计算黎曼曲率张量
691
-
692
- R_{ijkl} = -√det(g) ⟨[G_i, G_j] e_l, e_k⟩
693
-
694
- Args:
695
- i, j: 网格索引
696
-
697
- Returns:
698
- 曲率张量 (2x2 矩阵,简化2D情况)
699
- """
682
+ def riemann_curvature_tensor(self, i: int, j: int) -> np.ndarray:
683
+ """
684
+ Compute the Riemann curvature tensor.
685
+
686
+ R_{ijkl} = -√det(g) ⟨[G_i, G_j] e_l, e_k⟩
687
+
688
+ Args:
689
+ i, j: grid indices
690
+
691
+ Returns:
692
+ Curvature tensor (2×2 matrix, simplified 2D case).
693
+ """
700
694
  R = np.zeros((2, 2), dtype=complex)
701
695
 
702
696
  R[0, 0] = self.gradient_op.commutator((i, j), 0, 0)
@@ -707,45 +701,45 @@ class CurvatureFromFrame:
707
701
  return R
708
702
 
709
703
 
710
- # ============================================================
711
- # 几何相位 (Geometric Phase)
712
- # ============================================================
713
-
714
- class BerryPhase:
715
- """
716
- Berry相位计算
717
-
718
- 几何相位公式:
719
- γ = ∮_C G_μ dx^μ = ∮_C (∂_μ Frame · Frame^{-1}) dx^μ
720
-
721
- 性质:
722
- - 与路径参数化无关
723
- - 仅依赖于路径的几何形状
724
- - 对应曲率的面积分(Stokes定理)
725
- """
726
-
727
- def __init__(self, gradient_operator: IntrinsicGradient):
728
- """
729
- 初始化Berry相位计算器
730
-
731
- Args:
732
- gradient_operator: 内禀梯度算子
733
- """
734
- self.gradient_op = gradient_operator
735
-
736
- def compute_along_path(self, path: List[Tuple], closed: bool = True) -> complex:
737
- """
738
- 沿路径计算Berry相位
739
-
740
- γ = ∮_C G_μ dx^μ
741
-
742
- Args:
743
- path: 路径点列表 [(i1, j1), (i2, j2), ...]
744
- closed: 是否闭合路径
745
-
746
- Returns:
747
- 几何相位(复数)
748
- """
704
+ # ============================================================
705
+ # Geometric Phase
706
+ # ============================================================
707
+
708
+ class BerryPhase:
709
+ """
710
+ Berry phase computation.
711
+
712
+ Geometric phase formula:
713
+ γ = ∮_C G_μ dx^μ = ∮_C (∂_μ Frame · Frame^{-1}) dx^μ
714
+
715
+ Properties:
716
+ - Independent of path parametrization
717
+ - Depends only on the geometry of the path
718
+ - Equals surface integral of curvature (Stokes' theorem)
719
+ """
720
+
721
+ def __init__(self, gradient_operator: IntrinsicGradient):
722
+ """
723
+ Initialize the Berry phase calculator.
724
+
725
+ Args:
726
+ gradient_operator: intrinsic gradient operator
727
+ """
728
+ self.gradient_op = gradient_operator
729
+
730
+ def compute_along_path(self, path: List[Tuple], closed: bool = True) -> complex:
731
+ """
732
+ Compute Berry phase along a path.
733
+
734
+ γ = ∮_C G_μ dx^μ
735
+
736
+ Args:
737
+ path: list of path points [(i1, j1), (i2, j2), ...]
738
+ closed: whether to close the path
739
+
740
+ Returns:
741
+ Geometric phase (complex).
742
+ """
749
743
  if len(path) < 2:
750
744
  return 0.0 + 0j
751
745
 
@@ -755,24 +749,24 @@ class BerryPhase:
755
749
  pos_current = path[k]
756
750
  pos_next = path[k + 1]
757
751
 
758
- # 确定方向
759
- dx = pos_next[0] - pos_current[0]
760
- dy = pos_next[1] - pos_current[1]
761
-
762
- # 计算梯度分量
763
- if abs(dx) > abs(dy):
764
- direction = 0 # x方向
765
- step = dx
766
- else:
767
- direction = 1 # y方向
768
- step = dy
752
+ # Determine direction
753
+ dx = pos_next[0] - pos_current[0]
754
+ dy = pos_next[1] - pos_current[1]
755
+
756
+ # Compute gradient component
757
+ if abs(dx) > abs(dy):
758
+ direction = 0 # x direction
759
+ step = dx
760
+ else:
761
+ direction = 1 # y direction
762
+ step = dy
769
763
 
770
764
  # G_μ dx^μ
771
765
  G_mu = self.gradient_op.compute_at(pos_current, direction)
772
766
  phase += G_mu * step
773
767
 
774
- # 闭合路径
775
- if closed and len(path) > 2:
768
+ # Close the path
769
+ if closed and len(path) > 2:
776
770
  pos_last = path[-1]
777
771
  pos_first = path[0]
778
772
 
@@ -792,157 +786,153 @@ class BerryPhase:
792
786
  return phase
793
787
 
794
788
 
795
- # ============================================================
796
- # 陈数 (Chern Number)
797
- # ============================================================
798
-
799
- class ChernNumber:
800
- """
801
- 第一陈数计算
802
-
803
- 拓扑不变量:
804
- c₁ = (1/2π) ∬_M R_{μν} dS^{μν}
805
- = (1/2π) ∬_M Tr([G_μ, G_ν]) dS^{μν}
806
-
807
- 物理意义:
808
- - 刻画纤维丛的拓扑性质
809
- - 量子霍尔效应中的拓扑不变量
810
- - Berry相位的关联(Stokes定理)
811
- """
812
-
813
- def __init__(self, curvature_calculator: CurvatureFromFrame):
814
- """
815
- 初始化陈数计算器
816
-
817
- Args:
818
- curvature_calculator: 曲率计算器
819
- """
820
- self.curvature = curvature_calculator
821
-
822
- def compute(self) -> float:
823
- """
824
- 计算第一陈数
825
-
826
- c₁ = (1/2π) Σ_{ij} R_{xy}(i,j) ΔS
827
-
828
- Returns:
829
- 陈数(实数)
830
- """
789
+ # ============================================================
790
+ # Chern Number
791
+ # ============================================================
792
+
793
+ class ChernNumber:
794
+ """
795
+ First Chern number computation.
796
+
797
+ Topological invariant:
798
+ c₁ = (1/2π) ∬_M R_{μν} dS^{μν}
799
+ = (1/2π) ∬_M Tr([G_μ, G_ν]) dS^{μν}
800
+
801
+ Physical meaning:
802
+ - Characterizes the topology of the fiber bundle
803
+ - Topological invariant in the quantum Hall effect
804
+ - Related to Berry phase via Stokes' theorem
805
+ """
806
+
807
+ def __init__(self, curvature_calculator: CurvatureFromFrame):
808
+ """
809
+ Initialize the Chern number calculator.
810
+
811
+ Args:
812
+ curvature_calculator: curvature calculator
813
+ """
814
+ self.curvature = curvature_calculator
815
+
816
+ def compute(self) -> float:
817
+ """
818
+ Compute the first Chern number.
819
+
820
+ c₁ = (1/2π) Σ_{ij} R_{xy}(i,j) ΔS
821
+
822
+ Returns:
823
+ Chern number (real).
824
+ """
831
825
  total = 0.0 + 0j
832
826
 
833
827
  ny, nx = self.curvature.ny, self.curvature.nx
834
828
 
835
829
  for i in range(1, ny - 1):
836
830
  for j in range(1, nx - 1):
837
- # 曲率 R_{xy}
838
- R_xy = self.curvature.gradient_op.commutator((i, j), 0, 1)
839
- total += R_xy
840
-
841
- # 归一化
842
- c1 = total / (2 * np.pi)
843
-
844
- # 陈数应为整数(拓扑不变量)
845
- return round(c1.real)
846
-
847
-
848
- # ============================================================
849
- # 谱分解 (Spectral Decomposition)
850
- # ============================================================
851
-
852
- class SpectralDecomposition:
853
- """
854
- 拉普拉斯算子的谱分解(经典几何谱理论)
855
-
856
- 数学框架:
857
- 拉普拉斯本征值问题:
858
- Δφ_n = -λ_n φ_n
859
- ∫ φ_m φ_n dV = δ_{mn}
860
-
861
- 谱分解定理:
862
- Δ = -Σ_n λ_n |φ_n⟩⟨φ_n|
863
-
864
- **FourierFrame作为本征态基础**:
865
- 在我们的框架中,FourierFrame场可展开为本征态的叠加:
866
-
867
- FourierFrame(x) = Σ_n c_n φ_n(x) FourierFrame_n
868
-
869
- 其中:
870
- - φ_n(x) 是拉普拉斯算子的标量本征函数
871
- - FourierFrame_n 是对应的标架本征态
872
- - c_n = ⟨φ_n | FourierFrame⟩ 是展开系数
873
-
874
- 谱的几何意义:
875
- - {λ_n} 编码流形的几何信息(形状DNA)
876
- - 低频模式(小λ)对应大尺度几何特征
877
- - 高频模式(大λ)对应局部细节
878
-
879
- Weyl渐近律:
880
- N(λ) ~ (ω_d / (2π)^d) Vol(M) λ^{d/2}
881
-
882
- 其中 N(λ) 是小于λ的本征值个数。
883
-
884
- 应用:
885
- - ShapeDNA:谱签名用于形状识别
886
- - 谱距离:流形间的几何距离度量
887
- - 多尺度分析:不同频段的几何特征
888
- - 热核展开:Tr(e^{tΔ}) = Σ_n e^{-tλ_n}
889
- """
890
-
891
- def __init__(self, frame_field: Union[List[List['FourierFrame']], 'FourierFrameSpectrum']):
892
- """
893
- 初始化谱分解
894
-
895
- Args:
896
- frame_field: FourierFrame场或其频谱表示
897
- """
898
- if isinstance(frame_field, list):
899
- # 离散标架场
900
- self.frame_field = frame_field
901
- self.gradient_op = IntrinsicGradient(frame_field)
902
- self.ny = len(frame_field)
903
- self.nx = len(frame_field[0]) if self.ny > 0 else 0
904
- self.spectrum = None
905
- else:
906
- # 频谱表示
907
- self.spectrum = frame_field
908
- self.frame_field = None
909
- self.gradient_op = None
910
- self.ny, self.nx = frame_field.shape
831
+ # Curvature R_{xy}
832
+ R_xy = self.curvature.gradient_op.commutator((i, j), 0, 1)
833
+ total += R_xy
834
+
835
+ # Normalize
836
+ c1 = total / (2 * np.pi)
837
+
838
+ # Chern number should be an integer (topological invariant)
839
+ return round(c1.real)
840
+
841
+
842
+ # ============================================================
843
+ # Spectral Decomposition
844
+ # ============================================================
845
+
846
+ class SpectralDecomposition:
847
+ """
848
+ Spectral decomposition of the Laplacian (classical spectral geometry).
849
+
850
+ Framework:
851
+ Laplacian eigenvalue problem:
852
+ Δφ_n = -λ_n φ_n
853
+ ∫ φ_m φ_n dV = δ_{mn}
854
+
855
+ Spectral decomposition theorem:
856
+ Δ = -Σ_n λ_n |φ_n⟩⟨φ_n|
857
+
858
+ FourierFrame as eigenstate basis:
859
+ FourierFrame(x) = Σ_n c_n φ_n(x) FourierFrame_n
860
+
861
+ Where:
862
+ - φ_n(x) are scalar Laplacian eigenfunctions
863
+ - FourierFrame_n are frame eigenstates
864
+ - c_n = ⟨φ_n | FourierFrame⟩ are expansion coefficients
865
+
866
+ Geometric meaning:
867
+ - {λ_n} encodes geometry (ShapeDNA)
868
+ - low-frequency modes (small λ) capture large-scale features
869
+ - high-frequency modes (large λ) capture local detail
870
+
871
+ Weyl asymptotics:
872
+ N(λ) ~ (ω_d / (2π)^d) Vol(M) λ^{d/2}
873
+
874
+ Applications:
875
+ - ShapeDNA: spectral signature for shape recognition
876
+ - Spectral distance: geometric distance between manifolds
877
+ - Multiscale analysis: geometry in different frequency bands
878
+ - Heat kernel trace: Tr(e^{tΔ}) = Σ_n e^{-tλ_n}
879
+ """
880
+
881
+ def __init__(self, frame_field: Union[List[List['FourierFrame']], 'FourierFrameSpectrum']):
882
+ """
883
+ Initialize spectral decomposition.
884
+
885
+ Args:
886
+ frame_field: FourierFrame field or its spectral representation
887
+ """
888
+ if isinstance(frame_field, list):
889
+ # Discrete frame field
890
+ self.frame_field = frame_field
891
+ self.gradient_op = IntrinsicGradient(frame_field)
892
+ self.ny = len(frame_field)
893
+ self.nx = len(frame_field[0]) if self.ny > 0 else 0
894
+ self.spectrum = None
895
+ else:
896
+ # Spectral representation
897
+ self.spectrum = frame_field
898
+ self.frame_field = None
899
+ self.gradient_op = None
900
+ self.ny, self.nx = frame_field.shape
911
901
 
912
902
  self._eigenvalues = None
913
903
  self._eigenvectors = None
914
904
 
915
- def compute_eigenspectrum(self) -> Tuple[np.ndarray, Optional[np.ndarray]]:
916
- """
917
- 计算拉普拉斯算子的本征谱
918
-
919
- Returns:
920
- (eigenvalues, eigenvectors)
921
- - eigenvalues: λ_n 数组(降序排列)
922
- - eigenvectors: 本征函数φ_n(简化实现可能为None
923
-
924
- 数值方法:
925
- 对于频谱表示,本征值对应 k² = |k|²
926
- 对于离散场,需要构造拉普拉斯矩阵并求解
927
- """
905
+ def compute_eigenspectrum(self) -> Tuple[np.ndarray, Optional[np.ndarray]]:
906
+ """
907
+ Compute the Laplacian eigenspectrum.
908
+
909
+ Returns:
910
+ (eigenvalues, eigenvectors)
911
+ - eigenvalues: λ_n array (descending)
912
+ - eigenvectors: eigenfunctions φ_n (may be None in simplified mode)
913
+
914
+ Numerical notes:
915
+ - Spectral representation: eigenvalues correspond to k² = |k|²
916
+ - Discrete field: requires Laplacian matrix and numerical solve
917
+ """
928
918
  if self._eigenvalues is not None:
929
919
  return self._eigenvalues, self._eigenvectors
930
920
 
931
- if self.spectrum is not None:
932
- # 频谱表示:本征值 = k²
933
- kx, ky = self.spectrum.momentum_grid
934
- k2 = kx[:, None]**2 + ky[None, :]**2
935
-
936
- # 展平并排序(降序)
937
- eigenvalues = np.sort(k2.flatten())[::-1]
921
+ if self.spectrum is not None:
922
+ # Spectral representation: eigenvalues = k²
923
+ kx, ky = self.spectrum.momentum_grid
924
+ k2 = kx[:, None]**2 + ky[None, :]**2
925
+
926
+ # Flatten and sort (descending)
927
+ eigenvalues = np.sort(k2.flatten())[::-1]
938
928
 
939
929
  self._eigenvalues = eigenvalues
940
930
  self._eigenvectors = None
941
931
 
942
- elif self.frame_field is not None:
943
- # 离散场:估算本征值
944
- # 完整实现需要构造拉普拉斯矩阵并数值求解
945
- eigenvalues_list = []
932
+ elif self.frame_field is not None:
933
+ # Discrete field: approximate eigenvalues
934
+ # Full implementation needs Laplacian matrix and numerical solve
935
+ eigenvalues_list = []
946
936
 
947
937
  for i in range(1, self.ny - 1):
948
938
  for j in range(1, self.nx - 1):
@@ -955,52 +945,52 @@ class SpectralDecomposition:
955
945
 
956
946
  return self._eigenvalues, self._eigenvectors
957
947
 
958
- def expand_frame_in_eigenbasis(self, frame: 'FourierFrame',
959
- n_modes: int = 10) -> np.ndarray:
960
- """
961
- FourierFrame展开到本征态基底
962
-
963
- FourierFrame = Σ_n c_n FourierFrame_n
964
-
965
- Args:
966
- frame: 要展开的FourierFrame
967
- n_modes: 使用的模式数量
968
-
969
- Returns:
970
- 展开系数 c_n
971
-
972
- 数学细节:
973
- c_n = ∫ φ_n*(x) FourierFrame(x) dV
974
-
975
- 简化实现:使用傅里叶系数作为近似
976
- """
977
- eigenvalues, _ = self.compute_eigenspectrum()
978
-
979
- # 简化:使用FourierFrameQ因子
980
- coefficients = np.zeros(n_modes, dtype=complex)
981
- q_value = frame.Q
982
-
983
- for n in range(min(n_modes, len(eigenvalues))):
984
- # 简化投影:c_n ∝ Q / √λ_n
985
- if eigenvalues[n] > 0:
986
- coefficients[n] = q_value / np.sqrt(eigenvalues[n])
948
+ def expand_frame_in_eigenbasis(self, frame: 'FourierFrame',
949
+ n_modes: int = 10) -> np.ndarray:
950
+ """
951
+ Expand FourierFrame in the eigenbasis.
952
+
953
+ FourierFrame = Σ_n c_n FourierFrame_n
954
+
955
+ Args:
956
+ frame: FourierFrame to expand
957
+ n_modes: number of modes
958
+
959
+ Returns:
960
+ Expansion coefficients c_n.
961
+
962
+ Notes:
963
+ c_n = ∫ φ_n*(x) FourierFrame(x) dV
964
+
965
+ Simplified implementation uses Fourier coefficients as an approximation.
966
+ """
967
+ eigenvalues, _ = self.compute_eigenspectrum()
968
+
969
+ # Simplified: use FourierFrame Q factor
970
+ coefficients = np.zeros(n_modes, dtype=complex)
971
+ q_value = frame.Q
972
+
973
+ for n in range(min(n_modes, len(eigenvalues))):
974
+ # Simplified projection: c_n ∝ Q / √λ_n
975
+ if eigenvalues[n] > 0:
976
+ coefficients[n] = q_value / np.sqrt(eigenvalues[n])
987
977
 
988
978
  return coefficients
989
979
 
990
- def reconstruct_from_modes(self, coefficients: np.ndarray,
991
- base_frame: 'FourierFrame') -> 'FourierFrame':
992
- """
993
- 从本征模式重建FourierFrame
994
-
995
- FourierFrame = Σ_n c_n FourierFrame_n
996
-
997
- Args:
998
- coefficients: 展开系数
999
- base_frame: 基础标架
1000
-
1001
- Returns:
1002
- 重建的FourierFrame
1003
- """
980
+ def reconstruct_from_modes(self, coefficients: np.ndarray,
981
+ base_frame: 'FourierFrame') -> 'FourierFrame':
982
+ """
983
+ Reconstruct FourierFrame from eigenmodes.
984
+
985
+ FourierFrame = Σ_n c_n FourierFrame_n
986
+
987
+ Args:
988
+ coefficients: expansion coefficients
989
+ base_frame: base frame
990
+
991
+ Returns:
992
+ Reconstructed FourierFrame.
993
+ """
1004
994
  eigenvalues, _ = self.compute_eigenspectrum()
1005
995
 
1006
996
  reconstructed_Q = 0.0 + 0j
@@ -1010,166 +1000,161 @@ class SpectralDecomposition:
1010
1000
 
1011
1001
  return FourierFrame(base_frame.base, reconstructed_Q)
1012
1002
 
1013
- def weyl_counting(self, lambda_threshold: float) -> int:
1014
- """
1015
- Weyl渐近计数函数
1016
-
1017
- N(λ) = #{n : λ_n < λ} (小于λ的本征值个数)
1018
-
1019
- Weyl律:
1020
- N(λ) ~ (ω_d / (2π)^d) Vol(M) λ^{d/2} (λ → ∞)
1021
-
1022
- 对于2维流形:N(λ) ~ (1/4π) Area(M) λ
1023
-
1024
- Args:
1025
- lambda_threshold: 本征值阈值λ
1026
-
1027
- Returns:
1028
- N(λ) - 本征值个数
1029
- """
1003
+ def weyl_counting(self, lambda_threshold: float) -> int:
1004
+ """
1005
+ Weyl asymptotic counting function.
1006
+
1007
+ N(λ) = #{n : λ_n < λ} (number of eigenvalues below λ)
1008
+
1009
+ Weyl law:
1010
+ N(λ) ~ (ω_d / (2π)^d) Vol(M) λ^{d/2} (λ → ∞)
1011
+
1012
+ For 2D manifolds: N(λ) ~ (1/4π) Area(M) λ
1013
+
1014
+ Args:
1015
+ lambda_threshold: eigenvalue threshold λ
1016
+
1017
+ Returns:
1018
+ N(λ) - eigenvalue count
1019
+ """
1030
1020
  eigenvalues, _ = self.compute_eigenspectrum()
1031
1021
  return int(np.sum(eigenvalues < lambda_threshold))
1032
1022
 
1033
- def shape_dna(self, n_modes: int = 50) -> np.ndarray:
1034
- """
1035
- 形状DNA(ShapeDNA)- 流形的谱签名
1036
-
1037
- n个本征值 {λ_1, λ_2, ..., λ_n} 唯一标识流形的几何形状
1038
- (在同谱异构的情况下)
1039
-
1040
- 这是谱几何中的核心概念:
1041
- "Can one hear the shape of a drum?" - Mark Kac (1966)
1042
-
1043
- 对于2维流形,谱通常可以听出形状,但存在反例
1044
- Gordon-Webb-Wolpert, 1992
1045
-
1046
- Args:
1047
- n_modes: 模式数量(默认50
1048
-
1049
- Returns:
1050
- n个本征值构成的谱签名
1051
-
1052
- 应用:
1053
- - 形状识别与检索
1054
- - 几何相似性度量
1055
- - 拓扑不变量提取
1056
- """
1023
+ def shape_dna(self, n_modes: int = 50) -> np.ndarray:
1024
+ """
1025
+ ShapeDNA: spectral signature of a manifold.
1026
+
1027
+ The first n eigenvalues {λ_1, λ_2, ..., λ_n} encode geometric shape
1028
+ (up to isospectral non-isometries).
1029
+
1030
+ Classic question in spectral geometry:
1031
+ "Can one hear the shape of a drum?" - Mark Kac (1966)
1032
+
1033
+ For 2D manifolds, spectra often distinguish shapes, with known counterexamples
1034
+ (Gordon-Webb-Wolpert, 1992).
1035
+
1036
+ Args:
1037
+ n_modes: number of modes (default 50)
1038
+
1039
+ Returns:
1040
+ Spectral signature of the first n eigenvalues.
1041
+
1042
+ Applications:
1043
+ - Shape recognition and retrieval
1044
+ - Geometric similarity metrics
1045
+ - Topological invariant extraction
1046
+ """
1057
1047
  eigenvalues, _ = self.compute_eigenspectrum()
1058
1048
  return eigenvalues[:n_modes]
1059
1049
 
1060
1050
 
1061
- # ============================================================
1062
- # 热核 (Heat Kernel)
1063
- # ============================================================
1064
-
1065
- class HeatKernel:
1066
- """
1067
- 热核 - 热方程的基本解(经典几何谱分析)
1068
-
1069
- 数学定义:
1070
- ∂u/∂t = Δu (热方程)
1071
- K(x, y, t) = 基本解满足: ∂K/∂t = Δ_x K, K(x,y,0) = δ(x-y)
1072
-
1073
- 热核的谱展开:
1074
- K(x, y, t) = Σ_n e^{-λ_n t} φ_n(x) φ_n(y)
1075
-
1076
- 其中 {λ_n, φ_n} 是拉普拉斯算子 Δφ_n = -λ_n φ_n 的本征系统。
1077
-
1078
- 热核迹的渐近展开(Minakshisundaram-Pleijel):
1079
- Tr(e^{tΔ}) ~ (4πt)^{-d/2} Σ_k a_k t^k
1080
-
1081
- 热核系数 {a_k} 编码流形的几何不变量:
1082
- - a₀ = Vol(M) (体积)
1083
- - a₁ ∝ ∫ R dV (曲率积分)
1084
- - a₂ ∝ ∫ (R² + 其他曲率不变量) dV
1085
-
1086
- **FourierFrame作为数学基础**:
1087
- 在我们的框架中,热核作为FourierFrame在扩散过程中的演化算子:
1088
-
1089
- FourierFrame(x, t) = ∫ K(x, y, t) FourierFrame(y, 0) dy
1090
- = e^{tΔ} FourierFrame(x, 0)
1091
-
1092
- 这将FourierFrame场视为"温度分布",热核描述其扩散传播。
1093
-
1094
- **与量子理论的关系及局限性**:
1095
- - 热核在形式上等价于量子力学的虚时间传播子(Wick旋转)
1096
- - 但这里是**纯几何**的扩散过程,非量子演化
1097
- - 不涉及态矢量、算符期望值等量子概念
1098
- - 适用于经典计算机的数值计算
1099
-
1100
- 应用:
1101
- - 形状识别(ShapeDNA)
1102
- - 几何不变量提取
1103
- - 多尺度几何分析
1104
- - 流形谱距离
1105
- """
1106
-
1107
- def __init__(self, frame_field: Union[List[List['FourierFrame']], 'FourierFrameSpectrum']):
1108
- """
1109
- 初始化热核
1110
-
1111
- Args:
1112
- frame_field: FourierFrame场(离散)或其频谱表示
1113
- """
1114
- if isinstance(frame_field, list):
1115
- # 离散标架场
1116
- self.frame_field = frame_field
1117
- self.gradient_op = IntrinsicGradient(frame_field)
1118
- self.ny = len(frame_field)
1119
- self.nx = len(frame_field[0]) if self.ny > 0 else 0
1120
- self.spectrum = None
1121
- else:
1122
- # 频谱表示
1123
- self.spectrum = frame_field
1124
- self.frame_field = None
1125
- self.gradient_op = None
1126
- self.ny, self.nx = frame_field.shape
1127
-
1128
- def evolution_operator(self, t: float, kappa: float = 1.0) -> Union[np.ndarray, List[List['FourierFrame']]]:
1129
- """
1130
- 热核演化算子: e^{tκΔ} FourierFrame
1131
-
1132
- 计算标架场在时间t后的扩散状态。
1133
-
1134
- Args:
1135
- t: 扩散时间(>0)
1136
- kappa: 扩散系数(默认1.0)
1137
-
1138
- Returns:
1139
- 演化后的标架场
1140
-
1141
- 数学细节:
1142
- 在频域中,热核演化简单地是:
1143
- FourierFrame(k, t) = e^{-κt|k|²} FourierFrame(k, 0)
1144
-
1145
- 这是高频抑制(低通滤波),对应空间的平滑化。
1146
- """
1147
- if t < 0:
1148
- raise ValueError("扩散时间必须非负")
1149
-
1150
- if self.frame_field is not None:
1151
- # 离散场:逐点演化
1152
- evolved_field = []
1153
- for i in range(self.ny):
1154
- row = []
1155
- for j in range(self.nx):
1156
- evolved_frame = self.frame_field[i][j].diffusion_evolution(t, kappa)
1051
+ # ============================================================
1052
+ # Heat Kernel
1053
+ # ============================================================
1054
+
1055
+ class HeatKernel:
1056
+ """
1057
+ Heat kernel: fundamental solution of the heat equation (classical spectral geometry).
1058
+
1059
+ Definition:
1060
+ ∂u/∂t = Δu (heat equation)
1061
+ K(x, y, t) satisfies ∂K/∂t = Δ_x K, with K(x,y,0) = δ(x-y)
1062
+
1063
+ Spectral expansion:
1064
+ K(x, y, t) = Σ_n e^{-λ_n t} φ_n(x) φ_n(y)
1065
+
1066
+ where {λ_n, φ_n} are eigenpairs of the Laplacian Δφ_n = -λ_n φ_n.
1067
+
1068
+ Heat trace asymptotics (Minakshisundaram-Pleijel):
1069
+ Tr(e^{tΔ}) ~ (4πt)^{-d/2} Σ_k a_k t^k
1070
+
1071
+ Heat kernel coefficients {a_k} encode geometric invariants:
1072
+ - a₀ = Vol(M) (volume)
1073
+ - a₁ ∝ ∫ R dV (curvature integral)
1074
+ - a₂ ∝ ∫ (R² + other invariants) dV
1075
+
1076
+ FourierFrame basis:
1077
+ FourierFrame(x, t) = ∫ K(x, y, t) FourierFrame(y, 0) dy
1078
+ = e^{tΔ} FourierFrame(x, 0)
1079
+
1080
+ Relation to quantum theory:
1081
+ - Formally analogous to imaginary-time propagators (Wick rotation)
1082
+ - Here it is purely geometric diffusion, not quantum evolution
1083
+ - No state vectors or operator expectations
1084
+ - Suitable for classical numerical computation
1085
+
1086
+ Applications:
1087
+ - Shape recognition (ShapeDNA)
1088
+ - Geometric invariant extraction
1089
+ - Multiscale geometric analysis
1090
+ - Spectral distance between manifolds
1091
+ """
1092
+
1093
+ def __init__(self, frame_field: Union[List[List['FourierFrame']], 'FourierFrameSpectrum']):
1094
+ """
1095
+ Initialize the heat kernel.
1096
+
1097
+ Args:
1098
+ frame_field: discrete FourierFrame field or its spectral representation
1099
+ """
1100
+ if isinstance(frame_field, list):
1101
+ # Discrete frame field
1102
+ self.frame_field = frame_field
1103
+ self.gradient_op = IntrinsicGradient(frame_field)
1104
+ self.ny = len(frame_field)
1105
+ self.nx = len(frame_field[0]) if self.ny > 0 else 0
1106
+ self.spectrum = None
1107
+ else:
1108
+ # Spectral representation
1109
+ self.spectrum = frame_field
1110
+ self.frame_field = None
1111
+ self.gradient_op = None
1112
+ self.ny, self.nx = frame_field.shape
1113
+
1114
+ def evolution_operator(self, t: float, kappa: float = 1.0) -> Union[np.ndarray, List[List['FourierFrame']]]:
1115
+ """
1116
+ Heat kernel evolution operator: e^{tκΔ} FourierFrame.
1117
+
1118
+ Computes the diffused frame field at time t.
1119
+
1120
+ Args:
1121
+ t: diffusion time (>0)
1122
+ kappa: diffusion coefficient (default 1.0)
1123
+
1124
+ Returns:
1125
+ Evolved frame field.
1126
+
1127
+ In frequency domain:
1128
+ FourierFrame(k, t) = e^{-κt|k|²} FourierFrame(k, 0)
1129
+
1130
+ This suppresses high frequencies (low-pass filtering), i.e., spatial smoothing.
1131
+ """
1132
+ if t < 0:
1133
+ raise ValueError("Diffusion time must be non-negative")
1134
+
1135
+ if self.frame_field is not None:
1136
+ # Discrete field: pointwise evolution
1137
+ evolved_field = []
1138
+ for i in range(self.ny):
1139
+ row = []
1140
+ for j in range(self.nx):
1141
+ evolved_frame = self.frame_field[i][j].diffusion_evolution(t, kappa)
1157
1142
  row.append(evolved_frame)
1158
1143
  evolved_field.append(row)
1159
1144
  return evolved_field
1160
1145
 
1161
- elif self.spectrum is not None:
1162
- # 频谱表示:频域衰减
1163
- kx, ky = self.spectrum.momentum_grid
1164
- k2 = kx[:, None]**2 + ky[None, :]**2
1165
-
1166
- # e^{-κt k²} 衰减因子
1167
- decay = np.exp(-kappa * t * k2)
1168
-
1169
- # 应用到各分量
1170
- evolved_spectrum = FourierFrameSpectrum(
1171
- ux_spectrum=self.spectrum.ux_spectrum * decay[..., None],
1172
- uy_spectrum=self.spectrum.uy_spectrum * decay[..., None],
1146
+ elif self.spectrum is not None:
1147
+ # Spectral representation: frequency-domain decay
1148
+ kx, ky = self.spectrum.momentum_grid
1149
+ k2 = kx[:, None]**2 + ky[None, :]**2
1150
+
1151
+ # e^{-κt k²} decay factor
1152
+ decay = np.exp(-kappa * t * k2)
1153
+
1154
+ # Apply to each component
1155
+ evolved_spectrum = FourierFrameSpectrum(
1156
+ ux_spectrum=self.spectrum.ux_spectrum * decay[..., None],
1157
+ uy_spectrum=self.spectrum.uy_spectrum * decay[..., None],
1173
1158
  uz_spectrum=self.spectrum.uz_spectrum * decay[..., None],
1174
1159
  origin_spectrum=self.spectrum.origin_spectrum * decay[..., None],
1175
1160
  momentum_grid=self.spectrum.momentum_grid,
@@ -1177,73 +1162,73 @@ class HeatKernel:
1177
1162
  )
1178
1163
  return evolved_spectrum
1179
1164
 
1180
- else:
1181
- raise ValueError("需要提供标架场或频谱")
1182
-
1183
- def trace(self, t: float, kappa: float = 1.0) -> float:
1184
- """
1185
- 热核迹:Tr(e^{tκΔ}) = Σ_n e^{-κt λ_n}
1186
-
1187
- 这是几何信息的凝聚,包含流形谱的全部信息。
1188
-
1189
- Args:
1190
- t: 扩散时间
1191
- kappa: 扩散系数
1192
-
1193
- Returns:
1194
- 热核迹值
1195
- """
1196
- if self.spectrum is not None:
1197
- # 使用频谱表示
1198
- density = self.spectrum.spectral_density()
1199
- kx, ky = self.spectrum.momentum_grid
1200
- k2 = kx[:, None]**2 + ky[None, :]**2
1201
-
1202
- # Tr(e^{-κt Δ}) = Σ e^{-κt k²}
1203
- trace_val = np.sum(np.exp(-kappa * t * k2))
1204
- return float(trace_val)
1205
-
1206
- elif self.frame_field is not None:
1207
- # 简化估计:使用标架场的"能量"
1208
- total = 0.0
1209
- for i in range(self.ny):
1210
- for j in range(self.nx):
1211
- laplacian = self.gradient_op.laplacian((i, j))
1212
- # e^{-t λ} ≈ 1 - tλ (小t近似)
1213
- total += np.exp(-kappa * t * abs(laplacian))
1214
- return total
1165
+ else:
1166
+ raise ValueError("Provide a frame field or spectrum")
1167
+
1168
+ def trace(self, t: float, kappa: float = 1.0) -> float:
1169
+ """
1170
+ Heat trace: Tr(e^{tκΔ}) = Σ_n e^{-κt λ_n}.
1171
+
1172
+ This aggregates spectral information of the manifold.
1173
+
1174
+ Args:
1175
+ t: diffusion time
1176
+ kappa: diffusion coefficient
1177
+
1178
+ Returns:
1179
+ Heat trace value.
1180
+ """
1181
+ if self.spectrum is not None:
1182
+ # Use spectral representation
1183
+ density = self.spectrum.spectral_density()
1184
+ kx, ky = self.spectrum.momentum_grid
1185
+ k2 = kx[:, None]**2 + ky[None, :]**2
1186
+
1187
+ # Tr(e^{-κt Δ}) = Σ e^{-κt k²}
1188
+ trace_val = np.sum(np.exp(-kappa * t * k2))
1189
+ return float(trace_val)
1190
+
1191
+ elif self.frame_field is not None:
1192
+ # Simplified estimate: use frame-field "energy"
1193
+ total = 0.0
1194
+ for i in range(self.ny):
1195
+ for j in range(self.nx):
1196
+ laplacian = self.gradient_op.laplacian((i, j))
1197
+ # e^{-t λ} ≈ 1 - tλ (small-t approximation)
1198
+ total += np.exp(-kappa * t * abs(laplacian))
1199
+ return total
1215
1200
 
1216
1201
  return 0.0
1217
1202
 
1218
- def asymptotic_expansion(self, t: float, kappa: float = 1.0, order: int = 2) -> float:
1219
- """
1220
- 热核迹的渐近展开(Minakshisundaram-Pleijel公式)
1221
-
1222
- Tr(e^{tκΔ}) ~ (4πκt)^{-d/2} [a₀ + a₁(κt) + a₂(κt)² + ...]
1223
-
1224
- Args:
1225
- t: 扩散时间(小t渐近)
1226
- kappa: 扩散系数
1227
- order: 展开阶数(默认2
1228
-
1229
- Returns:
1230
- 渐近估计值
1231
-
1232
- 几何意义:
1233
- - a₀ = Vol(M) - 流形体积
1234
- - a₁ ∝ ∫ R dV - 标量曲率积分
1235
- - a₂ ∝ ∫ (R² - |Ric|² + ...) dV - 更高阶曲率不变量
1236
- """
1237
- d = 2 # 2维流形
1238
- prefactor = (4 * np.pi * kappa * t) ** (-d / 2)
1239
-
1240
- # 估算热核系数
1241
- a0 = float(self.ny * self.nx) # 体积(网格点数)
1242
-
1243
- # a₁ 需要曲率信息
1244
- if self.gradient_op is not None:
1245
- curvature_sum = 0.0
1246
- for i in range(1, self.ny - 1):
1203
+ def asymptotic_expansion(self, t: float, kappa: float = 1.0, order: int = 2) -> float:
1204
+ """
1205
+ Asymptotic expansion of heat trace (Minakshisundaram-Pleijel).
1206
+
1207
+ Tr(e^{tκΔ}) ~ (4πκt)^{-d/2} [a₀ + a₁(κt) + a₂(κt)² + ...]
1208
+
1209
+ Args:
1210
+ t: diffusion time (small-t asymptotic)
1211
+ kappa: diffusion coefficient
1212
+ order: expansion order (default 2)
1213
+
1214
+ Returns:
1215
+ Asymptotic estimate.
1216
+
1217
+ Geometric meaning:
1218
+ - a₀ = Vol(M) - manifold volume
1219
+ - a₁ ∝ ∫ R dV - scalar curvature integral
1220
+ - a₂ ∝ ∫ (R² - |Ric|² + ...) dV - higher-order invariants
1221
+ """
1222
+ d = 2 # 2D manifold
1223
+ prefactor = (4 * np.pi * kappa * t) ** (-d / 2)
1224
+
1225
+ # Estimate heat kernel coefficients
1226
+ a0 = float(self.ny * self.nx) # volume (grid points)
1227
+
1228
+ # a₁ needs curvature information
1229
+ if self.gradient_op is not None:
1230
+ curvature_sum = 0.0
1231
+ for i in range(1, self.ny - 1):
1247
1232
  for j in range(1, self.nx - 1):
1248
1233
  R_xy = self.gradient_op.commutator((i, j), 0, 1)
1249
1234
  curvature_sum += abs(R_xy)
@@ -1251,10 +1236,10 @@ class HeatKernel:
1251
1236
  else:
1252
1237
  a1 = 0.0
1253
1238
 
1254
- a2 = 0.0 # 简化
1255
-
1256
- # 渐近级数
1257
- expansion = a0
1239
+ a2 = 0.0 # Simplified
1240
+
1241
+ # Asymptotic series
1242
+ expansion = a0
1258
1243
  if order >= 1:
1259
1244
  expansion += a1 * (kappa * t)
1260
1245
  if order >= 2:
@@ -1263,53 +1248,53 @@ class HeatKernel:
1263
1248
  return prefactor * expansion
1264
1249
 
1265
1250
 
1266
- # ============================================================
1267
- # 频率投影 (Frequency Projection)
1268
- # ============================================================
1269
-
1270
- class FrequencyProjection:
1271
- """
1272
- 几何频率投影算子
1273
-
1274
- ω_n = √|κ_n| · sign(κ_n)
1275
- P_Ω = Σ_{n: ω_n ∈ Ω} |Frame_n⟩⟨Frame_n|
1276
-
1277
- 应用:
1278
- - 频段滤波
1279
- - 多尺度分析
1280
- - 频域波函数
1281
- """
1282
-
1283
- def __init__(self, spectral_decomposition: SpectralDecomposition):
1284
- """
1285
- 初始化频率投影
1286
-
1287
- Args:
1288
- spectral_decomposition: 谱分解
1289
- """
1290
- self.spectral = spectral_decomposition
1291
-
1292
- def compute_frequencies(self) -> np.ndarray:
1293
- """
1294
- 计算几何频率:ω_n = √|κ_n| · sign(κ_n)
1295
-
1296
- Returns:
1297
- 频率数组
1298
- """
1251
+ # ============================================================
1252
+ # Frequency Projection
1253
+ # ============================================================
1254
+
1255
+ class FrequencyProjection:
1256
+ """
1257
+ Geometric frequency projection operator.
1258
+
1259
+ ω_n = √|κ_n| · sign(κ_n)
1260
+ P_Ω = Σ_{n: ω_n ∈ Ω} |Frame_n⟩⟨Frame_n|
1261
+
1262
+ Applications:
1263
+ - Band filtering
1264
+ - Multiscale analysis
1265
+ - Frequency-domain wavefunctions
1266
+ """
1267
+
1268
+ def __init__(self, spectral_decomposition: SpectralDecomposition):
1269
+ """
1270
+ Initialize frequency projection.
1271
+
1272
+ Args:
1273
+ spectral_decomposition: spectral decomposition
1274
+ """
1275
+ self.spectral = spectral_decomposition
1276
+
1277
+ def compute_frequencies(self) -> np.ndarray:
1278
+ """
1279
+ Compute geometric frequencies: ω_n = √|κ_n| · sign(κ_n).
1280
+
1281
+ Returns:
1282
+ Frequency array.
1283
+ """
1299
1284
  eigenvalues, _ = self.spectral.compute_eigenspectrum()
1300
1285
  frequencies = np.sqrt(np.abs(eigenvalues)) * np.sign(eigenvalues)
1301
1286
  return frequencies
1302
1287
 
1303
- def project_to_band(self, omega_min: float, omega_max: float) -> 'FrequencyBandState':
1304
- """
1305
- 投影到频段 [ω_min, ω_max]
1306
-
1307
- Args:
1308
- omega_min, omega_max: 频段范围
1309
-
1310
- Returns:
1311
- 频段态
1312
- """
1288
+ def project_to_band(self, omega_min: float, omega_max: float) -> 'FrequencyBandState':
1289
+ """
1290
+ Project onto band [ω_min, ω_max].
1291
+
1292
+ Args:
1293
+ omega_min, omega_max: band limits
1294
+
1295
+ Returns:
1296
+ Band state.
1297
+ """
1313
1298
  frequencies = self.compute_frequencies()
1314
1299
  mask = (frequencies >= omega_min) & (frequencies <= omega_max)
1315
1300
 
@@ -1322,91 +1307,90 @@ class FrequencyProjection:
1322
1307
  )
1323
1308
 
1324
1309
 
1325
- @dataclass
1326
- class FrequencyBandState:
1327
- """频段波函数"""
1310
+ @dataclass
1311
+ class FrequencyBandState:
1312
+ """Band-limited wavefunction."""
1328
1313
  frequency_range: Tuple[float, float]
1329
1314
  mode_indices: np.ndarray
1330
1315
  projection_operator: FrequencyProjection
1331
1316
 
1332
- def wavefunction(self, amplitudes: np.ndarray, phases: np.ndarray) -> complex:
1333
- """
1334
- Ψ_Ω = Σ_{n ∈ Ω} a_n Frame_n e^{iθ_n}
1335
-
1336
- Args:
1337
- amplitudes: 振幅数组
1338
- phases: 相位数组
1339
-
1340
- Returns:
1341
- 波函数值
1342
- """
1317
+ def wavefunction(self, amplitudes: np.ndarray, phases: np.ndarray) -> complex:
1318
+ """
1319
+ Ψ_Ω = Σ_{n ∈ Ω} a_n Frame_n e^{iθ_n}
1320
+
1321
+ Args:
1322
+ amplitudes: amplitude array
1323
+ phases: phase array
1324
+
1325
+ Returns:
1326
+ Wavefunction value.
1327
+ """
1343
1328
  psi = 0.0 + 0j
1344
1329
  for idx, amp, phase in zip(self.mode_indices, amplitudes, phases):
1345
1330
  psi += amp * np.exp(1j * phase)
1346
1331
  return psi
1347
1332
 
1348
1333
 
1349
- # ============================================================
1350
- # ============================================================
1351
- # 谱数据结构
1352
- # ============================================================
1334
+ # ============================================================
1335
+ # Spectral data structures
1336
+ # ============================================================
1353
1337
 
1354
1338
  @dataclass
1355
- class FourierFrameSpectrum:
1356
- """
1357
- 傅里叶标架谱表示 - 坐标场在动量空间的表示
1358
-
1359
- 存储坐标场各分量的傅里叶谱
1360
- """
1361
- ux_spectrum: np.ndarray # x轴基矢量谱
1362
- uy_spectrum: np.ndarray # y轴基矢量谱
1363
- uz_spectrum: np.ndarray # z轴基矢量谱
1364
- origin_spectrum: np.ndarray # 原点位置谱
1365
- momentum_grid: Tuple[np.ndarray, np.ndarray] # (kx, ky)
1366
- hbar: float = HBAR
1367
-
1368
- def __post_init__(self):
1369
- """验证维度一致性"""
1370
- shapes = [
1371
- self.ux_spectrum.shape,
1372
- self.uy_spectrum.shape,
1373
- self.uz_spectrum.shape,
1374
- self.origin_spectrum.shape
1375
- ]
1376
- if not all(s == shapes[0] for s in shapes):
1377
- raise ValueError("所有谱分量必须具有相同维度")
1339
+ class FourierFrameSpectrum:
1340
+ """
1341
+ FourierFrame spectrum: coordinate field in momentum space.
1342
+
1343
+ Stores Fourier spectra of each coordinate component.
1344
+ """
1345
+ ux_spectrum: np.ndarray # x-axis basis spectrum
1346
+ uy_spectrum: np.ndarray # y-axis basis spectrum
1347
+ uz_spectrum: np.ndarray # z-axis basis spectrum
1348
+ origin_spectrum: np.ndarray # origin position spectrum
1349
+ momentum_grid: Tuple[np.ndarray, np.ndarray] # (kx, ky)
1350
+ hbar: float = HBAR
1351
+
1352
+ def __post_init__(self):
1353
+ """Validate dimension consistency."""
1354
+ shapes = [
1355
+ self.ux_spectrum.shape,
1356
+ self.uy_spectrum.shape,
1357
+ self.uz_spectrum.shape,
1358
+ self.origin_spectrum.shape
1359
+ ]
1360
+ if not all(s == shapes[0] for s in shapes):
1361
+ raise ValueError("All spectral components must have the same shape")
1378
1362
 
1379
1363
  @property
1380
- def shape(self) -> Tuple[int, int]:
1381
- """谱的空间形状"""
1382
- return self.ux_spectrum.shape[:2]
1364
+ def shape(self) -> Tuple[int, int]:
1365
+ """Spatial shape of the spectrum."""
1366
+ return self.ux_spectrum.shape[:2]
1383
1367
 
1384
- def total_energy(self) -> float:
1385
- """总能量 E = ∫ |ψ̃(k)|² dk"""
1386
- return float(
1368
+ def total_energy(self) -> float:
1369
+ """Total energy E = ∫ |ψ̃(k)|² dk."""
1370
+ return float(
1387
1371
  np.sum(np.abs(self.ux_spectrum)**2) +
1388
1372
  np.sum(np.abs(self.uy_spectrum)**2) +
1389
1373
  np.sum(np.abs(self.uz_spectrum)**2) +
1390
1374
  np.sum(np.abs(self.origin_spectrum)**2)
1391
1375
  )
1392
1376
 
1393
- def spectral_density(self) -> np.ndarray:
1394
- """谱密度 ρ(k) = Σ_μ |ψ̃_μ(k)"""
1395
- density = (
1396
- np.abs(self.ux_spectrum)**2 +
1397
- np.abs(self.uy_spectrum)**2 +
1398
- np.abs(self.uz_spectrum)**2 +
1399
- np.abs(self.origin_spectrum)**2
1400
- )
1401
- return np.mean(density, axis=-1) if density.ndim > 2 else density
1402
-
1403
- def radial_average(self) -> Tuple[np.ndarray, np.ndarray]:
1404
- """
1405
- 径向平均谱 (ShapeDNA)
1406
-
1407
- Returns:
1408
- (k_bins, radial_spectrum)
1409
- """
1377
+ def spectral_density(self) -> np.ndarray:
1378
+ """Spectral density ρ(k) = Σ_μ |ψ̃_μ(k)|²."""
1379
+ density = (
1380
+ np.abs(self.ux_spectrum)**2 +
1381
+ np.abs(self.uy_spectrum)**2 +
1382
+ np.abs(self.uz_spectrum)**2 +
1383
+ np.abs(self.origin_spectrum)**2
1384
+ )
1385
+ return np.mean(density, axis=-1) if density.ndim > 2 else density
1386
+
1387
+ def radial_average(self) -> Tuple[np.ndarray, np.ndarray]:
1388
+ """
1389
+ Radial average spectrum (ShapeDNA).
1390
+
1391
+ Returns:
1392
+ (k_bins, radial_spectrum)
1393
+ """
1410
1394
  kx, ky = self.momentum_grid
1411
1395
  k_mag = np.sqrt(kx[:, None]**2 + ky[None, :]**2)
1412
1396
 
@@ -1423,13 +1407,13 @@ class FourierFrameSpectrum:
1423
1407
 
1424
1408
  return k_bins, radial_avg
1425
1409
 
1426
- def to_coord_field(self) -> List[List]:
1427
- """
1428
- 逆变换:谱坐标场
1429
-
1430
- Returns:
1431
- 二维坐标场列表
1432
- """
1410
+ def to_coord_field(self) -> List[List]:
1411
+ """
1412
+ Inverse transform: spectrum coordinate field.
1413
+
1414
+ Returns:
1415
+ 2D coordinate field list.
1416
+ """
1433
1417
  ny, nx = self.shape
1434
1418
 
1435
1419
  origin_field = Frame.inverse_spectral_transform_2d(self.origin_spectrum, self.hbar)
@@ -1454,82 +1438,82 @@ class FourierFrameSpectrum:
1454
1438
  return coord_field
1455
1439
 
1456
1440
 
1457
- # ============================================================
1458
- # 便利函数
1459
- # ============================================================
1460
-
1461
- def spectral_transform(coord_field: List[List],
1462
- hbar: float = HBAR,
1463
- use_gpu: bool = False) -> FourierFrameSpectrum:
1464
- """
1465
- 坐标场谱变换
1466
-
1467
- Args:
1468
- coord_field: 二维坐标场
1469
- hbar: 约化普朗克常数
1470
- use_gpu: 是否使用 GPU 加速
1471
-
1472
- Returns:
1473
- FourierFrameSpectrum 对象
1474
- """
1441
+ # ============================================================
1442
+ # Convenience functions
1443
+ # ============================================================
1444
+
1445
+ def spectral_transform(coord_field: List[List],
1446
+ hbar: float = HBAR,
1447
+ use_gpu: bool = False) -> FourierFrameSpectrum:
1448
+ """
1449
+ Coordinate field spectral transform.
1450
+
1451
+ Args:
1452
+ coord_field: 2D coordinate field
1453
+ hbar: reduced Planck constant
1454
+ use_gpu: whether to use GPU acceleration
1455
+
1456
+ Returns:
1457
+ FourierFrameSpectrum object.
1458
+ """
1475
1459
  return FourierFrame.from_coord_field(coord_field, hbar)
1476
1460
 
1477
1461
 
1478
- def inverse_spectral_transform(spectrum: FourierFrameSpectrum) -> List[List]:
1479
- """
1480
- 逆谱变换
1481
-
1482
- Args:
1483
- spectrum: FourierFrameSpectrum 对象
1484
-
1485
- Returns:
1486
- 重建的坐标场
1487
- """
1462
+ def inverse_spectral_transform(spectrum: FourierFrameSpectrum) -> List[List]:
1463
+ """
1464
+ Inverse spectral transform.
1465
+
1466
+ Args:
1467
+ spectrum: FourierFrameSpectrum object
1468
+
1469
+ Returns:
1470
+ Reconstructed coordinate field.
1471
+ """
1488
1472
  return spectrum.to_coord_field()
1489
1473
 
1490
1474
 
1491
- # ============================================================
1492
- # 演示
1493
- # ============================================================
1475
+ # ============================================================
1476
+ # Demonstration
1477
+ # ============================================================
1494
1478
 
1495
- def demonstrate():
1496
- """演示傅里叶标架代数与谱几何"""
1479
+ def demonstrate():
1480
+ """Demonstrate FourierFrame algebra and spectral geometry."""
1497
1481
  print("=" * 70)
1498
- print("傅里叶标架场与量子谱几何 (FourierFrame Field & Spectral Geometry)")
1482
+ print("FourierFrame Field & Spectral Geometry")
1499
1483
  print("=" * 70)
1500
1484
 
1501
- # 1. 创建基础 FourierFrame
1485
+ # 1. Create base FourierFrame
1502
1486
  if coord3 is not None:
1503
1487
  base_frame = coord3.from_position(vec3(1, 0, 0))
1504
1488
  frame = FourierFrame(base_frame, q_factor=1.0+0.5j)
1505
1489
  else:
1506
1490
  frame = FourierFrame(q_factor=1.0+0.5j)
1507
1491
 
1508
- print(f"\n1. 基础傅里叶标架: {frame}")
1509
- print(f" 相位: {frame.phase:.4f} rad")
1510
- print(f" 模: {frame.magnitude:.4f}")
1511
- print(f" 行列式: {frame.det:.4f}")
1492
+ print(f"\n1. Base FourierFrame: {frame}")
1493
+ print(f" Phase: {frame.phase:.4f} rad")
1494
+ print(f" Magnitude: {frame.magnitude:.4f}")
1495
+ print(f" Determinant: {frame.det:.4f}")
1512
1496
 
1513
- # 2. 傅里叶变换
1514
- print(f"\n2. 傅里叶变换:")
1497
+ # 2. Fourier transform
1498
+ print("\n2. Fourier transform:")
1515
1499
  ft = frame.fourier_transform()
1516
1500
  print(f" F[FourierFrame] = {ft}")
1517
1501
  print(f" F^4[FourierFrame] ≈ FourierFrame: {frame.fourier_transform(2*np.pi)}")
1518
1502
 
1519
- # 3. 共形变换
1520
- print(f"\n3. 共形变换:")
1503
+ # 3. Conformal transform
1504
+ print("\n3. Conformal transform:")
1521
1505
  conf = frame.conformal_transform(2.0)
1522
1506
  print(f" λ=2: {conf}")
1523
1507
 
1524
- # 4. 标架复合
1525
- print(f"\n4. 标架复合:")
1508
+ # 4. Frame composition
1509
+ print("\n4. Frame composition:")
1526
1510
  frame2 = FourierFrame(q_factor=0.5+0.5j)
1527
1511
  composed = frame * frame2
1528
1512
  print(f" FourierFrame1 * FourierFrame2 = {composed}")
1529
1513
 
1530
- # 5. 内禀梯度算子
1531
- print(f"\n5. 内禀梯度算子:")
1532
- # 创建简单标架场
1514
+ # 5. Intrinsic gradient operator
1515
+ print("\n5. Intrinsic gradient operator:")
1516
+ # Create a simple frame field
1533
1517
  frame_field = [[FourierFrame(q_factor=1.0 + 0.1j*(i+j)) for j in range(5)] for i in range(5)]
1534
1518
  grad_op = IntrinsicGradient(frame_field)
1535
1519
  G_x = grad_op.compute_at((2, 2), 0)
@@ -1537,48 +1521,48 @@ def demonstrate():
1537
1521
  print(f" G_x(2,2) = {G_x:.4f}")
1538
1522
  print(f" G_y(2,2) = {G_y:.4f}")
1539
1523
 
1540
- # 6. 曲率计算
1541
- print(f"\n6. 曲率计算:")
1524
+ # 6. Curvature computation
1525
+ print("\n6. Curvature computation:")
1542
1526
  curvature_calc = CurvatureFromFrame(frame_field)
1543
1527
  K = curvature_calc.gaussian_curvature(2, 2)
1544
1528
  H = curvature_calc.mean_curvature(2, 2)
1545
- print(f" 高斯曲率 K = {K:.6f}")
1546
- print(f" 平均曲率 H = {H:.6f}")
1529
+ print(f" Gaussian curvature K = {K:.6f}")
1530
+ print(f" Mean curvature H = {H:.6f}")
1547
1531
 
1548
- # 7. Berry相位
1549
- print(f"\n7. Berry相位:")
1532
+ # 7. Berry phase
1533
+ print("\n7. Berry phase:")
1550
1534
  berry = BerryPhase(grad_op)
1551
1535
  path = [(1, 1), (1, 3), (3, 3), (3, 1), (1, 1)]
1552
1536
  gamma = berry.compute_along_path(path, closed=True)
1553
1537
  print(f" γ = ∮ G_μ dx^μ = {gamma:.4f}")
1554
1538
 
1555
- # 8. 陈数
1556
- print(f"\n8. 陈数:")
1539
+ # 8. Chern number
1540
+ print("\n8. Chern number:")
1557
1541
  chern = ChernNumber(curvature_calc)
1558
1542
  c1 = chern.compute()
1559
- print(f" 第一陈数 c₁ = {c1}")
1543
+ print(f" First Chern number c₁ = {c1}")
1560
1544
 
1561
1545
  print("\n" + "=" * 70)
1562
- print("核心公式总结:")
1563
- print(" G_μ = d/dx^μ log FourierFrame(x) [内禀梯度]")
1564
- print(" R_{μν} = [G_μ, G_ν] [曲率]")
1565
- print(" FourierFrame * e^{iθ} = 傅里叶变换")
1566
- print(" FourierFrame * λ = 共形变换")
1567
- print(" γ = ∮ G_μ dx^μ [Berry相位]")
1568
- print(" c₁ = (1/2π) ∬ R_{μν} dS [陈数]")
1546
+ print("Core formula summary:")
1547
+ print(" - G_μ = d/dx^μ log FourierFrame(x) [intrinsic gradient]")
1548
+ print(" - R_{μν} = [G_μ, G_ν] [curvature]")
1549
+ print(" - FourierFrame * e^{iθ} = Fourier transform")
1550
+ print(" - FourierFrame * λ = conformal transform")
1551
+ print(" - γ = ∮ G_μ dx^μ [Berry phase]")
1552
+ print(" - c₁ = (1/2π) ∬ R_{μν} dS [Chern number]")
1569
1553
  print("=" * 70)
1570
1554
 
1571
1555
 
1572
- # ============================================================
1573
- # 导出
1574
- # ============================================================
1556
+ # ============================================================
1557
+ # Exports
1558
+ # ============================================================
1575
1559
 
1576
1560
  __all__ = [
1577
- # 核心类
1561
+ # Core classes
1578
1562
  'FourierFrame',
1579
1563
  'FourierFrameSpectrum',
1580
1564
 
1581
- # 谱几何核心
1565
+ # Spectral geometry core
1582
1566
  'IntrinsicGradient',
1583
1567
  'CurvatureFromFrame',
1584
1568
  'BerryPhase',
@@ -1588,11 +1572,11 @@ __all__ = [
1588
1572
  'FrequencyProjection',
1589
1573
  'FrequencyBandState',
1590
1574
 
1591
- # 便利函数
1575
+ # Convenience functions
1592
1576
  'spectral_transform',
1593
1577
  'inverse_spectral_transform',
1594
1578
 
1595
- # 常数
1579
+ # Constants
1596
1580
  'HBAR',
1597
1581
  'GPU_AVAILABLE',
1598
1582
  ]