表面码模拟:Stim + PyMatching 教程

表面码模拟:Stim + PyMatching 教程 | QuantumComputingCourses.com

Stim 是 Google 开发的高性能稳定子电路模拟器,专为量子纠错研究而构建。与通用模拟器不同,Stim 将电路表示为稳定子表(stabilizer tableau),并能在 CPU 上每秒模拟数百万次运行(shots),从而能够实际收集所需的统计数据,以测量现实码距下的逻辑错误率。

PyMatching 是表面码的标准最小权重完美匹配(MWPM)解码器。Stim + PyMatching 共同构成了容错量子计算研究的标准模拟栈。

安装

python 复制代码
pip install stim pymatching numpy matplotlib

什么是稳定子电路?

在编写代码之前,先快速回顾一下 Stim 为何如此快速。表面码在泡利稳定子上操作:即泡利算符 I、X、Y、Z 的张量积。关键性质在于,纠错循环中的所有操作(CNOT 门、Hadamard 门,以及 X 或 Z 基底的测量)都保持稳定子结构。Stim 直接追踪稳定子,而非态矢量,因此内存占用与量子比特数量呈线性关系,而非指数关系。

对于一个码距为 d 的表面码,其物理量子比特数量为 d² + (d-1)²:

  • 态矢量模拟器:需要 2ⁿ 个复振幅
  • Stim:需要 n + n² 比特用于稳定子表

当 d=3(17 个量子比特)时:态矢量需要 2¹⁷ = 131,072 个振幅,而 Stim 仅需约 289 比特。

在 Stim 中定义表面码

Stim 使用领域特定语言(DSL)来定义电路。以下是生成一个码距为 3 的表面码电路的方法:

python 复制代码
import stim

# Stim 可以程序化地生成标准编码
circuit = stim.Circuit.generated(
    code_task="surface_code:rotated_memory_z",
    distance=3,
    rounds=3,          # 纠错循环次数
    after_clifford_depolarization=0.001,   # 门错误率
    before_round_data_depolarization=0.001,
    before_measure_flip_probability=0.001,
)

print(circuit)        # 打印完整的 Stim 电路
print(f"Qubits: {circuit.num_qubits}")
print(f"Measurements: {circuit.num_measurements}")

surface_code:rotated_memory_z 任务将单个逻辑量子比特编码在旋转表面码中,并运行综合征测量循环,最终追踪逻辑 Z 可观测量是否发生翻转。

可用的编码任务:

  • surface_code:rotated_memory_z(Z 基底逻辑量子比特)
  • surface_code:rotated_memory_x(X 基底逻辑量子比特)
  • repetition_code:memory(更简单的 1D 编码,用于测试)

收集综合征数据

Stim 的探测器错误模型(DEM, Detector Error Model)是连接解码器的关键接口。探测器是一组测量值,在无错误时它们的异或(XOR)应为 0。当探测器触发(XOR = 1)时,表示某处发生了错误。

python 复制代码
import stim
import numpy as np

# 生成码距 d=3 的表面码,3 个循环,错误率 p=1%
circuit = stim.Circuit.generated(
    "surface_code:rotated_memory_z",
    distance=3,
    rounds=3,
    after_clifford_depolarization=0.01,
    before_round_data_depolarization=0.01,
    before_measure_flip_probability=0.01,
)

# 编译快速采样器
sampler = circuit.compile_detector_sampler()

# 采样 100,000 次运行
# detection_events: (n_shots, n_detectors) 布尔数组
# observable_flips: (n_shots, n_observables) 布尔数组(即"答案")
detection_events, observable_flips = sampler.sample(
    shots=100_000,
    separate_observables=True,
)

print(f"Detection events shape: {detection_events.shape}")
print(f"Observable flips shape: {observable_flips.shape}")
print(f"Fraction of shots with any detection: {detection_events.any(axis=1).mean():.3f}")
print(f"Raw logical error rate (no decoding): {observable_flips[:, 0].mean():.4f}")

使用 PyMatching 解码

