4. 协议开发环境搭建

超密编码协议的开发离不开一个稳定、可复现的量子计算开发环境。本节从零开始,完成 Python 与 Qiskit 的安装配置,理解量子模拟器后端的差异与选择依据,建立版本管理习惯,并最终搭建出第一个可运行、可观测的超密编码线路。整个过程以“能跑通、能看懂、能复现”为目标,而不是简单地把库装上。

一、Python 与 Qiskit 的安装配置

Qiskit 是一个基于 Python 的开源量子计算 SDK,当前主流版本为 1.x 系列,其核心包已拆分为 qiskit(含 Terra 编译与基础线路能力)与 qiskit-aer(高性能模拟器)。建议使用 Python 3.10~3.12,并用虚拟环境隔离项目依赖,避免不同项目间的版本冲突。以下命令在项目目录下创建并激活虚拟环境:

python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate

pip install --upgrade pip
pip install qiskit qiskit-aer

安装完成后,用一段最小脚本验证环境是否可用,同时打印版本号,便于后续记录:

import qiskit
from qiskit_aer import AerSimulator

print("Qiskit:", qiskit.__version__)
backend = AerSimulator()
print("AerSimulator 就绪:", backend.name)

如果输出正常且无导入错误,说明基础环境已就绪。若在安装 qiskit-aer 时遇到编译问题,可优先检查 Python 版本是否过高、是否缺少 C++ 编译工具链,或改用预编译 wheel 对应的平台版本。环境验证通过后,再进入后端选择环节。

二、量子模拟器后端的选择

Qiskit 提供多种模拟后端,选择依据主要是“是否需要噪声”和“线路规模”。AerSimulator 是通用高性能模拟器,支持状态向量、密度矩阵、稳定器等多种方法,可通过 method 参数指定;BasicAer 是较老的纯 Python 参考实现,速度慢但便于理解;FakeBackend 系列则用于模拟真实硬件的噪声特性。对于超密编码这类小规模线路,默认的状态向量法已足够,且能直接给出理想概率分布。

需要特别说明的是,超密编码的核心是“用 2 个经典比特编码 1 个量子比特”,其正确性验证依赖贝尔态测量后的联合概率分布。因此后端选择应保证测量结果可稳定复现,建议固定随机种子,并在需要时开启噪声模型做对比实验。下面的结构图展示了从环境到后端再到线路执行的关系:

超密编码开发环境与执行链路 Python 虚拟环境 .venv 隔离依赖 Python 3.10~3.12 Qiskit 核心包 qiskit 1.x QuantumCircuit / transpile AerSimulator 状态向量 / 密度矩阵 固定 seed 可复现 测量结果 计数 / 概率 00~11 超密编码线路关键阶段 ① 制备贝尔态 H(q0) + CX(q0,q1) ② 编码经典比特 X / Z 作用于 q0 ③ 解码与测量 CX + H + measure ④ 判读联合概率 目标态占比接近 1

三、开发工具链与版本管理

一个可复现的量子项目至少应固定三样东西:Python 版本、Qiskit 版本、随机种子。推荐在项目根目录维护 requirements.txt,把依赖版本写死,例如 qiskit==1.2.4、qiskit-aer==0.15.1,并在 README 中记录 Python 版本。代码层面,把线路构建、后端执行、结果统计拆成独立函数,便于单元测试和替换后端。

版本管理方面,使用 Git 管理源码,.gitignore 中排除 .venv/、__pycache__/ 和结果数据文件;对关键实验,把线路参数、种子、后端名称和测量计数一并保存为 JSON,形成“实验记录”。这样当 Qiskit 升级导致行为变化时,可以快速定位是环境问题还是线路逻辑问题。工具链上,编辑器可选 VS Code 并安装 Python 与 Jupyter 扩展,交互式调试线路时用 Notebook 观察中间态,正式脚本则用 .py 保证可测试性。

四、第一个超密编码线路

超密编码的协议约定如下:Alice 与 Bob 共享贝尔态 |Φ⁺⟩=(|00⟩+|11⟩)/√2,Alice 根据要发送的 2 位经典信息 b1b0 对自己持有的 q0 施加操作:00 不操作,01 施加 X,10 施加 Z,11 施加 ZX(顺序不影响结果)。Bob 收到 q0 后,执行 CX(q0→q1) 再对 q0 施加 H,最后测量两个比特,即可确定性地恢复出 b1b0。下面以发送 10 为例搭建线路:

from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator

def build_superdense(bits: str) -> QuantumCircuit:
    qc = QuantumCircuit(2, 2)
    # ① 制备贝尔态
    qc.h(0)
    qc.cx(0, 1)
    qc.barrier()
    # ② 按经典比特编码
    if bits[1] == "1":   # 低位 -> X
        qc.x(0)
    if bits[0] == "1":   # 高位 -> Z
        qc.z(0)
    qc.barrier()
    # ③ 解码
    qc.cx(0, 1)
    qc.h(0)
    # ④ 测量
    qc.measure([0, 1], [0, 1])
    return qc

qc = build_superdense("10")
backend = AerSimulator(seed_simulator=42)
result = backend.run(transpile(qc, backend), shots=1024).result()
counts = result.get_counts()
print(counts)   # 期望 {'10': 1024} 附近

运行后若 counts 中 '10' 的计数接近 1024(理想模拟器下应为全部),说明编码与解码一致。判断依据不是“有没有结果”,而是“目标比特串是否占据绝对主导”。若出现其他比特串,应检查编码映射是否与解码顺序匹配、测量比特顺序是否与经典寄存器对应。建议把四种比特串都跑一遍,形成一张对照表,作为后续协议扩展的基线。

固定 seed_simulator 后,同一线路的计数可复现;切换后端或升级 Qiskit 后应重新跑基线,确认结果未漂移。