Skip to content

量子线路编译 ​

学习如何使用 pyqpanda3 的编译模块将抽象量子线路转换为硬件可执行的形式。本教程涵盖芯片拓扑建模、线路路由、门分解以及完整的编译流程。

前置条件: 量子线路构建 —— 在学习本教程之前,您应该能够熟练构建 QProg 和 QCircuit 对象。


目录 ​


为什么需要编译 ​

当您在 pyqpanda3 中编写量子线路时,您使用抽象门集来表达计算——可以使用 core 模块提供的 37 种以上的门。例如,您可以使用 CNOT(0, 3) 在量子比特 0 和 3 之间施加受控非门,或使用 SWAP(1, 4) 交换量子比特 1 和 4 的状态。

然而,真实的量子硬件存在三个基本限制:

1. 原生门集。 量子处理器并不直接实现所有门。大多数超导芯片只支持一小组基本门,例如 {U3, CZ} 或 {RZ, X1, CNOT}。像 SWAP 或 TOFFOLI 这样的门必须在执行前分解为原生门的序列。

2. 量子比特连接性。 物理量子比特按特定拓扑排列。双量子比特门只能应用于物理上相邻的量子比特之间。如果您的线路包含 CNOT(0, 3),但硬件只连接量子比特 0-1、1-2 和 2-3,则编译器必须插入 SWAP 操作,将逻辑交互通过物理连接进行路由。

3. 门保真度和相干性。 不同的量子比特和门类型有不同的错误率。优秀的编译器会将逻辑量子比特放置在保真度最高的物理量子比特上,并最小化双量子比特门的总数。

如果没有编译,为理想化量子计算机编写的线路无法在真实硬件上运行。编译模块通过将您的抽象线路转换为满足硬件约束的线路(同时保持其逻辑行为)来弥合这一差距。

mermaid
flowchart LR
    subgraph "抽象线路"
        A1["H(0)"]
        A2["CNOT(0,3)"]
        A3["T(1)"]
        A4["SWAP(0,2)"]
    end

    subgraph "编译"
        T["Transpiler"]
    end

    subgraph "硬件线路"
        B1["RZ(0, pi/2)"]
        B2["X1(0)"]
        B3["CNOT(0,1)"]
        B4["CNOT(1,2)"]
        B5["CNOT(2,3)"]
        B6["CNOT(1,2)"]
        B7["CNOT(0,1)"]
        B8["RZ(1, pi/4)"]
    end

    A1 --> T
    A2 --> T
    A3 --> T
    A4 --> T
    T --> B1
    T --> B2
    T --> B3
    T --> B4
    T --> B5
    T --> B6
    T --> B7
    T --> B8

    style T fill:#50c878,color:#fff,stroke:#2d8a4e

编译流程 ​

pyqpanda3 中的编译由多个阶段组成,每个阶段解决一个或多个硬件约束:

mermaid
flowchart TD
    INPUT["输入 QProg / QCircuit"]

    subgraph "阶段 1:门分解"
        D1["非原生门<br/>分解为<br/>基本门集"]
    end

    subgraph "阶段 2:拓扑路由"
        D2["量子比特映射<br/>和 SWAP 插入<br/>使用 SABRE 算法"]
    end

    subgraph "阶段 3:优化"
        D3["门消除<br/>和线路<br/>简化"]
    end

    OUTPUT["输出 QProg"]

    INPUT --> D1
    D1 --> D2
    D2 --> D3
    D3 --> OUTPUT

    style INPUT fill:#4a90d9,color:#fff
    style OUTPUT fill:#50b86c,color:#fff
    style D1 fill:#f4a460,color:#fff
    style D2 fill:#f4a460,color:#fff
    style D3 fill:#f4a460,color:#fff

门分解将不在目标硬件原生门集中的门进行重写。例如,一个 TOFFOLI 门可能会被分解为六个 CNOT 门加上若干单量子比特旋转门。

拓扑路由将逻辑量子比特映射到物理量子比特,并在需要时插入 SWAP 门。pyqpanda3 使用 SABRE(SWAP-based BidiREctional 启发式搜索)算法,该算法效率高且能产生高质量的映射。

优化应用局部重写规则来消除冗余门对(例如,连续两个 H 门等价于恒等操作)并合并相邻的单量子比特旋转门。

transpilation 模块导出的三个函数分别对应此流程的不同部分:

函数用途
generate_topology(n, type)生成用于测试的合成芯片拓扑
Transpiler().transpile(...)完整流程:分解、路由和优化
decompose(...)独立的门分解(不进行路由)

1. 芯片拓扑 ​

1.1 什么是芯片拓扑? ​

芯片拓扑描述了哪些物理量子比特对可以直接执行双量子比特门。它用边列表表示:一组 [qubit_a, qubit_b] 对,表示量子比特 a 和 b 物理上相连。

例如,4 量子比特线性链的拓扑为:

[0, 1], [1, 2], [2, 3]

直观表示为:

q0 --- q1 --- q2 --- q3

4 量子比特方形(网格)拓扑增加了对角连接:

q0 --- q1
 |      |
q2 --- q3

拓扑决定了路由问题。在线性链中,非相邻量子比特之间的任何双量子比特门都需要 SWAP 门将逻辑状态移到一起。在全连接拓扑中,不需要路由,因为每个量子比特对都直接相连。

1.2 generate_topology() ​

pyqpanda3 提供 generate_topology() 来创建用于测试和实验的合成拓扑边列表。您无需手动构建常见拓扑的边列表。

