Skip to content

vv0.3.0

新功能和重要的更新

1.变分量子线路支持结构复用和表达式作为参数化门的门参数

python
from pyqpanda3.vqcircuit import VQCircuit
from pyqpanda3.core import QCircuit,X,RX,RY,Y

def get_vqc1():
  vqc = VQCircuit()
  vqc.set_Param([2]) # 1>约定参数θ为长度是2的一维向量,2>参数θ与变分量子线路U(θ)绑定,不可以用于其他变分量子线路
  p0 = vqc.Param([0],'p0') # 给θ_0加名称p0
  p1 = vqc.Param([1],'p1') # 给θ_1加名称p1
  e = 3.14*p0*p1+p1+4 #由参数θ的元素组成的表达式(支持加、乘和标量乘混合运算)
  vqc << X(0) #向变分量子线路U(θ)中加入X门
  vqc << RX(0,3.14) #向变分量子线路U(θ)中加入RX门,该门的参数为固定数值3.14
  vqc << RY(0,e) #向变分量子线路U(θ)中加入RY门,该门的参数是可变的,是由参数θ的元素组成的表达式
  return vqc
def get_vqc2():
  vqc2 = VQCircuit()
  vqc2.set_Param([3])
  P0 = vqc2.Param([0],'P0')
  P1 = vqc2.Param([1],'P1')
  P2 = vqc2.Param([2],'P2')
  cir = QCircuit()
  cir << Y(0)
  vqc2 << cir # 向变分量子线路U(θ)中加入QCircuit对象中的所有量子逻辑门
  vqc1= get_vqc1() #为了方便区分,将vqc1对应的参数θ称为θ1,+将vqc2对应的参数θ称为θ2;θ1的两个元素分别为θ1[0],θ1[1],各自的名称为p0,p1;θ2的3个元素分别为θ2[0],θ2[1],θ2[2],各自的名称为P0,P1,P2
  vqc2.append(vqc1,[(vqc1.Param([0]),vqc2.Param([0])),(vqc1.Param([1]),vqc2.Param([1]))])#复用vqc1的结构。对于参数θ,θ1[0]将使用θ2[0]替换,θ1[1]将使用θ2[1]替换
  return vqc2

vqc1 = get_vqc1()
print('vqc1:')
vqc1.display_ansatz() #打印变分量子线路的结构
print()
vqc2 = get_vqc2()
print('vqc2:')
vqc2.display_ansatz()

示例代码输出结果

bash
vqc1:
X q[0]
RX q[0],(3.14000000)
RY q[0],(((3.14*p0*p1+p1)+4))

vqc2:
Y q[0]
X q[0]
RX q[0],(3.14000000)
RY q[0],(((3.14*P0*P1+P1)+4))

2.变分量子线路支持梯度计算,提供同时获得期望值和梯度值的接口

python
from pyqpanda3.vqcircuit import VQCircuit,DiffMethod
from pyqpanda3.core import QCircuit,X,RX,RY,Y,CPUQVM,QProg
from pyqpanda3.hamiltonian import Hamiltonian
def get_vqc():
  # 准备变分量子线路U(θ)
  vqc = VQCircuit()
  vqc.set_Param([2])# 1>约定参数θ为长度是2的一维向量,2>参数θ与变分量子线路U(θ)绑定,不可以用于其他变分量子线路
  vqc << RX(0,vqc.Param([0])) #加入参数化量子门RX,该门的参数对应向量θ的第一个元素
  vqc << RY(1,vqc.Param([1]))
  return vqc
def get_param_val():
  # 准备参数θ的实际数值θval
  param_val = [2.14,3.14] # 元素个数应该与参数θ(向量)的元素个数保持一致
  return param_val

def get_hamiltonian():
  # 准备哈密顿算子H
  paulis = [
    ('YY', [0, 1], (12.36525580995888 + 14.85172018664403j)), #(泡利基,泡利基作用的量子比特索引,系数)
    ('YX', [0, 1], (12.920260765526914 + 26.29613065236354j)) #用到的量子比特索引应该与量子线路的用到的比特索引一致
  ]

  return Hamiltonian(paulis)
