使用指南 > QPanda 2.0 > 问答知基本 >

量子计算相关的问题

最后更新时间: 2018-10-11 10:28:45

问:量子科学是最新的科学吗?

答:量子科学不是新开始的科学,量子理论早在1900年就的提出并发展。该学科用来解释诸如原子,电子等微小粒子的奇怪行为。使得人们从根本上去重新认识了化学和物理学。在80年代后期,人们发现它与信息相关,从而导致了新信息技术的发展,诸如现今的绝对安全的量子通信和量子计算等。虽然量子理论研究了差不多一个世纪,但是量子科学的深度个广度难以估量,现在人们探索到量子计算可带来的巨大就算可能性,各国争相研发,因此,当下量子科学的研究依旧是世界上最尖端的研究之一。

问: 什么是量子?

答:量子并不是指代具体的某种粒子,物理学里指的是一个不可分割的基本个体。是诸如,电子,光子等具有量子现象的微观粒子总称。参考“量子化”。

问:什么是量子比特(Qubit)?

答:量子比特,在中文翻译中也常用着量子位(Quantum bit),是量子信息计算里的基本单位,相当于经典计算里的位(bit)。通常使用狄拉克符号|d>来表示一个量子比特处于|0>、|1>或者同时处于前面的两个状态,也就是叠加态。

问:什么叠加态?

答:叠加态表示的两个或者两个以上的量子态归一化通过线性组合而成的一个矢量态。在量子系统里,量子叠加态是很常见的状态。

问:为什么叠加态为什么难以想象?

答:因为在我们生活的经典世界是没有叠加现象的。当我们测量的时候(获取经典信息,经典世界观察量子世界),叠加态会以一定的概率坍塌到具体的某一个观测量基态上。因此,如果用经典世界的直观经验去理解和想象叠加态,那会非常困难。

问:什么是量子逻辑门?

答:在基于量子线路的计算模型里,量子逻辑门(量子门)是作用在量子比特上的基本量子线路操作。类似于经典逻辑门作用在传统的数字电路上。

问:什么是量子计算机,为什么要开发量子计算机?

答:量子计算机是一种遵循量子理论特性的新型计算模型,理论上,量子计算机在处理一些特殊的问题上,将完全的超越经典计算,以指数级的加速去完成任务。随着摩尔定律走到了极限,信息技术的发展对计算设备的依赖也变大,在处理海量数据,寻找最优解决方案,量子系统模拟等方面,唯有量子计算机。

问:量子计算机是否将会替代经典计算机?

答:事实上,量子计算机是经典计算机加量子系统的一个总称。因为量子系统处理的信息,需要通过经典计算机记录存储以及与用户通信。当前多数量子计算机研发都采用这种模式推进。目前,量子计算在解决某些问题上远远优越于经典计算机,但并不意味着是经典计算机的替代品,或者次世代的经典机。量子计算机是全新的东西,其巨大的潜力已经在科学研究界一致认同。

设计理念

最后更新时间: 2018-06-07 10:03:15
QPanda是一套用于处理量子电路,并适应近期开发出的各式量子计算机上开发应用和进行实验的一套软件。在QPanda里,总共由三个过程组成: 初始化生成编译运行。 初始化生成是允许用户设计不同的量子线路来处理对应需要解决的问题。而编译则是允许用户重写它们以在不同的后端运行(比如模拟器,量子芯片,不同公司的量子芯片等)。最后是运行,即是收集结果的过程,对于运行后的数据采集,取决于程序本身的设计需求去做相应的存储或者转化,运行的结果,也依赖于解决问题的需要而定。有的问题,可能需要依赖上一个量子程序运行结果才能执行下一个量子程序,诸如此类。

QPanda的整体设计思路涵盖如下:

1. 全系列兼容: QPanda 的目标是兼容所有量子计算机。底层量子计算机现在由于正处快速发展期,所以芯片、测控等实现细节都不确定。 QPanda简化并规避了诸多量子计算机的物理细节而为用户提供了标准化的接口。通过QPanda构建的量子计算机,本身是通 过经典的程序语言对其进行交互,所以它可以被用于任意的云量子计算机,本地量子计算机,或者是实验中的量子原型机。 通过QPanda构建的量子应用则不会受到硬件变动的影响。
2. 标准架构: QPanda提供了标准化的量子程序(Quantum Program)架构。架构者认为,在量子机器(Quantum Machine)中执行的程序和在经典计算机中执行的程序应该彻底区分开来, 特别是涉及到经典控制的部分。物理上,芯片的退相干(Decoherence)时间极为短暂,这使得量子程序中的控制流并非在狭义的CPU中完成, 而更有可能会采用极低延时的FPGA或其它嵌入式器件作为其测控系统实现。我们认为,量子机器包含了量子芯片与其测控系统,一个量子程序被 视作是对一个原子的操作,直到执行完毕才返回结果给经典计算机。
量子程序的架构包含:量子逻辑门、量子线路、量子分支程序和量子循环程序。在QPanda里这几种元素均以接口的形式被提供, 我们提供了一组这些接口的实现类作为基础的数据接口。用户可以重写这些接口并将实现类进行注册,系统会选择用户的类对默认实现类进行覆盖,并且保持其它结构的不变。
3. 标准化量子机器模型: 我们提供了标准化的量子机器模型。通常,量子程序是静态加载到量子机器里,并且量子程序本身也是被静态地构建的。这意味我们可以在量子程序被执行前, 对量子程序进行静态检查和分析,获取其中的信息(而非执行它)。能检查的要素例如: 量子比特是否越界,经典寄存器是否超过硬件允许的范围等等。 而能进行的预处理则包含:任意的量子程序被替换到对应真实芯片的拓扑结构和基本逻辑门集合上(硬件兼容),量子程序的运行时长判断,量子程序的优化等等。
量子机器模型还定义了量子程序的标准构建过程。例如从量子比特池中申请空闲比特,从内存中申请空间,将程序加载到量子机器中,或者在已有的量子程序中附加 一段新的量子程序。和量子程序的部分类似,量子机器本身的任何架构也是接口化的,用户也可以对接口进行覆写以应对不同硬件的需求。

项目架构

最后更新时间: 2018-06-07 10:03:15
QPanda 2.0 框架(framework)包括了量子机器(虚拟机),量子线路,量子算法,接口以及用户接口。量子机器包含了模拟器,以及可用的量子芯片组.

QPanda项目总共包括:

QPanda SDK:用于编写量子程序和应用程序的 C++宿主语言工具包。它使用户能够方便连接和执行量子程序。

QRunes:QRunes是本源量子制定的一套量子计算指令集。

QRunes Generator:QRunes Generator 是一个支持以函数调用方式生成QRunes指令的C++库。

QPanda使用文档:提供了QPanda软件的使用细节,以及一些常见算法的案例。包括算法概要,对应的量子线路图,对应的QPanda代码等,旨在指导用户快速正确的使用QPanda。

兼容性和拓展性

最后更新时间: 2018-10-12 07:56:15
目前,QPanda主要用在本云量子的云平台上,现在可以兼容的量子处理器有自主研发的6比特量子芯片。
非常感谢您使用QPanda开发工具包,这里包含了构建用户自己的量子计算程序和实验所需的工具。量子计算对与多数人来说,是含糊不清的, 虽然充满兴趣,但是无从下手。因此我们提供了一些算法的参考代码,以及量子程序的线路图,帮助初学者写他们第一个量子程序, 我们希望用户能通过该文档,对量子计算加深认识的同时,并且能快速高效率地融入到量子计算这个大家庭里,开发新的量子算法。同时,也欢迎给我们提供有趣的量子程序和讨论反馈。
为了更好的开始,请先查阅使用 安装使用说明 。此处整理的文档提供全部下载,如有需要,请 点击下载 。 如果需要参阅量子计算的基本知识教程,请前往 本源云量子科普与教程 ,以扩充相关的知识,有助于您更好的使用QPanda。

安装开发环境

最后更新时间: 2018-10-12 09:04:30

Windows:

开发环境
编译环境 C++
编译工具 Visual Studio 2017(推荐)
SDK QPanda 2.0
QPanda2.0 是用以C++作为宿主语言,因此开发环境也对应于C++开发环境。此处安装配置先以Windows为例,其他系统稍后补充。
1.请先前往 https://www.visualstudio.com/downloads/下载Visual Studio 2017。通常下载Visual studio Community 2017。(注意:必要的时候,升级到最新版本)
2.安装的时候,请确保CMake安装可用。
3.去往QPanda首页,下载最新版的QPanda文件,通常是QPanda2.0.x版本。下载到本地之后,解压缩包,文件中包含CMakeLists.txt文件。
4.Visual Studio 2017正常安装的情况下,就可以导入QPanda 2.0的开发环境,|文件(F) \ 打开(O) \ Cmake(M)
5.打开之后,资源管理器显示如下(由于版本的更新,请以最新版为准):
6.用户可在此新建添加运行测试相应的算法:
7.主函数运行:
8.使用PyQPanda

Linux 开发环境的安装:

Linu 开发环境,除去常规的配置。安装QPanda 2.0 首先是需要安装cmake,这与windows相应起来。
1.进入QPanda-2.0目录下的build文件夹
2.执行cmake .. 
3.执行make