python
from pyqpanda3.transpilation import generate_topology

# 生成 4 量子比特的线性链拓扑
topo = generate_topology(4, "linear")
print(topo)
# [[0, 1], [1, 2], [2, 3]]

运行结果:

[[0, 1], [1, 2], [2, 3]]

签名:

python
generate_topology(num_qubits: int, topology_type: str) -> list

参数:

参数类型说明
num_qubitsint拓扑中物理量子比特的数量
topology_typestr拓扑布局类型(见下文)

返回值: 表示物理连接的 [qubit_a, qubit_b] 对列表。

1.3 拓扑类型 ​

支持以下拓扑类型:

类型说明适用场景
"linear"链式:q0-q1-q2-...-q(n-1)简单测试线路
"square"二维网格排列基于网格的量子处理器
"all-to-all"每个量子比特与其他所有量子比特相连理想化测试

线性拓扑 ​

线性链将每个量子比特与其直接邻居相连:

python
from pyqpanda3.transpilation import generate_topology

topo = generate_topology(5, "linear")
print(topo)
# [[0, 1], [1, 2], [2, 3], [3, 4]]

运行结果:

[[0, 1], [1, 2], [2, 3], [3, 4]]
mermaid
graph LR
    Q0["Q0"] --- Q1["Q1"] --- Q2["Q2"] --- Q3["Q3"] --- Q4["Q4"]

    style Q0 fill:#4a90d9,color:#fff
    style Q1 fill:#4a90d9,color:#fff
    style Q2 fill:#4a90d9,color:#fff
    style Q3 fill:#4a90d9,color:#fff
    style Q4 fill:#4a90d9,color:#fff

方形(网格)拓扑 ​

方形拓扑将量子比特排列为二维网格。每个量子比特与其水平和垂直方向的邻居相连:

python
from pyqpanda3.transpilation import generate_topology

topo = generate_topology(4, "square")
print(topo)
# [[0,1], [0,3], [1,2], [1,4], [2,5],
#  [3,4], [3,6], [4,5], [4,7], [5,8],
#  [6,7], [7,8]]

运行结果:

[[0, 1], [0, 3], [1, 2], [1, 4], [2, 5], [3, 4], [3, 6], [4, 5], [4, 7], [5, 8], [6, 7], [7, 8]]

方形拓扑模拟了许多真实的超导芯片,其中量子比特在平面衬底上制造,具有最近邻耦合。

全连接(全对全)拓扑 ​

全连接拓扑将每个量子比特与所有其他量子比特相连:

python
from pyqpanda3.transpilation import generate_topology

topo = generate_topology(4, "all-to-all")
print(topo)
# [[0,1], [0,2], [0,3], [1,2], [1,3], [2,3]]

运行结果:

[[0, 1], [0, 2], [0, 3], [1, 2], [1, 3], [2, 3]]

在全连接的情况下,路由不需要 SWAP 门。这种拓扑适用于独立测试分解或模拟理想化硬件。真实的离子阱量子计算机通常具有全对全连接性。

1.4 自定义拓扑 ​

您也可以直接传递自定义边列表。例如,以量子比特 0 为中心的星形图:

python
custom_topo = [[0, 1], [0, 2], [0, 3], [0, 4]]

或者环形(环形)拓扑:

python
ring_topo = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 0]]

2. Transpiler 类 ​

Transpiler 类是线路编译的主要入口点。它将门分解、量子比特路由和线路优化组合为单个操作。

2.1 创建 Transpiler ​

创建 Transpiler 实例无需参数:

python
from pyqpanda3.transpilation import Transpiler

transpiler = Transpiler()

编译器是无状态的——它在调用之间不保存持久配置。所有参数在编译时提供。

2.2 使用边列表的 transpile() ​

使用编译器最常见的方式是提供描述芯片拓扑的边列表:

python
from pyqpanda3 import core
from pyqpanda3.transpilation import Transpiler, generate_topology

# Build a circuit that requires routing
prog = core.QProg()
prog << core.H(0)
prog << core.CNOT(0, 3)       # qubits 0 and 3 are not adjacent in a 4-qubit chain
prog << core.measure([0, 3], [0, 3])

# Define the chip topology as an edge list
chip_edges = [[0, 1], [1, 2], [2, 3]]

# Transpile: route through the linear chain and decompose to basic gates
transpiler = Transpiler()
transpiled = transpiler.transpile(
    prog,
    chip_edges,            # topology edge list
    {},                    # initial mapping (empty = automatic)
    2                      # optimization level
)

print(transpiled)

运行结果:

          ┌─┐         ┌─┐     
q_0:  |0>─┤H├ ───*── ─┤M├──── 
          └─┘ ┌──┴─┐  └╥┘ ┌─┐ 
q_1:  |0>──── ┤CNOT├ ──╫──┤M├ 
              └────┘   ║  └╥┘ 
 c :   / ══════════════╩═══╩═
                        0   3

在此示例中,原始线路施加 CNOT(0, 3),但量子比特 0 和 3 在线性链中相隔三跳。SABRE 算法会自动寻找最优的初始映射和路由方案。例如,它可能将逻辑量子比特 0 映射到物理量子比特 3,从而无需插入 SWAP 门即可直接执行 CNOT。最终的编译结果取决于 SABRE 算法的启发式决策。

签名:

python
transpiler.transpile(
    prog,                 # QProg: the circuit to transpile
    chip_topology_edges,  # list of [int, int]: physical connections
    init_mapping,         # dict: initial qubit mapping (empty dict for automatic)
    optimization_level,   # int: 0, 1, or 2
    basic_gates=None      # list of str: target gate set (optional)
) -> QProg

