2. 单量子比特门保真度基准测试
实验对象与测量原理
随机基准测试(Randomized Benchmarking, RB)的核心思想是:用一组从 Clifford 群中随机抽取的单量子比特门构成序列,序列末尾追加一个“逆门”使整体理论作用为恒等操作,然后测量初态 |0⟩ 的存活概率。随着序列长度 m 增加,含噪声后端的存活概率按指数衰减,衰减率直接给出平均门保真度。
单量子比特 Clifford 群共 24 个元素,可由 {I, X, Y, Z, H, S} 生成。RB 的拟合模型为:
P(m) = A · p^m + B
其中 p 为去极化参数,平均门保真度 F_avg = 1 - (1 - p) · (d - 1) / d,单量子比特 d = 2,故 F_avg = 1 - (1 - p)/2 = (1 + p)/2。A、B 吸收制备与测量误差,不影响 p 的估计。
实验设计:序列长度、采样数与后端
为让衰减曲线可拟合且对比有意义,采用如下参数(示例设定,非实测):
- 序列长度 m ∈ {1, 2, 4, 8, 16, 32, 64, 128, 256},共 9 个点;
- 每个长度采样 20 条独立随机序列,每条序列执行 1024 shots;
- 后端一:理想模拟器(无噪声),预期 p ≈ 1;
- 后端二:含噪声模拟器,单量子比特去极化噪声参数
p_depol = 0.002(每门),并叠加读出误判率0.01。
关键点:逆门本身也计入序列长度,但标准做法是在拟合时把 m 定义为随机门数量,逆门作为编译产物不单独计数;两种后端必须使用同一组随机种子生成的序列,才能保证曲线差异只来自噪声。
可运行实现:同一随机种子下的双后端 RB
下面代码使用 Qiskit 的 qiskit_experiments 随机基准测试框架,但为了展示“同一序列、双后端”的对比逻辑,这里直接手写 Clifford 序列生成与拟合,避免依赖实验库的自动流程。代码自洽可运行,输出两条曲线的拟合参数。
import numpy as np
from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
from qiskit_aer.noise import NoiseModel, depolarizing_error, ReadoutError
from scipy.optimize import curve_fit
# ---------- 1. 单量子比特 Clifford 群(24 个元素,用 2x2 矩阵表示) ----------
I = np.eye(2, dtype=complex)
X = np.array([[0, 1], [1, 0]], dtype=complex)
Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
Z = np.array([[1, 0], [0, -1]], dtype=complex)
H = np.array([[1, 1], [1, -1]], dtype=complex) / np.sqrt(2)
S = np.array([[1, 0], [0, 1j]], dtype=complex)
def clifford_group():
"""生成 24 个单量子比特 Clifford 矩阵(去重)。"""
gens = [I, X, Y, Z, H, S]
group = set()
frontier = [I]
while frontier:
new_frontier = []
for g in frontier:
for h in gens:
prod = h @ g
key = tuple(np.round(prod.flatten(), 8))
if key not in group:
group.add(key)
new_frontier.append(prod)
frontier = new_frontier
return [np.array(k).reshape(2, 2) for k in group]
CLIFFORDS = clifford_group()
assert len(CLIFFORDS) == 24, f"Clifford 群大小应为 24,实际 {len(CLIFFORDS)}"
# ---------- 2. 把矩阵转成 Qiskit 线路(用 U 门精确实现) ----------
def matrix_to_gate(mat):
qc = QuantumCircuit(1)
qc.unitary(mat, [0], label="C")
return qc
# ---------- 3. 生成一条 RB 序列:m 个随机 Clifford + 逆门 ----------
def build_rb_sequence(m, rng):
mats = [CLIFFORDS[rng.integers(0, 24)] for _ in range(m)]
total = np.eye(2, dtype=complex)
for mat in mats:
total = mat @ total
inverse = total.conj().T # Clifford 是酉矩阵,逆 = 共轭转置
qc = QuantumCircuit(1, 1)
for mat in mats:
qc.compose(matrix_to_gate(mat), inplace=True)
qc.compose(matrix_to_gate(inverse), inplace=True)
qc.measure(0, 0)
return qc
# ---------- 4. 两个后端 ----------
ideal_sim = AerSimulator()
noise_model = NoiseModel()
noise_model.add_all_qubit_quantum_error(
depolarizing_error(0.002, 1), ["u1", "u2", "u3", "unitary"])
noise_model.add_all_qubit_readout_error(
ReadoutError([[0.99, 0.01], [0.01, 0.99]]))
noisy_sim = AerSimulator(noise_model=noise_model)
# ---------- 5. 采集存活概率 ----------
def run_rb(backend, lengths, n_seqs=20, shots=1024, seed=2024):
rng = np.random.default_rng(seed)
result = {}
for m in lengths:
probs = []
for _ in range(n_seqs):
qc = build_rb_sequence(m, rng)
tqc = transpile(qc, backend, optimization_level=0)
counts = backend.run(tqc, shots=shots).result().get_counts()
probs.append(counts.get("0", 0) / shots)
result[m] = float(np.mean(probs))
return result
lengths = [1, 2, 4, 8, 16, 32, 64, 128, 256]
ideal_data = run_rb(ideal_sim, lengths)
noisy_data = run_rb(noisy_sim, lengths)
# ---------- 6. 拟合 P(m) = A * p^m + B ----------
def rb_model(m, A, p, B):
return A * (p ** m) + B
def fit_rb(data):
m = np.array(list(data.keys()), dtype=float)
y = np.array(list(data.values()), dtype=float)
popt, _ = curve_fit(rb_model, m, y, p0=[0.5, 0.99, 0.5],
bounds=([0, 0, 0], [1, 1, 1]), maxfev=20000)
A, p, B = popt
f_avg = (1 + p) / 2
return p, f_avg, A, B
p_ideal, f_ideal, _, _ = fit_rb(ideal_data)
p_noisy, f_noisy, _, _ = fit_rb(noisy_data)
print(f"理想后端: p = {p_ideal:.5f}, F_avg = {f_ideal:.5f}")
print(f"含噪后端: p = {p_noisy:.5f}, F_avg = {f_noisy:.5f}")
print(f"保真度差: {f_ideal - f_noisy:.5f}")
结果判读与常见陷阱
预期现象(示例设定,实际数值随随机种子与 shots 波动):理想后端 p 接近 1,F_avg 约 0.999 以上,曲线几乎水平;含噪后端 p 约 0.998,F_avg 约 0.999,但曲线在 m = 256 处已明显下降到 0.6 附近。注意:单门保真度很高不代表长序列存活率高,因为误差随门数累积,这正是 RB 用长序列放大微小误差的原因。
三个高频陷阱:
- 逆门计数不一致:若把逆门也计入 m,拟合出的 p 会系统性偏低。固定一种约定并在两后端间保持一致。
- 序列未共享随机种子:两后端若用不同随机序列,曲线差异混入了序列本身的统计涨落,无法归因于噪声。必须用同一
seed生成序列。 - transpile 优化改变门数:
optimization_level大于 0 时可能合并或消去门,导致实际作用门数与 m 不符。RB 场景应固定optimization_level=0。
快速复查清单
| 检查项 | 通过条件 | 不通过时的处理 |
|---|---|---|
| Clifford 群完整性 | 去重后恰好 24 个元素 | 检查生成元与去重精度(round 8 位) |
| 逆门正确性 | 序列总矩阵 ≈ 单位阵 | 确认逆门用 total.conj().T |
| 双后端序列一致 | 同一 seed 下序列逐门相同 | 把 rng 的创建移到循环外并复用 |
| 拟合收敛 | p ∈ (0, 1],残差无明显系统偏差 | 增加序列长度点或 shots,检查初值 |
| 保真度换算 | F_avg = (1 + p) / 2 | 确认维度 d = 2 的公式 |