检测事件告诉我们发生了 某些错误,但并未告诉我们在哪里。解码器的任务是根据综合征模式推断最可能的纠错方案。最小权重完美匹配(MWPM)寻找与观测综合征一致的最小权重错误集合。

python 复制代码
import pymatching

# 从电路构建探测器错误模型
# 这编码了 MWPM 解码器所需的图结构
dem = circuit.detector_error_model(decompose_errors=True)
matcher = pymatching.Matching.from_detector_error_model(dem)

# 一次性解码所有运行(向量化,速度快)
predictions = matcher.decode_batch(detection_events)

# 将预测结果与实际可观测量翻转进行比较
# 当解码器的预测与实际翻转不一致时,即发生逻辑错误
num_errors = np.sum(predictions != observable_flips)
logical_error_rate = num_errors / (len(predictions) * observable_flips.shape[1])

print(f"Logical error rate (with MWPM decoding): {logical_error_rate:.5f}")

对于码距为 3 的编码,在 1% 物理错误率下,使用 MWPM 解码后的逻辑错误率通常在 0.1-0.2% 左右,约为物理错误率的 5-10 倍低,这证实了该编码处于阈值以下。

测量编码阈值

阈值是指:当物理错误率低于该值时,增加编码码距可以降低逻辑错误率。在阈值以下,码距 d+2 的逻辑错误率低于码距 d。在阈值以上,则相反。

python 复制代码
import stim
import pymatching
import numpy as np
import matplotlib.pyplot as plt

distances = [3, 5, 7]
error_rates = np.logspace(-3, -1.3, 12)  # 0.001 到 0.05
shots = 50_000

results = {}

for d in distances:
    logical_errors = []
    for p in error_rates:
        circuit = stim.Circuit.generated(
            "surface_code:rotated_memory_z",
            distance=d,
            rounds=d,               # 循环次数 = 码距是标准做法
            after_clifford_depolarization=p,
            before_round_data_depolarization=p,
            before_measure_flip_probability=p,
        )
        dem = circuit.detector_error_model(decompose_errors=True)
        matcher = pymatching.Matching.from_detector_model(dem)

        sampler = circuit.compile_detector_sampler()
        detection_events, observable_flips = sampler.sample(
            shots=shots, separate_observables=True
        )
        predictions = matcher.decode_batch(detection_events)

        logical_err = np.sum(predictions != observable_flips) / (shots * observable_flips.shape[1])
        logical_errors.append(logical_err)
        print(f"d={d}, p={p:.4f}, logical_err={logical_err:.5f}")

    results[d] = logical_errors

# 绘制阈值曲线
plt.figure(figsize=(8, 5))
for d in distances:
    plt.semilogy(error_rates * 100, results[d], 'o-', label=f'd={d}')
plt.xlabel("Physical error rate (%)")
plt.ylabel("Logical error rate (log scale)")
plt.title("Surface Code Threshold")
plt.legend()
plt.grid(True, alpha=0.3)
plt.axvline(x=1.0, color='gray', linestyle='--', alpha=0.5, label='~1% threshold')
plt.tight_layout()
plt.savefig("surface_code_threshold.png", dpi=150)
plt.show()

# 这些曲线在 p ~ 0.9-1.1% 附近交叉:这就是阈值
# 阈值以下:更高的 d → 更低的逻辑错误率(好!)
# 阈值以上:更高的 d → 更高的逻辑错误率(坏)

这些曲线的交叉点即为阈值。对于退极化噪声模型,表面码的阈值约为 1%。这就是为何实现 99% 以上的双量子比特门保真度,是面向容错操作硬件的关键基准。

逻辑错误率与码距的关系(阈值以下)

在阈值以下,逻辑错误率随码距指数下降。一个有用的近似公式:

复制代码
logical_error_rate ≈ A * (p / p_threshold)^((d+1)/2)

我们来验证这一标度关系:

python 复制代码
# 在 p = 0.005(阈值的一半)处拟合亚阈值标度
p_fixed = 0.005
distances_fit = [3, 5, 7, 9, 11]
logical_errs_fit = []

