开放量子汇编语言—OpenQASM

2023-02-24 15:37:40 浏览数 (2)

开放量子汇编语言——OpenQASM

概述

OpenQASM(open quantum assembly language),即开放量子汇编语言,是一种命令式编程语言,它的特性类似于硬件描述语言(hardware description language),由 IBM 于 2017 年 7 月在其量子计算平台推出,它能够使用电路模型、基于测量的模型和近期量子计算实验来描述通用的量子计算,也是目前适用范围较广的量子汇编语言,目前已更新至 3.0 版本。

OpenQASM 作为一个开源框架,广泛用于基于门的设备的量子程序规范。借助 OpenQASM,用户可以对构成量子计算基石的量子门和测量操作进行编程。目前,许多量子编程库使用先前版本的 OpenQASM 2.0 来描述简单的程序。

OpenQASM 在框架中提供了一组参数化的物理逻辑门和并发的实时经典计算的集合。它的主要目标是作为高级编译器与量子硬件通信的中间表示载体,在表示形式上,也考虑到了人们使用它时的易读性。特别是,该语言允许同一程序的不同表示形式,所以 OpenQASM 可以由 Composer 生成,也支持手写,或者由更高层次的软件工具来完成,比如 ProjectQ、Quil、Liquid 等等。

设计目标

OpenQASM 3.0 与之前版本相比,增加了更多功能,例如脉冲电平控制、门定时和经典控制流程,以弥补最终用户界面和硬件描述语言之间的差距。总结起来,基本集中在以下三个方面:

  • 具有经典逻辑的更广泛的计算系列。OpenQASM 3.0 引入经典控制流、指令和数据类型来定义包括经典数据实时计算的电路。外部机制允许对作用于运行时数据的通用经典计算进行不透明引用。
  • 显式计时。OpenQASM 3.0 引入了一种灵活的机制来描述指令调度的设计意图,同时保持独立于门校准确定的特定持续时间。例如,这可以实现动态去耦,同时保留电路的栅极级描述。
  • 嵌入式脉冲电平定义。一种可扩展的机制,用于将低级定义附加到门。这与校准任务特别相关,校准任务使用最容易在门级描述的误差放大序列来优化脉冲参数。

细节实现

遵循上述设计目标,OpenQASM 3.0 相比之前的 OpenQASM 2.0 规范进行了大幅扩展升级。增加了许多经典控制流和计算的新功能,使编写量子算法更容易,并描述构成这些算法一部分的经典数据处理。然而,该语言并非设计用于通用经典计算,并且在短期内,任何执行 OpenQASM 3.0 程序的硬件都不太可能支持该语言可以描述的全套数据操作。

OpenQASM 3.0 的硬件能够保证它们在运行时将处理性能稳定在高效和实时执行的操作上。这组操作在不同的实现工具下,实现方式会根据硬件种类略有所不同,需要提前了解不同硬件在运行时可以实现哪些语言功能。随着时间的推移,随着量子控制的要求变得不那么繁重,实现组件可能会变得更加强大。

在将来 OpenQASM 3.0 的编译器也会支持一些经典操作,这些经典操作会被合理地判断为编译时常量,并在编译时执行这些操作。上面所说到的“合理推断”是指声明为常量的值以及字面意义。例如,这意味着“科学计算器函数”(如sin、exp 等)将始终对只涉及兼容类型的字面符号和声明为常量的值的表达式起作用,而且编译器会将这些表达式完全折叠成单个常量。具体能够如何实现,还需要我们继续等待相关的适配工作。

示例

因为目前不是所有基于门的量子设备和模拟器都支持 OpenQASM 3.0 ,所以在一些代码示例中,将会使用部分 OpenQASM 2.0 的内容。

首先展示一下如何利用 OpenQASM 中的语法规则设置部分量子门:

代码语言:javascript复制
OPENQASM 2.0;
include "qelib1.inc";
qreg q[10];
creg c[10];