问题与解决

最后更新时间: 2018-10-12 08:59:45

问:

答:

项目介绍

最后更新时间: 2018-10-12 10:02:00
QPanda 2.0(Quantum Panda 2.0 Software Development Kit) 是由本源量子推的开源量子程序开发工具包。其支持主流的量子逻辑门操作,并且可对不同平台下的量子程序进行针对性优化, 可适配多种量子芯片。QPanda 2.0 使用C++语言作为经典宿主语言,并支持以QRunes和QASM书写的量子语言。
目前,QPanda 2.0支持本地仿真运行模式,最高可支持到32位,它集成了量子虚拟机,封装了主流的量子算法。可在无芯片支持的情况下验证量子应用的可靠性和有效性。加上增加了控制流的概念使得量子程序可进行逻辑判断, 从而符合高级语言的编程习惯。QPanda 2.0 提供了一个可执行的命令行程序,通过指令控制量子程序的加载、运行和读出。另外,QPanda 2.0提供了一组API,可供用户自行定制功能。
自1985年Feynman提出量子计算这个概念后,科学界一直关注。量子系统用在信息计算上,其能力相较于经典计算呈指数级加速。如此的不可思议,作为“程序猿”如何能在上面写个Hello world入门量子程序呢?持有这个疑问的人 不少,虽然各大网站也会提供一些简要的介绍,可惜作为“门外汉”的多数人来说,对很多量子理论知识的理解成了障碍,更难以从程序的运行过程中去感受量子计算。QPanda 2.0的整体设计以及文档说明,期望从根本上解决这个问题。

这里将从有趣的两个点开始:

量子叠加

量子叠加是区别经典世界与量子世界的一大特征,通过单量子比特制备叠加态,测量后,得到您第一个量子程序结果。

纠缠态的制备

通过两个逻辑门的设置,将两个初始化的状态置为纠缠态,并输出结果,观察结果。
如果您有好的入门程序推荐,欢迎列入上面的列表。请邮件至:oqc@originqc.com

叠加态的制备(Quantum Superposition)

最后更新时间: 2018-06-07 10:03:15
实际上,任何经典比特能做的事情,量子比特都能够做到。现在,开始一个属于量子计算的Hello world编程: 叠加态(Superposition)的制备。

叠加态的量子线路:

量子叠加是量子世界里特有的性质,在经典世界里是不具备叠加状态的。如下是一段用QPanda来写的量子程序Hello world(叠加态的制备程序):

QPanda实例代码:

    bool HelloWorld()
{
	// This program is about introducing the basic
	// procedures to use a quantum computer by the
	// Q-Panda system.
	// The program has used only 1 qubit.
	// Firstly we make a Hadamard gate to the qubit,
	// then measure it by mapping the result to a 
	// CBit. Finally we readout the answer.

	init(); 
	// initialize the environment
    
	QProg & A_Hello_World_Program = CreateEmptyQProg();
	// Create an empty program

	Qubit  qb0 = qAlloc();
	// allocate a qubit

	CBit  cbit0 = cAlloc();
	// allocate a cbit

	A_Hello_World_Program
		<< H(qb0) 
		<< Measure(qb0, cbit0);
	// insert a Hadamard gate and a Measurement operation
	// after the empty program sequently

	load(A_Hello_World_Program);
	// And then load it into the quantum computer

    run();
	// simply run it

    auto resultMap = getResultMap();
	// you can get the result map, which save all the
	// measurement results in the classical register(CBit)

    for (auto aiter : resultMap)
    {
        cout << aiter.first << " ";
        cout << aiter.second << endl;
    }
	// Let's iterate over the map to see whether
	// the result is correct

    finalize();
	// Use finalize() to tell the quantum computer to stop

    return resultMap["c0"];
}
                            
复制代码

逐行解释:

init(); //初始化量子虚拟机
初始化量子程序的环境。特别注意,在程序里,以"//"结尾的都是注释部分。程序遇到注释标识符,自动跳过不执行。
 QProg & A_Hello_World_Program = CreateEmptyQProg();
创建⼀个空的程序A_Hello_World_Program. 这是本实例中的程序名称。
Qubit * qb0 = qAlloc();
分配一个量子比特位,qAlloc()用来申请量子比特位。本例中仅用了一个量子比特,此处分配了一个,命名为qb0,默认的量子比特都会被初始化为$|0 \rangle$态。 如果初始化了多个,对应起来即可。当然可以采用批量的方式进行初始化。这里Qubit* 也可以用auto代替,auto是自行识别类型,因此上面等价于auto qb0 = qAlloc()(提示:约定成俗的下标(index)是从0开始的)。
CBit * cbit0 = cAlloc();
分配一个经典寄存器cbit0,用户根据自己的需求来分配。cAlloc()用来申请经典比特位。 通常,量子计算里,对系统进行测量后,就会得到的经典信息,根据用户的自行需求,而申请经典 寄存器的数量,一般情况下,申请一个量子位对应申请一个经典寄存器。因为示例里仅用了一个量子位,此处定义一个经典寄存器。
A_Hello_World_Program
 << H(qb0)
 << Measure(qb0, cbit_0);
这里是对创建的量子线路进行操作,将量子逻辑门在QPanda里面,量子线路里量子门的放置规则,具有两个方向:从上到下,从左到右。也 就说,涉及多量子比特时,不同线路上设置的门遵循前面提到的上下左右规则,后续遇到多比特门问题时候再详细说明。该示例里,对初始化 的量子比特位,进行Hadamard门操作,然后测量,并把测量的结果计划存放的经典寄存器cbit1里。
load(A_Hello_World_Program);
载入这个量子程序,
run();
运行A_Hello_World_Program。
map<string,bool> resultMap = getResultMap();
运行测量后得到结果图,本示例将中,将测量的结果存到了Cbit1里。新型的量子计算机,实质是量子 计算与经典计算的结合。把编写好的程序,输入到量子系统里(或模拟系统里),待量子计算系统结束运 行之后,把经典信息反馈到经典设备上并存储,再送给用户。
for (auto aiter : resultMap)
{
cout << aiter.first << " ";
cout << aiter.second << endl;
}
                        
遍历读出存在结果图里的数据,来验证是否和预期⼀样。
finalize();
完成本次量子程序的运行。
return resultMap["c0"];
返回函数值,此处返回的是结果图寄存的值。

纠缠态制备(Entangled State)

奇妙的量子理论里,量子纠缠让很多人着迷。量子纠缠是量子计算里极重要的资源,量子 纠缠态的制备,使用到了Hadamard门和CNOT门。通常初始化两量子比特,通过门构造,使 他们处于纠缠状态。通俗理解是,两个相距万里的粒子,如果处于纠缠状态之后,他们能时时 的影响到对方。⼀方测量坍塌之后,对应的⼀方也会坍塌到相应的状态上去。在量子计算体验 里,如下是量子纠缠的制备。使用H门和CNOT门,这里制备了了常见的个Bell态
@@\left| {\Phi^+ } \right\rangle = {1 \over {\sqrt 2 }}\left( {\left| {\left. {0} \right\rangle_A\otimes\left| {0} \right\rangle_B + {\rm{\;}}} \left| {1} \right\rangle_A\otimes\left| {1} \right\rangle_B \right.} \right) @@

制备纠缠态的量子线路:

制备量子纠缠QPanda代码案例:

bool etanglement()
{
    init();
    auto qb0 = qAlloc();
    auto qb1 = qAlloc();
	// allocate qubits

	auto * cbit0 = cAlloc();
    auto * cbit1 = cAlloc();
	// allocate cbits

    QProg & etangle = CreateEmptyQProg();
    //Create an empty program named etangle

	etangle
		<< H(qb0)
        << CONT(qb0,qb1) 
		<< Measure(qb0, cbit0)
        << Measure(qb1, cbit1);
	// insert a Hadamard gate, CONT gate and Measurement operation
	// after the empty program sequently

	load(etangle);
	// And then load it into the quantum computer.

    run();
	// simply run it.

    auto resultMap = getResultMap();
	// you can get the result map, which save all the
	// measurement results in the classical register(CBit)

    for (auto aiter : resultMap)
    {
        cout << aiter.first << " ";
        cout << aiter.second << endl;
    }
	// Let's iterate over the map to see whether
	// the result is correct

    finalize();
	// Use finalize() to tell the quantum computer to stop

    return resultMap[];

}
                            
复制代码
用户可以对照一下叠加态制备程序段来理解这一段程序。初始化,到加载量子程序,以及获取结果等。

量子程序的构建流程

回顾基本案例中的讲解,通常QPanda里⼀个量子程序由如下部分组成:
1. 初始化量子程序。
 init();
                            
2. 创建量子程序。
 QProg & porgramName = CreateEmptyQProg();
                            
3. 分配量子程序所需的量子比特(如果无空闲的量子比特,则会申请失败,抛出异常)。
Qubit * qubitName = qAlloc();
                            
4. 分配量子程序所需的经典比特。
CBit * cBitName = cAlloc();
                            
5. 创建量子线路.
OriginQCircuit & CircuitName= CreateEmptyCircuit();
                            
6. 构造量子线路
CircuitName << Gate(qubitName) << Measure(qubitName, cBitName);
                            
7. 加载程序。
load(porgramName);
                            
