1. 量子程序异常分类与诊断流程建立
为什么先分类,再排障
一段带测量和条件分支的量子程序,从源码到硬件执行要穿过四道关卡:解析器 → 编译器/转译器 → 模拟器 → 硬件后端。每一道关卡失败时抛出的异常形态完全不同,如果一上来就盯着报错文本猜原因,很容易把“语法写错”误判成“硬件噪声”。因此第一步不是修 bug,而是定位异常发生在哪一层,再按层归类根因。
下面这段示例程序(Qiskit 风格)故意混合了多种潜在问题,用它来演示分层诊断:
from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.rz(0, 1) # 参数个数错误:rz 需要 (theta, qubit)
qc.measure(0, 0)
qc.measure(1, 1)
with qc.if_test((qc.clbits[0], 1)): # 条件分支:c0 == 1 时执行
qc.x(1)
backend = AerSimulator()
tqc = transpile(qc, backend)
result = backend.run(tqc, shots=1024).result()
print(result.get_counts())
四类异常的判别特征
| 异常类别 | 发生阶段 | 典型报错形态 | 判别要点 |
|---|---|---|---|
| 语法错误 | 构造线路 / 解析 | TypeError、参数个数不符、门名不存在 | 线路对象尚未生成,报错指向源码行 |
| 编译错误 | transpile / 映射 | TranspilerError、无法映射到后端耦合图 | 线路本身合法,但目标后端不支持 |
| 模拟器运行错误 | backend.run | QiskitError、条件分支不被支持、内存超限 | 线路已编译,执行期才失败 |
| 硬件执行错误 | 真实后端提交/回读 | 作业排队失败、校准过期、结果全为噪声 | 程序逻辑正确,结果不符合预期 |
可复用的排障检查清单
把上面的分层判断固化成清单,每次遇到异常按顺序勾选,避免跳层排查:
- 第 1 关 · 构造:线路对象能否成功创建?报错是否指向源码行?门名拼写、参数个数、寄存器索引是否与 API 签名一致?
- 第 2 关 · 编译:
transpile是否指定了目标后端?后端耦合图是否支持线路中的两比特门?是否需要optimization_level或basis_gates调整? - 第 3 关 · 模拟:模拟器是否支持条件分支(
if_test)?shots与内存是否合理?是否误用了只支持无噪声的模拟器? - 第 4 关 · 硬件:作业是否成功提交并回读?后端校准是否过期?结果分布是否与理论概率偏差过大(考虑噪声与读出误差)?
- 记录:每关记录“通过/失败 + 报错原文 + 定位行号”,形成可追溯的排障日志。
诊断顺序应严格从第 1 关向第 4 关推进:低层错误会伪装成高层异常。例如参数个数写错时,某些框架会在 transpile 阶段才抛出难以理解的映射错误,若直接跳到编译层排查就会走弯路。
示例中的
qc.rz(0, 1) 是故意写错的参数形式,用于演示语法错误判别;实际修复应写成 qc.rz(theta, 1) 并给出合法角度值。条件分支在不同框架/版本中的支持程度不同,提交前需确认目标后端能力。