x q[0];
h q[1];
tdg q[2];
sdg q[2];
cx q[0],q[2];
cx q[1],q[4];
u1(pi) q[0];
u2(pi,pi) q[1];
u3(pi,pi,pi) q[2];
cz q[2],q[5];
ccx q[3],q[4],q[6];
cu3(pi,pi,pi) q[0],q[1];
measure q[2] -> c[2];
measure q[0] -> c[0];

可以看到,OpenQASM 会直接对需要进行转置共轭操作的量子逻辑门与量子线路进行直接转化;并且在对量子程序转化 QASM 指令集之前,会对其中包含的控制操作进行分解。


目前在已开源的量子编程框架中,本源量子的 QPanda 框架提供了 QASM 转换的工具接口的,接口为std::string convert_qprog_to_qasm(QProg &, QuantumMachine*),使用方式也较为简单。接下来我们可以来看看QPanda框架是如何进行QASM转换的:

代码语言:javascript复制
#include "QPanda.h"
USING_QPANDA

int main(void)
{
    auto qvm = CPUQVM();
    qvm.init();

    auto prog = QProg();
    auto cir = Circuit();

    auto q = qvm.qAllocMany(6);
    auto c = qvm.cAllocMany(6);

    // 构建量子程序
    cir << Y(q[2]) << H(q[2]);
    cir.setDagger(true);
    auto h1 = H(q[1]);
    h1.setDagger(true);
    prog << H(q[1])
         << X(q[2])
         << h1
         << RX(q[1], 2 / PI)
         << cir
         << CR(q[1], q[2], PI / 2)
         <<MeasureAll(q,c);

    // 量子程序转换QASM,并打印QASM
    std::cout << convert_qprog_to_qasm(prog,qvm);

    return 0;
}

具体的操作步骤是这样的:

  1. 首先在主程序中用 CPUQVM() 初始化一个量子虚拟机对象,用于管理后续一系列行为
  2. 然后调用init()函数来初始化虚拟机
  3. 接着用 qAllocMany()cAllocMany() 初始化量子比特与经典寄存器数目
  4. 然后调用 QProg() 构建量子程序
  5. 最后调用接口 convert_qprog_to_qasm 输出QASM指令集并用 destroyQuantumMachine 释放系统资源

最终的输出结果如下:

代码语言:javascript复制
OPENQASM 2.0;
include "qelib1.inc";
qreg q[6];
creg c[6];
h q[1];
x q[2];
h q[1];
rx(0.636620) q[1];
h q[2];
y q[2];
rz(-0.785398) q[2];
cx q[1],q[2];
rz(-0.785398) q[2];
cx q[1],q[2];
rz(1.570796) q[2];
rx(1.570796) q[1];
ry(-0.785398) q[1];
rx(-1.570796) q[1];
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];

接下来我们可以看看目前已经支持了 OpenQASM 3.0 的 Amazon Braket,是如何利用 OpenQASM 3.0 语言的:

具体示例为如何利用 Braket 创建一个 OpenQASM 3.0 任务。比如,从准备一个Gz状态开始:

代码语言:javascript复制
// ghz.qasm
// Prepare a GHZ state
OPENQASM 3;

qubit[3] q;
bit[3] c;

h q[0];
cnot q[0], q[1];
cnot q[1], q[2];

c = measure q;

或者我们还可以使用 Boto 3 创建 OpenQASM 3.0 任务。在下面的实例中,使用了 ghz.qasm:

代码语言:javascript复制
import boto3
import json

my_bucket = "amazon-braket-my-bucket"
s3_prefix = "openqasm-tasks"

with open("ghz.qasm") as f:
    source = f.read()

action = {
    "braketSchemaHeader": {
        "name": "braket.ir.openqasm.program",
        "version": "1"
    },
    "source": source
}
device_parameters = {}
device_arn = "arn:aws:braket:::device/qpu/rigetti/Aspen-11"
shots = 100

