使用开源量子编程框架ProjectQ打印编译后的量子线路与绘制线路图
技术背景
在量子计算领域,基于量子芯片的算法设计(或简称为量子算法)是基于量子线路来设计的,类似于传统计算中使用的与
门和非
门之类的逻辑门。因此研究一个量子线路输入后的编译(可以简化为数量更少的量子门组合,或者适配硬件上可实现的量子逻辑门操作),并且输出编译后的量子线路与量子线路图,在各种场景下都会使用到。而且,量子线路编译也能够为量子计算资源估计带来更加准确的结果预测。
量子计算与量子线路
针对于量子计算,这里我们尽量的避免硬件上实现原理的解释,因为那是属于另外一个领域的研究课题。这里我们仅从矩阵力学的角度来理解,读者可以尝试从这篇介绍量子系统模拟的博客中先了解一部分量子门操作的实现。这些量子门的每一种排列组合,我们都可以将其视为一个量子线路,如下图所示是一种量子线路的图示。
这里的\(H\)门和\(CNOT\)门作用在不同的量子比特上,相当于执行了一项如下所示的任务:
\]
这里将\(U\)作用在初始的量子态\(\left|\psi_0\right>\)之后得到了一个新的量子态\(\left|\psi_t\right>\),当然,此时信息还被存储在量子态中。如果需要将量子态中的信息读取到经典信息,就需要对量子态进行采样,相关过程可以参考这篇介绍量子态采样的博客,最终我们得到的信息是一系列二进制比特串的分布。
ProjectQ编译与打印量子线路
我们先用ProjectQ量子编程框架写一个不会被编译优化的量子线路:
from projectq import MainEngine
from projectq.backends import CommandPrinter
from projectq.ops import H, CX, X, Z, Measure, All
circuit_backend = CommandPrinter()
eng=MainEngine(backend=circuit_backend)
qubits = eng.allocate_qureg(3)
All(H) | qubits
CX | (qubits[0], qubits[1])
CX | (qubits[1], qubits[2])
eng.flush()
这个程序的基本逻辑是:使用MainEngine
类来执行编译优化等工作;使用CommandPrinter
作为后端,表示只打印量子线路而不进行计算;分配3个量子比特进行计算,最后作用一个线路在该量子系统上。这个程序的执行输出如下,是一个包含有Allocate
的量子线路:
Allocate | Qureg[0]
H | Qureg[0]
Allocate | Qureg[1]
H | Qureg[1]
CX | ( Qureg[0], Qureg[1] )
Allocate | Qureg[2]
H | Qureg[2]
CX | ( Qureg[1], Qureg[2] )
这里在额外介绍几种优化操作:量子比特回收和量子线路编译。由于该分配的比特已经在内存中注册,需要手动的注销该量子系统所分配的量子比特:
from projectq import MainEngine
from projectq.backends import CommandPrinter
from projectq.ops import H, CX, X, Z, Measure, All
circuit_backend = CommandPrinter()
eng=MainEngine(backend=circuit_backend)
qubits = eng.allocate_qureg(3)
All(H) | qubits
CX | (qubits[0], qubits[1])
CX | (qubits[1], qubits[2])
eng.flush(deallocate_qubits=True)
这里python代码中唯一的变化就是增加了deallocate_qubits=True
这个选项,最终输出的量子线路里面也就会包含有Deallocate
的操作:
Allocate | Qureg[0]
H | Qureg[0]
Allocate | Qureg[1]
H | Qureg[1]
CX | ( Qureg[0], Qureg[1] )
Deallocate | Qureg[0]
Allocate | Qureg[2]
H | Qureg[2]
CX | ( Qureg[1], Qureg[2] )
Deallocate | Qureg[1]
Deallocate | Qureg[2]
如果在线路中遇到一些可以简化的模块,比如连续作用两次H
门之后,相当于没有执行任何的操作,即\(HH=I\)。这里的\(H\)的矩阵形式如下所示:
\begin{array}{l}
\frac{\sqrt{2}}{2} & \frac{\sqrt{2}}{2}\\
\frac{\sqrt{2}}{2} & -\frac{\sqrt{2}}{2}
\end{array}
\right)
\]
如下代码所示我们除了在所有量子比特上作用\(H\)门之外,在第二个量子比特上额外作用一个\(H\)门,这样理论上说两次连续作用的\(H\)门会被抵消:
from projectq import MainEngine
from projectq.backends import CommandPrinter
from projectq.ops import H, CX, X, Z, Measure, All
circuit_backend = CommandPrinter()
eng=MainEngine(backend=circuit_backend)
qubits = eng.allocate_qureg(3)
All(H) | qubits
H | qubits[1]
CX | (qubits[0], qubits[1])
CX | (qubits[1], qubits[2])
eng.flush(deallocate_qubits=True)
可以看到相应的结果如下:
Allocate | Qureg[0]
H | Qureg[0]
Allocate | Qureg[1]
CX | ( Qureg[0], Qureg[1] )
Deallocate | Qureg[0]
Allocate | Qureg[2]
H | Qureg[2]
CX | ( Qureg[1], Qureg[2] )
Deallocate | Qureg[1]
Deallocate | Qureg[2]
区别于上面的两个例子我们可以发现,这里仅有2个\(H\)门而上面的例子中都有3个\(H\)门,这就说明在量子编译中两个连续的\(H\)门成功的被抵消了。
ProjectQ输出量子线路图
from projectq import MainEngine
from projectq.backends import CircuitDrawer
from projectq.ops import H, CX, X, Z, Measure, All
circuit_backend = CircuitDrawer()
circuit_backend.set_qubit_locations({0: 2, 1: 1, 2:0})
eng=MainEngine(backend=circuit_backend)
qubits = eng.allocate_qureg(3)
All(H) | qubits
CX | (qubits[0], qubits[1])
CX | (qubits[1], qubits[2])
All(Measure) | qubits
eng.flush()
print (circuit_backend.get_latex())
执行输出的是一串完整的LaTex格式代码,可以存储为file_name.tex
再进行编译。
\documentclass{standalone}
\usepackage[margin=1in]{geometry}
\usepackage[hang,small,bf]{caption}
\usepackage{tikz}
\usepackage{braket}
\usetikzlibrary{backgrounds,shadows.blur,fit,decorations.pathreplacing,shapes}
\begin{document}
\begin{tikzpicture}[scale=0.8, transform shape]
\tikzstyle{basicshadow}=[blur shadow={shadow blur steps=8, shadow xshift=0.7pt, shadow yshift=-0.7pt, shadow scale=1.02}]\tikzstyle{basic}=[draw,fill=white,basicshadow]
\tikzstyle{operator}=[basic,minimum size=1.5em]
\tikzstyle{phase}=[fill=black,shape=circle,minimum size=0.1cm,inner sep=0pt,outer sep=0pt,draw=black]
\tikzstyle{none}=[inner sep=0pt,outer sep=-.5pt,minimum height=0.5cm+1pt]
\tikzstyle{measure}=[operator,inner sep=0pt,minimum height=0.5cm, minimum width=0.75cm]
\tikzstyle{xstyle}=[circle,basic,minimum height=0.35cm,minimum width=0.35cm,inner sep=-1pt,very thin]
\tikzset{
shadowed/.style={preaction={transform canvas={shift={(0.5pt,-0.5pt)}}, draw=gray, opacity=0.4}},
}
\tikzstyle{swapstyle}=[inner sep=-1pt, outer sep=-1pt, minimum width=0pt]
\tikzstyle{edgestyle}=[very thin]
\node[none] (line0_gate0) at (0.1,-0) {$\Ket{0}$};
\node[none] (line0_gate1) at (0.5,-0) {};
\node[none,minimum height=0.5cm,outer sep=0] (line0_gate2) at (0.75,-0) {};
\node[none] (line0_gate3) at (1.0,-0) {};
\draw[operator,edgestyle,outer sep=0.5cm] ([yshift=0.25cm]line0_gate1) rectangle ([yshift=-0.25cm]line0_gate3) node[pos=.5] {H};
\draw (line0_gate0) edge[edgestyle] (line0_gate1);
\node[none] (line1_gate0) at (0.1,-1) {$\Ket{0}$};
\node[none] (line1_gate1) at (0.5,-1) {};
\node[none,minimum height=0.5cm,outer sep=0] (line1_gate2) at (0.75,-1) {};
\node[none] (line1_gate3) at (1.0,-1) {};
\draw[operator,edgestyle,outer sep=0.5cm] ([yshift=0.25cm]line1_gate1) rectangle ([yshift=-0.25cm]line1_gate3) node[pos=.5] {H};
\draw (line1_gate0) edge[edgestyle] (line1_gate1);
\node[none] (line2_gate0) at (0.1,-2) {$\Ket{0}$};
\node[none] (line2_gate1) at (0.5,-2) {};
\node[none,minimum height=0.5cm,outer sep=0] (line2_gate2) at (0.75,-2) {};
\node[none] (line2_gate3) at (1.0,-2) {};
\draw[operator,edgestyle,outer sep=0.5cm] ([yshift=0.25cm]line2_gate1) rectangle ([yshift=-0.25cm]line2_gate3) node[pos=.5] {H};
\draw (line2_gate0) edge[edgestyle] (line2_gate1);
\node[xstyle] (line1_gate4) at (1.4000000000000001,-1) {};
\draw[edgestyle] (line1_gate4.north)--(line1_gate4.south);
\draw[edgestyle] (line1_gate4.west)--(line1_gate4.east);
\node[phase] (line2_gate4) at (1.4000000000000001,-2) {};
\draw (line2_gate4) edge[edgestyle] (line1_gate4);
\draw (line1_gate3) edge[edgestyle] (line1_gate4);
\draw (line2_gate3) edge[edgestyle] (line2_gate4);
\node[xstyle] (line0_gate4) at (1.9500000000000002,-0) {};
\draw[edgestyle] (line0_gate4.north)--(line0_gate4.south);
\draw[edgestyle] (line0_gate4.west)--(line0_gate4.east);
\node[phase] (line1_gate5) at (1.9500000000000002,-1) {};
\draw (line1_gate5) edge[edgestyle] (line0_gate4);
\draw (line0_gate3) edge[edgestyle] (line0_gate4);
\draw (line1_gate4) edge[edgestyle] (line1_gate5);
\node[measure,edgestyle] (line0_gate5) at (2.6000000000000005,-0) {};
\draw[edgestyle] ([yshift=-0.18cm,xshift=0.07500000000000001cm]line0_gate5.west) to [out=60,in=180] ([yshift=0.035cm]line0_gate5.center) to [out=0, in=120] ([yshift=-0.18cm,xshift=-0.07500000000000001cm]line0_gate5.east);
\draw[edgestyle] ([yshift=-0.18cm]line0_gate5.center) to ([yshift=-0.07500000000000001cm,xshift=-0.18cm]line0_gate5.north east);
\draw (line0_gate4) edge[edgestyle] (line0_gate5);
\node[measure,edgestyle] (line1_gate6) at (2.6000000000000005,-1) {};
\draw[edgestyle] ([yshift=-0.18cm,xshift=0.07500000000000001cm]line1_gate6.west) to [out=60,in=180] ([yshift=0.035cm]line1_gate6.center) to [out=0, in=120] ([yshift=-0.18cm,xshift=-0.07500000000000001cm]line1_gate6.east);
\draw[edgestyle] ([yshift=-0.18cm]line1_gate6.center) to ([yshift=-0.07500000000000001cm,xshift=-0.18cm]line1_gate6.north east);
\draw (line1_gate5) edge[edgestyle] (line1_gate6);
\node[measure,edgestyle] (line2_gate5) at (2.0500000000000003,-2) {};
\draw[edgestyle] ([yshift=-0.18cm,xshift=0.07500000000000001cm]line2_gate5.west) to [out=60,in=180] ([yshift=0.035cm]line2_gate5.center) to [out=0, in=120] ([yshift=-0.18cm,xshift=-0.07500000000000001cm]line2_gate5.east);
\draw[edgestyle] ([yshift=-0.18cm]line2_gate5.center) to ([yshift=-0.07500000000000001cm,xshift=-0.18cm]line2_gate5.north east);
\draw (line2_gate4) edge[edgestyle] (line2_gate5);
\end{tikzpicture}
\end{document}
不过这里推荐另外一种更加方便的做法,避免自己去安装众多的第三方tex包,可以直接使用Overleaf平台来执行tex
文件的编译操作,演示效果如下图所示:
在Overleaf里面会自动的帮我们配置好相关的Latex环境,大大减轻我们自己的工作量。这里的量子线路图绘制时跟比特顺序本身是相关的,比如这里我们尝试切换一种量子比特的映射编号,就会得到不同的线路图(在数学和物理上是等价的):
from projectq import MainEngine
from projectq.backends import CircuitDrawer
from projectq.ops import H, CX, X, Z, Measure, All
circuit_backend = CircuitDrawer()
circuit_backend.set_qubit_locations({0: 1, 1: 2, 2:0})
eng=MainEngine(backend=circuit_backend)
qubits = eng.allocate_qureg(3)
All(H) | qubits
CX | (qubits[0], qubits[1])
CX | (qubits[1], qubits[2])
All(Measure) | qubits
eng.flush()
print (circuit_backend.get_latex())
生成的latex代码这里就不做展示了,我们可以直接看下编译后输出的量子线路图:
ProjectQ输出资源统计结果
说到量子计算的资源估计,这里面就需要结合实际场景来分析,这是因为即使我们给出了一个非常精妙的线路,但是这个量子线路最终可能也很难真正在量子计算硬件上实现,这是由于不同的硬件体系本身所具备的局限性。这里我们可以考虑在给定量子门集合的条件下的资源估计,我们先还是用给定的量子门集合来编译上述的示例:
from projectq import MainEngine
from projectq.backends import CommandPrinter
from projectq.ops import H, CX, X, Z, Rx, Ry, Rz, Measure, All
from projectq.setups import linear
compiler_engines = linear.get_engine_list(num_qubits=16,
one_qubit_gates=(Rx, Ry, Rz),
two_qubit_gates=(CX, ))
circuit_backend = CommandPrinter()
eng=MainEngine(backend=circuit_backend, engine_list=compiler_engines)
qubits = eng.allocate_qureg(3)
All(H) | qubits
CX | (qubits[0], qubits[1])
CX | (qubits[1], qubits[2])
eng.flush(deallocate_qubits=True)
这里我们使用的是\(\{R_x,R_y,R_z,CX\}\)这个组合,而并不包含上述用例中使用到的\(H\)门,这里我们可以看下输出结果(其实就是用\(R_x\)和\(R_y\)的组合来构建一个\(H\)门):
Allocate | Qureg[1]
Ry(1.570796326795) | Qureg[1]
Rx(9.424777960769) | Qureg[1]
Allocate | Qureg[0]
Ry(1.570796326795) | Qureg[0]
Rx(9.424777960769) | Qureg[0]
CX | ( Qureg[0], Qureg[1] )
Allocate | Qureg[2]
Ry(1.570796326795) | Qureg[2]
Rx(9.424777960769) | Qureg[2]
CX | ( Qureg[1], Qureg[2] )
Deallocate | Qureg[1]
Deallocate | Qureg[2]
Deallocate | Qureg[0]
针对于这种场景,我们切换下后端就可以实现量子计算资源的统计:
from projectq import MainEngine
from projectq.backends import ResourceCounter
from projectq.ops import H, CX, X, Z, Rx, Ry, Rz, Measure, All
from projectq.setups import linear
compiler_engines = linear.get_engine_list(num_qubits=16,
one_qubit_gates=(Rx, Ry, Rz),
two_qubit_gates=(CX, ))
circuit_backend = ResourceCounter()
eng=MainEngine(backend=circuit_backend, engine_list=compiler_engines)
qubits = eng.allocate_qureg(3)
All(H) | qubits
CX | (qubits[0], qubits[1])
CX | (qubits[1], qubits[2])
All(Measure) | qubits
eng.flush(deallocate_qubits=True)
print (circuit_backend)
这个程序实际上就是统计上一个示例代码中输出的量子线路的门的数量,对应输出结果为:
Gate class counts:
AllocateQubitGate : 3
CXGate : 2
DeallocateQubitGate : 3
MeasureGate : 3
Rx : 3
Ry : 3
Gate counts:
Allocate : 3
CX : 2
Deallocate : 3
Measure : 3
Rx(9.424777960769) : 3
Ry(1.570796326795) : 3
Max. width (number of qubits) : 3.
这里我们可以看到,统计中的\(R_x,R_y,CX\)的门的数量与上面输出的结果是保持一致的,那么我们的示例到这里就成功完成演示。
总结概要
这篇文章中,我们通过介绍开源量子计算编程框架ProjectQ的一些常规使用方法,来讲解了如何使用程序来编译和生成量子线路,以及将该量子线路作为字符串或者Latex格式代码输出,这同时也使得我们可以通过输出结果来统计量子计算的资源,以用于预测在大规模场景下所需要的大致的量子比特数以及门操作数量(或用量子线路深度来衡量)的量级。这种编译的手段和资源估计的方法,在工程和科学研究上都有较大的意义。
版权声明
本文首发链接为:https://www.cnblogs.com/dechinphy/p/circuit.html
作者ID:DechinPhy
更多原著文章请参考:https://www.cnblogs.com/dechinphy/
参考链接
使用开源量子编程框架ProjectQ打印编译后的量子线路与绘制线路图的更多相关文章
- 用量子计算模拟器ProjectQ生成随机数,并用pytest进行单元测试与覆盖率测试
技术背景 本文中主要包含有三个领域的知识点:随机数的应用.量子计算模拟产生随机数与基于pytest框架的单元测试与覆盖率测试,这里先简单分别介绍一下背景知识. 随机数的应用 在上一篇介绍量子态模拟采样 ...
- 开源软件实践之linux高性能服务器编程框架和选型
很多人学习编程技术一般都通过一本编程语言的入门书籍,然后尝试做一些例子和小项目.但是这些都不能让我们深入的学习很多的编程技巧和高深技术,当然这个时候很多有经验的学习人员就会告诉大家,找一个好的开源软件 ...
- 开源框架---通过Bazel编译使用tensorflow c++ API 记录
开源框架---通过Bazel编译使用tensorflow c++ API 记录 tensorflow python API,在python中借用pip安装tensorflow,真的很方便,几句指令就完 ...
- 开源图计算框架GraphLab介绍
GraphLab介绍 GraphLab 是由CMU(卡内基梅隆大学)的Select 实验室在2010 年提出的一个基于图像处理模型的开源图计算框架.框架使用C++语言开发实现. 该框架是面向机器学习( ...
- Google的开源C++单元测试框架Google Test
玩转Google开源C++单元测试框架Google Test系列(gtest)(总) 前段时间学习和了解了下Google的开源C++单元测试框架Google Test,简称gtest,非常的不错. 我 ...
- 28款GitHub最流行的开源机器学习项目,推荐GitHub上10 个开源深度学习框架
20 个顶尖的 Python 机器学习开源项目 机器学习 2015-06-08 22:44:30 发布 您的评价: 0.0 收藏 1收藏 我们在Github上的贡献者和提交者之中检查了用Python语 ...
- ZKWeb网站框架的动态编译的实现原理
ZKWeb网站框架是一个自主开发的网页框架,实现了动态插件和自动编译功能. ZKWeb把一个文件夹当成是一个插件,无需使用csproj或xproj等形式的项目文件管理,并且支持修改插件代码后自动重新编 ...
- 【开源】OSharp框架解说系列(1):总体设计及系列导航
系列文章导航 [开源]OSharp框架解说系列(1):总体设计 [开源]OSharp框架解说系列(2.1):EasyUI的后台界面搭建及极致重构 [开源]OSharp框架解说系列(2.2):EasyU ...
- 二十三、【开源】EFW框架Web前端开发之常用组件(FusionCharts图表、ReportAll报表等)
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.2:http://pan.baidu.com/s/1hcnuA EFW框架实例源代码下载:http://pan ...
随机推荐
- 【Problems】Could not set property 'id' of 'xxx' with value '' Cause argument type mismatch
一个问题:向comment表添加记录时,报错, 无法设置值. reflection.ReflectionException: Could not set property 'id' of 'class ...
- 两万字长文总结,梳理 Java 入门进阶那些事
大家好,我是程序员小跃,一名在职场已经写了6年程序的老程序员,从一开始的菊厂 Android 开发到现在某游戏公司的Java后端架构,对Java还是相对了解的挺多. 大概是半年前吧,在知乎上有个知友私 ...
- 【Python】PDF转WORD
注意,下文中的PDF文档是纯文字格式,而且非扫描版的PDF文件. 如果是扫描版或者带有图片的.可能转起来会出现排版异常并且图片无法保存到.doc文件中. 正文开始: 需要安装依赖包 pdfminer3 ...
- 【ASM】介绍Oracle自带的一些ASM维护工具 (kfod/kfed/amdu)
转自:http://blog.csdn.net/wenzhongyan/article/details/47043253 非常感谢作者的文章,很有价值!至此转载,非常感谢 1.前言 ASM(Autom ...
- 攻防世界—pwn—cgpwn2
题目分析 题目提示 checksec检查文件保护机制 使用ida查看伪代码 hello函数存在溢出,与level2类似 信息收集 system地址 name的地址 编写脚本 from pwn impo ...
- 【Android】关于连续多次点击控件的控制方案(新建监听类)
参考:防止Android过快点击造成多次事件的三种方法_胖胖的博客-CSDN博客 实现逻辑很简单: 设置限定时间 在用户点击时开始计时 若计时未超过限定时间,则不允许触发点击事件 因还未学习过Rxja ...
- VirtualBox Guest Additions 下载地址以及简介
下载者可将以下链接粘贴到浏览器上,根据Vbox的版本找到自己对应的增强. http://download.virtualbox.org/virtualbox/5.0.10/ 虚拟机安装VBoxAddi ...
- 为失败设计,大量引入对SRE的理解,鲁棒性高
https://go-kratos.dev/#/ Principles 简单:不过度设计,代码平实简单 通用:通用业务开发所需要的基础库的功能 高效:提高业务迭代的效率 稳定:基础库可测试性高,覆盖率 ...
- 编译安装 codeblocks 20.03 mips64el
期末考试要用哦,不然谁会愿意去踩这么多坑. qaq 龙梦 Fedora28 中有 codeblocks 17.12,但是 Ctrl-v 粘贴会闪退,导致压根不能用.Bing了一下发现这其实是 code ...
- 20201103gryz模拟赛解题报告
写在前面 昨天忘写了来补上 T1位运算乱搞一会没搞出来, 打完T4floyd暴力分之后发现T2树状数组可以骗点分 打完T3暴力手模了一遍样例之后发现T3就是个线段树板子 最后就非常愉快的拿到175pt ...