isQ-core python包安装使用说明

环境

python == 3.8

安装

pip直接安装

pip install isqopen

通过源码进行离线安装

git clone https://gitee.com/arclight_quantum/isq-core/
python setup.py build
python setup.py install

硬件支持

isQ-core支持创新院云平台的12比特量子硬件,使用量子硬件需先去该云台注册相应的账号密码。

isQ-core支持aws braket对接的硬件,可通过设置硬件编号和s3存储桶使用对应量子硬件,当离线使用时,请先安装aws-braket-sdk,注册aws账号,并开通braket相关权限,申请s3存储桶。在isQ云平台时,平台提供aws使用权限,运行需消耗平台积分。

使用

使用时通过import isq 引入isqopen

Device使用

用户需先定义好使用的Device,然后编写好isQ-core程序,调用Device的run接口即可运行,Device初始化参数可详见API说明。LocalDevice返回结果为测量的统计结果,以dict的形式返回。QcisDeviceAwsDevice返回ISQTask,可通过result接口获取结果(等待时间超过max_wait_time则返回空字典,可根据state属性查询任务执行状态)。使用示例如下

from isq import LocalDevice, QcisDevice, AwsDevice

isq_str = '''
    qbit a, b;
    X(a);
    CNOT(a, b);
    M(a);
    M(b);
    '''

# local device
ld = LocalDevice(shots = 200)
# 返回dict
ld_res = ld.run(isq_str)
print(ld_res)

#qcis device
qd = QcisDevice(user = "xxx", passwd = "xxx", max_wait_time = 60)
#返回ISQTask
task = qd.run(file = './test.isq')
#输出状态和结果
print(task.state)
print(task.result())

import logging
logger = logging.getLogger()    # initialize logging class
logger.setLevel(logging.CRITICAL)

#aws device
from isq import TaskState
ad = AwsDevice(shots=100, device_arn = "arn:aws:braket:::device/qpu/ionq/ionQdevice", s3 = ("amazon-braket-arclight", "simulate"), max_wait_time=10, logger = logger)
task = ad.run(isq_str)
print(task.state)
#等待结果直到执行完成
while task.state == TaskState.WAIT:
    task.result()
print(task.result())

Device提供compile_to_ir接口,可将isq编译到openqasm/qcis,示例如下:


'''
isQ-core -> openqasm2.0
qreg大小与isQ-core定义的量子比特数目一致
creg大小与测量的比特数目一致
测量结果按测量顺序从creg[0]开始依次存储
'''
ld = LocalDevice()
ir = ld.compile_to_ir(file = './test.isq', target="openqasm")
print(ir)


isq_str = '''
    qbit a,b;
    H(a);
    CNOT(a,b);
    M(a);
    M(b);
'''
ld = LocalDevice()
ir = ld.compile_to_ir(isq_str, target="qcis")
print(ir)

量子核函数

isQ-core提供了函数修饰符isq.qpu,通过该修饰符可定义一个量子核函数,该修饰符有如下参数

参数名 类型 说明 默认值
device Device 量子后端,可为LocalDeivceQcisDeivceAwsDeivce

用该修饰符修饰的函数内部需采用注释的形式用isQ-core的相关语法进行编程。量子核函数的调用方式和python的函数调用方式一致,其返回结果与使用Device的run函数一致

#使用模拟器运行,制备bell态
import isq
from isq import LocalDevice, QcisDevice, AwsDevice

ld = LocalDevice()

@isq.qpu(ld)
def bell_sim():
    '''
    qbit a, b;
    X(a);
    CNOT(a, b);
    M(a);
    M(b);
    '''

res = bell_sim()
print(res)
ir = ld.get_ir()
print(ir)

#使用12bit量子硬件运行,制备bell态

qd = QcisDevice(user = "xxx", passwd = "xxx")

@isq.qpu(qd)
def bell_qcis():
    '''
    qbit a, b;
    X(a);
    CNOT(a, b);
    M(a);
    M(b);
    '''

task = bell_qcis()
res = task.result()
print(res)

带参电路

isQ-core 支持编写带参的电路,并在编译运行时传入具体的参数值。用户可直接在编写电路时使用参数,并在Device调用编译运行的接口中传入__同名__参数的具体值,如


isq_str = '''
    qbit a, b;
    RX(theta[0], a);
    RY(theta[1], b);
    M(a);
    M(b);
    '''
from isq import LocalDevice

# local device
ld = LocalDevice(shots = 200)
# 返回dict
ld_res = ld.run(isq_str, theta = [0.2, 0.4])
print(ld_res)    

或者通过量子核函数的方式,在定义核函数时确定参数名,并在调用函数时传入具体值,如

#带参数的量子核函数
import isq
from isq import LocalDevice

ld = LocalDevice()

