coordinate-system 7.0.0__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.
@@ -0,0 +1,1602 @@
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
+ """
31
+
32
+ __version__ = '6.0.3'
33
+
34
+ import numpy as np
35
+ from typing import List, Tuple, Dict, Optional, Union, Any, Callable
36
+ from dataclasses import dataclass
37
+ import warnings
38
+
39
+ # 导入坐标系统
40
+ try:
41
+ from .coordinate_system import coord3, vec3, quat
42
+ except ImportError:
43
+ try:
44
+ from coordinate_system import coord3, vec3, quat
45
+ except ImportError:
46
+ # 延迟导入,允许独立使用
47
+ coord3 = None
48
+ vec3 = None
49
+ quat = None
50
+
51
+ # 物理常数
52
+ HBAR = 1.0 # 约化普朗克常数(自然单位)
53
+
54
+ # GPU 可用性检查
55
+ try:
56
+ import cupy as cp
57
+ import cupyx.scipy.fft as cufft
58
+ GPU_AVAILABLE = True
59
+ except ImportError:
60
+ GPU_AVAILABLE = False
61
+ cp = None
62
+ cufft = None
63
+
64
+
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
+ """
125
+ if base_coord is None:
126
+ if coord3 is not None:
127
+ self.base = coord3.identity()
128
+ else:
129
+ self.base = None
130
+ else:
131
+ self.base = base_coord
132
+
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
149
+ ) if vec3 else None
150
+
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
157
+ return vec3(
158
+ s_base.x * self.Q.real + 1j * s_base.x * self.Q.imag,
159
+ s_base.y * self.Q.real + 1j * s_base.y * self.Q.imag,
160
+ s_base.z * self.Q.real + 1j * s_base.z * self.Q.imag
161
+ ) if vec3 else None
162
+
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)
172
+
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
+ return NotImplemented
242
+
243
+ def __eq__(self, other):
244
+ """相等比较"""
245
+ if not isinstance(other, FourierFrame):
246
+ return False
247
+ return np.isclose(self.Q, other.Q)
248
+
249
+ def __repr__(self):
250
+ if self.base is not None:
251
+ return f"FourierFrame(Q={self.Q:.4f}, o={self.base.o})"
252
+ return f"FourierFrame(Q={self.Q:.4f})"
253
+
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
327
+
328
+ return FourierFrame(self.base, evolved_Q)
329
+
330
+ @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])
351
+
352
+ if i <= 0 or i >= ny - 1 or j <= 0 or j >= nx - 1:
353
+ return 0.0 + 0j
354
+
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)
366
+
367
+ return laplacian
368
+
369
+ # -------------------- 谱变换 --------------------
370
+
371
+ @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
397
+
398
+ @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
+ """
410
+ if spectrum.ndim >= 2:
411
+ axes = (0, 1)
412
+ else:
413
+ axes = None
414
+
415
+ denormalization = np.sqrt(2 * np.pi * hbar)
416
+ return np.fft.ifft2(spectrum * denormalization, axes=axes).real
417
+
418
+ @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 加速")
423
+
424
+ field_gpu = cp.asarray(field)
425
+ spectrum_gpu = cufft.fft2(field_gpu, axes=(0, 1))
426
+ normalization = 1.0 / np.sqrt(2 * np.pi * hbar)
427
+ spectrum_gpu *= normalization
428
+ return cp.asnumpy(spectrum_gpu)
429
+
430
+ @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):
451
+ coord = coord_field[i][j]
452
+ tensor_field[i, j, 0:3] = [coord.o.x, coord.o.y, coord.o.z]
453
+ tensor_field[i, j, 3:6] = [coord.ux.x, coord.ux.y, coord.ux.z]
454
+ tensor_field[i, j, 6:9] = [coord.uy.x, coord.uy.y, coord.uy.z]
455
+ tensor_field[i, j, 9:12] = [coord.uz.x, coord.uz.y, coord.uz.z]
456
+
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
466
+
467
+ return FourierFrameSpectrum(
468
+ ux_spectrum=ux_spectrum,
469
+ uy_spectrum=uy_spectrum,
470
+ uz_spectrum=uz_spectrum,
471
+ origin_spectrum=origin_spectrum,
472
+ momentum_grid=(kx, ky),
473
+ hbar=hbar
474
+ )
475
+
476
+
477
+ # ============================================================
478
+ # 内禀梯度算子 (Intrinsic Gradient Operator)
479
+ # ============================================================
480
+
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
+ """
509
+ self.frame_field = frame_field
510
+ self.is_discrete = isinstance(frame_field, list)
511
+
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
+ """
525
+ if self.is_discrete:
526
+ return self._compute_discrete(position, direction)
527
+ else:
528
+ return self._compute_continuous(position, direction, delta)
529
+
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]
541
+
542
+ # G_x ≈ (log Q_{j+1} - log Q_{j-1}) / 2
543
+ return (np.log(frame_forward.Q) - np.log(frame_backward.Q)) / 2.0
544
+
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]
549
+
550
+ return (np.log(frame_forward.Q) - np.log(frame_backward.Q)) / 2.0
551
+
552
+ return 0.0 + 0j
553
+
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()
561
+ pos_forward[direction] += delta
562
+ pos_backward[direction] -= delta
563
+
564
+ frame_forward = self.frame_field(tuple(pos_forward))
565
+ frame_backward = self.frame_field(tuple(pos_backward))
566
+
567
+ # G_μ = d/dx^μ log Frame
568
+ return (np.log(frame_forward.Q) - np.log(frame_backward.Q)) / (2 * delta)
569
+
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])
623
+
624
+
625
+ # ============================================================
626
+ # 曲率计算 (Curvature from Frames)
627
+ # ============================================================
628
+
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
+ """
646
+ self.frame_field = frame_field
647
+ self.gradient_op = IntrinsicGradient(frame_field)
648
+ self.ny = len(frame_field)
649
+ self.nx = len(frame_field[0]) if self.ny > 0 else 0
650
+
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)
685
+
686
+ return 0.5 * (R_xx.real + R_yy.real)
687
+
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
+ """
700
+ R = np.zeros((2, 2), dtype=complex)
701
+
702
+ R[0, 0] = self.gradient_op.commutator((i, j), 0, 0)
703
+ R[0, 1] = self.gradient_op.commutator((i, j), 0, 1)
704
+ R[1, 0] = self.gradient_op.commutator((i, j), 1, 0)
705
+ R[1, 1] = self.gradient_op.commutator((i, j), 1, 1)
706
+
707
+ return R
708
+
709
+
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
+ """
749
+ if len(path) < 2:
750
+ return 0.0 + 0j
751
+
752
+ phase = 0.0 + 0j
753
+
754
+ for k in range(len(path) - 1):
755
+ pos_current = path[k]
756
+ pos_next = path[k + 1]
757
+
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
769
+
770
+ # G_μ dx^μ
771
+ G_mu = self.gradient_op.compute_at(pos_current, direction)
772
+ phase += G_mu * step
773
+
774
+ # 闭合路径
775
+ if closed and len(path) > 2:
776
+ pos_last = path[-1]
777
+ pos_first = path[0]
778
+
779
+ dx = pos_first[0] - pos_last[0]
780
+ dy = pos_first[1] - pos_last[1]
781
+
782
+ if abs(dx) > abs(dy):
783
+ direction = 0
784
+ step = dx
785
+ else:
786
+ direction = 1
787
+ step = dy
788
+
789
+ G_mu = self.gradient_op.compute_at(pos_last, direction)
790
+ phase += G_mu * step
791
+
792
+ return phase
793
+
794
+
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
+ """
831
+ total = 0.0 + 0j
832
+
833
+ ny, nx = self.curvature.ny, self.curvature.nx
834
+
835
+ for i in range(1, ny - 1):
836
+ 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
911
+
912
+ self._eigenvalues = None
913
+ self._eigenvectors = None
914
+
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
+ """
928
+ if self._eigenvalues is not None:
929
+ return self._eigenvalues, self._eigenvectors
930
+
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]
938
+
939
+ self._eigenvalues = eigenvalues
940
+ self._eigenvectors = None
941
+
942
+ elif self.frame_field is not None:
943
+ # 离散场:估算本征值
944
+ # 完整实现需要构造拉普拉斯矩阵并数值求解
945
+ eigenvalues_list = []
946
+
947
+ for i in range(1, self.ny - 1):
948
+ for j in range(1, self.nx - 1):
949
+ lap = self.gradient_op.laplacian((i, j))
950
+ eigenvalues_list.append(abs(lap))
951
+
952
+ eigenvalues = np.sort(np.array(eigenvalues_list))[::-1]
953
+ self._eigenvalues = eigenvalues
954
+ self._eigenvectors = None
955
+
956
+ return self._eigenvalues, self._eigenvectors
957
+
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
+ # 简化:使用FourierFrame的Q因子
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])
987
+
988
+ return coefficients
989
+
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
+ """
1004
+ eigenvalues, _ = self.compute_eigenspectrum()
1005
+
1006
+ reconstructed_Q = 0.0 + 0j
1007
+ for n in range(len(coefficients)):
1008
+ if n < len(eigenvalues) and eigenvalues[n] > 0:
1009
+ reconstructed_Q += coefficients[n] * np.sqrt(eigenvalues[n])
1010
+
1011
+ return FourierFrame(base_frame.base, reconstructed_Q)
1012
+
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
+ """
1030
+ eigenvalues, _ = self.compute_eigenspectrum()
1031
+ return int(np.sum(eigenvalues < lambda_threshold))
1032
+
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
+ """
1057
+ eigenvalues, _ = self.compute_eigenspectrum()
1058
+ return eigenvalues[:n_modes]
1059
+
1060
+
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)
1157
+ row.append(evolved_frame)
1158
+ evolved_field.append(row)
1159
+ return evolved_field
1160
+
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],
1173
+ uz_spectrum=self.spectrum.uz_spectrum * decay[..., None],
1174
+ origin_spectrum=self.spectrum.origin_spectrum * decay[..., None],
1175
+ momentum_grid=self.spectrum.momentum_grid,
1176
+ hbar=self.spectrum.hbar
1177
+ )
1178
+ return evolved_spectrum
1179
+
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
1215
+
1216
+ return 0.0
1217
+
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):
1247
+ for j in range(1, self.nx - 1):
1248
+ R_xy = self.gradient_op.commutator((i, j), 0, 1)
1249
+ curvature_sum += abs(R_xy)
1250
+ a1 = curvature_sum / 6.0
1251
+ else:
1252
+ a1 = 0.0
1253
+
1254
+ a2 = 0.0 # 简化
1255
+
1256
+ # 渐近级数
1257
+ expansion = a0
1258
+ if order >= 1:
1259
+ expansion += a1 * (kappa * t)
1260
+ if order >= 2:
1261
+ expansion += a2 * (kappa * t)**2
1262
+
1263
+ return prefactor * expansion
1264
+
1265
+
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
+ """
1299
+ eigenvalues, _ = self.spectral.compute_eigenspectrum()
1300
+ frequencies = np.sqrt(np.abs(eigenvalues)) * np.sign(eigenvalues)
1301
+ return frequencies
1302
+
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
+ """
1313
+ frequencies = self.compute_frequencies()
1314
+ mask = (frequencies >= omega_min) & (frequencies <= omega_max)
1315
+
1316
+ selected_indices = np.where(mask)[0]
1317
+
1318
+ return FrequencyBandState(
1319
+ frequency_range=(omega_min, omega_max),
1320
+ mode_indices=selected_indices,
1321
+ projection_operator=self
1322
+ )
1323
+
1324
+
1325
+ @dataclass
1326
+ class FrequencyBandState:
1327
+ """频段波函数"""
1328
+ frequency_range: Tuple[float, float]
1329
+ mode_indices: np.ndarray
1330
+ projection_operator: FrequencyProjection
1331
+
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
+ """
1343
+ psi = 0.0 + 0j
1344
+ for idx, amp, phase in zip(self.mode_indices, amplitudes, phases):
1345
+ psi += amp * np.exp(1j * phase)
1346
+ return psi
1347
+
1348
+
1349
+ # ============================================================
1350
+ # ============================================================
1351
+ # 谱数据结构
1352
+ # ============================================================
1353
+
1354
+ @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("所有谱分量必须具有相同维度")
1378
+
1379
+ @property
1380
+ def shape(self) -> Tuple[int, int]:
1381
+ """谱的空间形状"""
1382
+ return self.ux_spectrum.shape[:2]
1383
+
1384
+ def total_energy(self) -> float:
1385
+ """总能量 E = ∫ |ψ̃(k)|² dk"""
1386
+ return float(
1387
+ np.sum(np.abs(self.ux_spectrum)**2) +
1388
+ np.sum(np.abs(self.uy_spectrum)**2) +
1389
+ np.sum(np.abs(self.uz_spectrum)**2) +
1390
+ np.sum(np.abs(self.origin_spectrum)**2)
1391
+ )
1392
+
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
+ """
1410
+ kx, ky = self.momentum_grid
1411
+ k_mag = np.sqrt(kx[:, None]**2 + ky[None, :]**2)
1412
+
1413
+ density = self.spectral_density()
1414
+
1415
+ k_max = np.max(k_mag)
1416
+ k_bins = np.linspace(0, k_max, 50)
1417
+ radial_avg = np.zeros(len(k_bins))
1418
+
1419
+ for i in range(len(k_bins) - 1):
1420
+ mask = (k_mag >= k_bins[i]) & (k_mag < k_bins[i + 1])
1421
+ if np.any(mask):
1422
+ radial_avg[i] = np.mean(density[mask])
1423
+
1424
+ return k_bins, radial_avg
1425
+
1426
+ def to_coord_field(self) -> List[List]:
1427
+ """
1428
+ 逆变换:谱 → 坐标场
1429
+
1430
+ Returns:
1431
+ 二维坐标场列表
1432
+ """
1433
+ ny, nx = self.shape
1434
+
1435
+ origin_field = Frame.inverse_spectral_transform_2d(self.origin_spectrum, self.hbar)
1436
+ ux_field = Frame.inverse_spectral_transform_2d(self.ux_spectrum, self.hbar)
1437
+ uy_field = Frame.inverse_spectral_transform_2d(self.uy_spectrum, self.hbar)
1438
+ uz_field = Frame.inverse_spectral_transform_2d(self.uz_spectrum, self.hbar)
1439
+
1440
+ coord_field = []
1441
+ for i in range(ny):
1442
+ row = []
1443
+ for j in range(nx):
1444
+ o = vec3(origin_field[i, j, 0], origin_field[i, j, 1], origin_field[i, j, 2])
1445
+ ux = vec3(ux_field[i, j, 0], ux_field[i, j, 1], ux_field[i, j, 2])
1446
+ uy = vec3(uy_field[i, j, 0], uy_field[i, j, 1], uy_field[i, j, 2])
1447
+ uz = vec3(uz_field[i, j, 0], uz_field[i, j, 1], uz_field[i, j, 2])
1448
+
1449
+ c = coord3(o, quat(1, 0, 0, 0), vec3(1, 1, 1))
1450
+ c.ux, c.uy, c.uz = ux, uy, uz
1451
+ row.append(c)
1452
+ coord_field.append(row)
1453
+
1454
+ return coord_field
1455
+
1456
+
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
+ """
1475
+ return FourierFrame.from_coord_field(coord_field, hbar)
1476
+
1477
+
1478
+ def inverse_spectral_transform(spectrum: FourierFrameSpectrum) -> List[List]:
1479
+ """
1480
+ 逆谱变换
1481
+
1482
+ Args:
1483
+ spectrum: FourierFrameSpectrum 对象
1484
+
1485
+ Returns:
1486
+ 重建的坐标场
1487
+ """
1488
+ return spectrum.to_coord_field()
1489
+
1490
+
1491
+ # ============================================================
1492
+ # 演示
1493
+ # ============================================================
1494
+
1495
+ def demonstrate():
1496
+ """演示傅里叶标架代数与谱几何"""
1497
+ print("=" * 70)
1498
+ print("傅里叶标架场与量子谱几何 (FourierFrame Field & Spectral Geometry)")
1499
+ print("=" * 70)
1500
+
1501
+ # 1. 创建基础 FourierFrame
1502
+ if coord3 is not None:
1503
+ base_frame = coord3.from_position(vec3(1, 0, 0))
1504
+ frame = FourierFrame(base_frame, q_factor=1.0+0.5j)
1505
+ else:
1506
+ frame = FourierFrame(q_factor=1.0+0.5j)
1507
+
1508
+ print(f"\n1. 基础傅里叶标架: {frame}")
1509
+ print(f" 相位: {frame.phase:.4f} rad")
1510
+ print(f" 模: {frame.magnitude:.4f}")
1511
+ print(f" 行列式: {frame.det:.4f}")
1512
+
1513
+ # 2. 傅里叶变换
1514
+ print(f"\n2. 傅里叶变换:")
1515
+ ft = frame.fourier_transform()
1516
+ print(f" F[FourierFrame] = {ft}")
1517
+ print(f" F^4[FourierFrame] ≈ FourierFrame: {frame.fourier_transform(2*np.pi)}")
1518
+
1519
+ # 3. 共形变换
1520
+ print(f"\n3. 共形变换:")
1521
+ conf = frame.conformal_transform(2.0)
1522
+ print(f" λ=2: {conf}")
1523
+
1524
+ # 4. 标架复合
1525
+ print(f"\n4. 标架复合:")
1526
+ frame2 = FourierFrame(q_factor=0.5+0.5j)
1527
+ composed = frame * frame2
1528
+ print(f" FourierFrame1 * FourierFrame2 = {composed}")
1529
+
1530
+ # 5. 内禀梯度算子
1531
+ print(f"\n5. 内禀梯度算子:")
1532
+ # 创建简单标架场
1533
+ frame_field = [[FourierFrame(q_factor=1.0 + 0.1j*(i+j)) for j in range(5)] for i in range(5)]
1534
+ grad_op = IntrinsicGradient(frame_field)
1535
+ G_x = grad_op.compute_at((2, 2), 0)
1536
+ G_y = grad_op.compute_at((2, 2), 1)
1537
+ print(f" G_x(2,2) = {G_x:.4f}")
1538
+ print(f" G_y(2,2) = {G_y:.4f}")
1539
+
1540
+ # 6. 曲率计算
1541
+ print(f"\n6. 曲率计算:")
1542
+ curvature_calc = CurvatureFromFrame(frame_field)
1543
+ K = curvature_calc.gaussian_curvature(2, 2)
1544
+ H = curvature_calc.mean_curvature(2, 2)
1545
+ print(f" 高斯曲率 K = {K:.6f}")
1546
+ print(f" 平均曲率 H = {H:.6f}")
1547
+
1548
+ # 7. Berry相位
1549
+ print(f"\n7. Berry相位:")
1550
+ berry = BerryPhase(grad_op)
1551
+ path = [(1, 1), (1, 3), (3, 3), (3, 1), (1, 1)]
1552
+ gamma = berry.compute_along_path(path, closed=True)
1553
+ print(f" γ = ∮ G_μ dx^μ = {gamma:.4f}")
1554
+
1555
+ # 8. 陈数
1556
+ print(f"\n8. 陈数:")
1557
+ chern = ChernNumber(curvature_calc)
1558
+ c1 = chern.compute()
1559
+ print(f" 第一陈数 c₁ = {c1}")
1560
+
1561
+ 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 [陈数]")
1569
+ print("=" * 70)
1570
+
1571
+
1572
+ # ============================================================
1573
+ # 导出
1574
+ # ============================================================
1575
+
1576
+ __all__ = [
1577
+ # 核心类
1578
+ 'FourierFrame',
1579
+ 'FourierFrameSpectrum',
1580
+
1581
+ # 谱几何核心
1582
+ 'IntrinsicGradient',
1583
+ 'CurvatureFromFrame',
1584
+ 'BerryPhase',
1585
+ 'ChernNumber',
1586
+ 'SpectralDecomposition',
1587
+ 'HeatKernel',
1588
+ 'FrequencyProjection',
1589
+ 'FrequencyBandState',
1590
+
1591
+ # 便利函数
1592
+ 'spectral_transform',
1593
+ 'inverse_spectral_transform',
1594
+
1595
+ # 常数
1596
+ 'HBAR',
1597
+ 'GPU_AVAILABLE',
1598
+ ]
1599
+
1600
+
1601
+ if __name__ == "__main__":
1602
+ demonstrate()