Python魔法函数与两比特量子系统模拟
技术背景
本文主要涵盖两个领域的知识点:python的魔法函数和量子计算模拟,我们可以通过一个实际的案例来先审视一下这两个需求是如何被结合起来的。
量子计算模拟背景
ProjectQ
是一个非常优雅的开源量子计算编程框架,其原作者是来自与瑞士联邦理工的博士Damian和Thomas。该量子计算编程框架是一个从量子计算应用->量子线路编译->哈密顿量模拟->量子计算模拟->量子硬件API对接都有相应实现的、非常全面的量子计算编程框架。其开源地址为:https://github.com/ProjectQ-Framework/ProjectQ,支持使用pip进行安装:python3 -m pip install projectq --upgrade
。
下面来看一个例子,关于如何使用projectq
进行量子计算的模拟:
[dechin@dechin-manjaro simulator]$ ipython
Python 3.8.5 (default, Sep 4 2020, 07:30:14)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.19.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: from projectq import MainEngine
In [2]: from projectq.ops import X
In [3]: eng = MainEngine()
In [4]: qubits = eng.allocate_qureg(2)
In [5]: X | qubits[0]
In [6]: from projectq.ops import CX
In [7]: CX | (qubits[0], qubits[1])
In [8]: eng.flush()
In [9]: print (eng.backend.cheat()[1])
[0j, 0j, 0j, (1+0j)]
在这个案例中,我们一共分配了2个量子比特,这2个比特的初始状态都是\(\left|0\right>\)态,对应于projectq
输出的amplitude矢量应为[1, 0, 0, 0]
。这个矢量中的4个元素,分别对应00,01,10,11
这四个量子态可能出现的概率幅,如果需要计算某一个态被测量所出现的概率的话,需要对其进行取模平方操作:
\]
注意概率幅是一个复数(Complex Number),因此需要取厄米共轭之后再进行点乘操作。
那么回到上述projectq的使用案例,这个案例在分配了两个比特之后,对其中的第一个比特执行了泡利矩阵\(\sigma^X\)操作,然后又执行了一个纠缠门操作CX
。这里CX(i,j)
量子门操作对应的操作为:如果量子比特i
处于\(\left|0\right>\)态,不进行任何的操作;但是如果量子比特i
出于\(\left|1\right>\)态,则对量子比特j
执行取反操作
,也就是说,如果原来j
是\(\left|0\right>\)就会变成\(\left|1\right>\),如果原来j
是\(\left|1\right>\)就会变成\(\left|0\right>\)。这就是量子纠缠在量子计算中的作用,而多比特的门操作在实际的硬件体系中的高质量实现,目前依旧是一大难题。而量子叠加特性就体现在,一个量子比特可能处于\(\left|0\right>\)态,也可能处于\(\left|1\right>\)态,还有可能处在\(\left|0\right>\)和\(\left|1\right>\)的中间态,这种中间态会以上述提到的概率幅的形式来对\(\left|0\right>\)和\(\left|1\right>\)进行划分:
P(1)=(a_1+b_1i)\cdot(a_1-b_1i)
\]
这些的概率幅就可以用一个矢量的形式组织起来:
\]
最终这个矢量的元素个数会随着比特数的增加而指数增长
,当比特数增长到41
时,所需要存储的内存空间需要32TB
以上!要注意的是,因为计算过程中需要将所有的概率幅加载到内存中,所以这里区别于硬盘存储空间,单指内存就需要到32TB
的大小!因此,使用经典计算机去模拟量子计算,其实是一种非常消耗资源的手段。当然,量子计算模拟器依然有其研究的价值,在现阶段量子芯片规模和质量无法提升的状态下,模拟器就起到了重要的作用。
Python的魔法函数实现
如果读者需要了解详细全面Python的魔法函数的实现方案,可以从本文的参考链接中获取两篇不错的文章。这里我们仅针对上述projectq
的代码用例中所可能使用到的部分功能:__or__
和__str__
,并且可以针对其进行一个简单的复现。
Python的魔法函数可用于定义一个类(class)的特殊运算算符,如:类的加减乘除等,在引入魔法函数之后,就不需要单独对类中的元素进行操作,而可以用魔法函数对操作进行封装。最后的效果,我们可以直接在代码中使用操作符对不同的类进行操作,比如可以自定义class1 + class2
这样的二元操作算符。在本章节我们不详细展开介绍,可以参考下述的具体使用示例或者参考链接中的博文。
量子态定义及实现
根据第一个章节中对量子态矢量的介绍,这里我们可以实现一个简单的量子态的类,我们可以仅考虑两个量子比特的简单系统:
# QubitPair.py
import numpy as np
class QubitPair:
def __init__(self):
self.state = np.array([1, 0, 0, 0], dtype=complex)
def __str__(self):
return str(self.state)
这个量子态的类的定义非常简单,就是一个4×1
的矩阵。需要补充说明的是,这里我们定义了一个__str__(self)
的魔法函数,该函数主要用于打印类的字符串表示,如我们这里直接将量子态矢量转化成str
格式之后进行输出。那么我们如果去print
一个自定义的QubitPair
类的话,就会展示当前类所对应的概率幅的字符串表示。
量子门操作定义及实现
关于量子门操作,我们可以将其视作作用在量子态矢量上的矩阵,这里我们可以先展示定义好的门操作的Python类再对其进行展开说明:
# Operator.py
import numpy as np
class QubitOperator:
"""Pauli rotations and entanglement on qubit-pair"""
def __init__(self, operation=None, theta=0, index=0):
self.index = index
self.name = operation
paulix = np.array([[0, 1], [1, 0]], dtype=complex)
pauliy = np.array([[0, -1j], [1j, 0]], dtype=complex)
pauliz = np.array([[1, 0], [0, -1]], dtype=complex)
cnot = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0]])
if operation == 'X' or operation == 'Rx':
self.operation = np.cos(theta/2)*np.identity(2)-1j*np.sin(theta/2)*paulix
elif operation == 'Y' or operation == 'Ry':
self.operation = np.cos(theta/2)*np.identity(2)-1j*np.sin(theta/2)*pauliy
elif operation == 'Z' or operation == 'Rz':
self.operation = np.cos(theta/2)*np.identity(2)-1j*np.sin(theta/2)*pauliz
elif operation == 'CX' or operation == 'CNOT':
self.operation = cnot
def __or__(self, qubitpair):
if self.name == 'CX' or self.name == 'CNOT':
qubitpair.state = np.dot(self.operation, qubitpair.state)
return None
elif self.index == 0:
operation = np.kron(self.operation, np.identity(2))
else:
operation = np.kron(np.identity(2), self.operation)
qubitpair.state = np.dot(operation, qubitpair.state)
单位矩阵与泡利矩阵的定义
这些是基本的泡利矩阵,这三个两能级体系的泡利矩阵具有非常好的物理性质,如都是酉矩阵且存在特殊的对易关系等:
\begin{array}{1}
1 & 0\\
0 & 1
\end{array}
\right),
\sigma^X=\left(
\begin{array}{1}
0 & 1\\
1 & 0
\end{array}
\right),
\sigma^Y=\left(
\begin{array}{1}
0 & -i\\
i & 0
\end{array}
\right),
\sigma^Z=\left(
\begin{array}{1}
1 & 0\\
0 & -1
\end{array}
\right)
\]
矩阵指数与旋转门操作
矩阵的指数计算一般采用泰勒级数展开的方法来进行定义:
\]
这里如果我们代入上述介绍的泡利矩阵就会得到这样的结果:
\]
CX门操作的定义
在上述提到的所有的量子门操作中,CX
是唯一的一个两比特量子门操作,也就是同时作用在两个量子比特上面,其矩阵形式的定义如下所示:
\begin{array}{1}
1 & 0 & 0 & 0\\
0 & 1 & 0 & 0\\
0 & 0 & 0 & 1\\
0 & 0 & 1 & 0
\end{array}
\right)
\]
使用魔法函数__or__
来实现量子门操作运算
我们首先简单谈一下为什么要用__or__
这个魔法函数而不是其他的二元运算符来实现,这点跟开源库ProjectQ
是同步的,理由是我们在量子力学中的运算,一般写成如下的形式:
\]
将量子态写成狄拉克符号的形式,中文称为"左矢"和"右矢",英文称之为"bra"和"ket"。因此竖线形式的定义,在形式上会更加契合量子力学的思维,当然,就算是换成其他的符号也是无可厚非的。
功能测试验证
在定义了量子态
的类和量子门操作的类
之后,我们可以写如下所示的一个测试脚本来测试程序的执行效果:
# TestQubits.py
from QubitPair import QubitPair
from Operator import QubitOperator
if __name__ == '__main__':
qubits = QubitPair()
print ('The initial state is: {}'.format(qubits))
QubitOperator('X', 3.1415926, 0) | qubits
print ('Applying X on the 0th qubit...')
print ('The new state is: {}'.format(qubits))
QubitOperator('CX') | qubits
print ('Applying entanglement on qubits...')
print ('The new state is: {}'.format(qubits))
QubitOperator('X', 3.1415926, 0) | qubits
print ('Applying X on the 0th qubit...')
print ('The new state is: {}'.format(qubits))
QubitOperator('CX') | qubits
print ('Applying entanglement on qubits...')
print ('The new state is: {}'.format(qubits))
这个程序的测试逻辑为:先定义一个两比特的量子系统,然后对第一个比特执行X
门操作,使得其从\(\left|0\right>\)态变成\(\left|1\right>\)态,再对这两个比特执行纠缠门CX
操作,观察其态的变化情况。之后再将第一个比特的状态变回\(\left|0\right>\)态,再观察作用CX
的态的变化情况,执行结果如下所示:
[dechin@dechin-manjaro simulator]$ python3 TestQubits.py
The initial state is: [1.+0.j 0.+0.j 0.+0.j 0.+0.j]
Applying X on the 0th qubit...
The new state is: [2.67948966e-08+0.j 0.00000000e+00+0.j 0.00000000e+00-1.j
0.00000000e+00+0.j]
Applying entanglement on qubits...
The new state is: [2.67948966e-08+0.j 0.00000000e+00+0.j 0.00000000e+00+0.j
0.00000000e+00-1.j]
Applying X on the 0th qubit...
The new state is: [ 7.17966483e-16+0.00000000e+00j -1.00000000e+00+0.00000000e+00j
0.00000000e+00-2.67948966e-08j 0.00000000e+00-2.67948966e-08j]
Applying entanglement on qubits...
The new state is: [ 7.17966483e-16+0.00000000e+00j -1.00000000e+00+0.00000000e+00j
0.00000000e+00-2.67948966e-08j 0.00000000e+00-2.67948966e-08j]
这个结果所展示出来的数字也许比较乱,这是因为在运算过程中的计算精度不足所导致的,这里低于1e-06
的数字其实我们可以认为就是0
。那么我们从这个结果中可以分析总结出量子态的演变历程:
\]
这里我们就完成了基于魔法函数的量子计算模拟的过程,感兴趣的读者可以自行尝试更多的玩法,这里就不进行更多的测试了!
总结概要
本文主要尝试了用Python的魔法函数__str__
来定义一个量子态,以及使用__or__
来定义一个量子门操作的运算,我们附带的也简单介绍了一下量子计算模拟的一些背景知识。因为程序有简单而明确的执行逻辑,因此用程序语言的方式来定义和理解科学常识,也能够加深对科学的理解。
版权声明
本文首发链接为:https://www.cnblogs.com/dechinphy/p/magic.html
作者ID:DechinPhy
更多原著文章请参考:https://www.cnblogs.com/dechinphy/
参考链接
Python魔法函数与两比特量子系统模拟的更多相关文章
- python魔法函数__dict__和__getattr__的妙用
python魔法函数__dict__和__getattr__的妙用 __dict__ __dict__是用来存储对象属性的一个字典,其键为属性名,值为属性的值. 既然__dict__是个字典那么我们就 ...
- Python魔法函数
python中定义的以__开头和结尾的的函数.可以随意定制类的特性.魔法函数定义好之后一般不需要我们自己去调用,而是解释器会自动帮我们调用. __getitem__(self, item) 将类编程一 ...
- python魔法函数之__getattr__与__getattribute__
getattr 在访问对象的属性不存在时,调用__getattr__,如果没有定义该魔法函数会报错 class Test: def __init__(self, name, age): self.na ...
- python魔法函数(二)之__getitem__、__len__、__iter__
魔法函数会增强python类的类型,独立存在 __getitem class Company: def __init__(self, employees): self.employees = empl ...
- python魔法函数的一些疑问
看了魔法函数,有一点疑问.1中需要用self.word才能执行,而2直接用self就可以执行.而1中Word继承了int基本类型,但在__new__时并没有什么卵用.当用 Word(“123”)来实例 ...
- raindi python魔法函数(一)之__repr__与__str__
__repr__和__str__都是python中的特殊方法,都是用来输出实例对象的,如果没有定义这两个方法在打印的时候只会输出实例所在的内存地址 这种方式的输出没有可读性,并不能直观的体现实例.py ...
- python 进阶读书笔记2 -- python魔法函数
#!/usr/bin/env python# -*- coding: utf-8 -*- class student: def __init__(self, name_list): self.stud ...
- python基础-函数基本特性和用法
函数: 初中数学函数定义:一般的,在一个变化过程中,如果有两个变量x和y,并且对于x的每一个确定的值,y都有唯一确定的值与其对应,那么我们就把x称为自变量,把y称为因变量,y是x的函数.自变量x的取值 ...
- Python的魔法函数系列 __getattrbute__和__getattr__
#!/usr/bin/env python # -*- coding: utf-8 -*- import sys __metaclass__ = type """ _ ...
随机推荐
- Java学习日报7.7
今天进一步学习了eclipse软件,遇到了几次程序运行不成功的问题,检查之后运行成功!明天继续学习程序逻辑控制!
- 关于BackTop按钮的实现
今天在处理,首页面的制作的时候,在实现backtop按键的时候,有些思路,作为记录. 功能为,点击backtop即可,立马跳到首页的最上面,且backtop只有在页面后1/2处才显示出来. 首先,我们 ...
- Java图片的灰度处理方法
通过看网上各种大牛的总结,和自己亲身测试总结一下Java图片的灰度处理方法 (1)我们熟知的图片中的像素点有RGB值. (2)图片灰度化的方式大概分为四种,第一种是最大值法(取颜色RGB中的最大值作为 ...
- Java基础--接口回调(接口 对象名 = new 类名)理解
接口 对象名1 = new 类名和类名 对象名2 = new 类名的区别是什么? 实例 /** *Person.java 接口 */ public interface Person { void in ...
- Web Service 服务无法连接Oracle数据库
这个问题之前部署就遇到过,但是后来忘了,所以记录一下吧. 我部署Web Service服务的时候,服务没法正常运行,与Oracle数据库无法正常通信. 检查了数据库连接字没有任何问题,写了个测试接口, ...
- MySql中的有条件插入 insert where
假设现在我们有这样的需求:当数据库中不存在满足条件的记录时,可以插入一条记录,否则程序退出.该怎么实现? 1年以上工作经验的人应该都能立即想到:去检查一下库里有没有记录,没有就插入,有就结束. int ...
- 当Django设置DEBUG为False时,发现admin和html的静态资源文件加载失败的解决办法
当Django设置DEBUG为False时,发现admin和html的静态资源文件加载失败,折腾一段时间终于找到解决办法: 1.先在setting文件增加BASE_DIR(项目的路径) BASE_DI ...
- Docker haproxy应用构建 (五)
编写dockerfile from centos-base:v1 MAINTAINER 57674891@qq.com RUN mkdir -p /data/{soft,src,logs,script ...
- 面试官:Netty的线程模型可不只是主从多Reactor这么简单
笔者看来Netty的内核主要包括如下图三个部分: 其各个核心模块主要的职责如下: 内存管理 主要提高高效的内存管理,包含内存分配,内存回收. 网通通道 复制网络通信,例如实现对NIO.OIO等底层JA ...
- Java开发手册之设计规约
1.谨慎使用继承的方式来进行扩展,优先使用聚合/组合的方式来实现.说明:不得已使用继承的话,必须符合里氏代换原则,此原则说父类能够出现的地方子类一定能够出现,比如,"把钱交出来", ...