输出算法操作

首先介绍一个最基本的使用方法,就是使用projectq来打印量子算法中所输入的量子门操作,这里使用到了projectq中的dummyengine后端用于保存操作的指令。比如最简单的一个bell state的制备,可以通过如下代码实现,并且打印出所保存的基本操作:

from projectq import mainengine
from projectq.cengines import dummyengine
from projectq.ops import h, cx, all, measure

backend = dummyengine(save_commands=true)
eng = mainengine(backend=backend)

qureg = eng.allocate_qureg(2)
h | qureg[0]
cx | (qureg[0], qureg[1])

all(measure) | qureg
eng.flush(deallocate_qubits=true)

for cmd in backend.received_commands:
    print (cmd)

运行结果如下:

allocate | qureg[0]
h | qureg[0]
allocate | qureg[1]
cx | ( qureg[0], qureg[1] )
measure | qureg[0]
measure | qureg[1]
deallocate | qureg[0]
deallocate | qureg[1]

这里有一点需要注意的是,如果是单次运算,我们到measure就可以结束了。但是如果同一个线程的任务还没有结束的话,需要在measure之后加上一个deallocate_qubits=true的配置项,用于解除当前分配的量子比特所占用的内存。

封装的操作

在量子算法的实现中,我们可以用一些函数或者类来封装一部分的量子算法操作指令,但是这可能会导致一个问题,那就是在projectq上打印出来的操作指令没有把封装的模块的内容输出出来,比如如下的案例:

from projectq import mainengine
from projectq.cengines import dummyengine
from projectq.ops import h, cx, all, measure, timeevolution, qubitoperator

backend = dummyengine(save_commands=true)
eng = mainengine(backend=backend)

qureg = eng.allocate_qureg(3)
h | qureg[0]
cx | (qureg[0], qureg[1])
timeevolution(1, qubitoperator('x2 x1')) | qureg

all(measure) | qureg
eng.flush()

for cmd in backend.received_commands:
    print (cmd)

执行结果如下:

allocate | qureg[0]
h | qureg[0]
allocate | qureg[1]
cx | ( qureg[0], qureg[1] )
measure | qureg[0]
allocate | qureg[2]
exp(-1j * (1.0 x0 x1)) | qureg[1-2]
measure | qureg[1]
measure | qureg[2]

我们发现这里的含时演化的操作算符没有被分解,而是直接打印输出了出来。但是如果在硬件系统中,只能够识别支持的指令操作,这里的含时演化操作可能并未在量子硬件体系中被实现,因此我们就需要在将指令发送给量子硬件之前,就对其进行分解。

含时演化算符的分解

这里我们直接调用projectq的配置中的restrictedgateset方法进行操作分解,我们将单比特门操作的范围放宽到所有的操作,但是双比特操作只允许cx操作,并将这个配置作为engin_list配置到projectq的mainengine中:

from projectq import mainengine
from projectq.cengines import dummyengine
from projectq.ops import h, cx, all, measure, timeevolution, qubitoperator
from projectq.setups import restrictedgateset

engine_list = restrictedgateset.get_engine_list(one_qubit_gates="any",two_qubit_gates=(cx,))
backend = dummyengine(save_commands=true)
eng = mainengine(backend=backend,engine_list=engine_list)

qureg = eng.allocate_qureg(3)
h | qureg[0]
cx | (qureg[0], qureg[1])
timeevolution(1, qubitoperator('x2 x1')) | qureg

all(measure) | qureg
eng.flush(deallocate_qubits=true)

for cmd in backend.received_commands:
    print (cmd)

打印输出的结果如下:

allocate | qureg[0]
h | qureg[0]
allocate | qureg[1]
cx | ( qureg[0], qureg[1] )
measure | qureg[0]
allocate | qureg[2]
h | qureg[2]
h | qureg[1]
cx | ( qureg[1], qureg[2] )
rz(2.0) | qureg[2]
cx | ( qureg[1], qureg[2] )
h | qureg[1]
measure | qureg[1]
h | qureg[2]
measure | qureg[2]
deallocate | qureg[0]
deallocate | qureg[1]
deallocate | qureg[2]