参数:

参数类型说明
progQProg要编译的量子程序
chip_topology_edgeslist[list[int]]芯片拓扑的边列表
init_mappingdict初始逻辑到物理量子比特映射。传 {} 表示自动。
optimization_levelint优化级别:0(无)、1(基本)、2(积极)
basic_gateslist[str] 或 None目标门集名称。如果为 None,使用默认门集。

2.3 使用后端对象的 transpile() ​

您可以使用 generate_topology() 创建用于开发和测试的芯片拓扑:

python
from pyqpanda3 import core
from pyqpanda3.transpilation import Transpiler, generate_topology

# Generate a 4-qubit linear topology
chip_edges = generate_topology(4, "linear")
print(f"Chip topology: {chip_edges}")

# Build a circuit
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1) << core.SWAP(0, 2)
prog << core.measure([0, 1, 2], [0, 1, 2])

# Transpile using the edge list
transpiler = Transpiler()
transpiled = transpiler.transpile(
    prog,
    chip_edges,
    {},                    # initial mapping
    2                      # optimization level
)
print("Transpile succeeded")

运行结果:

Chip topology: [[0, 1], [1, 2], [2, 3]]
Transpile succeeded

面向真实量子硬件时,您需要通过云服务进行认证并从后端获取芯片拓扑。generate_topology() 适用于本地测试和模拟。

2.4 优化级别 ​

optimization_level 参数控制编译器优化输出线路的程度。更高级别产生更短的线路,但编译时间更长。

级别行为适用场景
0无优化。仅路由和分解。调试;查看原始路由输出
1基本优化。消除相邻的逆门并合并旋转门。快速编译并清理
2积极优化。所有重写规则,包括基于交换性的重排序。面向硬件的生产线路
python
# 级别 0:原始输出,无简化
transpiled = transpiler.transpile(prog, chip_edges, {}, 0)

# 级别 1:基本门消除
transpiled = transpiler.transpile(prog, chip_edges, {}, 1)

# 级别 2:积极优化(推荐用于硬件执行)
transpiled = transpiler.transpile(prog, chip_edges, {}, 2)

2.5 初始量子比特映射 ​

init_mapping 参数允许您指定哪个逻辑量子比特应从哪个物理量子比特开始。这是一个将逻辑量子比特索引映射到物理量子比特索引的字典:

python
from pyqpanda3 import core
from pyqpanda3.transpilation import Transpiler

# 构建 2 量子比特线路
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
prog << core.measure([0, 1], [0, 1])

# 3 量子比特线性链:物理量子比特 0-1-2
chip_edges = [[0, 1], [1, 2]]

# 将逻辑量子比特 0 映射到物理量子比特 2
# 将逻辑量子比特 1 映射到物理量子比特 0
init_mapping = {0: 2, 1: 0}

transpiler = Transpiler()
transpiled = transpiler.transpile(prog, chip_edges, init_mapping, 2)
print("Transpile succeeded with custom mapping")

运行结果:

Transpile succeeded with custom mapping

当您传递空字典 {} 时,编译器使用 SABRE 算法自动查找初始映射。在大多数情况下,自动映射已经足够,您无需手动提供。

您可能需要在以下情况下指定自定义映射:

  • 您知道硬件上某些量子比特的保真度更高,希望将重要的逻辑量子比特放置在那里。
  • 您要运行多个线路并希望它们使用相同的映射以便比较结果。

2.6 指定基本门集 ​

basic_gates 参数限制输出线路仅使用指定门集中的门。不在该门集中的任何门都将被分解:

python
from pyqpanda3 import core
from pyqpanda3.transpilation import Transpiler

# 构建线路
prog = core.QProg()
prog << core.H(0) << core.CNOT(0, 1)
prog << core.measure([0, 1], [0, 1])

chip_edges = [[0, 1], [1, 2]]
transpiler = Transpiler()

# 以 IBM 风格的门集为目标:U3 + CNOT 是通用门集
transpiled = transpiler.transpile(
    prog, chip_edges, {}, 2,
    basic_gates=["U3", "CNOT"]
)
print("Transpiled with U3/CNOT gate set")

运行结果:

Transpiled with U3/CNOT gate set

常见门集:

门集门硬件
IBM 风格["U3", "CNOT"] 或 ["RZ", "X1", "CNOT"]超导
OriginQ 风格["U3", "CZ"] 或 ["RZ", "X1", "CZ"]超导
Clifford+T["H", "S", "T", "CNOT"]理论分析
离子阱["RXX", "RZ", "RX"] 或 ["MS", "RZ"]离子阱

如果未指定 basic_gates(或为 None),编译器使用默认门集。


3. 门分解 ​

decompose 函数执行门分解而不进行路由。它接收线路(或矩阵)并将所有门重写为指定基本门集的形式。当您想单独查看门分解效果而不修改量子比特分配时,这非常有用。

3.1 为什么要分解门? ​

门分解有多个目的:

  1. 硬件兼容性: 真实的量子处理器实现一组固定的物理操作。该门集之外的任何门都必须表示为支持门的序列。

  2. 线路分析: 分解为标准门集使资源计数更容易(例如,实际需要多少双量子比特门)。

  3. 门数量优化: 像层次门 TOFFOLI 这样的高级门在分解时需要 6 个 CNOT 门。了解这一点有助于估算线路成本。

  4. 验证: 将酉矩阵分解为门,然后检查生成线路的矩阵是否与原始矩阵匹配,可以验证正确性。

