从薛定谔方程到 NNQS¶
NNQS 的核心问题来自定态薛定谔方程:
在数值计算中,这常常变成一个巨大 Hamiltonian 矩阵的最小本征值问题。神经网络量子态的想法是用一个可微函数 \(\psi_\theta(x)\) 表示本征向量分量,再用变分 Monte Carlo 估计能量和梯度。
对应到教学版程序:
物理问题 H |Psi> = E |Psi>
矩阵语言 求 Hamiltonian 最小本征值
basis 标签 occupation bitstring x
NNQS 表示 psi_theta(x)
VMC 估计 sample x -> E_loc(x) -> energy/gradient
代码流程 state -> model -> sampler -> hamiltonian -> trainer
定态方程¶
含时薛定谔方程为:
许多电子结构计算关心定态,尤其是能量最低的基态。定态问题写作:
这就是线性代数中的本征值问题。\(E\) 是能量本征值,\(|\Psi\rangle\) 是对应的波函数;基态能量 \(E_0\) 是最小本征值。
如果选定一组 basis \(\{|x\rangle\}\),波函数可以展开为:
代回定态方程得到:
于是物理问题落成了矩阵问题:求矩阵 \(H\) 的最小本征值和本征向量。
Occupation Bitstring Basis¶
电子结构问题先选一组 spin orbital。每个 spin orbital 只能空着或被占据,因此一个 many-body basis state 可以写成 occupation bitstring:
在二次量子化语言中,Hamiltonian 常写为:
这里 \(a_p^\dagger\) 和 \(a_p\) 分别创建、湮灭第 \(p\) 个 spin orbital 上的电子。选定 basis 后,occupation bitstring 就成为矩阵行列的标签。
教学版采用的 qubit 顺序为:
例如:
表示 \(\alpha_0\) 占据、\(\beta_1\) 占据,其余为空。
如果有 \(M\) 个 spin orbital,完整 Fock space 维度为:
固定电子数 \(N\) 后,维度降为:
如果进一步固定 \(\alpha,\beta\) 电子数:
这解释了 state.py 为什么要处理 n_alpha、n_beta 和 electron conservation mask。
维度困难¶
小体系可以显式构造 Hamiltonian 矩阵并对角化:
但 Hilbert space 维度随 orbital 数组合爆炸。例如:
这意味着:
- 波函数向量 \(\psi(x)\) 无法完整存储。
- Hamiltonian 矩阵更无法显式存储。
- 精确对角化只能处理很小的 active space。
所以需要一个压缩表示:给定 state \(x\),能按需计算 \(\psi(x)\),同时避免保存完整向量。
变分原理¶
变分原理给出:
只要给出一个合法的候选波函数,就可以算出一个基态能量上界。求基态可以转化成优化问题:
NNQS 把候选波函数写成神经网络:
这样,模型参数 \(\theta\) 替代完整的波函数向量成为优化对象。
NNQS 表示¶
教学版使用复波函数:
其中:
AmplitudeTransformer输出 \(\log A_\theta(x)\)。PhaseMLP输出 \(\phi_\theta(x)\)。NeuralQuantumState.forward(states)返回log_amp、phase、psi。
代码接口为:
对应公式:
自回归振幅¶
VMC 需要从概率分布中采样:
教学版把 bitstring 按 spatial orbital 合成 token:
| pair | token |
|---|---|
| \(00\) | 0 |
| \(10\) | 1 |
| \(01\) | 2 |
| \(11\) | 3 |
自回归模型写出联合概率:
取对数:
由于采样概率等于模方:
振幅部分定义为:
这个结构让 amplitude 可以直接逐 token 采样,并自然给出 normalized probability。
相位¶
相位不影响 \(x\) 被采样到的概率,因为:
但 local energy 里会出现:
当 Hamiltonian 连接不同 basis state 时,相位决定不同贡献的相干叠加。教学版用 PhaseMLP 直接读取完整 bitstring,输出一个实数相位:
Local Energy¶
能量期望为:
整理成采样友好的形式:
其中:
这个公式很重要:对采样到的 \(x\),只需要找出 Hamiltonian 能连接到哪些 \(x'\),再调用模型计算 \(\psi_\theta(x')\) 和 \(\psi_\theta(x)\)。
如果 Hamiltonian 是 Pauli string 之和:
每个 \(P_k\) 作用到 bitstring 后只产生一个 connected state 以及一个矩阵元因子。ExactHamiltonian 正是在逐项执行这件事。
采样与 Counts¶
采样 \(10^5\) 次时,很多 state 会重复出现。VMC 估计只需要知道每个 unique state 出现了几次,所以采样器返回:
权重为:
能量估计写成:
教学版采样器还在每一步使用 restricted electron mask,保证最终 bitstring 满足固定的 \(N_\alpha\) 和 \(N_\beta\)。
VMC 梯度¶
目标是最小化:
VMC 梯度可以写成:
教学版构造一个 proxy loss:
对这个 proxy 调用 backward(),PyTorch 就会把 VMC 梯度写入模型参数。
代码总结构¶
整个程序可以按物理概念对应到模块:
| 物理概念 | 代码模块 | 作用 |
|---|---|---|
| occupation basis | state.py |
bitstring、token、电子数约束 |
| 波函数 ansatz | models.py |
AmplitudeTransformer + PhaseMLP |
| ( | \psi | ^2) 采样 |
| Hamiltonian | hamiltonian.py |
local energy |
| 变分优化 | trainer.py |
energy mean、loss proxy、optimizer |
| 实验配置 | config.py |
YAML 到 dataclass |
| 命令行 | cli/train.py |
训练入口 |
一轮训练可以压缩为:
sample states
-> evaluate local energies
-> estimate energy mean
-> build VMC proxy loss
-> backward and optimizer.step
阅读建议¶
初读代码可以按这个顺序:
state.py:先确认 bitstring 和 token 表示。models.py:看log_amp、phase、psi如何生成。sampling.py:看自回归采样和 counts。hamiltonian.py:看 local energy。trainer.py:看一轮训练如何串联。cli/train.py:看命令行如何进入 trainer。
修改代码时,建议每次只动一条链路,并同步补对应测试:
| 修改对象 | 优先测试 |
|---|---|
| 模型 | tests/test_models.py、tests/test_sampling.py |
| 采样 | tests/test_sampling.py、trainer smoke |
| Hamiltonian | tests/test_hamiltonian.py、CPU CLI smoke |
| 训练公式 | tests/test_trainer.py、CPU/GPU smoke |
一句话总结¶
NNQS+VMC 的图像是: