4. 量子模拟器后端实战
在Qiskit中,Aer是本地高性能模拟器框架,它并不是一个单一后端,而是一组面向不同任务的后端集合。初学者最容易混淆的是:同样运行一个量子线路,为什么有时能拿到完整态矢量,有时只能拿到测量计数,有时又能得到整个酉矩阵?答案在于后端保存和计算的对象不同。本节围绕三个最常用的Aer后端——StatevectorSampler(态矢量)、QasmSimulator(含噪声采样)、UnitarySimulator(酉矩阵)——展开对比,并演示噪声模型与快照(snapshot)的用法。
三个后端到底在算什么
先明确各自的核心输出对象。态矢量后端保存的是线路执行到某一时刻的完整量子态 \(|\psi\rangle\),对 \(n\) 个量子比特给出 \(2^n\) 个复数振幅,因此可以精确读出每个基态的振幅与相位,适合验证叠加、纠缠、干涉等算法逻辑。QASM后端模拟的是含噪声的真实采样过程,它按概率从最终态中抽样,输出的是经典寄存器中的比特串计数,更接近真实量子硬件的测量行为。酉矩阵后端则忽略测量,把整个线路当作一个线性算符 \(U\) 来计算,输出 \(2^n \times 2^n\) 的复矩阵,用于验证线路实现的变换是否正确。
三者的资源开销差异极大。态矢量随比特数呈 \(2^n\) 增长,酉矩阵则呈 \(4^n\) 增长,因此酉矩阵后端通常只能处理十几个比特以内的小线路;QASM后端虽然也依赖内部态演化,但输出规模小,且支持噪声,是工程验证的主力。
用Statevector后端观察叠加与相位
下面用两比特线路演示态矢量后端的典型用法。线路先对 qubit 0 施加 H 门,再以 qubit 0 为控制、qubit 1 为目标施加 CX 门,生成 Bell 态。使用 StatevectorSampler 时,我们通过 run 提交线路并读取 result 中的态矢量数据。
from qiskit import QuantumCircuit
from qiskit_aer.primitives import SamplerV2 as StatevectorSampler
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
sampler = StatevectorSampler()
result = sampler.run([qc], shots=1024).result()
data = result[0].data
print(data.meas.get_counts())
若改用 Statevector 类直接获取振幅,可调用 Statevector.from_instruction(qc),得到形如 [0.707+0j, 0, 0, 0.707+0j] 的向量。注意这里的顺序约定:Qiskit 采用小端序,索引 0 对应 |00⟩,索引 3 对应 |11⟩。振幅的模平方给出各基态概率,相位则决定了后续干涉行为,这是计数结果无法直接体现的。
用Qasm后端执行噪声模拟
真实设备存在退相干、门误差和读出误差。Aer 允许我们构建噪声模型并注入 QASM 后端。一个常用的教学示例是:给单比特门加去极化噪声,给双比特门加去极化噪声,再给测量加读出翻转误差。
from qiskit_aer.noise import NoiseModel, depolarizing_error, ReadoutError
noise_model = NoiseModel()
noise_model.add_all_qubit_quantum_error(
depolarizing_error(0.001, 1), ['h', 'x', 'rx'])
noise_model.add_all_qubit_quantum_error(
depolarizing_error(0.01, 2), ['cx'])
readout = ReadoutError([[0.98, 0.02], [0.03, 0.97]])
noise_model.add_all_qubit_readout_error(readout)
把该模型传给 AerSimulator(noise_model=noise_model) 后运行同一 Bell 线路,理想情况下 {'00': ~512, '11': ~488},加入噪声后会出现少量 '01' 与 '10' 计数,例如 {'00': 498, '11': 476, '01': 26, '10': 24}(此处为示例性数值,用于说明噪声导致的错误分布)。通过对比理想与含噪计数,可以估算线路的保真度,并判断噪声参数是否在可接受范围。
快照:在线路中间抓取量子态
有时我们关心的不是最终结果,而是线路执行到中间某一步的态。Aer 提供 save_statevector 指令,可在指定位置保存态矢量。例如在 H 门之后、CX 门之前插入快照,就能看到此时 qubit 0 处于叠加态而 qubit 1 仍为 |0⟩,态矢量为 [0.707, 0.707, 0, 0];执行 CX 后变为纠缠态 [0.707, 0, 0, 0.707]。这种中间态观测对调试算法非常关键,尤其是验证纠缠是否按预期生成。
qc = QuantumCircuit(2)
qc.h(0)
qc.save_statevector(label='after_h')
qc.cx(0, 1)
qc.save_statevector(label='after_cx')
sim = AerSimulator(method='statevector')
res = sim.run(qc).result()
print(res.data()['after_h'])
print(res.data()['after_cx'])
性能与适用场景对照
| 后端 | 核心输出 | 资源增长 | 是否支持噪声 | 典型适用场景 |
|---|---|---|---|---|
| Statevector | 完整态矢量 | 2ⁿ | 否 | 算法逻辑、相位、纠缠验证 |
| QasmSimulator | 测量计数 | 2ⁿ(内部) | 是 | 噪声评估、硬件结果对照 |
| UnitarySimulator | 酉矩阵 | 4ⁿ | 否 | 门序列正确性、小线路验证 |
总结来看,Statevector 后端回答“量子态长什么样”,Qasm 后端回答“含噪声测量会得到什么”,Unitary 后端回答“这段线路整体实现了什么变换”。理解三者的计算对象与资源特性,才能在量子应用开发中选对工具、读懂结果、定位问题。