分解规则遵循量子线路合成中的著名恒等式。例如:

3.2 decompose(prog, basic_gates) ​

将 QProg 中的所有门分解为指定的基本门集:

python
from pyqpanda3 import core
from pyqpanda3.transpilation import decompose

# Build a circuit with non-native gates
prog = core.QProg()
prog << core.H(0)
prog << core.SWAP(0, 1)        # SWAP is not in most native gate sets
prog << core.TOFFOLI(0, 1, 2)  # TOFFOLI is always decomposed
prog << core.measure([0, 1, 2], [0, 1, 2])

# Decompose into H + CNOT + rotation gates
decomposed = decompose(prog, ["H", "CNOT", "RZ", "X1"])

print(f"Original gate count: {prog.count_ops()}")
print(f"Decomposed gate count: {decomposed.count_ops()}")

运行结果:

Original gate count: {'H': 1, 'SWAP': 1, 'CCX': 1}
Decomposed gate count: {'CNOT': 9, 'H': 3, 'RZ': 7}

签名:

python
decompose(prog: QProg, basic_gates: list) -> QProg

参数:

参数类型说明
progQProg输入量子程序
basic_gateslist[str]目标门集名称

返回值: 一个新的 QProg,其中所有门都用 basic_gates 表示。

原始程序不会被修改。decompose 函数总是返回一个新的程序对象。

3.3 decompose(circuit, basic_gates) ​

分解 QCircuit 对象中的门:

python
from pyqpanda3 import core
from pyqpanda3.transpilation import decompose

# Build a circuit module
circuit = core.QCircuit()
circuit << core.SWAP(0, 1)
circuit << core.CZ(1, 2)

# Decompose into CNOT + single-qubit gates
decomposed_circuit = decompose(circuit, ["H", "CNOT", "RZ", "X1"])

print(f"Original depth: {circuit.depth()}")
print(f"Decomposed depth: {decomposed_circuit.depth()}")

运行结果:

Original depth: 2
Decomposed depth: 7

签名:

python
decompose(circuit: QCircuit, basic_gates: list) -> QCircuit

参数:

参数类型说明
circuitQCircuit输入量子线路
basic_gateslist[str]目标门集名称

返回值: 一个新的 QCircuit,其中所有门都用 basic_gates 表示。

此重载适用于处理可复用的线路模块而非完整程序时。分解后的线路可以嵌入到任何 QProg 中。

3.4 decompose(matrix, qubits) ​

将酉矩阵分解为量子线路。这是最强大的分解形式——它接收一个任意 2n×2n 酉矩阵并合成为实现该矩阵的线路。

python
import numpy as np
from pyqpanda3.transpilation import decompose

# Define a 2x2 unitary matrix (single-qubit gate)
# This is a phase gate: diag(1, exp(i*pi/4))
mat = np.array([
    [1, 0],
    [0, np.exp(1j * np.pi / 4)]
], dtype=complex)

# Decompose into a circuit acting on qubit 0
circuit = decompose(mat, [0])
print(f"Circuit depth: {circuit.depth()}")
print(f"Circuit size: {circuit.size()}")

运行结果:

Circuit depth: 1
Circuit size: 1

签名:

python
decompose(matrix: np.ndarray, qubits: list) -> QCircuit

参数:

参数类型说明
matrixnp.ndarray要分解的酉矩阵。对于 n 个量子比特,必须是 2n×2n。
qubitslist[int]线路作用的量子比特索引。长度必须为 n。

返回值: 一个 QCircuit,在指定量子比特上实现给定的酉操作。

双量子比特示例:

python
import numpy as np
from pyqpanda3.transpilation import decompose

# A 4x4 unitary (two-qubit gate)
# Create a controlled-phase gate matrix
cp_mat = np.array([
    [1, 0, 0, 0],
    [0, 1, 0, 0],
    [0, 0, 1, 0],
    [0, 0, 0, np.exp(1j * np.pi / 3)]
], dtype=complex)

# Decompose into a circuit on qubits 0 and 1
circuit = decompose(cp_mat, [0, 1])
print(f"2Q circuit depth: {circuit.depth()}")
print(f"2Q gate count: {circuit.count_ops(only_q2=True)}")

运行结果:

2Q circuit depth: 5
2Q gate count: {'CZ': 2}

验证:

您可以验证分解后的线路是否正确实现了原始矩阵:

python
import numpy as np
from pyqpanda3 import core
from pyqpanda3.transpilation import decompose

# Original matrix
mat = np.array([
    [1, 0],
    [0, np.exp(1j * np.pi / 4)]
], dtype=complex)

# Decompose
circuit = decompose(mat, [0])

# Compute the circuit's unitary
circuit_matrix = circuit.matrix()

# Check that they match
print("Matrices match:", np.allclose(mat, circuit_matrix))
# Matrices match: True

运行结果:

Matrices match: True

3.5 分解规则 ​

分解引擎应用著名的量子线路恒等式。以下是最重要的几个:

SWAP 分解:

SWAP(a,b)=CNOT(a,b)⋅CNOT(b,a)⋅CNOT(a,b)

这需要 3 个 CNOT 门。

python
from pyqpanda3 import core
from pyqpanda3.transpilation import decompose

swap_prog = core.QProg()
swap_prog << core.SWAP(0, 1)
result = decompose(swap_prog, ["H", "CNOT", "RZ", "X1"])
# result 现在包含:CNOT(0,1), CNOT(1,0), CNOT(0,1)