braket_client = boto3.client('braket', region_name='us-west-1')
rsp = braket_client.create_quantum_task(
    action=json.dumps(
        action
    ),
    deviceParameters=json.dumps(
        device_parameters
    ),
    deviceArn=device_arn,
    shots=shots,
    outputS3Bucket=my_bucket,
    outputS3KeyPrefix=s3_prefix,
)

在噪声模拟方面,我们也可以使用 OpenQASM 3.0 来完成。在 Braket 中提交以下程序即可完成噪声模拟:

代码语言:javascript复制
// ghz.qasm
// Prepare a GHZ state
OPENQASM 3;

qubit[3] q;
bit[3] c;

h q[0];
#pragma braket noise depolarizing(0.75) q[0] cnot q[0], q[1];
#pragma braket noise depolarizing(0.75) q[0]
#pragma braket noise depolarizing(0.75) q[1] cnot q[1], q[2];
#pragma braket noise depolarizing(0.75) q[0]
#pragma braket noise depolarizing(0.75) q[1]

c = measure q;

以下列表中提供了所有受支持的编译指示噪声运算符的规范:

代码语言:javascript复制
#pragma braket noise bit_flip(<float>) <qubit>
#pragma braket noise phase_flip(<float>) <qubit>
#pragma braket noise pauli_channel(<float>, <float>, <float>)  <qubit>
#pragma braket noise depolarizing(<float in [0,3/4]>) <qubit>
#pragma braket noise two_qubit_depolarizing(<float in [0,15/16]>) <qubit>, <qubit>
#pragma braket noise two_qubit_dephasing(<float in [0,3/4]>) <qubit>, <qubit>
#pragma braket noise amplitude_damping(<float in [0,1]>) <qubit>
#pragma braket noise generalized_amplitude_damping(<float in [0,1]> <float in [0,1]>)  <qubit>
#pragma braket noise phase_damping(<float in [0,1]>) <qubit>
#pragma braket noise kraus([[<complex m0_00>, ], ...], [[<complex m1_00>, ], ...], ...) <qubit>[, <qubit>]     // maximum of 2 qubits and maximum of 4 matrices for 1 qubit, 16 for 2
) <qubit>[, <qubit>]     // maximum of 2 qubits

QuQASM量子汇编语言

目前除了较为通用的 OpenQASM 开放量子汇编语言外,其实还存在很多专用汇编语言,这些语言在对应设备的适配兼容性上,可能表现会更好。比如,启科量子推出的一款量子汇编语言—— QuQASM ,是针对自研的量子编程框架 QuTrunk 来进行适配的。

QuTrunk 使用 Python 作为宿主语言,利用 Python 的语法特性实现针对量子程序的 DSL (领域专用语言), 把用于量子编程的专用语言称为:QuQASM。它的主要特点是最左边是一个量子门操作,中间加入( * )号链接符,最右边是操作的量子比特,形式如下:

代码语言:javascript复制
gate * qubits

为了方便理解,我们可以再多看看几个例子:

代码语言:javascript复制
H * q[0];               # 对q[0]做hadamard门操作
CNOT * (q[0], q[1]);    # q[0]为控制位,q[1]为目标位
All(Measure) * q        # 对q代表的所有量子比特做测量操作

使用该标准是充分利用了 Python 语法对( * )运算符的重载特性。该表形式更接近量子物理计算公式,同时 ( * )在计算机编程语言上表示乘法的意思,借此表示左边的量子门操作实际上是对量子比特做矩阵乘法运算。

使用该标准编写的量子汇编是可以直接被 QuTrunk 解析运行的,不需要做语法方面的解析处理工作。基于该特性,QuTrunk 可以无缝衔接 QuBranch 通过可视化量子编程生成的量子线路。即 QuTrunk可以直接运行 QuBranch 生成的量子线路(只需做一些简单的初始化工作),而无需做语法上的转译处理。

下面是 QuQASM 每个量子门操作介绍:

代码语言:javascript复制
//H(hadamard): 哈德马门,对a做H门操作,常用于使量子比特处于叠加态
H * a

//X(NOT): 非门(Pauli-X)对a进行取反操作, 量子比特绕布洛赫球的x轴旋转pi角度
X * a