8. 运行量子程序。
 run();
                            
9. 得到测量结果图。
map<string,bool> resultMap = getResultMap();
                            
10. 导出数据
Please input the code .

量子逻辑门

最后更新时间: 2018-06-07 10:03:15
量子计算里,携带信息的量子态为了保证信息不丢失,所用的演化都必须为“幺正”演化。所以,量子 计算的通用逻辑门是由幺正门组成。下面列出QPanda 2.0 里已经定义了可以直接用的量子逻辑门。 根据作用量子比特的数量差异,暂时有单 量子比特门双量子比特门。根据量子逻辑门特性,可将门组成的基分为 连续基离散基

单量子比特门及测量 :

顾名思义,单量子比特门就是门作用在一位量子比特上。该过程在Deutsch的量子线路模型中如下:
单线条代表了一个量子比特位,而方框中的U,所表示的正是幺正变换。这里需要强调的是 ,上图从左到右,并不是代表空间的移动方向,而是时间的进行方向。理论上,一 条线上面可以放无穷个门,要读出这条线所代表的量子比特信息,必须在线条末尾添加测量操作。
给定任意单量子逻辑门U,都可以表示为:
@@U=e^{ai}R_z\left ( {\beta } \right )R_y \left ( {\gamma } \right )R_z\left ( \delta \right )@@
在QPanda里默认提供了一些单量子比特门直接可用,如下逐个说明:

X()

X(Qubit* qbit);
线路中插入X门,Qubit*指代的是将执行这个门操作的量子比特。对应的矩阵表示为:

@@X=\begin{bmatrix}0& 1\\1 & 0 \end{bmatrix}@@

RX()

RX(Qubit*, double angle);
创建⼀个带⻆度参数的旋转X门,括号里写入的是将执行这个门操作的量子比特,double angle是旋转的⻆度参数。对应的矩阵表示:

@@RX(\theta)=\begin{bmatrix}\cos (\theta/2) & -i\sin (\theta/2) \\ -i\sin (\theta/2) & \cos (\theta/2) \end{bmatrix}@@

其中$\theta$是选择的角度,下同。

Y()

Y(Qubit* qbit);
创建一个Y门,括号里写入的是对应将执行这个门操作的量子比特。对应的矩阵表示:

@@Y=\begin{bmatrix}0 & -1i \\ -i & 0 \end{bmatrix}@@

RY()

 RY(Qubit*, double angle);
创创建一个带参数的旋转Y门,括号里写入的是将执行这个门操作的量子比特,以及后续跟上旋转的角度参数。对应的矩阵表示:

@@RY(\theta)=\begin{bmatrix}\cos (\theta/2) & -\sin (\theta/2) \\ \sin (\theta/2) & \cos (\theta/2) \end{bmatrix}@@

Z

 Z(Qubit* qbit);
创建⼀个Z门,括号里写入的是对应将执行这个门操作的量子比特,对应的矩阵表示:

@@Z=\begin{bmatrix}1 & 0 \\ 0 & -1 \end{bmatrix}@@

RZ()

 RZ(Qubit*, double angle);
创建⼀个带参数的旋转Z门,括号里写入的是将执行这个门操作的量子比特,以及后续跟上旋 转的⻆度参数。对应的矩阵表示:

@@RZ(\theta)\begin{bmatrix} exp(-i\theta/2) & 0 \\ 0 & exp(i\theta/2) \end{bmatrix}@@

S()

 S(Qubit* qbit);
创建⼀个S门,括号里写入的是对应将执行这个门操作的量子比特。对应的矩阵表示:
@@\begin{bmatrix} 1&&0\\ 0&&1i \end{bmatrix} @@

H

H(Qubit* qbit); // Create Hadamard Gate
Hadamard 门,这是制备叠加态重要的门。括号里⾯写入的是将执行这个门操作对应的量子比 特。H门对应的矩阵表示是:
$$\begin{bmatrix}\frac{1}{\sqrt{2}} &\frac{1}{\sqrt{2}}\\\frac{1}{\sqrt{2}}&-\frac{1}{\sqrt{2}}\end{bmatrix}

T

T(Qubit* qbit);
创建一个S门,括号里写入的是对应将执行这个门操作的量子比特。对应的矩阵表示:
@@T=\begin{bmatrix}1 &0\\0&exp(i\pi/4)\end{bmatrix}@@

U1

U1(Qubit* qbit);
创建一个U1门,相较于Z方向上的翻转,U1门多了全局相位。同上,括号里写入的是对应将执行这个门操作的量子比特。对应的矩阵表示:
@@U1(\theta)=\begin{bmatrix}1 &0\\0&exp(i\theta)\end{bmatrix}@@

Measure

Measure(Qubit * targetQuBit, CBit * targetCbit);
对目标量子比特进行测量操作,并制定测量结果寄存的位置。通常,一个量子比特对应着一个经典寄存器。在量子计算里,通常所说的测量,就是计算基(Computational Basis)的测量,也称为Z方向上的测量。

双量子比特门 :

顾名思义,双量子比特门,即是对两个量子比特操作的门。
控制U门
控制门是常见的两量子比特门,要点是其中一个量子态的变化会影响另外一个量 子位做相应的酉变换操作。通常,把第一个位称为控制位(control qubit), 第二个位称为靶位(traget qubit). 如下图所示:
带有黑圆点的量子线代表控制位,方框里隔离开的量子位表示靶位。  当且仅当,控制位为$|1\rangle$的时候,靶位才执行U门操作。 而当控制位的是状态是$|0 \rangle$时,靶位不发生任何变化。
在控制门的设计里,都遵循这样的“控制”思想。当将控制位的黑点变成空心圆时,它代表的是控制位的状态处于$|0 \rangle$态时靶位会发生翻转, 反之无操作。具体的翻转,依赖于程序的设计需求,而所谓的翻转,就是控制位响应的时候,靶位里的量子位执行方框里的幺正变换。控制U门的矩阵表示为:
@@CU = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 &u_0 & u_1 \\ 0 & 0 & u_1 & u_0 \end{bmatrix}@@

常见的两比特量子门

下⾯是QPanda里常用的两个双量子比特门:

CNOT 门

CNOT(Qubit* targetQBit, Qubit* controlQBit)
CNOT称为 控制非门(control NOT gate ),这个门作用在两个量子位上。QPanda里使用 CNOT时,应注意靶位在前,控制位在后。先后顺序需对应,如下图:
该门操作实际是对输入的$|0\rangle$ 不操作,当控制位为$|1 \rangle$时,靶位作X(NOT)翻转。在量子位态矢量空间里,控制非门是一个4*4的矩阵,其矩阵表示如下:
@@CNOT = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \end{bmatrix}@@
在实际应用中,CNOT门应用广泛,它可以方便快捷的让两个粒子纠缠起来,比如制备纠缠态。

CZ门

CZ(Qubit* targetQBit, Qubit* controlQBit);
该门操作实际是对输入的$|0\rangle$ 不操作,当控制位为$|1 \rangle$时,靶位作Z翻转。
在量子位态⽮量空间里,控制相位门是4*4的矩阵,矩阵表示如下:
@@CZ = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & -1 \end{bmatrix}@@

SWAP ()

SWAP(Qubit* QBit1, Qubit* QBit2);
这个门的作用是交换互联的门的量子比特的状态,两两交换。当然,SWAP门可以轻松的用三个CNOT门构建而成,形如 SWAP(q1,q2)=CNOT(q1,q2)CNOT(q2,q1)CNOT(q1,q2)。在实际应用中也可以做此转化,直接用线路的形式表示。考虑使用的易用性,QPanda支持直接使用SWAP门。矩阵表示如下:
@@SWAP = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}@@

ISWAP()

ISWAP(Qubit* QBit1, Qubit* QBit2);
ISWAP门也是交换门,其性质可以参考SWAP门。ISWAP门的矩阵表示为:
@@ISWAP = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & i & 0 \\ 0 & i & 0 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}@@

SQISWAP ()

SQISWAP(Qubit* QBit1, Qubit* QBit2);
SQISWAP于ISWAP是一个类型的。矩阵表示为:
@@SQISWAP = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & \frac{1}{\sqrt{2}} & \frac{i}{\sqrt{2}} & 0 \\ 0 & \frac{i}{\sqrt{2}} & \frac{1}{\sqrt{2}} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}@@

量子线路

最后更新时间: 2018-10-12 14:28:01
量子线路,是在抽象概念下对量子信息存储单元(量子位)进行的操作线路,量子线路上包括了一切初始化的量子存储单元、 量子位的线、所需的门。如果需要线路最后输出经典信息值,就需要测量操作,把结果读取出。当然,在实际的物理环境下 实施量子计算的时候,则需要做一些转换。
在QPanda里,量子线路的构建非常简洁,回顾Hello world案例里的一个片段:
...
 	QProg & A_Hello_World_Program = CreateEmptyQProg();
	Qubit * qb0 = qAlloc();
	CBit * cbit0 = cAlloc();
	A_Hello_World_Program
		<< H(qb0) 
		<< Measure(qb0, cbit0);
...
                            
