# 调试 · 量子程序怎么 debug

> 量子程序没法打断点、没法 print 变量，一测还坍缩——那怎么 debug？靠模拟器的「上帝视角」：随时打印中途状态向量、看概率分布、把整段线路当矩阵看、画 Bloch 球。这一章给一套可操作的量子调试工作流，并抓一个真实的 bug。

- 作者：David（道雾轩）
- 专栏：写给程序员的量子计算（https://daiw.org/manual/quantum-computing.md）
- 最后更新：2026-07-14
- 原文：https://daiw.org/manual/quantum-computing/debugging
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# 调试 · 量子程序怎么 debug

这是「写给程序员」这个专栏的立身之本。写普通程序卡壳了，你打断点、`print` 变量、单步跟踪。可量子程序呢？qubit 看不见摸不着，你想 `print` 它——一[测量](https://daiw.org/manual/quantum-computing/measurement)就坍缩，把要调的状态给毁了。那还怎么 debug？

答案是：**在模拟器上调，用它的「上帝视角」。**

## 核心工具：随时打印状态向量

模拟器和真机最大的区别，是它**知道全部内幕**——任何时刻的完整状态向量，它都能给你（真机给不了）。所以调试量子程序的头号手段，就是**在线路的任意位置，把状态向量打印出来，和你脑子里的预期对比**。

技巧很简单：**想看第 k 步之后的状态，就构造「只到第 k 步」的线路，`Statevector` 它。**（注意别加测量。）

```python
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector

# 想调一个「本应造出 Bell 态」的线路,一步步看
qc = QuantumCircuit(2)

qc.h(0)
print("H 之后:", Statevector(qc).probabilities_dict())
# {'00': 0.5, '01': 0.5}   ← qubit0 叠加,符合预期

qc.cx(0, 1)
print("CX 之后:", Statevector(qc).probabilities_dict())
# {'00': 0.5, '11': 0.5}   ← Bell 态,对了
```

`probabilities_dict()` 比原始振幅更好读（直接给每个基础态的测量概率）。一步步打印、一步步核对——**这就是量子版的「单步调试」。**

## 其它几件趁手的工具

| 工具 | 干什么 | 代码 |
| --- | --- | --- |
| `qc.draw()` | 画出线路 ASCII 图，核对结构 | `print(qc.draw())` |
| `Statevector(qc)` | 看完整振幅（含相位） | 如上 |
| `.probabilities_dict()` | 看测量概率（更好读） | 如上 |
| `Operator(qc)` | 把整段线路当一个矩阵看 | `print(Operator(qc).data)` |
| `plot_bloch_multivector` | 画 Bloch 球(1~2 qubit) | 需 matplotlib |

<Callout type="info">
  **`Operator` 是个被低估的调试利器。** 当你写了一段子线路、怀疑它整体做的变换不对，别一个个门去看——直接 `Operator(qc).data` 把它整体的矩阵打出来，和你期望的幺正矩阵比对。比如你想实现一个 $X$ 门，却发现整段线路的矩阵不是 $\begin{bmatrix}0&1\\1&0\end{bmatrix}$，那就是搭错了。**把一段线路「压平」成一个矩阵来看，常常一眼看穿 bug。**
</Callout>

## 抓一个真实的 bug

调试讲一百遍不如抓一个虫。看这段「想造 Bell 态」却有问题的代码：

```python
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(1, 0)      # ← bug 在这
print(Statevector(qc).probabilities_dict())
# {'00': 0.5, '01': 0.5}     ← 不对!这不是 Bell 态
```

预期 Bell 态应该是 `{'00': 0.5, '11': 0.5}`，实际却是 `{'00': 0.5, '01': 0.5}`——**qubit 1 根本没被纠缠进来**。打印状态一眼看出「结果不对」，再回头看代码：`cx(1, 0)` 把控制位和目标位**写反了**——我们想用 qubit 0（叠加的那个）当控制去翻 qubit 1，却写成了用 qubit 1（还是 $\ket0$）当控制。控制位是 0，CNOT 什么都不做，自然没纠缠。改成 `cx(0, 1)` 就对了。

<Callout type="warn">
  **量子程序最高频的几类 bug，靠「打印中途状态」几乎都能抓到：** ① **qubit 顺序 / 控制目标写反**（如上，也呼应[小端序陷阱](https://daiw.org/manual/quantum-computing/multi-qubit)）；② **门作用在错的 qubit 上**；③ **相位错误**——这个最阴险，因为相位[单独测不出](https://daiw.org/manual/quantum-computing/single-gates)，`probabilities_dict()` 也看不出来（它只看模平方）。要抓相位 bug，得看**完整的 `Statevector`（含正负号 / 复数）**，或者故意加一段干涉把相位「逼」成概率差异再测。**调相位问题，一定要看振幅本身，不能只看概率。**
</Callout>

## 真机上怎么办

诚实地说：**上面这套「打印状态向量」的调试法，只在模拟器上成立**——真正的量子计算机**给不了**你状态向量（[测量即坍缩](https://daiw.org/manual/quantum-computing/measurement)）。所以标准工作流是：

1. **先在模拟器上，用状态向量调到完全正确**（逻辑对了）。
2. **再拿到真机 / 含噪模拟器上跑**，这时结果会因为**噪声**而偏离理想（[后面](https://daiw.org/manual/quantum-computing/noise-nisq)专讲）——这已经不是「逻辑 bug」，而是「物理误差」，是另一类问题。

换句话说：**「逻辑对不对」在模拟器上调；「真机上准不准」是噪声问题**，两者分开对付。先在模拟器上把逻辑锤对，是省心的前提。

## 小结与下一章

量子程序 debug 的核心，是借模拟器的上帝视角：**想看哪一步，就构造到那一步的线路、打印 `Statevector` / `probabilities_dict()`，和预期逐步核对**；`Operator` 把整段线路压成矩阵看；高频 bug（顺序反、控制目标反、相位错）基本都能这么抓——但**相位 bug 必须看完整振幅、不能只看概率**。逻辑在模拟器上调，噪声问题另算。

调对了只是「看起来对」。作为工程师，你还想要**自动化的、可复现的正确性保证**——给量子线路写**单元测试和断言**。下一章讲怎么验证。👉 [验证：给量子线路写断言和测试](https://daiw.org/manual/quantum-computing/verification)。

## 参考文献

- [1] Qiskit 官方文档.「Statevector / Operator / visualization.」https://docs.quantum.ibm.com/api/qiskit/quantum_info —— 调试相关 API。
- [2] Qiskit 官方文档.「Visualize circuits & states.」https://docs.quantum.ibm.com/guides/visualize-circuits —— 线路与状态可视化。
- [3] IBM Quantum Learning.「Debugging quantum programs.」https://learning.quantum.ibm.com —— 调试工作流。