@isq.qpu(ld)
def test(theta, a):
    '''
    qbit t[5];
    if (a < 5){
        X(t[0]);
    }else{
        RX(theta[1],t[1]);
    }
    M(t[1]);
    '''
res = test([0.1, 0.2], 3)

自定义酉门

可使用quantumCor.addGate函数在kernel外部声明自定义酉门,这些酉门可在所有kernel中直接使用(酉操作)。kernel中声明同名酉门则会在内部覆盖。自定义酉门需传入两个参数,门名称(str)和门的矩阵表示(list/np.array),示例如下

from isq import quantumCor
import isq
a = [[0.5+0.8660254j,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]
quantumCor.addGate("Rs", a)

ld = LocalDevice()
@isq.qpu(ld)
def test():
  '''
  qbit a, b;
  ...
  Rs(a, b);
  ...
  '''

电路图生成

isQ-core可通过Device的draw_circuit函数,打印指令集的电路展示图。由于为从编译结果生成,电路图只包含基础门集,用户自定义门会被分解后展示。RX,RY,RZ的旋转角度默认不显示,如需显示,可通过showparam参数设置


from isq import LocalDevice

#定义量子线路
isq_str = '''
    qbit a,b;
    H(a);
    CNOT(a,b);
    RX(2.333, a);
    M(a);
    M(b);
'''

ld = LocalDevice()
ld.run(isq_str)

ld.draw_circuit()
ld.draw_circuit(True)

自动微分

isQ-core可对参数化电路进行自动微分,并利用优化器进行参数优化。LocalDevice内置了probs接口,其在编译阶段进行带参编译,生成参数化电路(目前只支持RX, RY, RZ门带参),这些参数是需要优化的参数,在调用接口传入时需用optv进行封装,在模拟阶段,返回测量比特的概率值(不进行测量,直接返回概率)。

isQ-core提供了基于梯度下降法的优化器optimizer,其opt接口接收用户自定义的损失函数,及需要优化的参数,并返回优化后参数及当次损失函数值

示例如下:


import isq
from isq import LocalDevice, optv


#定义量子线路
isq_str = '''
    qbit q[2];
    RX(theta[0], q[0]);
    RY(theta[1], q[1]);
    M(q[0]);
'''

#定义device
ld = LocalDevice()

#定义损失函数
def loss(params):
    #使用probs函数进行带参编译和模拟,其中需要优化的参数通过optv封装后传入
    c = ld.probs(isq_str, theta = optv(params))
    return c[0] - c[1]

#定义optimizer
opt = isq.optimizer(0.01)
#获取优化后参数及当次损失函数计算值
newp, cost = opt.opt(loss, [0.2, 0.4])
print(newp, cost)

自定义optimizer

isQ-core提供自动微分接口grad以使用户可根据微分结果自定义优化器。grad接收损失函数及损失函数中需要微分的参数位置作为输入,返回一个可调用类型,再传入计算函数所需参数,即可返回参数的微分结果,示例如下

import isq
from isq import LocalDevice, optv

#定义量子线路
isq_str = '''
    qbit q[2];
    RX(theta[0], q[0]);
    RY(theta[1], q[1]);
    M(q[0]);
'''

#定义device
ld = LocalDevice()

#定义计算函数
def calc(params):
    #使用probs函数进行带参编译和模拟,其中需要微分的参数通过optv封装后传入
    c = ld.probs(isq_str, theta = optv(params))
    return c[0] - c[1]

#定义grad,并调用,对第0个参数求微分
g = isq.grad(calc, [0])
d = g([0.2, 0.4])
print(d)

批量处理

isQ-core通过jax的vmap提供自动微分的批处理功能,该功能在单次微分的运行效率上不如上述grad接口,但是在批处理上有着明显的优势。

使用时需先安装jax环境,并在损失函数中使用LocalDeviceprobs接口时添加mod参数,并设置为1(默认为0)。微分采用jax自带的grad函数,批处理采用jax的vmap函数,示例如下

from isq import LocalDevice
from jax import grad, vmap
from jax import numpy as jnp

#定义量子线路
isq_str = '''
    qbit q[2];
    RX(theta[0], q[0]);
    RY(theta[1], q[1]);
    M(q[0]);
'''

#定义device
ld = LocalDevice()

#定义计算函数
def calc(params):
    #使用probs函数进行带参编译和模拟,其中需要优化的参数通过optv封装后传入,mod值为1,使用jax.numpy计算
    c = ld.probs(isq_str, mod = 1, theta = optv(params))
    return c[0] - c[1]

theta = jnp.array([[0.2, 0.4] for _ in range(10)])

#微分
g = grad(calc)
#vmap批处理,以第0轴索引,输出每个划分的微分结果。该例子中即为以行为划分,输出10个结果
c = jax.vmap(g)
d = c(theta)
print(d)