验证 · 给量子线路写断言和测试

「看起来对」不等于「真的对」。这一章把量子程序当软件工程对待:用状态向量断言、幺正矩阵比对、统计检验,给量子线路写可复现的单元测试(pytest),并直面一个根本难题——大规模量子程序为什么难以经典验证。

作者 David更新于 第 9 篇(共 15 篇)

验证 · 给量子线路写断言和测试

上一章靠肉眼「打印状态、逐步核对」抓 bug。但作为工程师,你不会满足于「我盯着看了一遍,应该没问题」——你要自动化、可复现的正确性保证:单元测试、断言、CI 里一跑就知道对不对。这一章讲怎么给量子线路写测试。

断言一:状态向量相等

最直接的验证:跑出来的状态向量,等不等于理论上应该得到的那个。 Qiskit 的 Statevector 支持相等判断:

import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector

def make_bell():
    qc = QuantumCircuit(2)
    qc.h(0)
    qc.cx(0, 1)
    return qc

def test_bell_statevector():
    got  = Statevector(make_bell())
    want = Statevector([1/np.sqrt(2), 0, 0, 1/np.sqrt(2)])   # (|00⟩+|11⟩)/√2
    assert got.equiv(want)

用 .equiv(),而不是 ==。 量子态有个特点:整体乘一个「全局相位」(比如整个向量乘 −1-1 或 eiθe^{i\theta})是物理上完全等价的态——测量分布一模一样,没有任何可观测差别。.equiv() 会忽略这个全局相位,只比较「本质上是不是同一个态」;直接用 == 比原始数组,则会被这种无意义的相位差异误判为「不相等」。验证量子态相等,认准 .equiv()。

断言二:整段线路的矩阵

如果你验证的是一个门 / 子线路(而不是某个具体状态),更该比的是它的幺正矩阵——它对任意输入的作用都对,才算真对。用 Operator:

from qiskit.quantum_info import Operator

def test_hzh_equals_x():
    qc = QuantumCircuit(1)
    qc.h(0); qc.z(0); qc.h(0)          # 我们在「叠加与干涉」一章声称过 HZH = X
    assert Operator(qc).equiv(Operator.from_label('X'))

这条测试证明了「HZHHZH 确实等于 XX」对所有输入成立——比「拿几个具体输入试试」强得多。验证一段变换逻辑,比矩阵;验证一个具体结果,比状态向量。

断言三:统计检验(测量分布)

有时你没有模拟器的上帝视角(或想模拟真机行为),只能靠测量统计来验证。这时验证变成统计检验:跑足够多 shots,断言频率落在容差内、或断言某些结果不该出现。

from qiskit import transpile
from qiskit_aer import AerSimulator

def test_bell_only_correlated():
    qc = make_bell(); qc.measure_all()
    sim = AerSimulator()
    counts = sim.run(transpile(qc, sim), shots=2000).result().get_counts()
    # Bell 态只能测出 00 或 11,绝不会有 01 / 10
    assert set(counts.keys()) <= {'00', '11'}
    # 两者各约一半,给个宽松容差(统计涨落)
    assert abs(counts.get('00', 0) - counts.get('11', 0)) < 200

统计检验必须留容差,别写死。 量子测量是概率的,2000 次里 00 和 11 不会精确各 1000,而是 1000 上下浮动。断言写成 == 1000 必然时不时挂掉(flaky test)。正确做法:① 用足够多的 shots(shots 越多,频率越稳);② 断言落在一个合理容差内(像上面的 < 200);③ 对「绝不该出现」的结果(如这里的 01/10)才用硬断言。把量子测试当成统计实验来写,而不是确定性函数。

一个务实的验证策略

把上面拼成一套可操作的流程:

  1. 小规模用状态向量 / 矩阵精确验证(.equiv())——逻辑对不对,一测便知,不看运气。
  2. 端到端用统计检验(带容差)——模拟真机的采样行为。
  3. 拿已知答案的输入回归测试——比如让 Grover 在一个你知道答案的小搜索问题上跑,断言它高概率返回正确解。
  4. 把这些塞进 pytest + CI——每次改线路自动跑,防止改坏。

一个绕不开的根本难题

最后必须诚实面对一件事,它是量子验证独有的困境:

能用经典电脑「精确验证」的,只有小规模量子程序。 上面的 Statevector / Operator 验证,靠的是经典模拟——可经典模拟一个 nn-qubit 系统要 2n2^n 的内存,四十几个 qubit 就模拟不动了。而量子计算真正有价值的,恰恰是那些大到经典模拟不了的规模——可那时,你又没法用经典办法算出「正确答案」来对比。这是个深刻的悖论:量子优势的验证本身就是难题。

现实中的应对:① 在小规模上把算法逻辑验证到底(相信它对大规模同样成立);② 用结构化的自检(比如某些算法的答案能被经典地快速验证,即使不能被经典地快速求出——想想大数分解:分解很难,但验证「这两个因子乘起来等于原数」很容易);③ 在含噪模拟器上评估噪声影响。「求解难、验证易」的问题,天然更适合量子——因为你至少能验证它的输出。

小结与下一章

把量子程序当软件工程:用 Statevector.equiv() 断言状态、用 Operator.equiv() 断言整段变换的矩阵、用带容差的统计检验断言测量分布,塞进 pytest + CI。务实策略是「小规模精确验证 + 端到端统计检验 + 已知答案回归」。但要清醒:大规模量子程序难以经典验证,这是量子优势自带的悖论,「求解难验证易」的问题因此格外适合量子。

零件、调试、验证都备齐了,是时候看看这些东西拼成真正的算法能干什么。下一站从一个关键概念开始——量子算法怎么把一个经典函数,变成能被叠加「一次性喂进去」的黑箱。👉 预言机:把经典函数变成量子黑箱。

参考文献

本页目录