CZ 分解:

CZ(a,b)=(I⊗H)⋅CNOT(a,b)⋅(I⊗H)

TOFFOLI 分解:

Toffoli(CCX)门分解为 6 个 CNOT 门和 7 个单量子比特门:

TOFFOLI(a,b,c)=6 个 CNOT + T/Tdg + H 门的序列

单量子比特门分解:

任何单量子比特酉操作 U 都可以使用 ZYZ 分解最多分解为 3 个旋转门:

U=RZ(α)⋅RY(β)⋅RZ(γ)

或分解为 U3 门:

U=U3(θ,ϕ,λ)

4. 综合应用 ​

4.1 完整编译工作流 ​

以下是将线路从抽象表示编译为硬件就绪形式的完整工作流:

mermaid
flowchart TD
    A["1. 使用 core 门构建<br/>抽象线路"] --> B["2. 定义芯片拓扑<br/>或从后端获取"]
    B --> C["3. 选择优化级别<br/>和基本门集"]
    C --> D["4. 调用 transpiler.transpile()"]
    D --> E["5. 验证:对比<br/>编译前后结果"]
    E --> F{结果匹配?}
    F -->|是| G["6. 在模拟器上运行<br/>或提交到硬件"]
    F -->|否| H["调试映射<br/>或分解"]
    H --> C

    style A fill:#4a90d9,color:#fff
    style G fill:#50b86c,color:#fff
    style H fill:#c0392b,color:#fff

完整示例:

python
from pyqpanda3 import core
from pyqpanda3.transpilation import Transpiler, generate_topology, decompose

# Step 1: Build the abstract circuit
prog = core.QProg()
prog << core.H(0)
prog << core.CNOT(0, 1)
prog << core.SWAP(0, 2)
prog << core.T(1)
prog << core.measure([0, 1, 2], [0, 1, 2])

print("=== Original Circuit ===")
print(f"Depth: {prog.depth(only_q2=True)}")
print(f"Gates: {prog.count_ops()}")
print(f"2Q Gates: {prog.count_ops(only_q2=True)}")

# Step 2: Define chip topology (4-qubit linear chain)
chip_edges = generate_topology(4, "linear")
print(f"\nChip topology: {chip_edges}")

# Step 3: Transpile with optimization level 2
transpiler = Transpiler()
transpiled = transpiler.transpile(
    prog,
    chip_edges,
    {},                           # automatic qubit mapping
    2,                            # aggressive optimization
    basic_gates=["H", "RZ", "X1", "CNOT"]
)

print("\n=== Transpiled Circuit ===")
print(f"Depth: {transpiled.depth(only_q2=True)}")
print(f"Gates: {transpiled.count_ops()}")
print(f"2Q Gates: {transpiled.count_ops(only_q2=True)}")

# Step 4: Verify correctness on a simulator
machine = core.CPUQVM()
machine.run(prog, 10000)
orig_probs = machine.result().get_prob_dict()

machine.run(transpiled, 10000)
transpiled_probs = machine.result().get_prob_dict()

print("\n=== Verification ===")
print(f"Original probabilities:    {orig_probs}")
print(f"Transpiled probabilities:  {transpiled_probs}")

运行结果:

=== Original Circuit ===
Depth: 2
Gates: {'CNOT': 1, 'H': 1, 'SWAP': 1, 'T': 1}
2Q Gates: {'CNOT': 1, 'SWAP': 1}

Chip topology: [[0, 1], [1, 2], [2, 3]]

=== Transpiled Circuit ===
Depth: 4
Gates: {'RZ': 3, 'X1': 1, 'CNOT': 4}
2Q Gates: {'CNOT': 4}

=== Verification ===
原始概率:    {'000': 0.4984, '110': 0.5016}
编译后概率:  {'000': 0.5018, '110': 0.4982}

4.2 编译前后对比 ​

编译后,务必在模拟器上对比原始线路和编译后的线路。测量概率应在统计噪声范围内匹配。第 4.1 节中展示的工作流演示了此模式:在 CPUQVM 上运行两个线路并比较 get_prob_dict() 输出。对于 10,000 次采样,每个比特串的概率应在约 0.05 的容差范围内一致。

4.3 面向真实硬件的编译 ​

编译器在硬件拓扑约束量子比特连接性时处理线路路由。以下示例使用 4 量子比特线性链,其中循环 CNOT 模式强制编译器插入 SWAP 门:

python
from pyqpanda3 import core
from pyqpanda3.transpilation import Transpiler, generate_topology

# 4 量子比特线性链:0-1-2-3
chip_edges = generate_topology(4, "linear")

# 构建带有回路的线路,强制编译器进行路由
prog = core.QProg()
prog << core.H(0)
prog << core.CNOT(0, 1)
prog << core.CNOT(1, 2)
prog << core.CNOT(2, 3)
prog << core.CNOT(3, 0)
prog << core.measure([0, 1, 2, 3], [0, 1, 2, 3])

print("=== Original Circuit ===")
print(f"Depth: {prog.depth(only_q2=True)}")
print(f"Gates: {prog.count_ops()}")
print(f"2Q Gates: {prog.count_ops(only_q2=True)}")

# 基本优化级别编译
transpiler = Transpiler()
transpiled = transpiler.transpile(prog, chip_edges, {}, 1)

print("\n=== Transpiled Circuit (level 1) ===")
print(f"Depth: {transpiled.depth(only_q2=True)}")
print(f"Gates: {transpiled.count_ops()}")
print(f"2Q Gates: {transpiled.count_ops(only_q2=True)}")