上面定义了一个叫A_Hello_World_Program的量子程序,此处已经创建了一个量子线路,线路上包含一个量子位(qb0),一个单量子比特门(Hadamard门),一个测量操作(Measure),一个经典寄存器(cbit0)。 程序里先对qb0进行Hadamard门操作,之后对该比特执行测量,并把测量值寄存在经典寄存器cbit0里。正常连接量子处理器的时候,就将该量子线路输入量子计算机中运行,运行结束后,读取经典寄存器内的信息(运行结果),然后通过云端传给用户。

初级算法演示

最后更新时间: 2018-06-07 10:03:15

随机数生成器(Random Number Generator)

随机数的制备相对来说是简单的。我们知道,现在计算机生产的随机数 ,其实并非真正的随机数。经典随机数可以理解为一个函数的输入和输出。 在经典计算当中,所得的随机数是由一个函数所产生,意味着如果人们知道输入, 就能预测得到输出。但是量子随机数是真随机(Truly Random),得意于量子测量结果的不可预测性, 也即是量子测量的输出是不可预测的,完全随机分布。那量子态编码的输出,自然就是真随机数了。
简单思路,随机数的制备其实就是对叠加态的测量。测量后得到的随机数就是真随机数。 也可以通过少量的量子位测量然后搜集输出结果,以此来制备随机源。比如,制备0到127中的一个随机数,这里提供一个简单思路。

参考线路图:

一系列的H门将7个初始化的状态置为叠加态,之后进行测量。这样,每次测量就能得到0 到127范围的任意一个数字(参考代码里并没有把二进制数转为十进制,用户可自行增加此转换)。

随机数生成的参考代码:

void rondamNumber()
{
	init();
	QProg & random = CreateEmptyQProg();
	//Create an empty program named etangle

	auto qbit0 = qAlloc();
	auto qbit1 = qAlloc();
	auto qbit2 = qAlloc();
	auto qbit3 = qAlloc();
	auto qbit4 = qAlloc();
	auto qbit5 = qAlloc();
	auto qbit6 = qAlloc();
	 
	// allocate 6 qubits

	auto cbit0 = cAlloc();
	auto cbit1 = cAlloc();
	auto cbit2 = cAlloc();
	auto cbit3 = cAlloc();
	auto cbit4 = cAlloc();
	auto cbit5 = cAlloc();
	auto cbit6 = cAlloc();
	// allocate 7 cbits

	random
		<< H(qbit0) 
		<< H(qbit1) << H(qbit2) << H(qbit3) 
		<< H(qbit4) << H(qbit5) << H(qbit6) 
		<< Measure(qbit0, cbit0) << Measure(qbit1, cbit1)
        << Measure(qbit2, cbit2) << Measure(qbit3, cbit3)
        << Measure(qbit4, cbit4) << Measure(qbit5, cbit5)
		<< Measure(qbit6, cbit6);
	// Required quantum circuit.

	load(random);
	// And then load it into the quantum computer.

	run();
	// simply run it.

	auto resultMap = getResultMap();
	// you can get the result map, which save all the
	// measurement results in the classical register(CBit)
	auto Num000 = resultMap["c0"];
	auto Num001 = resultMap["c1"];
	auto Num010 = resultMap["c2"];
	auto Num011 = resultMap["c3"];
	auto Num101 = resultMap["c4"];
	auto Num110 = resultMap["c5"];
	auto Num111 = resultMap["c6"];

	cout <<"The random number of this production is;"
		<< Num000 << Num001 << Num010 
		<< Num011 << Num101 << Num110 << Num111;

	finalize();
	// Use finalize() to tell the quantum computer to stop.
}
                            
复制代码
上面输出的是二进制的数字,用户如果想生成十进制的数字。就能够得到对应的0到127的随机数。 当程序在真实量子芯片上执行的时候,得出的结果是确切的真随机数。上面分别从测量结果中把数据取出来, 也就说,当需求生产更大的随机数时,可以增加比特位获得。但是实际应用中,我们只需要提供简单的真随机源, 就能结合经典随机构造一切随机数。真随机数在信息安全里充当了重要的角色。

函数判断算法(Deutsch-Jozsa Algorithm)

通常,开发量子计算的主要驱动力来源于量子计算相较于经典计算体现的优越性。通常也是从这样的比较里来认识量子计算。通过简单直观的对比,来扣住“量子霸权”真正含义所在,下面就从简单Deutsch问题说起。

问题概要:

考虑二进制变量0,1。给定函数$f:\{0,1\} \rightarrow \{0,1\}$。
比如对$x \in \{0,1\} $有$f_{00}(x)=1,f_{01}(x)=0,f_{10}(x)=x,f_{11}(x)=x\oplus 1,
$ (其中$\oplus$表示模加(Addition modulo two)). 我们称函数为:**常量函数(Constant)**: 即$f(0)=f(1)$.可以理解为,对于任意的二进制输入,输出都是100%的0,或者100%的1,实例中$f_{00}(x),f_{01}(x)$就属于该类。
**均衡函数(Balanced)**: 即$f(0)\neq f(1)$。可以理解为,对于任意二进制的输入,输出各占一半。实例中$f_{10}(x),f_{11}(x)$就属于该类。

问题点:


把给定的函数$ f(x) $理解成黑盒子(Black box),通过输二进制数来测试,这个函数属于“常量函数”还是“均衡函数”?,需要多少次可以确定?
**经典计算机:** 需要运行**两次**才能确定函数属于哪一类。
可以直接了当的看到,对于输入的0或1,执行两次就可以确认结果。比如:输入$x=0$,发现$f(x)=0$,这意味着$f$可能是$f_{00}$或者是$f_{01}$,紧接着我么输入$x=1$,就可以确认$f$属于哪一种函数。很明显,在经典计算机上最少也得=需执行**两次**才可以判断函数属于哪一种类型。量子计算机:仅需运行**一次**就能确定函数属于哪一类。
上面讨论的是Deutsch问题,整体涉及了一个量子位(qubit).对于两量子位以上的变量就涉及到了需要强调的Deutsch-Jozsa算法中对常数函数和均衡函数的判定问题。
但是,在涉及两个以上量子位的问题时候,我们有必要保证所运行的函数只具备常量函数和均衡函数两种属性,不会发生其他情况。为此, 该算法也称为“承诺算法”。
比如:考虑两个变量的情况。二进制表示分别为$f(00),f(01),f(10),f(11)$4种情况,返回值只有1或者0,我们用二进制函数$f(x_0,x_1)$表示。这里,对于常数函数$f(x_0,x_1)$有$f(00)=f(01)=f(10)=f(11)=0$或$1$两种情况。而均衡函数$f(x_0,x_1)$则有如下的情况:
1.$f(00)=f(01)=0$ ,$ f(10)=f(11)=1 $
2.$f(00)=f(11)=0$ ,$ f(01)=f(10)=1 $
3.$f(00)=f(10)=0$ ,$ f(01)=f(11)=1 $
4.$f(00)=f(01)=1$ ,$ f(10)=f(11)=0 $
5.$f(00)=f(11)=1$ ,$ f(01)=f(10)=0 $
6.$f(00)=f(10)=1$ ,$ f(01)=f(11)=0 $
在经典算法中,函数需要**3次**才能确定该函数是常数函数或是均衡函数。而量子算 法,则只需要⼀次就可以决定结果。也就是说,如果有n比特数的增加,经典算法需要$2^{n1}+1$指数级才能确定,其复杂的为$O(2^n)$的增加。但是,量子算法对于变量n的增加不受 影响。其复杂的为$O(1)$。由此可以窥见,量子计算确值得所有人期待。

参考线路:

QPanda 代码案例 :

