上一章: 噪声
下一章: 量子中间编译
Transpiler 模块教程
本教程提供了 Transpiler 模块的功能概览,其中包括生成线路拓扑、编译量子程序以及分解量子线路。这些操作对于优化和调整量子算法以适应特定的硬件架构至关重要。
概述
Transpiler
模块旨在帮助量子程序做好执行准备,包括生成拓扑结构、编译程序以适应特定架构,并将线路分解为更简单的组件。
函数与类
Transpiler 类
Transpiler 类用于将量子程序编译为符合特定拓扑结构和优化级别的版本。其提供了一个构造函数用于初始化一个新的 Transpiler 类实例。以下是 Transpiler
的构造示例:
Python
transpiler = Transpiler()
transpile 方法
transpile 接口用于通过多个编译过程(passes)将量子程序(QProg)编译到指定的后端拓扑上。此过程通常包括以下步骤:
- 优化量子线路:通过不同的优化策略减少量子门的数量和复杂度,从而提高量子程序的执行效率。
- 映射到指定拓扑:根据目标量子计算机的拓扑,将逻辑量子比特映射到实际物理量子比特。该步骤考虑量子计算机的连通性限制,以确保量子门的物理可行性。
- 量子门转换:将量子子程序中的高级量子门转换为目标硬件支持的低级量子门。这可能涉及对某些门的分解,以适应目标硬件的能力。
- 注解
- 芯片拓扑边(Chip Topology edges):如果
chip_topology_edges
为空,编译过程中将跳过初始映射和路由流程,这可能会影响最终线路的优化和性能。因此,在使用时应提供有效的芯片拓扑信息。
- 优化级别:
0
:不进行优化。
1
:应用基本优化,包括简单的双量子逻辑门抵消和单量子逻辑门合并。
2
:执行高级优化,包括矩阵优化、双量子逻辑门抵消和单量子逻辑门合并。
以下是使用 Transpiler
类编译量子线路的示例:
Python
from pyqpanda3.core import QProg,H,RX,CNOT,U1,measure,draw_qprog,QCircuit
prog_1 = QProg()
prog_1 << H(0) << RX(0, 1.25) << CNOT(0, 1) << U1(1, 0.0001) << CNOT(0, 1) << CNOT(1, 2)
for i in range(3):
prog_1 << measure(i, i)
print('prog: \n', draw_qprog(prog_1))
topo = generate_topology(20, "square")
transpiler = Transpiler()
basic_gates = ['RX','RY','RZ','CZ']
prog_level_0 = transpiler.transpile(prog_1, topo, {}, 0,basic_gates)
prog_level_1 = transpiler.transpile(prog_1, topo, {}, 1,basic_gates)
prog_level_2 = transpiler.transpile(prog_1, topo, {}, 2,basic_gates)
print('Transpiler lavel 0: \n', draw_qprog(prog_level_0))
print('Transpiler lavel 1: \n', draw_qprog(prog_level_1))
print('Transpiler lavel 2: \n',draw_qprog(prog_level_2))
运行结果如下所示:
prog:
┌─┐ ┌──┐ ┌─┐
q_0: |0>─┤H├ ┤RX├ ───*── ──── ───*── ───────┤M├ ───────
└─┘ └──┘ ┌──┴─┐ ┌──┐ ┌──┴─┐ └╥┘ ┌─┐
q_1: |0>──── ──── ┤CNOT├ ┤U1├ ┤CNOT├ ───*────╫─ ─┤M├───
└────┘ └──┘ └────┘ ┌──┴─┐ ║ └╥┘┌─┐
q_2: |0>──── ──── ────── ──── ────── ┤CNOT├──╫─ ──╫─┤M├
└────┘ ║ ║ └╥┘
c : / ═════════════════════════════════════╩════╩══╩═
0 1 2
Transpiler lavel 0:
┌──┐ ┌──┐ ┌──┐ ┌─┐ >
q_0: |0>─┤RY├ ┤RX├ ┤RX├ ──*─ ──── ──── ──── ──── ──── ──── ──── ──*─ ─────┤M├ ──── ──── ──── ──────── >
├──┤ ├──┤ ├──┤ ┌─┴┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌─┴┐ ┌──┐ └╥┘ ┌──┐ ┌──┐ ┌─┐ >
q_1: |0>─┤RZ├ ┤RX├ ┤RZ├ ┤CZ├ ┤RZ├ ┤RX├ ┤RZ├ ┤RZ├ ┤RZ├ ┤RX├ ┤RZ├ ┤CZ├ ┤RZ├──╫─ ┤RX├ ┤RZ├ ──*─ ─────┤M├ >
├──┤ ├──┤ ├──┤ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ ║ └──┘ └──┘ ┌─┴┐ ┌──┐ └╥┘ >
q_2: |0>─┤RZ├ ┤RX├ ┤RZ├ ──── ──── ──── ──── ──── ──── ──── ──── ──── ──────╫─ ──── ──── ┤CZ├ ┤RZ├──╫─ >
└──┘ └──┘ └──┘ ║ └──┘ └──┘ ║ >
c : / ═══════════════════════════════════════════════════════════════════╩═══════════════════════╩═
0 1
q_0: |0>──── ──── ────
q_1: |0>──── ──── ────
┌──┐ ┌──┐ ┌─┐
q_2: |0>┤RX├ ┤RZ├ ─┤M├
└──┘ └──┘ └╥┘
c : / ════════════╩═
2
Transpiler lavel 1:
┌──┐ ┌──┐ ┌──┐ ┌─┐ >
q_0: |0>─┤RZ├ ┤RX├ ┤RZ├ ──*─ ──── ──── ──── ──── ──── ──── ──── ──*─ ─────┤M├ ──── ──── ──── ──────── >
├──┤ ├──┤ ├──┤ ┌─┴┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌─┴┐ ┌──┐ └╥┘ ┌──┐ ┌──┐ ┌─┐ >
q_1: |0>─┤RZ├ ┤RX├ ┤RZ├ ┤CZ├ ┤RZ├ ┤RX├ ┤RZ├ ┤RZ├ ┤RZ├ ┤RX├ ┤RZ├ ┤CZ├ ┤RZ├──╫─ ┤RX├ ┤RZ├ ──*─ ─────┤M├ >
├──┤ ├──┤ ├──┤ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ ║ └──┘ └──┘ ┌─┴┐ ┌──┐ └╥┘ >
q_2: |0>─┤RZ├ ┤RX├ ┤RZ├ ──── ──── ──── ──── ──── ──── ──── ──── ──── ──────╫─ ──── ──── ┤CZ├ ┤RZ├──╫─ >
└──┘ └──┘ └──┘ ║ └──┘ └──┘ ║ >
c : / ═══════════════════════════════════════════════════════════════════╩═══════════════════════╩═
0 1
q_0: |0>──── ──── ────
q_1: |0>──── ──── ────
┌──┐ ┌──┐ ┌─┐
q_2: |0>┤RX├ ┤RZ├ ─┤M├
└──┘ └──┘ └╥┘
c : / ════════════╩═
2
Transpiler lavel 2:
┌──┐ ┌──┐ ┌──┐ ┌─┐ >
q_0: |0>─┤RZ├ ┤RX├ ┤RZ├ ──*─ ──── ──── ──── ──── ──── ──── ──── ──*─ ─────┤M├ ──── ──── ──── ──────── >
├──┤ ├──┤ ├──┤ ┌─┴┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌─┴┐ ┌──┐ └╥┘ ┌──┐ ┌──┐ ┌─┐ >
q_1: |0>─┤RZ├ ┤RX├ ┤RZ├ ┤CZ├ ┤RZ├ ┤RX├ ┤RZ├ ┤RZ├ ┤RZ├ ┤RX├ ┤RZ├ ┤CZ├ ┤RZ├──╫─ ┤RX├ ┤RZ├ ──*─ ─────┤M├ >
├──┤ ├──┤ ├──┤ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ ║ └──┘ └──┘ ┌─┴┐ ┌──┐ └╥┘ >
q_2: |0>─┤RZ├ ┤RX├ ┤RZ├ ──── ──── ──── ──── ──── ──── ──── ──── ──── ──────╫─ ──── ──── ┤CZ├ ┤RZ├──╫─ >
└──┘ └──┘ └──┘ ║ └──┘ └──┘ ║ >
c : / ═══════════════════════════════════════════════════════════════════╩═══════════════════════╩═
0 1
q_0: |0>──── ──── ────
q_1: |0>──── ──── ────
┌──┐ ┌──┐ ┌─┐
q_2: |0>┤RX├ ┤RZ├ ─┤M├
└──┘ └──┘ └╥┘
c : / ════════════╩═
2
如果 chip_topology_edges
参数未提供,则路由(Routing)操作将被跳过。如果 basic_gates
参数未提供,则转化(Translation)操作将被跳过。
Python
basic_gates = ['RX','RY','RZ','CZ']
prog_2 = transpiler.transpile(prog_1, init_mapping ={}, optimization_level = 2,basic_gates=basic_gates)
print('no chip_topology_edges prog: \n',draw_qprog(prog_2))
运行结果如下所示:
no chip_topology_edges prog:
┌──┐ ┌──┐ ┌──┐ ┌─┐ >
q_0: |0>─┤RZ├ ┤RX├ ┤RZ├ ──*─ ──── ──── ──── ──── ──── ──── ──── ──*─ ─────┤M├ ──── ──── ──── ──────── >
├──┤ ├──┤ ├──┤ ┌─┴┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌─┴┐ ┌──┐ └╥┘ ┌──┐ ┌──┐ ┌─┐ >
q_1: |0>─┤RZ├ ┤RX├ ┤RZ├ ┤CZ├ ┤RZ├ ┤RX├ ┤RZ├ ┤RZ├ ┤RZ├ ┤RX├ ┤RZ├ ┤CZ├ ┤RZ├──╫─ ┤RX├ ┤RZ├ ──*─ ─────┤M├ >
├──┤ ├──┤ ├──┤ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ ║ └──┘ └──┘ ┌─┴┐ ┌──┐ └╥┘ >
q_2: |0>─┤RZ├ ┤RX├ ┤RZ├ ──── ──── ──── ──── ──── ──── ──── ──── ──── ──────╫─ ──── ──── ┤CZ├ ┤RZ├──╫─ >
└──┘ └──┘ └──┘ ║ └──┘ └──┘ ║ >
c : / ═══════════════════════════════════════════════════════════════════╩═══════════════════════╩═
0 1
q_0: |0>──── ──── ────
q_1: |0>──── ──── ────
┌──┐ ┌──┐ ┌─┐
q_2: |0>┤RX├ ┤RZ├ ─┤M├
└──┘ └──┘ └╥┘
c : / ════════════╩═
2
如果提供了 init_mappings
参数,则会基于 init_mappings
进行路由。
Python
init_mapping = {0:2, 1:1, 2:0}
basic_gates = ['RX','RY','RZ','CZ']
prog_3 = transpiler.transpile(prog_1, topo, init_mapping=init_mapping, optimization_level = 2,basic_gates=basic_gates)
print('init_mapping prog: \n',draw_qprog(prog_3))
运行结果如下所示:
init_mapping prog:
┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌─┐
q_0: |0>─┤RZ├ ┤RX├ ┤RZ├ ──── ──── ──── ──── ──── ──── ──── ──── ──── ──── ──── ──── ┤CZ├ ┤RZ├ ┤RX├ ┤RZ├ ─┤M├
├──┤ ├──┤ ├──┤ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ └─┬┘ └┬─┤ └──┘ └──┘ └╥┘
q_1: |0>─┤RZ├ ┤RX├ ┤RZ├ ┤CZ├ ┤RZ├ ┤RX├ ┤RZ├ ┤RZ├ ┤RZ├ ┤RX├ ┤RZ├ ┤CZ├ ┤RZ├ ┤RX├ ┤RZ├ ──*─ ─┤M├ ──── ──── ──╫─
├──┤ ├──┤ ├──┤ └─┬┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └─┬┘ └┬─┤ └──┘ └──┘ └╥┘ ║
q_2: |0>─┤RZ├ ┤RX├ ┤RZ├ ──*─ ──── ──── ──── ──── ──── ──── ──── ──*─ ─┤M├ ──── ──── ──── ──╫─ ──── ──── ──╫─
└──┘ └──┘ └──┘ └╥┘ ║ ║
c : / ═══════════════════════════════════════════════════════════════╩═══════════════════╩══════════════╩═
0 1 2
transpile 方法重载
transpile 接口有一个重载函数,该函数用于将量子程序转换为适合特定量子芯片后端的格式,并根据指定的优化级别进行优化。
参数说明如下:
prog
: 需要转换的量子程序。
backend
: 量子芯片的后端配置。该参数定义了芯片的拓扑结构、支持的门操作等信息。
init_mapping
: 初始映射,从虚拟量子比特到物理量子比特的映射关系。默认为空映射。
optimization_level
: 优化级别,指定转换过程中应用的优化策略。默认值为 2。
这个接口可以配合to_instruction
和run_instruction
使用,将一个量子程序编译到云平台的指定芯片上,转成指令文件,运行到芯片上。 以下是一个完整流程的示例代码:
api_key = ""
def run_instruction_test(prog_1: QProg):
service = QCloudService(api_key)
backend_wukong = service.backend("72")
chip_info = backend_wukong.chip_info()
backend: ChipBackend = chip_info.get_chip_backend()
transpiler = Transpiler()
prog_2 = transpiler.transpile(prog_1, backend, {}, 2)
use_pattern = False
ins = prog_2.to_instruction(backend, 1, use_pattern)
options = QCloudOptions()
options.set_mapping(False)
options.set_amend(False)
job = backend_wukong.run_instruction([ins], 1000, options)
result = job.result()
print(result.get_probs_list())
if __name__ == "__main__":
ir = """
QINIT 8
CREG 8
H q[0]
H q[1]
H q[2]
H q[3]
H q[4]
H q[5]
CNOT q[0],q[4]
RZ q[4],(0.93926449)
CNOT q[0],q[4]
CNOT q[0],q[5]
RZ q[5],(0.42459902)
CNOT q[0],q[5]
CNOT q[1],q[4]
RZ q[4],(0.88779795)
CNOT q[1],q[4]
CNOT q[1],q[5]
RZ q[5],(0.46319893)
CNOT q[1],q[5]
CNOT q[2],q[5]
RZ q[5],(1.132264)
CNOT q[2],q[5]
CNOT q[3],q[5]
RZ q[5],(0.86206467)
CNOT q[3],q[5]
RX q[0],(2.3543679)
RX q[1],(2.3543679)
RX q[2],(2.3543679)
RX q[3],(2.3543679)
RX q[4],(2.3543679)
RX q[5],(2.3543679)
MEASURE q[0],c[0]
MEASURE q[1],c[1]
MEASURE q[2],c[2]
MEASURE q[3],c[3]
MEASURE q[4],c[4]
MEASURE q[5],c[5]
"""
prog_1 = convert_originir_string_to_qprog(ir)
run_instruction_test(prog_1)
运行结果如下:
[{'0x0': 0.077, '0x1': 0.007, '0x10': 0.032, '0x11': 0.005, '0x12': 0.043, '0x13': 0.006,
'0x14': 0.009, '0x15': 0.002, '0x16': 0.018, '0x17': 0.005, '0x18': 0.022, '0x19': 0.002,
'0x1a': 0.018, '0x1b': 0.005, '0x1c': 0.018, '0x1d': 0.002, '0x1e': 0.025, '0x1f': 0.003,
'0x2': 0.084, '0x20': 0.036, '0x21': 0.004, '0x22': 0.039, '0x23': 0.003, '0x24': 0.013,
'0x26': 0.011, '0x27': 0.006, '0x28': 0.03, '0x29': 0.004, '0x2a': 0.024, '0x2b': 0.002,
'0x2c': 0.016, '0x2d': 0.006, '0x2e': 0.029, '0x2f': 0.006, '0x3': 0.018, '0x30': 0.014,
'0x31': 0.003, '0x32': 0.019, '0x33': 0.005, '0x34': 0.006, '0x35': 0.002, '0x36': 0.009,
'0x37': 0.002, '0x38': 0.009, '0x39': 0.002, '0x3a': 0.012, '0x3b': 0.001, '0x3c': 0.008,
'0x3d': 0.001, '0x3e': 0.016, '0x3f': 0.001, '0x4': 0.023, '0x5': 0.002, '0x6': 0.03,
'0x7': 0.012, '0x8': 0.042, '0x9': 0.008, '0xa': 0.042, '0xb': 0.004, '0xc': 0.038,
'0xd': 0.005, '0xe': 0.046, '0xf': 0.008}]
生成拓扑
generate_topology 用于基于特定参数生成量子线路的拓扑结构。
分解
decompose 函数可用于将量子程序和线路分解为其基本组成部分。如果 basic_gates
参数未提供,则转化(Translation)操作将被跳过。以下是 decompose 函数的使用示例:
Python
basic_gates = ['RX','RY','RZ','CZ']
decomposed_prog = decompose(prog_1,basic_gates)
print('decomposed prog: \n',draw_qprog(decomposed_prog))
circuit = QCircuit()
circuit << H(0) << RX(0, 1.25) << CNOT(0, 1) << U1(1, 0.0001) << CNOT(0, 1) << CNOT(1, 2)
basic_gates = ['RX','RY','RZ','CZ']
decomposed_circuit = decompose(circuit,basic_gates)
运行结果如下所示:
decomposed prog:
┌──┐ ┌──┐ ┌──┐ ┌─┐ >
q_0: |0>─┤RY├ ┤RX├ ┤RX├ ──*─ ──── ──── ──── ──── ──── ──── ──── ──*─ ─────┤M├ ──── ──── ──── ──────── >
├──┤ ├──┤ ├──┤ ┌─┴┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌─┴┐ ┌──┐ └╥┘ ┌──┐ ┌──┐ ┌─┐ >
q_1: |0>─┤RZ├ ┤RX├ ┤RZ├ ┤CZ├ ┤RZ├ ┤RX├ ┤RZ├ ┤RZ├ ┤RZ├ ┤RX├ ┤RZ├ ┤CZ├ ┤RZ├──╫─ ┤RX├ ┤RZ├ ──*─ ─────┤M├ >
├──┤ ├──┤ ├──┤ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ ║ └──┘ └──┘ ┌─┴┐ ┌──┐ └╥┘ >
q_2: |0>─┤RZ├ ┤RX├ ┤RZ├ ──── ──── ──── ──── ──── ──── ──── ──── ──── ──────╫─ ──── ──── ┤CZ├ ┤RZ├──╫─ >
└──┘ └──┘ └──┘ ║ └──┘ └──┘ ║ >
c : / ═══════════════════════════════════════════════════════════════════╩═══════════════════════╩═
0 1
q_0: |0>──── ──── ────
q_1: |0>──── ──── ────
┌──┐ ┌──┐ ┌─┐
q_2: |0>┤RX├ ┤RZ├ ─┤M├
└──┘ └──┘ └╥┘
c : / ════════════╩═
2
在 V0.2.0 版本以后,也可以使用 decompose
接口来分解矩阵,使用示例如下:
Python
import numpy as np
A = np.random.rand(4, 4) + 1j * np.random.rand(4, 4)
Q, R = np.linalg.qr(A)
basic_gates = ['RX', 'RY', 'RZ', 'CP']
prog = decompose(Q, basic_gates=basic_gates)
print(prog)