for d in distances_fit:
    circuit = stim.Circuit.generated(
        "surface_code:rotated_memory_z",
        distance=d,
        rounds=d,
        after_clifford_depolarization=p_fixed,
        before_round_data_depolarization=p_fixed,
        before_measure_flip_probability=p_fixed,
    )
    dem = circuit.detector_error_model(decompose_errors=True)
    matcher = pymatching.Matching.from_detector_error_model(dem)
    sampler = circuit.compile_detector_sampler()
    detection_events, observable_flips = sampler.sample(100_000, separate_observables=True)
    predictions = matcher.decode_batch(detection_events)
    logical_errs_fit.append(np.sum(predictions != observable_flips) / (100_000 * observable_flips.shape[1]))

# 拟合 log(p_L) 与 d 的关系
log_errs = np.log(logical_errs_fit)
coeffs = np.polyfit(distances_fit, log_errs, 1)
print(f"Exponential suppression factor per 2 distance steps: {np.exp(2 * coeffs[0]):.3f}")
# 预期:大致为 (0.005/0.01)^1 = 0.5,每 (d+1)/2 步

加速技巧

用于生产环境:

  • 按内存容量分批采样:sampler.sample(shots=1_000_000) 在 8GB 内存下对 d=7 是可行的
  • pymatching 使用 C++ 实现的 MWPM,数百万次运行在数秒内完成
  • 用于交叉验证时,也可尝试 beliefmatching(置信传播 + MWPM),在高码距下性能可超越纯 MWPM
python 复制代码
# 运行时间基准测试
import time

circuit = stim.Circuit.generated(
    "surface_code:rotated_memory_z",
    distance=7,
    rounds=7,
    after_clifford_depolarization=0.005,
)
dem = circuit.detector_error_model(decompose_errors=True)
matcher = pymatching.Matching.from_detector_error_model(dem)
sampler = circuit.compile_detector_sampler()

t0 = time.time()
detection_events, observable_flips = sampler.sample(1_000_000, separate_observables=True)
predictions = matcher.decode_batch(detection_events)
t1 = time.time()

print(f"1M shots of d=7, decoded in {t1-t0:.1f}s")
# 在笔记本电脑上通常 3-10 秒 ------ Stim 很快

后续进阶

本教程涵盖了在简单退极化噪声模型下模拟表面码的基础。真实的量子纠错研究需要更进一步:

  • 关联噪声:包含串扰和泄漏的电路级噪声需要修改解码方案
  • 偏置噪声:某些硬件主要存在退相位或弛豫错误;定制编码(如 XZZX 表面码)可利用这一特性
  • 容错门:本教程仅涵盖存储实验;实现逻辑门需要横贯操作或编码切换
  • 魔法态蒸馏:容错地实现 T 门需要工厂电路,这些电路也可以用 Stim 模拟
  • 置信传播解码器:在更高速率编码和近阈值错误率下,性能优于 MWPM

Stim 的文档包含了所有这些内容的工作示例。Stim 论文和 PyMatching 论文是主要参考文献。

原文

相关推荐
Eloudy5 小时前
伊辛解码(Ising Decoding)
人工智能·量子计算
国际学术会议-杨老师8 小时前
2026年量子算法、密码学与数据分析国际会议(QACDA 2026)
数据分析·密码学·量子计算
浔川python社8 小时前
走进奇妙的量子世界:原理与现实应用
量子计算
AI科技星9 小时前
第四卷:橡皮泥江湖(拓扑学)
c语言·开发语言·网络·量子计算·agi·拓扑学
MicroTech20259 小时前
量子隐形传态路线的瓶颈与突破,微算法科技(MLGO)以技术创新助力量子通信长距离组网
科技·算法·量子计算
Eloudy10 小时前
最小权重完美匹配(MWPM)与表面码纠错
算法·量子计算
Litluecat1 天前
2026年6月11日科技热点新闻
科技·量子计算·热点·新闻·每日·速览
Eloudy1 天前
ns-3 在数据中心网络仿真
网络·人工智能·量子计算
Eloudy1 天前
ns-3 网络仿真简介
网络·机器学习·量子计算·量子力学