4. 量子线路的构建与序列化
在量子云计算的任务提交链路中,线路构建与序列化是连接“本地算法设计”和“云端硬件执行”的关键一环。用户在本地的 Qiskit、Cirq 或 ProjectQ 中搭建的线路对象,本质上只是内存中的 Python 数据结构;而云端服务需要的是一个可传输、可解析、可复现的文本或二进制描述。理解这一转换过程,才能避免“本地跑得通、云端报错”的常见问题。
一、三种框架的线路构建方式与对象模型
Qiskit 以 QuantumCircuit 为核心对象,通过 qc.h(0)、qc.cx(0,1)、qc.measure_all() 这类方法逐步追加指令,线路内部维护一个按时间顺序排列的指令列表,并记录量子寄存器与经典寄存器的位宽。Cirq 采用更“函数式”的风格:先定义 LineQubit 或 GridQubit,再用 cirq.Circuit() 配合 cirq.H(q0)、cirq.CNOT(q0,q1) 构造 Moment 序列,Moment 表示同一时刻可并行执行的门的集合。ProjectQ 则通过 MainEngine 加命令生成器(如 eng 上下文中的 H、CNOT)把门操作“流式”写入引擎,线路在引擎内部以命令列表形式累积。
三者的共同点是:线路对象都包含“门类型 + 作用比特 + 参数(旋转角等)+ 测量/复位等非酉操作”这几类信息。差异在于比特标识方式(整数索引 vs 具名 Qubit 对象)、并行语义(Moment vs 顺序列表)以及是否内建经典寄存器。这些差异直接决定了序列化后中间表示的形态。
二、中间表示:QASM、Quil 与 JSON 的取舍
OpenQASM 2.0/3.0 是当前最通用的线路交换格式,文本形式形如:
OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[2];
h q[0];
cx q[0],q[1];
measure q -> c;
它可读性强、被多数云平台接受,但对自定义门、经典控制流(如 if)和复杂参数表达的支持有限,QASM 3.0 才逐步补齐这些能力。Quil 是 Rigetti 体系的原生指令集,语法接近汇编,天然支持 DECLARE 声明内存区和 MEASURE 写回,适合表达脉冲级或参数化程序。JSON 则不是某一家厂商的标准,而是各平台自定义的线路描述(如 Qiskit 的 qpy 二进制、Cirq 的 cirq.to_json、以及云厂商的 IR JSON),优点是能完整保留对象元数据,缺点是跨框架兼容性差。
选择原则可以概括为:跨平台提交优先 QASM;面向特定硬件后端且需要精细控制时用该后端原生格式;需要在本地保存完整线路对象(含自定义门定义、校准信息)时用框架自带的 JSON/二进制序列化。
三、序列化与反序列化的实际操作
以 QASM 为例,Qiskit 中导出与导入分别使用 qc.qasm()(或 qiskit.qasm2.dumps(qc))与 QuantumCircuit.from_qasm_str(text)。Cirq 提供 cirq.qasm(circuit) 与 cirq.circuit_from_qasm(text)。需要注意,QASM 往返并不总是无损:自定义酉门若未在 qelib1.inc 中定义,导出时会被展开或报错;比特顺序在部分实现中可能被重排,导入后应核对 qc.num_qubits 与测量映射。
JSON 序列化方面,Qiskit 的 qpy.dump(qc, file) 能保留完整对象,包括自定义门和校准;Cirq 的 cirq.to_json(circuit) 返回字符串,cirq.read_json(json_text=...) 还原。跨版本兼容是常见坑:用较新版本序列化的对象在旧版本反序列化时可能因字段缺失而失败,因此生产环境应固定框架版本,或在提交前统一转换为 QASM 这类稳定文本格式。
四、提交前的线路校验清单
校验的目标是“在消耗云端排队时间之前,把明显不合法的线路拦下来”。建议至少覆盖以下几项:
- 比特规模:线路使用的物理比特数不超过目标后端可用比特数,且比特索引在合法范围内。
- 门集兼容:线路中的门是否属于后端原生门集(如
rz、sx、cx);非原生门需先经transpile分解。 - 耦合约束:两比特门的作用比特对是否在硬件耦合图中;不在则需插入 SWAP 或重映射。
- 测量与经典寄存器:测量数量与经典寄存器位宽一致,避免结果解析时越界。
- 参数合法性:旋转角是否为有限实数,参数化线路的绑定是否完整。
- 深度与噪声:线路深度是否超出后端建议上限,过深线路结果可信度下降。
一个可复用的本地预校验片段如下(以 Qiskit 为例,示例参数为假设):
from qiskit import QuantumCircuit, transpile
from qiskit.providers.fake_provider import FakeManilaV2
backend = FakeManilaV2() # 示例后端,5 比特
qc = QuantumCircuit(3, 3)
qc.h(0); qc.cx(0, 1); qc.cx(1, 2)
qc.measure([0,1,2], [0,1,2])
assert qc.num_qubits <= backend.configuration().n_qubits
tqc = transpile(qc, backend=backend, optimization_level=1)
print(tqc.count_ops(), tqc.depth())
若 transpile 报错或深度异常增大,说明原线路与后端拓扑不匹配,应在本地调整比特映射后再提交,而不是把问题留给云端。
最后要强调的是,序列化不是简单的“存成字符串”,而是线路语义在另一种表示下的重建。只有保证反序列化后的线路与原始线路在门序列、比特映射和测量语义上等价,云端执行的结果才具备可解释性。把校验做在提交之前,是量子云任务管理中最省成本的一步。