//Y: Pauli-Y, 量子比特绕布洛赫球的y轴旋转pi角度
Y * a

//Z: Pauli-Z, 量子比特绕布洛赫球的z轴旋转pi角度
Z * a

//CNOT(CX): 受控非门,a作为控制位,b为目标位,如果a为1则对b进行取反,如果a为0则不做任何操作
CNOT * (a, b)

//Toffoli: 托佛利门,a, b作为控制位,c为目标位, 如果a,b均为1则对b进行取反,否则不做任何操作
Toffoli * (a, b, c)

//Measure: 测量门,对a进行测量,结果要么是0,要么是1,测量结果受概率振幅影响
Measure * a

//P: 相移门,将量子比特0>态和1>态的相位根据给定的角度进行移动
P(theta) * a

//Rx: 量子比特绕布洛赫球的x轴旋转theta角度
Rx(theta) * a

//Ry: 量子比特绕布洛赫球的y轴旋转theta角度
Ry(theta) * a

//Rz: 量子比特绕布洛赫球的z轴旋转theta角度
Rz(theta) * a

//S: 量子比特绕布洛赫球的z轴旋转pi/2角度
S * a

//Sdg: 对S门的反向操作, 绕布洛赫球的z轴反方向旋转pi/2角度
Sdg * a

//T: 量子比特绕布洛赫球的z轴旋转pi/4角度
T * a

//Tdg: 对T门的反向操作, 绕布洛赫球的z轴反方向旋转pi/4角度
Tdg * a

//Swap: 交换两个量子比特的状态
Swap * (a, b)

//SqrtSwap: 对两个量子比特做sqrt交换
SqrtSwap * (a, b)

//SqrtX: 平方根X门
SqrtX * a

//Rxx: 两个量子比特绕x^x旋转,旋转角度为theta
Rxx(theta) * (a, b)

//Ryy: 两个量子比特绕y^y旋转,旋转角度为theta
Ryy(theta) * (a, b)

//Rzz: 两个量子比特绕z^z旋转,旋转角度为theta
Rzz(theta) * (a, b)

//Barrier: 分隔量子比特,阻止量子线路对相应量子比特做优化等处理
Barrier * a
Barrier * (a, b)

//U1: 对单个量子比特绕z轴旋转
U1(lambda) * a

//U2: 对单个量子比特绕x z轴旋转
U1(phi, lambda) * a

//U3: 通用单量子比特旋转门
U1(theta, phi, lambda) * a

//All: 对其他量子门操作进行封装,提供对多量子比特便捷操作
All(Measure) * qreg (对qreg代表的所有量子比特进行测量)
All(H) * qreg (对qreg代表的所有量子比特进行H门操作)

我们可以利用 QuQASM 语言来完成量子电路图的编译和输出,具体操作方法如下:

代码语言:javascript复制
# import package
from QuTrunk.circuit import QCircuit
from QuTrunk.circuit.gates import H, CNOT, Measure, All
# allocate resource
qc = QCircuit()
qr = qc.allocate(2)
# apply quantum gates
H * qr[0]
CNOT * (qr[0], qr[1])
All(Measure) * qr
# print circuit
qc.print()
# run circuit
res = qc.run(shots=1024)
# print result
print(res.get_counts())
# draw circuit
print(qc.draw())

输出结果如下所示:

代码语言:javascript复制
qreg q[2]
creg c[2]
H(0) * (q[0])
CX(1) * (q[0], q[1])
Measure(0) * (q[0])
Measure(0) * (q[1])
[{"00": 519}, {"11": 505}]
参考链接:
  1. OpenQASM 3.0.x Live Specification — OpenQASM Live Specification 文档
  2. 动态电路简介 - IBM Quantum
  3. IBM量子计算机编程语言-OpenQASM简介
  4. 量子程序转化QASM — QPanda 文档 (qpanda-tutorial.readthedocs.io)
  5. 使用 OpenQASM 3.0 运行你的电路 - Amazon Braket

0 人点赞