# 在模拟器上验证
machine = core.CPUQVM()
machine.run(prog, 10000)
orig_probs = machine.result().get_prob_dict()

machine.run(transpiled, 10000)
tran_probs = machine.result().get_prob_dict()

print(f"\n=== Verification ===")
print(f"Original probabilities:    {orig_probs}")
print(f"Transpiled probabilities:  {tran_probs}")

运行结果:

=== Original Circuit ===
Depth: 4
Gates: {'CNOT': 4, 'H': 1}
2Q Gates: {'CNOT': 4}

=== Transpiled Circuit (level 1) ===
Depth: 7
Gates: {'U4': 1, 'CNOT': 4, 'SWAP': 3}
2Q Gates: {'CNOT': 4, 'SWAP': 3}

=== Verification ===
Original probabilities:    {'0000': 0.5076, '1110': 0.4924}
Transpiled probabilities:  {'0000': 0.5104, '1110': 0.4896}

本地编译的关键优势在于对优化级别、初始映射和基本门集的精细控制。面向真实量子硬件时,您需要通过云服务进行认证以获取芯片拓扑和门集,然后应用相同的编译工作流。


4.4 保真度感知布局与指令导出 ​

从 pyqpanda3 0.4.0 开始,ChipBackend 可以携带单比特、读出和双比特门的保真度映射。你既可以通过 layout_method="fidelity" 让后端重载自动计算布局,也可以先手动调用 fidelity_layout() 查看初始映射。

python
from pyqpanda3.core import QProg, H, CZ, measure
from pyqpanda3.transpilation import ChipBackend, Transpiler, fidelity_layout

prog = QProg()
prog << H(0) << CZ(0, 1) << measure(0, 0) << measure(1, 1)

backend = ChipBackend()
backend.chip_topology_edges = [[0, 1], [1, 2]]
backend.basic_gates = ["RPhi", "CZ"]
backend.single_gate_fidelity = {0: 0.99, 1: 0.99, 2: 0.99}
backend.readout_fidelity = {0: 0.90, 1: 0.90, 2: 0.99}
backend.double_gate_fidelity = {(0, 1): 0.90, (1, 2): 0.99}

mapping = fidelity_layout(
    prog,
    backend.chip_topology_edges,
    backend.single_gate_fidelity,
    backend.readout_fidelity,
    backend.double_gate_fidelity,
)

transpiled = Transpiler().transpile(prog, backend, {}, 1, "fidelity")

print(mapping)
print(len(transpiled.operations()) > 0)

如果后续要导出指令 JSON,请先确保程序处在 virtual_z() 支持的门族中。一个稳妥的做法是先分解到 ["X1", "RZ", "CZ"],再转换成虚拟 Z 形式,设置后端时序后导出带调度的 JSON:

python
import json

from pyqpanda3.core import QProg, H, CZ, measure
from pyqpanda3.transpilation import ChipBackend, decompose, virtual_z

prog = QProg()
prog << H(0) << CZ(0, 1) << measure(0, 0) << measure(1, 1)

backend = ChipBackend()
backend.chip_topology_edges = [[0, 1], [1, 2]]
backend.basic_gates = ["RPhi", "CZ"]
backend.single_gate_timing = 40
backend.double_gate_timing = 80

instruction_ready = virtual_z(decompose(prog, ["X1", "RZ", "CZ"]))
instruction_json = instruction_ready.to_instruction(
    backend,
    offset=1,
    is_scheduling=True,
    compensate_pulse=False,
)
instructions = json.loads(instruction_json)

print(type(instruction_json).__name__, len(instructions))
print(instructions[0])

输出:

text
str 3
{'RPhi': [1, 270.0, 90.0, 0]}

如果你需要更完整的云端工作流,可以继续阅读专门的 QCloud 保真度布局 教程。

4.5 高级选项:LightSABRE 路由与转译指标 ​

当默认转译不足以满足需求时——比如耦合度受限、线路较深,或想显式控制布局/路由策略并回收指标——可以使用 0.4.1 引入的强类型入口 TranspilationOptions,配合 TranspilationResult 一次性拿到转译后的程序、编译耗时和指标。

python
from pyqpanda3.core import QProg, H, CZ, measure
from pyqpanda3.transpilation import (
    ChipBackend,
    LayoutMethod,
    RoutingMethod,
    Transpiler,
    TranspilationOptions,
)

prog = QProg()
prog << H(0) << CZ(0, 1) << measure(0, 0) << measure(1, 1)

backend = ChipBackend()
backend.chip_topology_edges = [[0, 1], [1, 2], [1, 3]]
backend.basic_gates = ["RPhi", "CZ"]
backend.single_gate_fidelity = {0: 0.99, 1: 0.99, 2: 0.99, 3: 0.99}
backend.readout_fidelity = {0: 0.95, 1: 0.95, 2: 0.95, 3: 0.95}
backend.double_gate_fidelity = {(0, 1): 0.97, (1, 2): 0.96, (1, 3): 0.96}

options = TranspilationOptions()
options.optimization_level = 2
options.layout_method = LayoutMethod.FIDELITY
options.routing_method = RoutingMethod.LIGHT_SABRE
options.approximation_degree = 0.99
options.execution.routing_trials = 8
options.execution.seed = 42

result = Transpiler().transpile(prog, backend, options)

print(type(result).__name__)
print(result.compile_time_ns > 0)
print(sorted(result.metrics.keys()))
print(result.metrics["two_qubit_gate_count"])

