3. 转译核心概念
在 Qiskit 中写下的量子电路,描述的是“逻辑上要做什么”:用哪些量子比特、施加哪些门、测量谁。但真实设备只有固定的耦合拓扑、有限的基门集合和带噪声的物理量子比特。转译(transpile)就是在这两者之间搭桥的过程:把逻辑电路改写成能在指定后端上真正执行的物理电路,同时尽量保持语义等价、控制代价。
理解转译,关键是抓住一个目标与一组约束。目标是语义等价且可执行——转译后的电路在理想情况下与原始电路作用相同;约束则来自硬件:哪些两比特门是原生支持的、哪些比特之间能直接做两比特门、单比特门允许用哪些基门实现。转译不是一次简单的“翻译”,而是由初始布局、路由、门分解与优化四个环节协同完成的映射过程。
初始布局:先决定“谁站在哪里”
布局解决的是逻辑比特到物理比特的初始映射。假设一个 5 比特设备,耦合边为 (0,1)、(1,2)、(2,3)、(3,4) 的链式拓扑,而逻辑电路里 q0 与 q4 之间有一个 CX。如果按平凡布局把逻辑 q0→物理 0、q4→物理 4,这个 CX 两端相距 4 跳,路由代价很高。若把逻辑 q0 放到物理 2、q4 放到物理 3,则它们直接相邻,CX 可原生执行。这就是布局的价值:在路由发生之前,先把交互频繁的比特放到靠近的位置。
Qiskit 提供多种布局策略:TrivialLayout 按编号一一对应,简单但常不优;DenseLayout 选择连通度高的物理比特子集;SabreLayout 则结合路由代价反复试排,通常效果更好。实际使用中,transpile(circuit, backend, layout_method='sabre', routing_method='sabre') 是常见组合。需要注意,布局一旦确定,后续所有门操作都基于这个映射进行,因此布局质量会放大到整条电路。
路由:用 SWAP 把“远距离”变成“可执行”
路由处理的是布局之后仍不满足耦合约束的两比特门。设备只允许在耦合边上的比特间做 CX,若逻辑 CX 的两端映射到不相邻的物理比特,就必须通过插入 SWAP 门把其中一个量子态“搬”到相邻位置。一个 SWAP 在基门层面通常分解为 3 个 CX,因此路由的代价直接体现为额外的 CX 数量和电路深度。
以链式拓扑 0—1—2—3—4 为例,若需要在物理 0 和物理 4 之间做 CX,路由会沿路径逐步交换,把态从 0 搬到 4 附近,执行 CX 后再视需要搬回。路径越长,SWAP 越多。这也是为什么布局阶段要尽量缩短关键交互的距离。Qiskit 的 SabreSwap 会基于启发式搜索选择交换序列,BasicSwap 则更朴素。转译结果中的 depth 和 CX 计数,是判断路由开销是否可接受的直接指标。
门分解:把“任意门”落到“基门”
真实后端只支持有限的基门集合,例如 {rz, sx, x, cx} 或 {rz, ry, ecr}。逻辑电路中的 H、Y、T、任意旋转门等,都需要展开成基门的组合。例如 H 可写成 rz(π/2)·sx·rz(π/2) 的等价形式,受控旋转则需拆成 CX 与单比特旋转的组合。分解必须保证数学等价,否则语义就被破坏。
分解的粒度由后端的 basis_gates 决定,而不是由我们随意选择。若目标设备原生支持 ecr 而非 cx,则所有 CX 还要进一步转换为 ECR 加单比特门的组合。这一步往往会让门数上升,因此分解之后通常紧跟优化。
优化:在不改变语义的前提下压缩代价
优化环节做的是“减法”:合并相邻的同轴旋转、消去互逆门对(如 X·X、CX·CX)、把连续单比特门折叠成一个等效门、在允许时减少 CX 数量。Qiskit 用 optimization_level 控制强度,0 表示几乎不优化,3 表示最激进的优化。级别越高,转译耗时越长,但通常电路更短、噪声累积更少。
需要强调的是,优化不能改变电路的可观测行为。判断转译是否成功,不能只看门数变少,还要确认语义等价。实践中可以对比转译前后的状态向量模拟结果(小规模电路),或检查转译后电路是否只含基门、是否满足耦合约束。
一次完整的转译观察
下面是一段可直接运行的示例,用于观察四个环节的实际效果(示例参数为教学假设,实际数值随后端与随机种子变化):
from qiskit import QuantumCircuit, transpile
from qiskit.providers.fake_provider import FakeSherbrooke
qc = QuantumCircuit(5)
qc.h(0)
qc.cx(0, 4) # 远距离交互
qc.cx(1, 3)
qc.measure_all()
backend = FakeSherbrooke()
tqc = transpile(qc, backend,
layout_method='sabre',
routing_method='sabre',
optimization_level=2)
print("原始 CX 数:", qc.count_ops().get('cx', 0))
print("转译后 CX 数:", tqc.count_ops().get('cx', 0))
print("转译后深度:", tqc.depth())
print("使用的基门:", set(tqc.count_ops().keys()))
print("最终布局:", tqc.layout.final_layout)
观察要点有三:其一,转译后电路的操作集合应完全落在后端 basis_gates 内;其二,CX 数通常因路由而增加,若增加过多,说明布局或路由策略不理想,可尝试更换 layout_method 或提高优化级别;其三,final_layout 告诉我们逻辑比特最终落在哪些物理比特上,测量结果解读时需要据此对应。把这三项结合起来,就能对一次转译的质量做出基本判断,而不是盲目提交执行。