def get_gradient(vqc,param_val,ham):
  # 获取梯度值(方法1)
  return vqc.get_gradients(params=param_val,observable=ham,diff_method=DiffMethod.ADJOINT_DIFF)

def get_gradient2(vqc:VQCircuit,param_val,ham):
  # 获取梯度值(方法2)
  # 接口get_gradients_and_expectation可同时获得梯度值和期望值
  return vqc.get_gradients_and_expectation(params=param_val,observable=ham,diff_method=DiffMethod.ADJOINT_DIFF)

vqc = get_vqc() # 准备变分量子线路U(θ)
param_val = get_param_val() # 准备参数θ的实际数值θval
ham = get_hamiltonian() #建议变量名不要使用H,以避免与H门发生名称冲突.
res1 = get_gradient(vqc,param_val,ham)# 获取梯度值(方法1)
res2 = get_gradient2(vqc,param_val,ham)# 获取梯度值(方法2)
print('res1:',res1)
print('res1 gradient:',res1.gradients())
print('res2:',res2)
print('res2 gradient:',res2.gradients())

示例代码输出结果

bash
res1: {gradient(double):{Parameter.at([0]):0.0110905,Parameter.at([1]):23.3932}}
res1 gradient: [0.011090474368968659, 23.39317090007428]
res2: (gradient and expectation){"expectation":-0.017333,"gradients":{Parameter.at([0]):0.0110905,Parameter.at([1]):23.3932}}
res2 gradient: [0.011090474368968659, 23.39317090007428]

3.增加对SQISWAP、ECHO、IDLE、CRX、CRY、CRZ的支持

python
from pyqpanda3.intermediate_compiler import convert_qprog_to_originir,convert_originir_string_to_qprog
from pyqpanda3.core import QProg
from pyqpanda3.core import X,CP,CRX,CRY,CRZ,ECHO,SQISWAP,IDLE
from pyqpanda3.vqcircuit import VQCircuit,DiffMethod
ir_str="""
QINIT 2
CREG 1
CRX q[0],q[1],(3.14000000)
CRY q[0],q[1],(4.14000000)
CRZ q[0],q[1],(5.14000000)
ECHO q[0]
SQISWAP q[0],q[1]
IDLE q[0],(3.66666006000)
"""

prog = QProg(ir_str)    # OriginIR -> QProg
ir_2 = prog.originir(8) # QProg -> OriginIR
print('ir_2:\n',ir_2)

prog3 = QProg()
prog3 << CRX(0,1,30.14) # append CRX to prog3
prog3 << CRY(0,1,40.14) # append CRY to prog3
prog3 << CRZ(0,1,50.14) # append CRZ to prog3
prog3 << ECHO(0) # append ECHO to prog3
prog3 << SQISWAP(0,1)   # append SQISWAP to prog3
prog3 << IDLE(0,30.66666) # append IDLE to prog3
ir_3 = prog3.originir(8) # QProg -> OriginIR
print('ir_3:\n',ir_3)

vqc = VQCircuit()
vqc.set_Param([0])
vqc << CRX(0,1,30.14) # append CRX to vqc
vqc << CRY(0,1,40.14) # append CRY to vqc
vqc << CRZ(0,1,50.14) # append CRZ to vqc
vqc << ECHO(0) # append ECHO to vqc
vqc << SQISWAP(0,1)   # append SQISWAP to vqc
vqc << IDLE(0,30.66666) # append IDLE to vqc
cir = vqc([]).at([0])
print('cir ir:\n',cir.originir(8))

示例代码输出结果

bash
ir_2:
 QINIT 2
CREG 1
CONTROL q[0]
RX q[1],(3.14000000)
ENDCONTROL
CONTROL q[0]
RY q[1],(4.14000000)
ENDCONTROL
CONTROL q[0]
RZ q[1],(5.14000000)
ENDCONTROL
ECHO q[0]
SQISWAP q[0],q[1]
IDLE q[0],(3.00000000)

ir_3:
 QINIT 2
CREG 1
CONTROL q[0]
RX q[1],(30.14000000)
ENDCONTROL
CONTROL q[0]
RY q[1],(40.14000000)
ENDCONTROL
CONTROL q[0]
RZ q[1],(50.14000000)
ENDCONTROL
ECHO q[0]
SQISWAP q[0],q[1]
IDLE q[0],(30.00000000)