运行结果(指标数值随后端标定变化):

TranspilationResult
True
['depth', 'fidelity_exact', 'fidelity_fallback', 'fidelity_unknown', 'log_expected_fidelity', 'two_qubit_gate_count']
1

几点说明:

  • RoutingMethod.LIGHT_SABRE(也可传字符串 "light_sabre")启用分层前瞻路由器,按层扩展交互图,通常能减少双比特门插入与交换深度,适合耦合度受限或线路较深的后端。
  • approximation_degree 控制保真度驱动的双比特门近似合成强度:1.0 表示精确,None 使用目标双比特门错误率,[0, 1] 内的值按比例缩放。
  • result.metrics 与独立函数 transpilation_metrics(prog, backend) 返回的字典结构一致,包含 two_qubit_gate_count、depth、log_expected_fidelity 等。详见 转译选项与指标。
  • 0.5.0:这些选项背后的布局与路由栈已围绕共享的 LightSABRE 引擎重建——带均衡布局-路由目标函数的双向 SABRE 布局搜索、面向可嵌入子图的 VF2 补全、环形邻域布局候选,以及针对病态实例的工作量熔断器。Python API 保持不变,但编译时间显著下降、输出质量可度量地改善(在与 Qiskit 2.5.2 的 1,044 例 benchpress 套件上,pyqpanda3 0.5.0 在 1,040 例上更快,几何平均时间比 0.233x,同时双量子比特门数保持 0.957x)。固定 execution.seed 后同一程序的重复转译产生完全相同的输出;execution.max_threads 与 execution.compile_time_budget_ms 分别约束线程池与墙钟预算。完整分析见基准测试页面。

5. 实际示例 ​

5.1 编译 GHZ 线路 ​

GHZ(Greenberger-Horne-Zeilinger)态是一种多量子比特最大纠缠态。由于物理量子比特的连接性受限,在真实硬件上制备 GHZ 态需要编译器通过芯片拓扑路由 CNOT 门。

python
from pyqpanda3 import core
from pyqpanda3.transpilation import Transpiler, generate_topology

# Build a 4-qubit GHZ state circuit
# Logical circuit: H(0) -> CNOT(0,1) -> CNOT(0,2) -> CNOT(0,3)
prog = core.QProg()
prog << core.H(0)
prog << core.CNOT(0, 1)
prog << core.CNOT(0, 2)
prog << core.CNOT(0, 3)
prog << core.measure([0, 1, 2, 3], [0, 1, 2, 3])

print("=== GHZ State Circuit ===")
print(f"Logical depth: {prog.depth(only_q2=True)}")
print(f"Logical gates: {prog.count_ops()}")

# Transpile for a linear chain topology
# Qubit 0 must interact with qubits 1, 2, 3
# In a linear chain: 0-1-2-3
# CNOT(0,2) and CNOT(0,3) require SWAP routing
chip_edges = generate_topology(4, "linear")
transpiler = Transpiler()
transpiled = transpiler.transpile(prog, chip_edges, {}, 2)

print("\n=== Transpiled GHZ Circuit ===")
print(f"Physical depth: {transpiled.depth(only_q2=True)}")
print(f"Physical gates: {transpiled.count_ops()}")
print(f"Physical 2Q gates: {transpiled.count_ops(only_q2=True)}")

# Verify
machine = core.CPUQVM()
machine.run(prog, 10000)
orig = machine.result().get_prob_dict()
machine.run(transpiled, 10000)
trans = machine.result().get_prob_dict()

print(f"\nOriginal GHZ:   {orig}")
print(f"Transpiled GHZ: {trans}")

运行结果:

=== GHZ 态线路 ===
逻辑深度: 3
逻辑门数: {'CNOT': 3, 'H': 1}

=== 编译后 GHZ 线路 ===
物理深度: 4
物理门数: {'CNOT': 3, 'H': 1, 'SWAP': 1}
物理双量子比特门数: {'CNOT': 3, 'SWAP': 1}

原始 GHZ:   {'0000': 0.5017, '1111': 0.4983}
编译后 GHZ: {'0000': 0.5033, '1111': 0.4967}

在线性链上,编译器必须通过量子比特 1 和 2 路由 CNOT(0,3) 交互。这会引入额外的 SWAP 门,增加线路深度。在全连接拓扑上,不需要路由:

python
# No routing needed with all-to-all connectivity
full_topo = generate_topology(4, "all-to-all")
transpiled_full = transpiler.transpile(prog, full_topo, {}, 2)
print(f"\nAll-to-all depth: {transpiled_full.depth(only_q2=True)}")

运行结果:


All-to-all depth: 3

5.2 编译随机线路 ​

随机线路适用于基准测试编译性能。此示例生成一个 3 量子比特随机线路并在 100 量子比特方形拓扑上编译:

python
import time
from pyqpanda3 import core
from pyqpanda3.transpilation import Transpiler, generate_topology

qubits = list(range(3))
circuit = core.random_qcircuit(qubits, 20, ["RX", "RY", "RZ", "H", "CNOT", "SWAP"])

prog = core.QProg()
prog.append(circuit)
for q in qubits:
    prog.append(core.measure(q, q))

topo = generate_topology(100, "square")
transpiler = Transpiler()

start = time.time()
transpiled = transpiler.transpile(prog, topo, {}, 2)
elapsed = (time.time() - start) * 1000
print(f"Transpilation time: {elapsed:.2f} ms")
print(f"Before depth: {prog.depth(only_q2=True)}, After depth: {transpiled.depth(only_q2=True)}")

