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
的形式返回。QcisDevice
及AwsDevice
返回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 | 量子后端,可为LocalDeivce ,QcisDeivce ,AwsDeivce |
无 |
用该修饰符修饰的函数内部需采用注释的形式用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
环境,并在损失函数中使用LocalDevice
的probs
接口时添加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)