/*
Copyright (c) 2017-2018 Origin Quantum Computing. All Right Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "DJ_Algorithm.h"

void DJ_Algorithm()
{
	bool fx0 = 0, fx1 = 0;
	cout << "input the input function" << endl
		<< "The function has a boolean input" << endl
		<< "and has a boolean output" << endl
		<< "f(0)= (0/1)?";
	cin >> fx0;
	cout << "f(1)=(0/1)?";
	cin >> fx1;
	vector<bool> oracle_function({ fx0,fx1 });
	cout << "Programming the circuit..." << endl;
	init();
	auto q1 = qAlloc();
	auto q2 = qAlloc();
	auto c1 = cAlloc();

	Reset_Qubit(q1, false);
	Reset_Qubit(q2, true);

	append(Two_Qubit_DJ_Algorithm_Circuit(q1, q2, c1, oracle_function));

	run();

	//auto resultMap = getResultMap();
	if (getCBitValue(c1) == false)
	{
		cout << "Constant function!";
	}
	else if (getCBitValue(c1) == true)
	{
		cout << "Balanced function!";
	}
}

QProg & Two_Qubit_DJ_Algorithm_Circuit(
	Qubit * qubit1, 
	Qubit * qubit2, 
	CBit * cbit, 
	vector<bool> oracle_function)

{
	auto &prog = CreateEmptyQProg();
	//Firstly, create a circuit container

	prog << H(qubit1) << H(qubit2);
	// Perform Hadamard gate on all qubits

	if (oracle_function[0] == false
		&&
		oracle_function[1] == false)
		// different oracle leads to different circuit
		// f(x) = oracle_function[x]
	{
		// f(x) = 0, do nothing
	}
	else if (oracle_function[0] == false
		&&
		oracle_function[1] == true
		)
	{
		// f(x) = x;
		prog << CNOT(qubit1, qubit2);
	}
	else if (oracle_function[0] == true
		&&
		oracle_function[1] == false
		)
	{
		// f(x) = x + 1;
		prog << RX(qubit2)
			<< CNOT(qubit1, qubit2)
			<< RX(qubit2);
	}
	else if (oracle_function[0] == true
		&&
		oracle_function[1] == true
		)
	{
		// f(x) = 1
		prog << RX(qubit2);
	}

	// Finally, Hadamard the first qubit and measure it
	prog << H(qubit1) << Measure(qubit1, cbit);
	return prog;
}
                            
复制代码

高级开发者文档

通用门在使用过程中,带来了便捷,但是对特殊问题的解决,仅仅使用常用量子逻辑门是不够 的。因此,在更深层次使用时,我们需要在原有基础上自定义量子线路和相应的参数,函数, 以及条件控制等来有效解决更复杂问题。QPanda⾼级使用时的处理机制可能会涉及如下:
1. 创建 : 创建量子程序,创建时间段程序,创建条件量子程序,创建量子线路。
2. 自定义:自定义量子线路,自定义参数等。
3. 释放:释放量子比特,释放经典比特。
4. 载入和运行:载入程序,运行程序,追加程序,。
5. 状态结果:获取当前机器的状态,获取测量具体的结果。
6. 导出数据:可将结果一SVG格式导出。
这里,本节主要强调一些与上一节不同的高级使用,分别从创建与自定义,释放,程序追加,结果获取等一一描述。

创建与自定义

初始化量子程序:
init();
定义可能用到的量子比特和经典比特:
Qubit* qubit0 = qAlloc(); //Register qubit
Qubit* qubit1 = qAlloc(); //
CBit*  cbit0 =  cAlloc();  //Register cbit
CBit*  cbit1 =  cAlloc(); 

自定义量子线路

最后更新时间: 2018-10-12 14:53:15
很多问题涉及到 了复杂的线路图,复杂的逻辑门构造,比如下面是HHL算法的部分QPanda代码(详细请查阅章节末尾);
...
OriginQCircuit& hhlPse(vector<Qubit*> qVec){
    OriginQCircuit & PSEcircuit = CreateEmptyCircuit();
    PSEcircuit << H(qVec[1]) << H(qVec[2]) << RZ(qVec[2], 0.75*PI);
    OriginQGateNode & gat1 = QDouble(PI, 1.5*PI, -0.5*PI, PI / 2, qVec[2], qVec[3]);
    OriginQGateNode & gat2 = QDouble(PI, 1.5*PI, -PI, PI / 2, qVec[1], qVec[3]);
    PSEcircuit << gat1 << RZ(qVec[1], 1.5*PI) << gat2;
    PSEcircuit << CNOT(qVec[1], qVec[2]) << CNOT(qVec[2], qVec[1]) << CNOT(qVec[1], qVec[2]);
    OriginQGateNode & gat3 = QDouble(-0.25*PI, -0.5*PI, 0, 0, qVec[2], qVec[1]);
    PSEcircuit << H(qVec[2]) << gat3 << H(qVec[1]);
    return PSEcircuit;
}
...
                            
复制代码
如上的示例里就涉及了自定义量子线路,自定义逻辑门和自定义函数。

自定义量子线路

自定义量子量子线路,自定义的线路,在其他地方就可以用来定义量子线路:
QCircuit& hhlPse(vector qVec)
{
}
                            
使用自定义的量子线路:
QCircuit & PSEcircuit = hhlPse(qVec); 
                            

自定义量子逻辑门

常见的量子逻辑门在上一节当中已经罗列,但在实际问题解决中, 用基础逻辑门很难构造出具体问题的量子线路,很多参数,需要自定义。 在QPanda里面,对于任意的量子比特逻辑门U,都可用矩阵表示(Matrix representation)如下(幺正变换):
@@ U=\begin{bmatrix} e^{i\left ( a-\frac{\beta}{2} - \frac{\delta}{2}\right )}cos(\frac{\gamma}{2}) & -e^{i\left ( a-\frac{\beta}{2} +\frac{\delta}{2}\right )}sin(\frac{\gamma}{2})\\ e^{i\left ( a+\frac{\beta}{2} - \frac{\delta}{2}\right )}sin(\frac{\gamma}{2}) & -e^{i\left ( a+\frac{\beta}{2} +\frac{\delta}{2}\right )}cos(\frac{\gamma}{2}) \end{bmatrix}@@
比如,常见的单量子比特门带参数的RZ门的形式是:
QGateNode & gateName = RZ(targetQuBitName, 1.5*PI);
                            
由于这里已经指明了作用的量子位(对应targetQuBitName),所以在线路上无需再指明作用量子,直接使用gateName就可以(下同)。
QProg << gateName;
                            

自定义单量子逻辑门

单量子比特的参数门表示(其中qubitName是执行该量子门对应的量子位):
QGateNode & gateName = QSingle(double alpha, double beta, double gamma, double delta, QubitName)

                            
其中$alpha$,$beta$,$gama$,$delta$对应如下:
@@U=e^{ia}R_z\left ( {\beta } \right )R_y \left ( {\gamma } \right )R_z\left ( \delta \right )@@
案例:
QGateNode & gate1 = QSingle(PI/2, 0, PI, PI / 2,Qubit1)
                            
这个参数实际等级与常用门中的X门。

自定义多量子逻辑门

控制门的参数表示(注意控制位和靶位的前后顺序,与CNOT⼀致):
QGateNode & gateName = QDouble(double alpha, double beta,
double gamma, double delta, Qubit *, Qubit *);
                            
自定义控制门案例:
QGateNode & gateName = QDouble(PI, 1.5*PI,
-0.5*PI, PI / 2, targetQBit, controlQBit);
                            

创建程序与子控制流

更为高级的程序创建里,除了常规的程序创建,QPanda 2.0 里还具备条件Q-If的创建和循环q-whlie的创建,给定如下示例代码:
...
ClassicalCondition cc1 = bind_a_cbit(cbit0);
QProg & ifProg = CreateEmptyQProg();
ifProg << H(qubit1);
QIfNode& ifnode = CreateIfProg(&cc1, &ifProg);
prog << H(qubit0) << Measure(qubit0,cbit0)
     << ifnode << Measure(qubit1,cbit1);
load(prog);
run();
auto resultMap = getResultMap();
finalize();
                        
下面做一些解释:
将 Cbit1 绑定到经典条件变量(CBit1已经提前定义):
ClassicalCondition* CbitName = bind_a_cbit(cbit1);
在示例中定义了cc1,绑定对象在bind_a_cbit()里指定。
创建条件程序:
QProg & ifProg = CreateEmptyQProg();
ifProg << H(qubit1);
QIfNode& ifnode = CreateIfProg(&cc1, &ifProg);
                        
定义了ifProg量子程序,然后对该程序上的qubit1做H门操作。之后创建ifnode,注意参数,cc1是绑定到经典条件的变量,指向cbit1。ifnode关联了ifProg程序。所以最后的测量如下:
prog << H(qubit0) << Measure(qubit0,cbit0)
     << ifnode << Measure(qubit1,cbit1);
如下是Q-If的参考量子线路示例,黑色部分对应了程序中的prog,而红色框则对应了ifProg。
创建条件程序格式:
QIfNode &ifProgName = CreateIfProg(ccName, cbitName);
创建时间段程序:
QWhileNode & WhileProgName = CreateWhileProg(ccName, cbitName);

自定义类

在QPanda 2.0 文件目录下的Config.xml 文件,它的作用是配置Qpanda 2.0 需要使用的类的类型,用户可在QPanda 2.0框架下自行定义对应的类,

Config.xml:

<?xml version="1.0" encoding="utf-8" ?>
<head>
	<ClassNameConfig>
		<QProg>OriginProgram</QProg>
		<QCircuit>OriginCircuit</QCircuit>
		<QIfProg>OriginIf</QIfProg>
		<QWhileProg>OriginWhile</QWhileProg>
		<QMeasure>OriginMeasure</QMeasure>
		<QuantumMachine>OriginQVM</QuantumMachine>
		<QubitPool>OriginQubitPool</QubitPool>
		<Qubit>OriginQubit</Qubit>
		<PhysicalQubit>OriginPhysicalQubit</PhysicalQubit>
		<CBit>OriginCBit</CBit>
		<CMem>OriginCMem</CMem>
		<QResult>OriginQResult
		<CExpr>OriginCExpr</CExpr>
     </ClassNameConfig>
 </head>
                        
MetadataConfig.xml的作用是记录量子芯片的特征,其特征分别为量子比特的拓扑结构、支持的单门、支持的双门

记录量子芯片特征

QPanda-2.0/TinyXML/MetadataConfig.xml
该xml 文件的作用是记录量子芯片的特征,其中量子芯片的特征分别为:
量子比特的拓扑结构。
支持的单量子逻辑门
支持的双量子逻辑门。
<?xml version="1.0" encoding="utf-8" ?>
<head>
	<QubitCount>4</QubitCount>
    <QubitMatrix>
		<Qubit QubitNum = 1>
			<AdjacentQubit QubitNum = 2>1</AdjacentQubit>
            <AdjacentQubit QubitNum = 3>1</AdjacentQubit>
		</Qubit>
		<Qubit QubitNum = 2>
			<AdjacentQubit QubitNum = 1>1</AdjacentQubit>
			<AdjacentQubit QubitNum = 4>1</AdjacentQubit>
		</Qubit>
		<Qubit QubitNum = 3>
			<AdjacentQubit QubitNum = 1>1</AdjacentQubit>
			<AdjacentQubit QubitNum = 4>1</AdjacentQubit>
		</Qubit>
		<Qubit QubitNum = 4>
			<AdjacentQubit QubitNum = 2>1</AdjacentQubit>
			<AdjacentQubit QubitNum = 3>1</AdjacentQubit>
		</Qubit>
	</QubitMatrix>
	<SingleGate>
		<Gate>rx</Gate>
		<Gate>Ry</Gate>
		<Gate>RZ</Gate>
		<Gate>S</Gate>
	</SingleGate>
     <DoubleGate>
		<Gate>CNOT</Gate>
		<Gate>CZ</Gate>
		<Gate>ISWAP</Gate>
	</DoubleGate>
</head>
                        

释放及运行

最后更新时间: 2018-10-12 15:30:15

释放量子比特和经典比特

QPanda在释放辅助量子比特和经典比特的这个机制,比如辅助比特完成了特定任务之后,是可以将其释放的。
量子比特的释放:
qFree(Qubit* qubit);
                                
括号里紧跟的是所释放的量子比特的下标,同理经典比特的释放如下:
cFree(CBit* cbit);
                                

追加程序

通常,简单的程序仅有单次载入,有时会因为量子软件的设计需求需再追加一个量子程序,这时则需要进行追加处理,使用方法:
append(QProg& qProgName);
                                
这样,就可以追加qProgName到当前的加载程序中,一并运行。

运行状态及结果

获取量子机器的运行状态:
QMachineStatus* getstat();
                                
获取运行结果:
QResult* getResult();
                                
直接得到结果图:
map<string, bool> getResultMap();
                                
直接获取指定的经典值:
bool getCBitValue(CBit* cbit);
                                

统计转换与输出

最后更新时间: 2018-10-12 16:02:15

数据的统计和程序转换

统计线路中的量子逻辑门数量:
extern size_t countQGateUnderQCircuit(AbstractQuantumCircuit *);
                                
统计程序中的量子逻辑门数:
extern size_t countQGateUnderQProg(AbstractQuantumProgram * pQProg);
                                
将量子程序转换成QRunes
extern void qRunesProg(QProg &pQPro);
                                

数据导出

运行的结果数据,将以CSV文件格式导出。导出的方法

典型算法演示

最后更新时间: 2018-06-07 10:03:15

搜索算法(Grover Algorithm)

大数据时代,造就了大数据的恐慌,如今每天产生的数据量,是过去十年积累的总和还要多,海量数据已经给寻找有效的数据带来了阻碍 ,这俨然成信息处理相关的产业都面临的巨大挑战。1996年,Lov Grover提出了量子搜索算法,对于N个序列数据里寻求1个有效数据, 经典算法给出的有效时间复杂度为$O(N)$,而Grover证明了处理同样的问题,量子算法可以做到时间复杂度为$O(\sqrt N )$。 也就说Grover的搜索算法可以以指数级的加速改善搜索复杂度。 如何更直观理解:假设给定相同的问题,量子计算用10000次就解决, 但是经典计算机则需要$10000^2=100000000$ ,这是一万和一亿的差距。由此可见,对于大数据的搜索,Grover算法印证了量子计算能大显身手,可有效解决搜索问题。

参考线路图 :

参考代码:

/*
Copyright (c) 2017-2018 Origin Quantum Computing. All Right Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "Grover_Algorithm.h"

QProg& Grover(vector<Qubit*> qVec, vector<CBit*> cVec, int target)
{
    QProg & grover = CreateEmptyQProg();
    OriginQCircuit & init = CreateEmptyCircuit();
    OriginQCircuit & oracle = CreateEmptyCircuit();
    OriginQCircuit & reverse = CreateEmptyCircuit();
    init << H(qVec[0]) << H(qVec[1]) << RX(qVec[2]) << H(qVec[2]);
    vector<Qubit *> controlVector;
    controlVector.push_back(qVec[0]);
    controlVector.push_back(qVec[1]);
    //QSingleGate  sqrtH(0.5*PI, 0, 0.25*PI, PI);
    OriginQGateNode  &toff = RX(qVec[2]);
    toff.setControl(controlVector);
    switch (target)
    {
    case 0:
        oracle << RX(qVec[0]) << RX(qVec[1]) << toff << RX(qVec[0]) << RX(qVec[1]);
        break;
    case 1:
        oracle << RX(qVec[0]) << toff << RX(qVec[0]);
        break;
    case 2:
        oracle << RX(qVec[1]) << toff << RX(qVec[1]);
        break;
    case 3:
        oracle << toff;
        break;
    }
    reverse << H(qVec[0]) << H(qVec[1]) << RX(qVec[0]) << RX(qVec[1])
        << H(qVec[1]) << CNOT(qVec[0], qVec[1]);
    reverse << H(qVec[1]) << RX(qVec[0]) << RX(qVec[1]) << H(qVec[0]) << H(qVec[1]) << RX(qVec[2]);
    grover << init << oracle << reverse << Measure(qVec[0], cVec[0]) << Measure(qVec[1], cVec[1]);
    return grover;
}
void Grover_Algorithm()
{
    int target;
    cout << "input the input function" << endl
        << "The function has a boolean input" << endl
        << "and has a boolean output" << endl
        << "target=(0/1/2/3)?";
    cin >> target;
    cout << "Programming the circuit..." << endl;
    init();
    vector<Qubit*> qv;
    int qubitnum = 3;
    for (size_t i = 0; i < qubitnum; i++)
    {
        qv.push_back(qAlloc());
    }
    vector<CBit*> cv;
    int cbitnum = 2;
    for (size_t i = 0; i < cbitnum; i++)
    {
        cv.push_back(cAlloc());
    }
    auto &groverprog = Grover(qv, cv, target);
    load(groverprog);
    run();
    auto resultMap = getResultMap();
    if (resultMap["c0"])
    {
        if (resultMap["c1"])
        {
            cout << "target number is 3 !";
        }
        else
        {
            cout << "target number is 2 !";
        }
    }
    if (!resultMap["c0"])
    {
        if (resultMap["c1"])
        {
            cout << "target number is 1 !";
        }
        else
        {
            cout << "target number is 0 !";
        }
    }
    finalize();
}
                            
复制代码

量子线性系统分析(HHL Algorithm)

量子计算机利用诸如叠加和纠缠之类的量子力学现象来进行计算。这在经典计算机上是无法计算的,量子算法在其经典计算对比下,呈指数级加速。 Harrow, Hassidim和Lloyd(HHL)提出了一种求解线性系统$Ax=b$(其中A是算子,x,b是向量)中$x$信息的量子线性系统分析。HHL算法解决 了什么样的问题?那就是求解线性方程的问题,众所周知 ,线性系统是很多科学和工程领域的核心,由于HHL算法在特定条件下实现了相较于经典 算法有指数加速效果,从而未来能够在机器学习、数值计算等场景有优势体现。配合Grover算法在数据方面的加速,将是未来量子机器学习,人工智等科技得以突破的关键性技术。

HHL算法的输入和输出 :

输入:一个n*n的矩阵A和一个n维向量b,
输出:n维向量x,满足Ax=b。
HHL的的限制条件的:
1. 输入的矩阵,必须是adjoint矩阵,当A不是Hermitian时,需要构造成adjoint矩阵。算法的输入部分如图1中红色方框所标出。输入q[2]存放在底部寄存器中,输入A作为相位估计中酉算子的一个组成部分。
2. 输出x的形式:算法的输出如红色部分标出(同一个寄存器)。底部寄存器存放的是一个蕴含了向量x的量子态。 此处不需要知道这个状态具体情况。

HHL量子算法线路参考图 :

如上的线路图中涉及到了门的定义,这些门不在常用门里。用户可以尝试定义这些逻辑门。通过本章节提到的自定义法。详情参考QPanda 2.0代码。

HHL量子算法参考代码:

#include "HHL_Algorithm.h"

void HHL_Algorithm()
{
    map<string, bool> temp;
    int x0 = 0;
    int x1 = 0;
    for (size_t i = 0; i < 1000;i++)
    {
        temp = hhlalgorithm();
        if (temp["c0"])
        {
            if (temp["c1"])
            {
                x1++;
            }
            else
            {
                x0++;
            }
        }
    }
    int sum = x0 + x1;
    cout << "prob0:" << x0*1.0/sum << endl;
    cout << "prob1:" << x1*1.0/sum << endl;
}

map<string, bool> hhlalgorithm()
{
    init();
    int qubitnum = 4;
    vector<Qubit*> qv;
    for (size_t i = 0; i < qubitnum; i++)
    {
        qv.push_back(qAlloc());
    }
    vector<CBit*> cv;
    int cbitnum = 2;
    for (size_t i = 0; i < cbitnum; i++)
    {
        cv.push_back(cAlloc());
    }
    auto hhlprog =CreateEmptyQProg(); 
    hhlprog << RY(qv[3], PI / 2);       //  change vecotr b in equation Ax=b
    hhlprog << hhl(qv, cv);
    load(hhlprog);
    run();
    auto resultMap = getResultMap();
    finalize();
    return resultMap;
}

int HHL_Test(int repeat)
{
	try
	{
		init();
		int qubitnum = 4;
		vector<Qubit*> qv;
		for (size_t i = 0u; i < qubitnum; i++)
		{
			qv.push_back(qAlloc());
		}
		vector<CBit*> cv;
		int cbitnum = 2;
		for (size_t i = 0u; i < cbitnum; i++)
		{
			cv.push_back(cAlloc());
		}
		auto hhlprog = CreateEmptyQProg();
		hhlprog << RY(qv[3], PI / 2);
		hhlprog << hhl(qv, cv);
		load(hhlprog);

		int x0 = 0;
		int x1 = 1;
		for (size_t i = 0u; i < repeat; ++i)
		{
			run();
			auto resultMap = getResultMap();
			if (resultMap["c0"])
			{
				if (resultMap["c1"])
				{
					x1++;
				}
				else
				{
					x0++;
				}
			}
		}
		finalize();
		cout << "x0: " << x0 << endl
			<< "x1: " << x1 << endl;
	}
	catch (QPandaException &e)
	{
		cout << e.what();
		return 1;
	}
	return 0;
}


QProg hhl(vector<Qubit*> qVec, vector<CBit*> cVec)
{
    ClassicalCondition cc0=bind_a_cbit(cVec[0]);

	// meaningless sentence
    QCircuit  ifcircuit = CreateEmptyCircuit();

    QCircuit  PSEcircuit = hhlPse(qVec);//PSE
    QCircuit  CRot = CRotate(qVec);//control-lambda
    QCircuit  PSEcircuitdag = hhlPse(qVec);
    //hhl circuit
    QProg  PSEdagger = CreateEmptyQProg();

    PSEdagger << PSEcircuitdag.dagger() << Measure(qVec[3], cVec[1]);
    QIfProg  ifnode = CreateIfProg(cc0, &PSEdagger);
    QProg  hhlProg = CreateEmptyQProg();
    //hhlProg << PSEcircuit <<CRot<<  Measure(qVec[0], cVec[0])<<ifnode;
    hhlProg << PSEcircuit << CRot << Measure(qVec[0], cVec[0]) << ifnode;
    return hhlProg;
}
QCircuit hhlPse(vector<Qubit*> qVec)
{
    QCircuit  PSEcircuit = CreateEmptyCircuit();
    PSEcircuit << H(qVec[1]) << H(qVec[2]) << RZ(qVec[2], 0.75*PI);
    QGate  gat1 = CU(PI, 1.5*PI, -0.5*PI, PI / 2, qVec[2], qVec[3]);
    QGate   gat2 = CU(PI, 1.5*PI, -PI, PI / 2, qVec[1], qVec[3]);
    PSEcircuit << gat1 << RZ(qVec[1], 1.5*PI) << gat2;
    PSEcircuit << CNOT(qVec[1], qVec[2])
    << CNOT(qVec[2], qVec[1]) << CNOT(qVec[1], qVec[2]);
    //PSEcircuit << gat1 << RZ_GATE(q1, 1.5*PI)<<gat2 ;
    QGate  gat3 = CU(-0.25*PI, -0.5*PI, 0, 0, qVec[2], qVec[1]);
    PSEcircuit << H(qVec[2]) << gat3 << H(qVec[1]);     //PSE over
    return PSEcircuit;
}
QCircuit CRotate(vector<Qubit*> qVec)
{
    QCircuit  CRot = CreateEmptyCircuit();
    vector<Qubit *> controlVector;
    controlVector.push_back(qVec[1]);
    controlVector.push_back(qVec[2]);
    QGate  gat4 = RY(qVec[0], PI);
    gat4.setControl(controlVector);
    QGate  gat5 = RY(qVec[0], PI / 3);
    gat5.setControl(controlVector);
    QGate  gat6 = RY(qVec[0], 0.679673818908);  //arcsin(1/3)
    gat6.setControl(controlVector);
    CRot << X(qVec[1]) << gat4 << X(qVec[1])
     << X(qVec[2]) << gat5 << X(qVec[2]) << gat6;
    //CRot << X(qVec[1]) << gat4 << X(qVec[1]);
    return CRot;
}
                            
复制代码

非局域游戏测试(Non-local Game )

非局域博弈游戏(Non-local Game),也称心灵感应测试(Telepathy-testing )。 这也是CHSH不等式的另一个表示。该游戏是经典情况下,玩家自由意志参与游戏,通过多次的统计得出了游戏的胜利失败分布。 通常情况下,玩家玩游戏的胜率不超过75%(理论最大值),当玩家在使用量子资源(共享量子纠缠态)融入自己的策略中时, 发现能够得到更高的胜利可能,能高达85%。这个游戏引出了很多值得探讨的问题, 尤其非局域性的讨论。当然,游戏本身值得思考的一点是,在博弈过程中,运用量子物理资源,所带来的增益作用。 从75%到85%这个没有信息交流的过程隐含了什么?进一步让人思考世界是局域的或者非局域的,也凸显了量子理论所描述的”真实“世界。

游戏策略的参考线路图:

游戏策略的参考代码

#include "Nonlocal_Game.h"

bool Winning_Test(pair<bool, bool> question, pair<bool, bool> answer)
{
	bool question_condition = question.first && question.second;
	bool answer_condition = answer.first || answer.second;

	if (question_condition == answer_condition)
	{
		return true; // Alice and Bob win the game.
	}
	else
	{
		return false; // Alice and Bob lose the game.
	}
}

pair<bool, bool> getRefereeQuestion()
{
	bool toAlice, toBob;
	srand(time(0));
	toAlice = static_cast<bool>(rand() % 2);
	toBob = static_cast<bool>(rand() % 2);
	// Random number simulation function is used to 
	// simulate the problem that Referee will ask Alice and Bob.
	return make_pair(toAlice, toBob);
}

QProg& Game(
	Qubit* alice_qubit,
	Qubit* bob_qubit,
	CBit* alice_meas,
	CBit* bob_meas,
	pair<bool, bool> &question)
{
	auto & game = CreateEmptyQProg();
	auto & entangled = CreateEmptyCircuit();
	auto & oracle = CreateEmptyCircuit();

	auto & Gate_I = RY(alice_qubit, 0);
	auto & Gate_T = RZ(bob_qubit, PI / 4);
	auto & Gate_T_Daga = RZ(bob_qubit, - PI / 4);
	// Custom Quantum logic Gates

	entangled << H(alice_qubit) << CNOT(bob_qubit, alice_qubit);
	// Make two qubit entangled, Here alice_qubit
    represent the qubit of Alice, and bob_qubit represent the qubit of bob. 
	question = getRefereeQuestion();

	if (question.first)
	{
		if (question.second)
		{
			oracle << H(alice_qubit) << S(bob_qubit)
            << H(bob_qubit) << Gate_T_Daga << H(bob_qubit);
		}
		else
		{
			oracle << H(alice_qubit) << S(bob_qubit)
            << H(bob_qubit) << Gate_T << H(bob_qubit);
		}
	}

	else
	{
		if (question.second)
		{
			oracle << Gate_I << S(bob_qubit)
            << H(bob_qubit) << Gate_T_Daga << H(bob_qubit);
		}
		else
		{
			oracle << Gate_I << S(bob_qubit)
             << H(bob_qubit) << Gate_T << H(bob_qubit);
		}
	}
	game << entangled << oracle << Measure(alice_qubit, alice_meas)
     << Measure(bob_qubit, bob_meas);
	return game;
}

void Nonlocal_Game(){
	size_t Round = 10;
	size_t win = 0;
	size_t lose = 0;
	for (size_t i = 0; i < Round; i++)
	{
		init();
		auto alice_qubit = qAlloc();
		auto   bob_qubit = qAlloc();
		auto  alice_meas = cAlloc();
		auto    bob_meas = cAlloc();
		pair<bool, bool> question;
		auto &GameProg = Game(alice_qubit,bob_qubit,alice_meas,bob_meas, question);
		load(GameProg);
		run();
		auto alice_answer = getCBitValue(alice_meas);
		auto   bob_answer = getCBitValue(bob_meas);
		bool final_result = Winning_Test(question,
        make_pair(alice_answer, bob_answer));
		if (final_result==true)
		{
			win++;
		}
		else
		{
			lose++;
		}
		cout << "The number of times player have won is;" << win;
		cout << "The number of times player have lose is;" << lose;
		finalize();

	}
}
                            
复制代码

用户API介绍

最后更新时间: 2018-10-12 17:03:09

1.函数CreateEmptyQProg

函数CreateEmptyQProg的作用是创建空的量子程序;
QProg CreateEmptyQProg();
函数CreateEmptyQProg的返回值数据类型是QProg类,该类是量子线路的容器,开发者可向QProg中添加QProg、QGate、QCircuit、QIfProg、QWhileProg。类QProg的用户API如下所示
class QProg
{
public:
    QProg & operator << ( QIfProg );
    QProg & operator << ( QWhileProg );
    QProg & operator << (QMeasure );
    QProg & operator << ( QProg );
    QProg & operator << ( QGate &);
    QProg & operator << ( QCircuit );
};
                            
成员函数QProg & operator << ( QIfProg )的作用是把QIfProg添加到容器QProg的尾部;
成员函数QProg & operator << ( QWhileProg)的作用是把QWhileProg添加到容器QProg的尾部;
成员函数QProg & operator << ( QMeasure)的作用是把QMeasure添加到容器QProg的尾部;
成员函数QProg & operator << ( QProg)的作用是把QProg添加到容器QProg的尾部;
成员函数QProg & operator << ( QGate)的作用是把QGate添加到容器QProg的尾部;
成员函数QProg & operator << ( QCircuit)的作用是把QCircuit添加到容器QProg的尾部。

2.函数CreateWhileProg

函数CreateWhileProg的作用是创建一个循环控制流量子线路,该线路可根据开发者输入条件判断表达式,判断是否正确,如果正确则执行循环控制流的正确分支量子线路,如果不正确则跳出循环。
QWhileProg CreateWhileProg(ClassicalCondition &ccCond , QNode * trueNode);
函数CreateWhileProg的输入参数分别是条件判断类ClassicalCondition和QNode类指针。 函数CreateWhileProg的返回值数据类型为QWhileProg类, 该类型同样是量子线路的容器,与QProg不同的是其记录了条件判断表达式。开发者可向QWhileProg中添加QCircuit。

3.函数CreateIfProg

函数CreateIfProg的作用是创建一个条件判断控制流量子线路,该线路可根据开发者输入的条件判断表达式, 判断是否正确,如果正确则执行条件判断控制流的正确分支量子线路,如果错误则执行错误分支或执行下一条量子线路。
QIfProg CreateIfProg(ClassicalCondition & ccCond, QNode *trueNode);
QIfProg CreateIfProg(ClassicalCondition & ccCond ,QNode *trueNode, QNode *falseNode);
函数CreateIfProg分为两种:创建只包含正确分支的条件判断控制流量子线路;创建包含正确分支与错误分支的条件判断控制流量子线路;
函数CreateIfProg的输入参数分别是条件判断类ClassicalCondition和QNode类指针。 函数CreateWhileProg的 返回值数据类型为QIfProg类,该类型同样是量子线路的容器,与QProg不同的是其记录了条件判断表达式。开发者可向Q IfProg中添加QCircuit。

4.函数CreateEmptyCircuit

函数CreateEmptyCircuit的作用是创建空的量子程序;
QCircuit CreateEmptyCircuit ();
函数CreateEmptyCircuit的返回值数据类型是QCircuit类,该类是量子线路的容器,开发者可向QCircuit中添加QGate。
类QCircuit的用户API如下所示
class QCircuit
{
public:
    QCircuit & operator << (QMeasure );
    QCircuit & operator << ( QCircuit );
};
                            
成员函数QCircuit & operator << ( QMeasure)的作用是把QMeasure添加到容器QCircuit的尾部;
成员函数QCircuit & operator << ( QCircuit)的作用是把QCircuit添加到容器QCircuit的尾部。

5.函数Measure

函数Measure的作用是创建测量目标量子比特的逻辑门。
QMeasure Measure(Qubit * targetQuBit, CBit * targetCbit);
函数Measure的输入参数分别为:目标量子比特targetQuBit和目标经典寄存器targetCbit;

6.函数RX

函数RX的作用是创建针对目标量子比特的RX逻辑门操作。 函数RX分为两种:不包含旋转角度的RX门操作;
extern QGate & RX(Qubit* qbit);
包含旋转角度的RX门操作。
extern QGate & RX(Qubit*, double angle);

7.函数RY

函数RY的作用是创建针对目标量子比特的RY逻辑门操作。 函数RY分为两种:不包含旋转角度的RY门操作; extern QGate & RY (Qubit* qbit);
包含旋转角度的RY门操作。
extern QGate & RY (Qubit*, double angle);
### 函数RZ 函数RZ的作用是创建针对目标量子比特的RZ逻辑门操作。
函数RZ分为两种:不包含旋转角度的RZ门操作;
extern QGate & RZ (Qubit* qbit);
包含旋转角度的RZ门操作。
extern QGate & RZ (Qubit*, double angle);

8.函数S

函数S的作用是创建针对目标量子比特的S逻辑门操作。
QGate & RZ (Qubit* qbit);

9.函数H

函数H的作用是创建针对目标量子比特的Hadamard逻辑门操作。
QGate & H (Qubit* qbit);

10.函数CNOT

函数CNOT的作用是创建包含目标量子比特和控制量子比特的CNOT逻辑门操作。
QGate & CNOT(Qubit * targetQBit, Qubit * controlQBit);

11.函数CZ

函数CZ的作用是创建包含目标量子比特和控制量子比特的CZ逻辑门操作。
QGate & CZ(Qubit * targetQBit, Qubit * controlQBit);

12.函数QSingle

函数QSingle的作用是创建包含目标量子比特、全局相位、三个旋转门角度的单比特逻辑门操作。
QGate & QSingle(double alpha, double beta, double gamma, double delta, Qubit *);

13.函数QDouble

函数QDoubles的作用是创建包含目标量子比特、全局相位、三个旋转门角度的双比特逻辑门操作。
QGate & QDouble(double alpha, double beta, double gamma, double delta, Qubit *, Qubit *);

14.函数init

函数init的作用是初始化系统化环境
void init();

15.函数finalize

函数finalize的作用是释放化系统化环境
void finalize ();

16.函数qAlloc

函数qAlloc的作用是申请量子比特,返回值类型是量子比特类指针。
Qubit * qAlloc()

17.函数cAlloc

函数cAlloc的作用是申请经典寄存器,返回值类型是经典寄存器类指针。
CBit * cAlloc()

18.函数qFree

函数qFree的作用是释放量子比特,输入值类型为量子比特指针。
void qFree(Qubit * q)

19.函数cFree

函数cFree的作用是释放经典寄存器,输入值类型是经典寄存器类指针。
void cFree(CBit * c);

20.函数load

函数load的作用是加载量子程序,输入值类型是QProg。
void load(QProg & q)

21.函数append

函数append的作用是追加量子程序,输入值类型是QProg。
void append(QProg & q);

22.函数getstat

函数getstat的作用是获取量子芯片(量子虚拟机)状态,返回值类型是QuantumMachine类型指针。
QMachineStatus* getstat();

23.函数bind_a_cbit

函数bind_a_cbit的作用是根据CBit类型指针创建一个条件判断表达式节点。
ClassicalCondition bind_a_cbit(CBit * c);

24.函数run

函数run的作用是运行量子程序。
void run();

25.函数getResultMap

函数getResultMap的作用是获取量子程序结果,返回值类型为Map<string,bool>。
map getResultMap();

26.函数getResultMap

函数getCBitValue的作用是获取经典寄存器的值,输入值类型为经典寄存器指针,返回值类型为bool。
bool getCBitValue(CBit* cbit);

27.函数countQGateUnderQCircuit

函数countQGateUnderQCircuit的作用是获取量子线路下逻辑门的个数,输入值为量子线路指针,返回值为量子逻辑门的个数。函数如下所示:
size_t countQGateUnderQCircuit(AbstractQuantumCircuit *);

28.函数CreateHadamardQCircuit

函数CreateHadamardQCircuit的作用是产生一个针对所有输入量子比特进行Hadamard门操作的量子线路,输入值为量子比特的vector,返回值是一个量子线路,函数如下所示:
HadamardQCircuit CreateHadamardQCircuit(vector<Qubit *> & pQubitVector);

XML配置文档说明

XML配置文档有两种,一种是项目配置文档,一种是元数据配置文档;

1. 项目配置文档

程序配置文档的作用是配置项目中通过工厂生成的实例化类的类型、配置元数据XML的路径,如图所示:
程序配置文档分为两大部分:ClassNameConfig、MetadataPath; 配置文件如图所示:

ClassNameConfig

ClassNameConfig的作用是配置通过工厂生成的实例化类的类型;
ClassNameConfig子节点分为:QProg、QCircuit、QIfProg、QWhileProg、QMeasure、QuantumMachine、QubitPool、Qubit、PhysicalQubit、CBit、CMem、QResult、CExpr。
QProg节点的作用是保存量子程序实例化类的类型;
QCircuit节点的作用是保存量子线路实例化类的类型;
QWhileProg节点的作用是保存量子循环控制流实例化类的类型;
QIfProg节点的作用是保存量子条件判断控制流实例化类的类型;
QMeasure节点的作用是保存测量逻辑门实例化类的类型;
QuantumMachine节点的作用是保存量子机器实例化类的类型;
QubitPool节点的作用是保存量子比特池实例化类的类型;
Qubit节点的作用是保存量子比特实例化类的类型;
PhysicalQubit节点的作用是保存物理量子比特实例化类的类型;
CBit节点的作用是保存经典寄存器实例化类的类型;
CMem节点的作用是保存经典寄存器池实例化类的类型;
QResult节点的作用是保存量子程序测量结果实例化类的类型;
CExpr节点的作用是保存量子判断条件节点实例化类的类型;

MetadataPath

MetadataPath的作用是保存Metadata(元数据)XML文件的保存路径;