运行结果:

Transpilation time: 6.19 ms
Before depth: 15, After depth: 6

5.3 分解酉矩阵 ​

将酉矩阵分解为线路,然后验证生成的线路是否与原始矩阵匹配:

python
import numpy as np
from pyqpanda3.transpilation import decompose

# Custom U3 matrix
theta, phi, lam = np.pi / 5, np.pi / 7, np.pi / 11
u3_mat = np.array([
    [np.cos(theta / 2), -np.exp(1j * lam) * np.sin(theta / 2)],
    [np.exp(1j * phi) * np.sin(theta / 2),
     np.exp(1j * (phi + lam)) * np.cos(theta / 2)]
], dtype=complex)

circuit = decompose(u3_mat, [0])
print("Correct:", np.allclose(u3_mat, circuit.matrix()))

运行结果:

Correct: True

5.4 自定义拓扑和门集 ​

以下示例展示如何将自定义 T 形拓扑与特定门集结合使用:

python
from pyqpanda3 import core
from pyqpanda3.transpilation import Transpiler, decompose

# T-shaped topology: q0--q2--q3, q2--q1, q2--q4
t_topo = [[0, 2], [1, 2], [2, 3], [2, 4]]

prog = core.QProg()
prog << core.H(0)
prog << core.CNOT(0, 1)  # requires routing: 0->2->1
prog << core.CNOT(3, 4)  # requires routing: 3->2->4
prog << core.measure([0, 1, 2, 3, 4], [0, 1, 2, 3, 4])

transpiler = Transpiler()
transpiled = transpiler.transpile(prog, t_topo, {}, 2, basic_gates=["H", "RZ", "X1", "CNOT"])

print(f"Original: {prog.count_ops()} gates")
print(f"Transpiled: {transpiled.count_ops()} gates, {transpiled.count_ops(only_q2=True)} 2Q")

# Compare with decomposition only (no routing)
decomposed_only = decompose(prog, ["H", "RZ", "X1", "CNOT"])
print(f"Decomposed only: {decomposed_only.count_ops()} gates")

运行结果:

Original: {'CNOT': 2, 'H': 1} gates
Transpiled: {'RZ': 2, 'X1': 1, 'CNOT': 5} gates, {'CNOT': 5} 2Q
Decomposed only: {'CNOT': 2, 'H': 1} gates

6. 性能考虑 ​

编译时间取决于线路大小、拓扑稀疏性和优化级别。对于高达 100 个量子比特、深度 1000 的线路,编译通常在不到一秒内完成。

通过稀疏拓扑路由会增加线路深度。如果两个量子比特在拓扑图中的最短路径距离为 d(即需要经过 d 条边才能从一个量子比特到达另一个,例如相邻量子比特的距离为 1),则它们之间的 CNOT 需要插入 2(d-1) 个 SWAP 门,每个 SWAP 消耗 3 个 CNOT 门,因此双量子比特门数量增加 6(d-1)。

距离增加的 SWAP双量子比特门增加量
1(相邻)00
2212
3424
d2(d-1)6(d-1)

选择拓扑: 使用 "all-to-all" 进行分解测试,使用 "linear" 进行最坏情况路由测试,使用 "square" 模拟真实芯片,使用 backend.chip_info() 获取真实硬件信息。

选择优化级别: 调试使用 0,快速测试使用 1,生产使用 2。对于非常大的线路(>50 个量子比特),级别 1 可能比级别 2 更快。


7. API 快速参考 ​

generate_topology ​

签名返回值说明
generate_topology(num_qubits, topology_type)list[list[int]]生成芯片拓扑边列表

拓扑类型: "linear"、"square"、"all-to-all"

Transpiler ​

方法返回值说明
Transpiler()Transpiler创建新的编译器实例
.transpile(prog, edges, init_map, opt_level)QProg使用边列表拓扑编译
.transpile(prog, backend, init_map, opt_level)QProg使用后端对象编译

decompose(3 个重载) ​

签名返回值说明
decompose(prog, basic_gates)QProg分解 QProg 中的门
decompose(circuit, basic_gates)QCircuit分解 QCircuit 中的门
decompose(matrix, qubits)QCircuit从酉矩阵合成线路

总结 ​

在本教程中,您学习了:

  1. 为什么需要编译 —— 真实的量子硬件具有有限的原生门集和受限的量子比特连接性。编译弥补了抽象线路与硬件约束之间的差距。

  2. 芯片拓扑 —— generate_topology(n, type) 创建用于测试的合成拓扑。提供三种类型:"linear"(链式)、"square"(网格)和 "all-to-all"(全对全)。

  3. Transpiler 类 —— Transpiler().transpile() 执行完整的编译流程:门分解、通过 SABRE 算法进行量子比特路由以及线路优化。您可以传递边列表或云后端对象。

  4. 优化级别 —— 级别 0 不做优化,级别 1 应用基本门消除,级别 2 应用积极优化规则。硬件执行推荐使用级别 2。

  5. 门分解 —— decompose 函数将门重写为指定基本集的形式。三个重载分别处理 QProg、QCircuit 和原始酉矩阵。

  6. 验证 —— 在提交到真实硬件之前,务必在模拟器上对比原始线路和编译后线路以确认正确性。

编译模块是您的量子算法与真实量子处理器之间的桥梁。理解其功能有助于您编写既正确又在硬件上高效的线路。

下一步:

Released under the MIT License.