可以看到含时演化算符已经被分解并输出了出来。由于已知单比特量子门加上一个cx是一个完备的量子门集合,因此一般我们可以直接使用这个集合来进行量子门操作指令集的限制。

qft的分解

qft是projectq中所自带支持的量子傅里叶变换的量子门操作封装,跟上一个章节中所介绍的含时演化算符类似的,我们可以用restrictedgateset来具体分解qft算符:

from projectq import mainengine
from projectq.cengines import dummyengine
from projectq.ops import h, cx, all, measure, timeevolution, qubitoperator, qft
from projectq.setups import restrictedgateset

engine_list = restrictedgateset.get_engine_list(one_qubit_gates="any",two_qubit_gates=(cx,))
backend = dummyengine(save_commands=true)
eng = mainengine(backend=backend,engine_list=engine_list)

qureg = eng.allocate_qureg(3)
h | qureg[0]
cx | (qureg[0], qureg[1])
qft | qureg

all(measure) | qureg
eng.flush(deallocate_qubits=true)

for cmd in backend.received_commands:
    print (cmd)

输出的结果如下:

allocate | qureg[2]
allocate | qureg[1]
h | qureg[2]
rz(0.785398163398) | qureg[2]
allocate | qureg[0]
h | qureg[0]
cx | ( qureg[0], qureg[1] )
r(0.785398163398) | qureg[1]
cx | ( qureg[1], qureg[2] )
rz(11.780972450962) | qureg[2]
cx | ( qureg[1], qureg[2] )
r(0.392699081698) | qureg[0]
rz(0.392699081698) | qureg[2]
cx | ( qureg[0], qureg[2] )
h | qureg[1]
rz(12.173671532661) | qureg[2]
cx | ( qureg[0], qureg[2] )
r(0.785398163398) | qureg[0]
rz(0.785398163398) | qureg[1]
cx | ( qureg[0], qureg[1] )
rz(11.780972450962) | qureg[1]
cx | ( qureg[0], qureg[1] )
h | qureg[0]
measure | qureg[0]
measure | qureg[1]
measure | qureg[2]
deallocate | qureg[1]
deallocate | qureg[2]
deallocate | qureg[0]

如果2比特门操作也不加以限制的化,projectq中会自动选取最简易的分解形式:

from projectq import mainengine
from projectq.cengines import dummyengine
from projectq.ops import h, cx, all, measure, timeevolution, qubitoperator, qft
from projectq.setups import restrictedgateset

engine_list = restrictedgateset.get_engine_list(one_qubit_gates="any",two_qubit_gates="any")
backend = dummyengine(save_commands=true)
eng = mainengine(backend=backend,engine_list=engine_list)

qureg = eng.allocate_qureg(3)
h | qureg[0]
cx | (qureg[0], qureg[1])
qft | qureg

all(measure) | qureg
eng.flush(deallocate_qubits=true)

for cmd in backend.received_commands:
    print (cmd)

输出结果如下:

allocate | qureg[0]
allocate | qureg[1]
h | qureg[0]
cx | ( qureg[0], qureg[1] )
allocate | qureg[2]
h | qureg[2]
cr(1.570796326795) | ( qureg[1], qureg[2] )
cr(0.785398163397) | ( qureg[0], qureg[2] )
h | qureg[1]
cr(1.570796326795) | ( qureg[0], qureg[1] )
h | qureg[0]
measure | qureg[0]
measure | qureg[1]
measure | qureg[2]
deallocate | qureg[1]
deallocate | qureg[2]
deallocate | qureg[0]

可以发现使用了cr来替代cx之后,分解出来的线路会更加的简短。

总结概要

本文主要从工程实现的角度,讲解在projectq开源量子计算模拟器框架中,实现量子门操作分解与输出的方法。通过这个方法,可以限制量子指令集的范围,将量子算法中不被支持的量子门操作等价(或近似地)变化到量子硬件体系所支持的量子指令集上。

以上就是python使用projectq生成量子算法指令集的详细内容,更多关于python 用projectq生成算法指令集的资料请关注www.887551.com其它相关文章!