cir ir:
 QINIT 2
CREG 1
CONTROL q[0]
RX q[1],(30.14000000)
ENDCONTROL
CONTROL q[0]
RY q[1],(40.14000000)
ENDCONTROL
CONTROL q[0]
RZ q[1],(50.14000000)
ENDCONTROL
ECHO q[0]
SQISWAP q[0],q[1]
IDLE q[0],(30.00000000)

4.新增ChipBackend类,这个类保存芯片后端用来编译的信息,新增transpile接口,通过传入ChipBackend参数将量子程序编译到指定芯片后端。同时QCloud增加获取云平台芯片后端的功能。 使用示例如下:

python
import time
from pyqpanda3.qcloud import *
from pyqpanda3.core import *
from pyqpanda3.transpilation import Transpiler

apikey = ''

def test_backend():
    print("test_get_topo")
    service = QCloudService(apikey)
    # service.setup_logging()
    backends = service.backends()
    for backend in backends:
        print(backend)

    backend_wukong = service.backend("WK_C102_400")
    backend = backend_wukong.chip_info().get_chip_backend()

    all_qbits = list(range(10))
    circuit = random_qcircuit(all_qbits, 100, ["RX", "RY", "RZ", "H", "U1", "U2", "U3", "CP", "CNOT", "SWAP"])

    prog_1 = QProg()
    prog_1 << circuit
    for i in all_qbits:
        prog_1 << measure(i, i)

    transpiler = Transpiler()
    print("Enter transpile")
    prog_2 = transpiler.transpile(prog_1, backend, {}, 2)

if __name__ == "__main__":
    test_backend()

5.新增QProg导出量子芯片指令的接口,量子芯片指令是可以直接发往芯片运行的文件。目前该接口的指令格式仅支持本源量子计算机。 使用该接口需要保证量子程序中已经全部是芯片的基础指令(RPhi、CZ、Measure和ECHO)。 to_instruction有三个参数,第一个参数是指定的芯片后端,第二个参数是转指令过程中qubit的偏移量,第三个参数是是否使用pattern对指令进行分层。

这个接口可以配合to_instructionrun_instruction使用,将一个量子程序编译到云平台的指定芯片上,转成指令文件,运行到芯片上。 以下是一个完整流程的示例代码:

python

from pyqpanda3.intermediate_compiler import convert_originir_file_to_qprog, convert_originir_string_to_qprog
from pyqpanda3.qcloud.qcloud import ChipBackend
from pyqpanda3.qcloud import QCloudService, LogOutput, QCloudOptions
from pyqpanda3.transpilation import Transpiler
from pyqpanda3.core import *

api_key = "" # 换成自己的key


def run_instruction_test(prog_1: QProg):
    # 获取服务
    service = QCloudService(api_key)

    # 获取指定芯片
    backend_wukong = service.backend("WK_C102_400")
    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)

运行结果如下:

python
[{'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}]

6.量子云服务添加指令集任务,可以将量子程序编译到指定后端支持的指令集上,然后直接运行指令集任务

python
from pyqpanda3.qcloud import QCloudService,QCloudOptions
from pyqpanda3.core import CZ, measure, QProg

prog = QProg()
prog << CZ(9, 10)
prog << CZ(10, 11)
prog.append(measure(9,9))

online_key = "api_key"

service = QCloudService(online_key)
service.setup_logging()
backend = service.backend("WK_C102_400")

options = QCloudOptions()
options.set_amend(False)

ins = prog.to_instruction(backend.chip_backend())
job = backend.run_instruction([ins,ins], 1000, options)

chip_info = backend.chip_info()

result = job.result()
print(result.get_probs_list())

输出如下:

python
[{'0x0': 0.7249999761581421, '0x1': 0.2749999940395355}, {'0x0': 0.75, '0x1': 0.25}]

问题修复

1.修复在多线程程序中进行OrginIR转换时出现的偶发崩溃问题

2.修复多控门在超过14比特触发simd优化计算时的报错问题

3.优化多控门分解算法,提高分解效率

4.提升transpile接口性能

Released under the MIT License.