Skip to content

Latest commit

 

History

History
2591 lines (1839 loc) · 110 KB

附录.md

File metadata and controls

2591 lines (1839 loc) · 110 KB

附录

附录1 量子计算数学基础

附录2 量子编程工具的安装与使用

附录3 量子化学工具的安装与使用

附录1 量子计算数学基础

1.1 概述

​ 对于不具有任何高等数学基础背景的读者,本节将从集合与映射、向量空间、矩阵与矩阵的运算、矩阵的特征、矩阵的函数以及线性算子与矩阵表示等相对简单易懂的数学开始讲起,以便各位循序渐进理解量子计算的数学原理。

1.2 集合与映射

1.2.1 集合的概念

​ 当提到中国古代四大发明时,大家一般会想到造纸术、印刷术、指南针和火药;当提到中国的四大名著时,大家会想起吴承恩的《西游记》、罗贯中的《三国演义》、曹雪芹的《红楼梦》、施耐庵的《水浒传》。生活中有很多类似于四大发明、四大名著的称呼,比如:世界上的所有国家、彩虹的颜色、三原色等等,这些称呼都有一个共同的特点,就是将具有明确地相同特性的事物放在一起的统称。

​ 在数学上,把具有某种特征事物的总体称为集合(set),组成该集合的事物称为该集合的元素(element)^[56,57]^。比如,中国的四大名著,就可以称为一个集合,《西游记》则是其中的一个元素。有时为了方便与简洁,在数学上会引进一些符号来表示一些数学名称,这就使得数学上了一个台阶,当通过练习知道这些符号代表的内在含义时,就很方便地去推导以及交流。

​ 但是这种符号表示的简化也为后来学习者或多或少带来了一些障碍。因为当没有介绍过某个概念,突然看到一个符号表示,智力再好也不可能知道它代表的含义。比如世界上第一个人发明“※”表示太阳,但他没有告诉你,这符号“※”表示太阳,而是给你画出这个符号“※”,问你这是什么时,这个问题换着任何人都不可能回答,除非是发明者,因为只有他一个人知道这个符号代表的含义,当人们都开始用这个符号“※”表示太阳时,这就极大地方便人们之间的交流,因为这符号写起来相对简单些。如果过仅有部分人知道,还可以作为密码来使用,从某种意义上来说,数学也是一门符号化的语言。所以,在学习数学的时候,首先要弄明白符号背后的含义是什么。

​ 下面,引进大写的拉丁字母A、B、C等符号来表示集合,用小写的拉丁字母a、b、c等符号表示集合的元素,需要注意的是有的时候拉丁字母不够多或者不方便时,也会引进其他的符号表示元素。比如用B这个符号表示四大名著,用$$b_1$$表示《西游记》、$$b_2$$表示《三国演义》、$$b_3$$表示《红楼梦》、$$b_4$$表示《水浒传》。$$b_1$$是B的元素,在数学上,通常说$$b_1$$属于B,记做$$ {b_1} \in B$$。假设,h表示《海底两万里》,h就不是集合B的元素,就说h不属于B,记做$$ {h} \notin B$$。

​ 像四大名著这样的集合有有限个元素,称为有限集;也可以通过列举法来表示这个集合。例如,可以将C的元素一一列举出来写在大括号里面

$$ C=\left{c_{1}, c_{2}, c_{3}, c_{4}\right} $$

​ 如果遇到像自然数集(自然数组成的集合)有无限多个元素该如何来表示呢?通常称有无限多个元素的集合为无限集,好在自然数集有了0和1,其他的数就都知道了;也可以通过列举法来列举出有限个,其余的用省略号代替。自然数集$$N$$用列举法表示为

$$ N={0,1,2, \cdots, n, \cdots} $$

​ 同样地,用列举法可以表示正整数集(所有正整数组成的集合)

$$ N^{+}={1,2,3, \cdots, n, \cdots} $$

​ 整数集(所有整数组成的集合)

$$ Z={\cdots,-n, \cdots, -2,-1,0,1,2, \cdots, n, \cdots} $$

​ 那像有理数集(所有有理数组成的集合)就不能用列举法来表示了,因为任意两个有理数之间一定还存在有理数(比如这两个有理数之间的中间值)。将有理数的性质描述出来写在大括号中:

$$ Q=\left{q \mid q=\frac{m}{n}, m \in Z, n \in N^{+} \text {且 } m, n \text { 互质 }\right} $$

​ 这种将用元素具有的性质来表示的方法叫描述法。若集合$$A$$由具有某种性质$$\Gamma$$ 的元素$$a$$组成,则描述法的一般形式为

$$ A={a \mid a \text { 具有性质 } \Gamma} $$

同样地,可以用描述法来表示无理数集

$$ P=\left{p \mid p \neq \frac{m}{n}, \forall m \in Z, \forall n \in N^{+} \text {且 } m, n \text { 互质 }\right} $$

其中符号$$\forall$$表示任意的。

​ 同时,也可以用自然语言描述法来描述集合,比如,实数集R是所有有理数和无理数组成的集合。

​ 在量子计算中常常会用到复数集

$$ C=\left{c \mid c=a+b i, a, b \in R, i^{2}=-1\right} $$

其中$$ {c}= {a}+ {bi}$$表示复数(complex number),实部$$a$$和虚部$$b$$都是实数,$$i$$ 在这里表示一个符号并且满足$$i^{2}=-1$$ 。 有时,用有序数对$$(a,b)$$来表示复数$$ {a}+b {i}$$。

​ 两个复数$$c_{1}=a_{1}+b_{1} i$$ 和$$c_{2}=a_{2}+b_{2} i$$ 相等的充要条件是实部和虚部分别对应相等,即 $$ c_{1}=c_{2} \Leftrightarrow a_{1}=a_{2}, b_{1}=b_{2} $$

​ 两个复数$$c_{1}=a_{1}+b_{1} i$$和$$c_{2}=a_{2}+b_{2} i$$ 做和相当于实部和虚部分别对应做和,即

$$ c_{1}+c_{2}=\left(a_{1}+a_{2}\right)+\left(b_{1}+b_{2}\right) i $$

​ 两个复数$$c_{1}=a_{1}+b_{1} i$$和$$c_{2}=a_{2}+b_{2} i$$ 做差相当于实部和虚部分别对应做差,即

$$ c_{1}-c_{2}=\left(a_{1}-a_{2}\right)+\left(b_{1}-b_{2}\right) i $$

​ 两个复数$$c_{1}=a_{1}+b_{1} i$$和$$c_{2}=a_{2}+b_{2} i$$ 乘法被定义为

$$ \begin{aligned} &c_{1} c_{2}=\left(a_{1}+b_{1} i\right)\left(a_{2}+b_{2} i\right) \\ &=a_{1}\left(a_{2}+b_{2} i\right)+b_{1} i\left(a_{2}+b_{2} i\right) \\ &=a_{1} a_{2}+a_{1} b_{2} i+b_{1} i a_{2}+b_{1} b_{2} i^{2} \\ &=a_{1} a_{2}+a_{1} b_{2} i+b_{1} a_{2} i+b_{1} b_{2} i^{2} \end{aligned} $$

因为$$i^{2}=-1$$,因此

$$ \left(a_{1}+b_{1} i\right)\left(a_{2}+b_{2} i\right)=\left(a_{1} a_{2}-b_{1} b_{2}\right)+\left(a_{1} b_{2}+b_{1} a_{2}\right) i $$

比如

$$ \begin{aligned} &(1-2 i)(-3+4 i)=1 \cdot(-3+4 i)+(-2 i)(-3+4 i) \\ &=1 \cdot(-3)+1 \cdot 4 i+(-2 i) \cdot(-3)+(-2 i) \cdot(4 i) \\ &=-3+4 i+6 i+8 \\ &=5+10 i \end{aligned} $$

​ 在给出两个复数除法的定义之前,先定义复数$$c=a+b i$$的复共轭(complex conjugate)为

$$ \bar{c}=a-b i $$

$$ c^{*}=a-b i $$

​ 由复数的乘法,可知

$$ c \bar{c}=(a+b i)(a-b i)=a^{2}+b^{2} $$

那么根据复共轭的定义,两个复数)$$c_{1}=a_{1}+b_{1} i$$ 和$$c_{2}=a_{2}+b_{2} i$$ 除法被定义为

$$ \frac{c_{1}}{c_{2}}=\frac{c_{1} \bar{c}{2}}{c{2} \bar{c}{2}}=\frac{\left(a{1}+b_{1} i\right)\left(a_{2}-b_{2} i\right)}{\left(a_{2}+b_{2} i\right)\left(a_{2}-b_{2} i\right)}=\frac{\left(a_{1} a_{2}+b_{1} b_{2}\right)+\left(b_{1} a_{2}-a_{1} b_{2}\right) i}{a_{2}^{2}+b_{2}^{2}} $$

​ 比如,将$$\frac{1+2 i}{3-4 i}$$写成$$a+b i$$的形式为

$$ \frac{1+2 i}{3-4 i}=\frac{1+2 i}{3-4 i} \cdot \frac{3+4 i}{3+4 i}=\frac{-5+10 i}{3^{2}+4^{2}}=-\frac{1}{5}+\frac{2}{5} i $$

1.2.2 集合的关系

​ 把集合看成一个对象,那么集合之间有什么关系呢?集合是由元素组成,因此还要从元素进行分析。

​ 假设有两个集合$$S_{1}$$和$$S_{2}$$,如果集合$$S_{1}$$的元素都是集合$$S_{2}$$的元素,那么称$$S_{1}$$是$$S_{2}$$的子集,记作$$S_{1} \subseteq S_{2}$$(读作$$S_{1}$$包含于$$S_{2}$$ )或$$S_{2} \supseteq S_{1}$$(读作$$S_{2}$$包含$$S_{1}$$)。比如无理数集就是实数集的子集,因为无理数集中的每一个元素都在实数集中。

​ 如果两个集合中的元素都相同,那么称这两个集合相等,即是说,如果集合$$S_{1}$$与集合$$S_{2}$$互为子集,那么就称集合$$S_{1}$$与$$S_{2}$$相等,记作$$S_{1}=S_{2}$$ 。例如,偶数集$$S_{1}$$ 与集合$$S_{2}={n \mid n % m=0, m \in Z, n \in Z, m=2}$$ 相等。注:这里的%表示取余运算(取余运算是指n除以m得到的余数)。

​ 如果$$S_{1} \subseteq S_{2}$$且$$S_{1} \neq S_{2}$$,那么称$$S_{1}$$是$$S_{2}$$的真子集,记作$$S_{1} \subset S_{2}$$(读作$$S_{1}$$真包含于$$S_{2}$$)或$$S_{1} \subset S_{2}$$(读作$$S_{2}$$ 真包含$$S_{1}$$)。比如,$$Q \subset R$$。

​ 通常,没有元素的集合称为空集,记作$$\varnothing$$。比如,由既是有理数又是无理数的实数为元素组成的集合。

1.2.3 集合的运算

​ 类似于数的运算,集合也有运算规则。由于集合是具有共同特征事物的全体,因此会用到将两个集合 $$S_{1}$$$$S_{2}$$ 共同的部分提取出来,这就是取两个集合的交集。换句话说,由所有既属于 $$S_{1}$$ 又属于 $$S_{2}$$ 的元素组成的集合称为 $$S_{1}$$$$S_{2}$$ 的交集(简称交),记作 $$S_{1} \cap S_{2}$$ 。用描述法表示为

$$ S_{1} \cap S_{2}=\left{\mathrm{s} \mid \mathrm{s} \in S_{1} \text { 且 } \mathrm{s} \in S_{2}\right} $$

​ 比如,有理集 $$Q$$ 与无理数集 $$P$$ 的交集, $$Q \cap P=\varnothing$$.

​ 由所有属于 $$S_{1}$$ 或者属于 $$S_{2}$$ 的元素组成的集合称为 $$S_{1}$$$$S_{2}$$ 的并集 (简称并),记作 $$S_{1} \cup S_{2}$$ ,即

$$ S_{1} \cup S_{2}=\left{s \mid s \in S_{1} \text { 或 } s \in S_{2}\right} $$

​ 比如,有理集 $$Q$$ 与无理数集 $$P$$ 的并集

$$ Q \cup P=\mathrm{R} $$

​ 由所有属于 $$S_{1}$$ 而不属于 $$S_{2}$$ 的元素组成的集合称为 $$S_{1}$$$$S_{2}$$ 的差集(简称差),记作 $$S_{1} \backslash S_{2}$$ ,即

$$ S_{1} \backslash S_{2}=\left{s \mid s \in S_{1} \text { 且 } s \notin S_{2}\right} $$

​ 比如,有理集 $$Q$$ 与无理数集 $$P$$ 的差集

$$ Q \backslash P=Q $$

​ 差集的一种特殊情况:当 $$S_{1}$$ 为所研究问题的最大集合时,所要研究的其他集合 $$S_{2}$$ 都是 $$S_{1}$$ 的子集,称集合 $$S_{1}$$ 为全集,称 $$S_{1} \backslash S_{2}$$$$S_{2}$$ 的补集或余集,记作 $$S_{2}^{c}$$

比如,在复数集 $$C$$ 中,实数集 $$R$$ 的补集为

$$ R^{c}={x \mid x=a+b \cdot i, a \in R, b \in R \text { 且 } b \neq 0} $$

​ 除了集合之间的交、并和差运算之外, 还有一种常用的生成新集合的方式-直积或笛卡尔 (Descartes) 积。设 $$X $$、$$ Y$$ 是任意两个集合, 在集合X中任意取一个元素 $$x$$, 在集合Y中任意取一个元素y, 组成一个有序对 $$(\mathrm{x}$$,$$ \mathrm{y})$$ ,再把这样大的有序对作为新的元素,它们全体组成集合称为集合 $$\mathrm{X}$$ 与集合 $$\mathrm{Y}$$ 的直积,记作 $$X \times Y$$, 即

$$ X \times Y={(x, y) \mid x \in X \text { 且 } y \in Y} $$

​ 比如, $$C \times C={(x, y) \mid x \in C$$,$$ y \in C}$$ 为复平面上全体点的集合, $$C \times C$$ 常记为 $$C^{2}$$

1.2.4 集合的运算法则

​ 类似于数的运算法则,集合也有自己的运算法则。集合的交、并和补运算满足以下法则。

​ 假设有任意的三个集合 $$X $$、$$ Y$$ 、$$ Z $$, 则有以下法则:

​ (1) 交换律 $$X \cup Y=Y \cup X$$, $$\quad X \cap Y=Y \cap X$$;

​ (2) 结合律 $$(X \cup Y) \cup Z=X \cup(Y \cup Z)$$,$$ \quad(X \cap Y) \cap Z=X \cap(Y \cap Z)$$;

​ (3) 分配律 $$(X \cup Y) \cap Z=(X \cap Z) \cup(Y \cap Z)$$,$$(X \cap Y) \cup Z=(X \cup Z) \cap(Y \cup Z)$$;

​ (4) 对偶律 $$(X \cup Y)^{c}=X^{c} \cap Y^{c}$$,$$(X \cap Y)^{c}=X^{c} \cup Y^{c}$$.

​ 若对这些规则的证明感兴趣, 可以通过集合相等的定义来证明。

1.2.5 映射

​ 上面讲述了集合, 然而有的集合之间并不是完全孤立的,而是有对应关系的。比如,中国四大名著的作者组成的集合A与四大名著B之间存在对应关系。

​ 将这种普遍的共性抽象出来,设$$D$$、$$E$$ 是两个非空集合,如果存在一个对应法则 $$\mathrm{f}$$, 使得对 $$\mathrm{D}$$ 中每个元素 $$x$$, 按照对应法则 $$f$$, 在E中有唯一确定的元素 $$y$$$$x$$ 对应,则称$$f$$为从 $$D$$ 到$$E$$的映射 $$[1$$,$$3]$$, 记作

$$ f: D \rightarrow E $$

其中y称为元素 $$x$$ 在映射 $$f $$下 的像,并记作 $$f(x)$$ ,即 $$y=f(x)$$

​ 而元素$$x$$称为元素$$y$$在映射$$f$$下的一个原像; 集合$$D$$为映射的定义域;集合E称为映射的陪域; $$D$$中所有元素的像所组成的集合称为映射的值域,记作 $$R_{f}$$$$f(D)$$ ,即

$$ R_{f}=f(D)={f(x) \mid x \in D}={y \in E \mid \exists x \in D, f(x)=y} $$

其中符号$$\exists$$表示存在,可以看出,f的值域是f的陪域的子集。

​ 集合D到自身一个映射,通常称为D上的一个变换。集合D到数集E的一个映射,常称为从D到E的函数。

​ 如果映射f与映射g的定义域、陪域、对应法则分别对应相同,那么称这两个映射相等。

​ 映射$$f: D \rightarrow D$$如果把D中每一个元素对应到它自身,即 $$ \forall x \in D,有f(x)=x, $$ 那么称f为恒等映射(或D上的恒等变换),记作$$I_{D}$$。

​ 先后施行映射$$g: \mathrm{S}{1} \rightarrow S{2}$$和$$f: S_{2} \rightarrow S_{3}$$,得到$$S_{1}$$到$$S_{3}$$的一个映射,称为$$f$$与$$g$$的合成(或乘积),记作$$fg$$。即

$$ (f g)(x) \equiv f(g(x)), \forall x \in S_{1} $$

定理 映射的乘法适合结合律。即如果

$$ h: S_{1} \rightarrow S_{2}, g: \mathrm{S}{2} \rightarrow S{3}, f: S_{3} \rightarrow S_{4} $$

那么

$$ f(g h)=(f g) h $$

1.3 向量空间

​ 学习量子计算,要对量子力学有所了解,而量子力学是由希尔伯特空间来描述的,希尔伯特空间又是向量空间,因此首先要来介绍向量空间(vector spaces)^[59-62]^。

​ 向量空间本质上是一个由向量组成的集合,然后引进一些运算规则。那什么是向量呢?向量相对数量来说的,数量是只有大小的量,而向量不仅有大小而且还有方向的量。有时,向量也称为矢量。可以认为向量是数量的一个自然的扩充。

​ 假设有一个数域 $$K$$(集合 $$K$$ 中任意两个元素的和、差、积、商(除数不为0)还属于集合 $$K$$ ,称该集合为数域$K$),自然想到用直积将数域$K$进行扩充,$n$个数域$K$的直积可以表示为

$$ K^{n}=\left{\left(v_{1}, v_{2}, \cdots, v_{n}\right) \mid v_{i} \in K, i=1,2, \cdots, n\right} $$

其中 $$K^{n}$$ 元素 $$\left(v_{1}, v_{2}, \cdots, v_{n}\right)$$ 称为 $$n$$ 维向量,称 $$v_{i}$$ 为其第 $$i$$ 个分量。为了表示方便与统一将带小括号的元素 $$\left(v_{1}, v_{2}, \cdots, v_{n}\right)$$ 记作列向量, 即

$$ \left(v_{1}, v_{2}, \cdots, v_{n}\right):=\left[\begin{array}{c} v_{1} \\ v_{2} \\ \vdots \\ v_{n} \end{array}\right] $$

​ 在数学上,向量常用加粗的小写拉丁字母 $$a, b, c, \ldots$$ 或者带箭头的小写拉丁字母 $$\vec{a}$$,$$\vec{b}$$, $$ \vec{c}$$ ,$$ \ldots$$ 来 表示。而在量子物理上,常用带有狄拉克符号 $$(|*\rangle)$$ 的字母 $$|a\rangle$$,$$|b\rangle$$,$$|c\rangle$$,$$ \ldots$$ 来表示。这里统一采用带 有狄拉克符号的表示方法,即

$$ |v\rangle:=\left(v_{1}, v_{2}, \cdots, v_{n}\right):=\left[\begin{array}{c} v_{1} \\ v_{2} \\ \vdots \\ v_{n} \end{array}\right] $$

​ 两个向量 $$| {u}\rangle$$、$$| {v}\rangle$$ 相等的定义为向量的分量分别对应相等,即

$$ |u\rangle=|v\rangle \Leftrightarrow\left[\begin{array}{c} u_{1} \\ u_{2} \\ \vdots \\ u_{n} \end{array}\right]=\left[\begin{array}{c} v_{1} \\ v_{2} \\ \vdots \\ v_{n} \end{array}\right] \Leftrightarrow u_{1}=v_{1}, u_{2}=v_{2}, \cdots, u_{n}=v_{n} $$

其中 $$\Longleftrightarrow$$ 表示"等价于"。 规定 $$K^{n}$$ 中任意两向量 $$|u\rangle$$、$$|v\rangle$$的加法运算为两向量对应分量分别做普通加法,即 $$ |u\rangle+|v\rangle=\left[\begin{array}{c} u_{1} \ u_{2} \ \vdots \ u_{n} \end{array}\right]+\left[\begin{array}{c} v_{1} \ v_{2} \ \vdots \ v_{n} \end{array}\right]:=\left[\begin{array}{c} u_{1}+v_{1} \ u_{2}+v_{2} \ \vdots \ u_{n}+v_{n} \end{array}\right] $$

​ 规定数量 $$k \in K$$ 与向量 $$|u\rangle \in K^{n}$$ 之间的数乘运算为数量$k$与 $$|u\rangle$$ 的每一个分量分别做普通乘法,即

$$ k|u\rangle:=\left[\begin{array}{c} k u_{1} \\ k u_{2} \\ \vdots \\ k u_{n} \end{array}\right] $$

​ 设 $$V \equiv K^{n}$$ , 根据数域的性质,可以验证,对任意的 $$| {u}\rangle$$,$$| {v}\rangle$$,$$| {w}\rangle \in V$$ ,任意的 $$\alpha, \beta \in K$$ 满足以下运算法 则

​ (1) $$| {u}\rangle+| {v}\rangle=| {v}\rangle+| {u}\rangle$$;(加法交换律)

​ (2) $$ (|u\rangle+|v\rangle)+|w\rangle=|u\rangle+(|v\rangle+|w\rangle)$$; (加法结合律)

​ (3) $$\mathrm{V}$$ 中有一个元素 $$(0,0, \cdots, 0)$$ ,记作 $$|\hat{0}\rangle$$ .它满足 $$ |\hat{0}\rangle+|v\rangle=|v\rangle+|\hat{0}\rangle=|v\rangle, \forall|v\rangle \in V $$

具有该性质的元素 $$|\hat{0}\rangle$$ 称为V的零向量 (zero-vector) ;  

​ (4) 对于 $$|v\rangle \in V$$ 存在 $$\quad|\bar{v}\rangle:=\left[\begin{array}{c}-v_{1} \ -v_{2} \ \vdots \ -v_{n}\end{array}\right] \in V$$, 使得

$$ |v\rangle+|\bar{v}\rangle=|\hat{0}\rangle $$ 具有该性质的元素 $$|\bar{v}\rangle$$ 称为 $$|v\rangle$$ 的负向量 (inverse);

​ (5) $$1|v\rangle=|v\rangle$$, 其中 1 是 $K$的单位元;

​ (6) $$(\alpha \beta)|v\rangle=\alpha(\beta|v\rangle)$$;

​ (7) $$(\alpha+\beta)|v\rangle=\alpha| {v}\rangle+\beta|v\rangle$$;

​ (8) $$\alpha(|u\rangle+|v\rangle)=\alpha|u\rangle+\alpha|v\rangle$$

​ 数域$K$上所有n元有序数组组成的集合 $$K^{n}$$ ,再加上定义在其上的加法运算和数乘运算,以及满足的 8 条运算法则一起,称为数域$K$上的一个n维向量空间。 ​ 在$V$中,可以根据向量的加法运算来定义向量的减法运算为 $$ |u\rangle-|v\rangle:=|u\rangle+|\bar{v}\rangle $$

​ 在$V$上,定义加法运算和数乘运算之后,满足的8条运算法则可以推导出向量空间的一些其他性质:

  性质1: $V$中零向量是唯一的。

  性质2: $V$中每个向量 $$|v\rangle$$ 的负向量是唯一的。

  性质3: $$0|v\rangle=|0\rangle, \forall|v\rangle \in V$$

  性质4: $$\alpha|0\rangle=|0\rangle, \forall \alpha \in K$$

  性质5: 如果 $$\alpha|v\rangle=|0\rangle$$ ,那么 $$\alpha=0$$$$|v\rangle=|0\rangle$$

  性质6: $$(-1)|v\rangle=-|v\rangle, \forall|v\rangle \in V$$

​ 若 $$K^{n}$$ 的一个非空子集 $$U$$ 满足以下两条性质:

  (1) $$| {u}\rangle,| {v}\rangle \in U \Rightarrow| {u}\rangle+| {v}\rangle \in U$$,

  (2) $$| {u}\rangle \in U, k \in K \Rightarrow k| {u}\rangle \in U$$,

则称 $$U$$$$K^{n}$$ 的一个线性子空间,简称为子空间 (subspace)。

1.3.1 线性无关与基

​ 若想研究数域$K$上向量空间$V$的结构特征,根据向量空间的定义,只能从$V$的向量的加法以及数乘这两种运算开始。对于$V$中的一组向量 $$\left{\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \cdots,\left|v_{s}\right\rangle\right}$$ ,数域$K$中的一组元素 $$\left{\alpha_{1}, \alpha_{2}, \cdots, \alpha_{s}\right}$$ ,作数乘和加法得到

$$ \alpha_{1}\left|v_{1}\right\rangle+\alpha_{2}\left|v_{2}\right\rangle+\cdots+\alpha_{s}\left|v_{s}\right\rangle $$

​ 根据$V$中加法和数乘的封闭性, $$\alpha_{1}\left|v_{1}\right\rangle+\alpha_{2}\left|v_{2}\right\rangle+\cdots+\alpha_{s}\left|v_{s}\right\rangle$$ 还是V中的一个向量, 称该向量是 $$\left{\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \cdots,\left|v_{s}\right\rangle\right}$$ 一个线性组合 (linear combination), $$\left{\alpha_{1}, \alpha_{2}, \cdots, \alpha_{s}\right}$$ 称为系数。

​ 为了方便,像 $$\left{\ v_{1}, \ v_{2}, \cdots, \ v_{s}\right}$$ 这样按照一定顺序写出的有限多个向量称为 $$V$$ 的一个向量组。

​ 如果 $V$中的一个向量 $$| {u}\rangle$$ 可以表示成向量组 $$\left{\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \cdots,\left|v_{s}\right\rangle\right}$$ 的一个线性组合, 即 $$ |u\rangle=\sum_{i=1}^{s} \alpha_{i}\left|v_{i}\right\rangle $$

那么称 $$| {u}\rangle$$ 可以由向量组 $$\left{\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \cdots,\left|v_{s}\right\rangle\right}$$ 线性表示(或线性表出)。

​ 若向量组 $$\left{\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \cdots,\left|v_{s}\right\rangle\right}$$ 中至少存在一个向量可以由除自身外的其他向量线性表示, 则称这组向量线性相关 (linearly dependent)。否则, 向量组 $$\left{\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \cdots,\left|v_{s}\right\rangle\right}$$ 中任意一个向量都不可以由其他向量线性表示,则称这组向量线性无关 (linearly independent)。

​ 若向量空间V中的任意向量都可以由向量组 $$\left{\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \cdots,\left|v_{s}\right\rangle\right}$$ 线性表示, 则称该向量组为向量空间$V$的生成集 (spanning set)。

​ 线性无关的生成集称为极小生成集。向量空间的极小生成集定义为向量空间的基,极小生成集中向量的个数定义为向量空间的维数。比如,当数域 $$K$$ 为复数域 C时,向量空间 $$C^{2}$$ 的基为由向量 $$ \left|b_{1}\right\rangle:=\left[\begin{array}{l} 1 \ 0 \end{array}\right], \quad\left|b_{2}\right\rangle=\left[\begin{array}{l} 0 \ 1 \end{array}\right] $$

组成的集合。 因为向量空间 $$C^{2}$$ 中的任意向量 $$ |u\rangle=\left[\begin{array}{l}u_{1} \u_{2}\end{array}\right] $$

都可以写成向量组 $$\left{\left|b_{1}\right\rangle,\left|b_{2}\right\rangle\right}$$ 的线性组合,即

$$ |u\rangle=u_{1}\left|b_{1}\right\rangle+u_{2}\left|b_{2}\right\rangle $$

并且向量组 $$\left{\left|b_{1}\right\rangle,\left|b_{2}\right\rangle\right}$$ 线性无关。

​ 因此,当知道向量空间的基时,就可以来用它们来线性表示该向量空间中的任意的向量。也可以说这组基张成了这个向量空间。

然而需要注意的是向量空间的基并不唯一。比如,一组向量

$$ \left|b_{1}\right\rangle:=\frac{1}{\sqrt{2}}\left[\begin{array}{l}1 \1\end{array}\right],\left|b_{2}\right\rangle=\frac{1}{\sqrt{2}}\left[\begin{array}{c}1 \-1\end{array}\right] $$

就可以作为向量空间 $$C^{2}$$ 的另一组基。因为向量空间 $$C^{2}$$ 中的任意向量

$$ |u\rangle=\left[\begin{array}{l} u_{1} \\ u_{2} \end{array}\right] $$

可以写成 $$\left|b_{1}\right\rangle$$$$\left|b_{2}\right\rangle$$ 的线性组合

$$ |u\rangle=\frac{u_{1}+u_{2}}{\sqrt{2}}\left|b_{1}\right\rangle+\frac{u_{1}-u_{2}}{\sqrt{2}}\left|b_{2}\right\rangle $$

​ 假设给定 $$n$$ 维向量空间 V的基 $$\left{\left|b_{1}\right\rangle,\left|b_{2}\right\rangle, \cdots,\left|b_{n}\right\rangle\right}$$ 和任意向量 $$|u\rangle$$, 该向量都可以由该基线性表示,即

$$ |u\rangle=\alpha_{1}\left|b_{1}\right\rangle+\alpha_{2}\left|b_{2}\right\rangle+\cdots+\alpha_{n}\left|b_{n}\right\rangle $$

​ 将 $$|u\rangle$$ 在该基 $$\left{\left|b_{1}\right\rangle,\left|b_{2}\right\rangle, \cdots,\left|b_{n}\right\rangle\right}$$ 下的系数称为 $$|u\rangle$$ 在该基下的坐标表示, 可以写成列向量的形式,即

$$ |u\rangle=\left[\begin{array}{c} \alpha_{1} \\ \alpha_{2} \\ \vdots \\ \alpha_{n} \end{array}\right] $$

​ 从二维复向量空间的例子可以看出,同一个向量在不同的基下有着不同的坐标表示。

定理$$\mathrm{n}$$ 维向量空间中, 给定一个基, 向量空间中的任意向量的坐标表示是唯一的。

证明$$\left{\left|b_{1}\right\rangle,\left|b_{2}\right\rangle, \cdots,\left|b_{n}\right\rangle\right}$$ 为n维向量空间的一个基,根据基的定义,任意向量 $$|u\rangle$$ 都可以由这组基线性表示,即 $$ |u\rangle=\alpha_{1}\left|b_{1}\right\rangle+\alpha_{2}\left|b_{2}\right\rangle+\cdots+\alpha_{n}\left|b_{n}\right\rangle $$

假设 $$| {u}\rangle$$ 在该基下的坐标表示是不唯一的,因此,存在另一种线性表示方式,即

$$ |u\rangle=\bar{\alpha}{1}\left|b{1}\right\rangle+\bar{\alpha}{2}\left|b{2}\right\rangle+\cdots+\bar{\alpha}{n}\left|b{n}\right\rangle $$

将这两个不同的坐标表示的向量做差,得到

$$ |u\rangle-|u\rangle=\left(\alpha_{1}-\bar{\alpha}{1}\right)\left|b{1}\right\rangle+\left(\alpha_{2}-\bar{\alpha}{2}\right)\left|b{2}\right\rangle+\cdots+\left(\alpha_{n}-\bar{\alpha}{n}\right)\left|b{n}\right\rangle $$

$$ |\hat{0}\rangle=\left(\alpha_{1}-\bar{\alpha}{1}\right)\left|b{1}\right\rangle+\left(\alpha_{2}-\bar{\alpha}{2}\right)\left|b{2}\right\rangle+\cdots+\left(\alpha_{n}-\bar{\alpha}{n}\right)\left|b{n}\right\rangle $$

​ 因为基是线性无关的,所以有

$$ \alpha_{i}-\bar{\alpha}_{i}=0, i=1,2, \cdots, n $$

$$ \alpha_{i}=\bar{\alpha}_{i}, i=1,2, \cdots, n $$

​ 从而假设不成立,因此在给定基下,任意给定向量的坐标表示唯一。

1.3.2 向量的内积

​ 向量的内积是一个从向量空间 $$V \times V$$ 到数域K的一个映射 $$(-,-)$$, 并满足以下性质:

​ (1)映射 $$(-,-)$$ 对第二项是线性的,即

$$ \left(|u\rangle, \sum_{i} \lambda_{i}\left|v_{i}\right\rangle\right)=\sum_{i} \lambda_{i}\left(|u\rangle,\left|v_{i}\right\rangle\right) $$

​ (2)交换共轭性,即

$$ (|u\rangle,|v\rangle)=(|v\rangle,|u\rangle)^{*} $$

​ (3)自内积非负性,即

$$ (|v\rangle,|v\rangle) \geq 0 $$

等号成立当且仅当 $$|v\rangle$$ 为零向量 $$|\hat{0}\rangle$$ 。 比如 ,在 $$\mathrm{n}$$ 维复向量空间中,定义内积为 $$ (|u\rangle,|v\rangle):=\sum_{i} u_{i}^{*} v_{i} $$

其中

$$ |u\rangle=\left[\begin{array}{c} u_{1} \\ u_{2} \\ \vdots \\ u_{n} \end{array}\right],|v\rangle=\left[\begin{array}{c} v_{1} \\ v_{2} \\ \vdots \\ v_{n} \end{array}\right] $$

​ 在量子力学中,内积 $$(|u\rangle,|v\rangle)$$ 的标准符号为 $$\langle u \mid v\rangle$$ ,即

$$ \langle u \mid v\rangle :=(|u\rangle,|v\rangle) $$

这里 $$| {u}\rangle,| {v}\rangle$$ 均为内积空间中的向量,符号 $$\langle u|$$ 表示向量 $$| {u}\rangle$$ 的对偶向量 (dual vector),

$$ \langle u|:=\left[u_{1}^{}, u_{2}^{}, \cdots, u_{n}^{*}\right] $$

​ 将拥有内积的空间称为内积空间(inner product space)。量子力学中常提到希尔伯特空间(Hilbert space),在有限维的情况下,希尔伯特空间与内积空间是一致的。无限维的情况,这里不加考虑。

​ 若向量 $$| {u}\rangle$$ 和向量 $$| {v}\rangle$$ 的内积为 0 ,则称这两个向量正交 (orthogonal) 。比如,向量 $$| {u}\rangle \equiv(1$$,$$0)$$,$$|v\rangle \equiv(0$$,$$1) $$, 根据上面复向量空间内积的定义,可得 $$ \langle u \mid v\rangle=1 \times 0+0 \times 1=0 $$ 故 $$| {u}\rangle$$,$$| {v}\rangle$$ 两向量正交。

​ 向量 $$|v\rangle$$ 的模 (norm) 定义为 $$ || v\rangle |:=\sqrt{\langle v \mid v\rangle} $$

​ 若向量 $$| {v}\rangle$$ 满足 $$| v\rangle |=1$$ ,则称该向量为单位向量 (unit vector) 或归一化的 (normalized)。对于任意非零向量 $$| {u}\rangle$$ ,可以通过将该向量除以它的范数得到其 归一化形式,即

$$ \frac{|v\rangle}{|| v\rangle\ |} $$

​ 设 $$\left|b_{1}\right\rangle,\left|b_{2}\right\rangle, \cdots,\left|b_{n}\right\rangle$$ 为向量空间的一组基,满足每一个向量都是单位向量, 并且不同向量的内积为 0 , 即

$$ \left\langle b_{i} \mid b_{j}\right\rangle= \begin{cases}1, & i=j \ 0, & i \neq j\end{cases} $$

则称这组向量为向量空间的标准正交 (orthonormal) 基。

​ 标准正交基能带来很多方便,比如在计算向量的内积时,就可以将向量的坐标对应相乘。

​ 假设知道向量空间的一个非标准正交基 $$\left|u_{1}\right\rangle,\left|u_{2}\right\rangle, \cdots,\left|u_{n}\right\rangle$$ ,那么,可以通过Gram-Schmidt正交化来将非标准正交基转化为标准正交基。具体过程如下, 用向量组 $$\left{\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \cdots,\left|v_{n}\right\rangle\right}$$ 来表示待生成的标准正交基, 首先定义 $$ \left|v_{1}\right\rangle:=\frac{\left|u_{1}\right\rangle}{\mid\mid\left|u_{1}\right\rangle \mid\mid} $$

接着对 $$1 \leq k \leq n-1 $$, 递归地计算并定义

$$ \left|v_{k+1}\right\rangle:=\frac{\left|u_{k+1}\right\rangle-\sum_{i=1}^{k}\left\langle v_{i}\left|u_{k-1}\right\rangle \mid v_{i}\right\rangle}{|\left|u_{k+1}\right\rangle-\sum_{i=1}^{k}\left\langle v_{i} \mid u_{k-1}\right\rangle\left|v_{i}\right\rangle |} $$

​ 在量子计算中,通常,用一组带有指标 $$i$$ 的向量$$\mid i\rangle$$来表示标准正交基。

1.4 矩阵与矩阵的运算

​ 事实上,当提到矩阵时,并不陌生,只是在平时不把它叫做矩阵而已,而通常称作表。比如,一个班级有35名同学,这学期要修6门课程,在本学期期末考试后,为了便于管理和分析,老师将每位同学的各科成绩放在一起,做成一个35行,6列的表。在日常生活或在其他学科中有很多类似的表,将它们的特点进行提取,进而形成数学上的矩阵这样的抽象概念。其实这样的抽象过程也并不陌生,比如自然数的发明就是这样的一个过程。

1.4.1 矩阵的概念

定义1.4.1$$m \cdot n$$ 个数排成 $$m$$ 行、 $$n$$ 列的一张表称为一个 $$m \times n$$ 矩阵[3],其中的每一个数称为这个矩阵的一个元素,第 $$i$$ 行与第 $$j$$ 列交叉位置的元素称 为矩阵的 $$(i, j)$$ 元。如 $$\left[\begin{array}{lll}1 & 2 & 3 \ 4 & 5 & 6\end{array}\right]$$ 或 $$\left(\begin{array}{lll}1 & 2 & 3 \ 4 & 5 & 6\end{array}\right)$$ 都是一个矩阵。

​ 矩阵通常用大写英文字母 $$A$$,$$ B$$,$$ C$$,$$ \ldots$$ 表示。一个 $$m \times n$$ 矩阵可以简单地记作 $$A_{m m}$$ ,它的 $$(i$$,$$ j)$$ 元记作 $$A(i$$ , $$ j)$$ 。如果矩阵 $$A$$$$(i$$, $$j)$$ 元是 $$a_{i j}$$ ,那么可以 记作 $$A=\left[a_{i j}\right]$$$$A=\left(a_{i j}\right)$$

​ 如果某个矩阵 $$A$$ 的行数与列数相等, 则称之为方阵。 $$m$$$$m$$ 列的方阵也称为 $$m$$ 级矩阵。

​ 元素全为 0 的矩阵称为零矩阵,简记作 $$0 $$。$$ m$$ 行 $$n$$ 列的零矩阵可以记成 $$0_{n \times n}$$

​ 数域 $$G$$ 上两个矩阵称为相等,如果它们的行数相等,列数也相等,并且它们所有元素对应相等(即第一个矩阵的 $$(i$$,$$ j)$$ 元等于第二个矩阵的 $$(i$$,$$ j)$$ 元) 。

定义 1.4.2 设矩阵 $$A=\left(a_{i j}\right){m \times n}$$, 若矩阵 $$B=\left(b{i j}\right){n \times m}$$ 满足 $$a{i j}=b_{j i}$$ ,则称矩阵 $$B$$ 为矩阵 $$A$$ 的转置,将其记作 $$A^{T}$$$$A^{\prime}$$ 。一个矩阵 $$A$$ 如果满足 $$A=A^{T}$$, 那么称 $$A$$ 是对称矩阵。

定义 1.4 .3 设 $$ {n}$$ 级矩阵 $$A=\left(a_{i j}\right){n \times n}$$ ,称 $$T=\sum{i=1}^{n} a_{i i}$$ 为矩阵 $$A$$ 的迹,记作 $$\text{tr}(A)$$ 。 ​ 可以验证矩阵的迹有如下性质:

​ (1)$ \begin{aligned} {tr}(A B)=\text{tr}(B A)\end{aligned} $

​ (2)$ \begin{aligned} {tr}(A+B)=\text{tr}(A)+{tr}(B )\end{aligned} $

​ 由矩阵 $$A$$ 的若干行、若干列的交叉位置元素按原来顺序排列成的矩阵称为 $$A$$ 的一个子矩阵。

定义 1.4 .4 把一个矩阵 $$A$$ 的行分成若干组, 列也分成若干组,从而 $$A$$ 被分成若干个子矩阵,把 $$A$$ 看成是由 这些子矩阵组成的,这称为矩阵的分块,这种由子矩阵组成的矩阵称为分块矩阵。

​ 例如矩阵 $$A$$ 可写成分块矩阵的形式: $$ A=\left[\begin{array}{ll} A_{1} & A_{2} \ A_{3} & A_{4} \end{array}\right] $$

从而

$$ A^{T}=\left[\begin{array}{cc} A_{1}^{T} & A_{3}^{T} \\ A_{2}^{T} & A_{4}^{T} \end{array}\right] $$

1.4.2 矩阵的加法与乘法

定义1.4.5$$A=\left(a_{i j}\right), B=\left(b_{i j}\right)$$都是数域$$ G$$上$$ m \times n$$矩阵,令

$$ C=\left(a_{i j}+b_{i j}\right)_{m \times n} $$

则称矩阵 $$C$$ 是矩阵 $$A$$$$B$$ 的和,记作 $$C=A+B$$

定义1.4.6$$A=\left(a_{ij}\right)$$是数域$$G$$上$$m \times n$$矩阵, $$k \in G$$ ,令

$$ M=\left(k a_{i j}\right)_{m \times n} $$

则称矩阵 $$M$$是$$ k$$ 与矩阵 $$A$$ 的数量乘积,记作 $$M=k A$$ 。 8条运算法则:设 $$A$$,$$ B$$,$$ C$$, 都是 $$G$$$$m \times n$$矩阵$$k, l \in G$$, 有: (1) $$A+B=B+A$$

​ (2)$(A+B)+C=A+(B+C)$

​ (3)$A+0=0+A=A$

​ (4)$A+(-A)=(-A)+A=0$

​ (5)$1 A=A$

​ (6)$(k l) A=k(l A)$

​ (7)$(k+l) A=k A+l A$

​ (8)$k(A+B)=k A+k B$

​ 利用负矩阵的概念,可以定义矩阵的减法如下:设 $$A $$、$$ B$$ 都是 $$m \times n$$矩阵,则 $$A-B:=A+(-B)$$

定义1.4.7 设 $$A=\left(a_{i j}\right){m \times n}, B=\left(b{i j}\right)_{n \times s}$$, 令

$$ C=\left(c_{i j}\right)_{m \times s} $$

其中

$$ c_{i j}=a_{i1} b_{1 j}+a_{i2} b_{2 j}+\ldots+a_{i n} b_{n j}=\sum_{k=1}^{n} a_{ik} b_{b j} $$

$$i=1$$,$$2$$,$$ \ldots$$,$$ m $$;$$ j=1$$,$$2$$,$$ \ldots$$,$$ s$$ 。则矩阵 $$C$$ 称为矩阵 $$A$$$$B$$ 的乘积, 记作 $$C=A B$$.

​ 矩阵乘法需要注意以下两点:

​ (1) 只有左矩阵的列数与右矩阵的行数相同的两个矩阵才能相乘;

​ (2) 乘积矩阵的行数等于左矩阵的行数, 乘积矩阵的列数等于右矩阵的列数。

​ 例如设 $$ A=\left(\begin{array}{ll} 1 & 2 \ 3 & 4 \ 5 & 6 \end{array}\right), B=\left(\begin{array}{cc} 7 & 8 \ 9 & 10 \end{array}\right) $$

则:

$$ A B=\left(\begin{array}{cc}25 & 28 \57 & 64 \89 & 100\end{array}\right) $$

​ 矩阵的乘法有下面两条性质:

​ (1) 矩阵的乘法适合结合律,但一般不适合交换律。 ​ 设 $$A=\left(a_{ij}\right){m \times m}, B=\left(b{i j}\right){n \times s}, C=\left(c{i j}\right)_{s \times t}$$, 则 $$(A B) C=A(B C)$$. 一般对矩阵 $$A, B$$ 不成立 $$A B=B A$$ 如 $$ A=\left(\begin{array}{ll} 1 & 1 \end{array}\right), B=\left(\begin{array}{l} 1 \ 1 \end{array}\right), A B=(2), B A=\left(\begin{array}{ll} 1 & 1 \ 1 & 1 \end{array}\right), A B \neq B A $$ ​ 若对矩阵 $$A$$,$$ B$$ 成立 $$A B=B A$$ 则称 $$A$$$$B$$ 可交换。

​ (2)矩阵的乘法适合左分配律,也适合右分配律: $$ A(B+C)=A B+A C,(B+C) D=B D+C D $$

$$n$$级矩阵$$ A=\left(a_{i j}\right)$$中的元素$$ a_{i i}(i=1$$,$$ \ldots$$,$$ n)$$ 称为主对角线上元素。主对角线上元素都是 $$1 $$, 其余元素都是 0 的 $$n$$级矩阵称为$$n$$ 级单位阵,记作 $$I_{n}$$ ,或简记作 $$I$$ 。容易直接计算得

$$ I_{m} A_{m \times n}=A_{m \times n}, A_{m \times n} I_{n}=A_{m \times n} $$

​ 特别地,如果 $$A$$$$n$$ 及矩阵,则

$$ I A=A I=A $$

​ 矩阵的乘法与数量乘法满足下述关系式:

$$ k(A B)=(k A) B=A(k B) $$

​ 矩阵的加法、数量乘法、乘法与矩阵的转置有如下关系:

$$ (A+B)^{\prime}=A^{\prime}+B^{\prime} ;(k A)^{\prime}=k A^{\prime} ;(A B)^{\prime}=B^{\prime} A^{\prime} $$

	**定义 1.4.8** 主对角线以外的元素全为 0 的方阵称为对角矩阵,简记作

$$ \text{diag}\left{d_{1}, d_{2}, \ldots, d_{n}\right} $$

1.4.3 可逆矩阵和矩阵相似

定义 1.4 .9 对于数域 $$G$$ 上的矩阵 $$A$$ ,如果存在数域 $$G$$ 上的矩阵 $$B$$ ,使得 $$ A B=B A=I $$ 那么称 $$A$$ 是可逆矩阵 (或非奇异矩阵) ; 称 $$B$$$$A$$ 的逆矩阵,记作 $$A^{-1}$$

定义 1.4 .10$$A$$$$B$$ 都是数域 $$G$$ 上的 $$n$$ 级矩阵,如果存在数域 $$G$$ 上的一个 $$n$$ 级可逆矩阵 $$P$$ ,使得 $$P^{-1} A P=B$$,那么称 $$A$$$$B$$ 是相似的。

1.5 矩阵的特征

1.5.1 矩阵的特征值与特征向量

定义 1.5.1 设$$A$$是数域$$G$$上的$$n$$级矩阵,如果$$G^n$$中有非零列向量$$| {v}\rangle$$,使得

$$ A|v\rangle=v|v\rangle\text{且}v \in G $$

那么称$$v$$是$$A$$的一个特征值,称$$| {v}\rangle$$是$$A$$的属于特征值$$v$$的一个特征向量。

​ 注意这里数值$$v$$和列向量$$| {v}\rangle$$是两个不同的概念,只不过为了突出它们之间的关系,都采用了$$v$$这个记号。

​ 由线性代数中行列式及线性方程组的知识可知:

$$v$$是$$A$$的一个特征值,$$| {v}\rangle$$是$$A$$的属于特征值$$v$$的一个特征向量

​ $ &\Leftrightarrow A|v\rangle=v|v\rangle,|v\rangle \neq 0, v \in G \$

​ $&\Leftrightarrow(v I-A)|v\rangle=0,|v\rangle \neq 0, v \in G \$

	  $\Leftrightarrow|v I-A|=0|v\rangle \text {是} (v I-A)|v\rangle=0 \text {的一个非零解}, v \in G$

	  $\Leftrightarrow v \text {是多项式} |\lambda I-A| \text {在} G \text{中的一个根},|v\rangle \text{是} (v I-A)|x\rangle=0 \text{的一个非零解} $

​ 此处 $$|\lambda I-A|$$ 称为 $$A$$ 的特征多项式。

​ 设 $$ {v}$$ 是 $$A$$ 的一个特征值,把齐次线性方程组 $$(v I-A)|x\rangle=0$$ 的解空间称为 $$A$$ 的属于 $$v$$ 的特征子空间,其中的全部非零向量就是 $$A$$ 的属于 $$v$$ 的全部特征向量。

定义 1.5.2 如果 $$n$$ 级矩阵 $$A$$ 能够相似于一个对角矩阵,那么称 $$A$$ 可对角化。

定理 1.5.1 数域 $$G$$$$n$$ 级矩阵 $$A$$ 可对角化的充分必要条件是, $$G^{n}$$ 中有 $$n$$ 个线性无关的列向量 $$\left|x_{1}\right\rangle,\left|x_{2}\right\rangle, \ldots,\left|x_{n}\right\rangle$$, 以及 $$G$$ 中有 $$n$$ 个数 $$x_{1}, x_{2}, \ldots, x_{n}$$ (它们之中有些可能相等),使得 $$ A\left|x_{i}\right\rangle=x_{i}\left|x_{i}\right\rangle, i=1,2, \ldots, n $$

这时, 令 $$P=\left(\left|x_{1}\right\rangle,\left|x_{2}\right\rangle, \ldots,\left|x_{n}\right\rangle\right)$$ ,则

$$ P^{-1} A P=\text{diag}\left{x_{1}, x_{2}, \ldots, x_{n}\right} $$

证明$$A$$ 与对角矩阵 $$D=\text{diag}\left{x_{1}, x_{2}, \ldots, x_{n}\right}$$ 相似,其中 $$x_{i} \in G$$,$$ i=1$$,$$2$$,$$ \ldots$$,$$ n$$ 。这等价于存在 $$G$$$$n$$ 级可逆矩阵 $$P=(|x_{1}\rangle$$,$$|x_{2}\rangle$$,$$ \ldots$$,$$|x_{n}\rangle)$$, 使得 $$P^{-1} A P=D$$$$A P=P D $$, 即 $$A(|x_{1}\rangle$$,$$|x_{2}\rangle, \ldots$$,$$|x_{n}\rangle)=(|x_{1}\rangle$$,$$|x_{2}\rangle$$,$$ \ldots$$,$$|x_{n}\rangle) D $$, 即 $$(A|x_{1}\rangle$$, $$A|x_{2}\rangle$$,$$\ldots$$,$$ A|x_{n}\rangle)=(x_{1}|x_{1}\rangle$$,$$ x_{2}|x_{2}\rangle$$, $$\ldots$$, $$x_{n}|x_{n}\rangle)$$ 这等价于 $$G^{n}$$ 中有 $$n$$ 个线性无关的列向量 $$|x_{1}\rangle$$,$$|x_{2}\rangle$$, $$\ldots$$,$$|x_{n}\rangle$$, 使得

$$ A\left|x_{i}\right\rangle=x_{i}\left|x_{i}\right\rangle, i=1,2, \ldots, n $$

​ 证毕。

1.5.2 Hermite矩阵

定义 1.5 .3 若矩阵 $$B$$ 中的每个元素都是矩阵 $$A$$ 中相应元素的共轭,则称矩阵 $$B$$ 是矩阵 $$A$$ 的共轭矩阵,将 $$B$$ 记作 $$A^{*}$$

定义 1.5 .4 若矩阵 $$B$$ 满足 $$B=\left(A^{}\right)^{\prime}$$ ,则把 $$B$$ 记作 $$A^{\dagger}$$ 。若 $$A=A^{\dagger}$$ ,则称 $$A$$ 为Hermite矩阵。如果 $$| {v}\rangle_{\text {是 }}$$ 向量, 那么也记 $$\left(|v\rangle^{}\right)^{\prime}=|v\rangle^{+}:=\langle v|$$ 。

​ 易验证Hermite矩阵有如下性质:

​ (1)对于任意的向量 $$|v\rangle,|w\rangle$$及矩阵$$A$$ ,存在唯一的矩阵 $$A^{\dagger}$$ ,使得 $$ (|v\rangle, A|w\rangle)=\left(A^{\dagger}|v\rangle,|w\rangle\right) $$

​ (2)$$(A B)^{\dagger}=B^{\dagger} A^{\dagger}$$,$$(A|v\rangle)^{\dagger}=\langle v| A^{\dagger}$$,$$\left(A^{\dagger}\right)^{\dagger}=A$$

定义 1.5 .5 矩阵 $$A$$ 称为正规的 (normal),如果 $$A A^{\dagger}=A^{\dagger} A$$

定义 1.5.6 矩阵 $$U$$称为是酉的 (unitary),如果 $$U^{\dagger}$$ $$U=I $$

​ 易看出酉矩阵有如下性质: $$ (U|v\rangle, U|w\rangle)=\left\langle v\left|U^{\dagger} U\right| w\right\rangle=\langle v \mid w\rangle $$

定理 1.5 .2 酉矩阵的所有特征值的模都是 1 。

证明$$U$$是酉矩阵, $$v$$是$$U$$的一个特征值, $$|v \rangle$$是矩阵$$U$$ 的属于特征值 $$v$$的特征向量, 那么有 $$ 0 \neq\langle v \mid v\rangle=\left\langle v\left|U^{\dagger} U\right| v\right\rangle=(U|v\rangle)^{\dagger}(U|v\rangle)=(v|v\rangle)^{\dagger}(v|v\rangle)=v^{*} v\langle v \mid v\rangle $$ 所以$$v^*v=1$$,即$$v$$的模为1。

​ 证毕。

1.5.3 对易式与反对易式

定义 1.5.7 ^[61]^ 设有两个矩阵 $$A, B$$ ,称

$$ [A, B]:=A B-B A $$

$$A$$$$B$$ 之间的对易式 (commutator),若 $$[A, B]=0$$ ,即 $$A B=B A$$ ,则称 $$A$$$$B$$ 是对易的。类似 的,两个矩阵的反对易式 (anti-commutator) 定义为

$$ {A, B}:=A B+B A $$

如果 $${A, B}=0$$ ,即 $$A$$$$B$$ 反对易。

​ 下面几条性质的证明比较简单,请读者自己思考。

​ (1) 若 $$[A, B]=0,{A, B}=0$$ ,且 $$A$$ 可逆,则 $$B$$ 必为 0 。

​ (2)$$[A, B]^{\dagger}=\left[B^{\dagger}, A^{\dagger}\right],[A, B]=-[B, A]$$

​ (3) 设 $$A$$和$$B$$ 都是Hermite的,则 $$i[A, B]$$ 是Hermite的。

​ 下面不加证明地给出同时对角化定理。里面用到了一些线性代数的概念。

定理 1.5.3 (同时对角化定理) 设 $$A$$$$B$$ 是Hermite矩阵, $$[A, B]=0$$ 当且仅当存在一组标准正交基,使 $$A$$和$$B$$ 在这组基下是同时对角的。在这种情况下 $$A$$和$$B$$ 称为可同时对角化。

1.6 矩阵的函数

​ 类似于实数的函数,可以定义矩阵的函数。例如,在实数的多项式函数中只用戴高乐加法和幂运算,也可以类似地定义矩阵地多项式函数,这里的矩阵一般为方阵,因此需要用到幂运算。下面主要介绍矩阵(方阵)的指数函数。

定义 1.6.1 定义 $$e^{A}:=I+A+\frac{A^{2}}{2 !}+\frac{A^{3}}{3 !}+\frac{A^{4}}{4 !}+\ldots$$

​ 这个定义相当于把 $$f(x)=e^{x}$$ 在原点泰勒展开 $$($$ 关于泰勒展开可见于微积分书中内容),然后把矩阵 $$A$$ 带 入泰勒展开式进行运算。如果 $$A=\text{diag}\left{A_{11}, A_{22}, \ldots, A_{mm}\right}$$, 其中 $$A_{i i}$$ 是子矩阵。容易验证: $$ e^{A}=\text{diag}\left{e^{A_{1}}, e^{A_{2}}, \ldots e^{A_{n}}\right} $$

​ 如果 $$A$$ 不是一个对角阵,可以运用线性代数中的酉变换,找到一个酉矩阵 $$U$$使得对角矩阵$$D=\text{diag}\left{D_{11}, D_{22}, \ldots, D_{mm}\right}$$满足$$D=U A U^{\dagger}$$ 。易知 $$A^{n}=U^{\dagger} D^{n} U $$, 从而

$$ e^{A}=U^{\dagger} e^{D} U=U^{\dagger} \text{diag}\left{e^{d_{11}}, e^{D_{22}}, \ldots e^{D_{mm}}\right} U $$

​ 类似于矩阵指数函数的定义,可以定义矩阵的其它函数。把矩阵代入其它函数的泰勒展开式即可。如矩阵的 正弦函数可定义为:

$$ \sin (A):=A-\frac{A^{3}}{3 !}+\frac{A^{5}}{5 !}-\ldots $$

​ 矩阵的余弦函数可定义为:

$$ \cos (A):=I-\frac{A^{2}}{2 !}+\frac{A^{4}}{4 !}-\ldots+(-1)^{n} \frac{A^{2 n}}{(2 n) !}+\ldots $$

​ 下面介绍一个很重要的欧拉公式:

$$ e^{i \theta}=\cos \theta+i \sin \theta $$

​ 这个公式其实是说等式两边的泰勒展式是相等的,下面来验证一下。先给出一些泰勒展式:

$$ \begin{aligned} &e^{\theta}=1+\theta+\frac{\theta^{2}}{2 !}+\frac{\theta^{3}}{3 !}+\ldots+\frac{\theta^{n}}{n !}+\ldots, \\ &\cos \theta=1-\frac{\theta^{2}}{2 !}+\frac{\theta^{4}}{4 !}-\ldots+(-1)^{n} \frac{\theta^{2 n}}{(2 n) !}+\ldots \\ &\sin \theta=\theta-\frac{\theta^{3}}{3 !}+\frac{\theta^{5}}{5 !}-\ldots+(-1)^{n} \frac{\theta^{2 n+1}}{(2 n+1) !}+\ldots \end{aligned} $$

将以上三式代入欧拉公式等式两端,不难验证两端相等。

1.7 线性算子与矩阵表示

1.7.1 线性算子

​ 正比例函数 $$y=k x(k \neq 0)$$ ,即 $$f(x)=k x$$ 。比如,在日常生活中,一斤米k元,买了x斤,就要付给商家 $$\mathrm{kx}$$ 元钱。正比例函数对任意的实数 $$x_{1}$$,$$ x_{2}$$ , $$f\left(x_{1}+x_{2}\right)=k\left(x_{1}+x_{2}\right)=k x_{1}+k x_{2}=f\left(x_{1}\right)+f\left(x_{2}\right)$$; 对 任意的 $$x$$,$$ a$$,有 $$ f(a x)=k(a x)=a(k x)=a f(x)$$ 。这说明正比例函数保持加法运算与数乘运算 $$[4]$$ 。受这类事例启发,给出线性算子的概念。 ​ 如果数域$K$上的向量空 间 $$V \equiv K^{m}$$ 到向量空间 $$W \equiv K^{n}$$ 的一个映射 $$\sigma$$保持加法和数乘运算,即 $$\forall|u\rangle$$,$$| {v}\rangle \in V$$,$$ k \in K$$, 有 $$ \begin{aligned} &\sigma(|u\rangle+|v\rangle)=\sigma(|u\rangle)+\sigma|v\rangle \ &\sigma(k|u\rangle)=k \sigma(|u\rangle) \end{aligned} $$

​ 那么称 $$\sigma$$$$V$$到$$W$$的一个线性算子。

​ 根据线性算子的定义可以验证以下性质: $$ \sigma\left(\sum_{i} a_{i}\left|v_{i}\right\rangle\right)=\sum_{i} a_{i} \sigma\left(\left|v_{i}\right\rangle\right) $$

通常 $$\sigma(|v\rangle)$$简记为$$\sigma|v\rangle$$ 。当定义在向量空间 $$V$$ 上的线性算子 $$\sigma$$时, 意味着$$\sigma$$是从$$V$$ 到 $$V$$ 的一个线性算子。

​ 一个重要的线性算子是向量空间 $$V$$ 上的单位算子 $$I_{v}$$ (identity operator),它将 $$V$$ 中任意向量对应到自身 即

$$ I_{v}|v\rangle \equiv|v\rangle, \forall|v\rangle \in V $$

​ 另一个重要的线性算子是向量空间 V上的零算子0 (zero operator),它将 $$V$$ 中任意向量对应到V中零向量 $$|\hat{0}\rangle$$ , 即

$$ 0|v\rangle \equiv|\hat{0}\rangle, \forall|v\rangle \in V $$

​ 由于线性算子是映射的一种特殊情况,因此线性算子也可以做映射的合成,并满足合成的结合律。

1.7.2 矩阵表示

​ 最直观的理解线性算子的方式就是通过线性算子的矩阵表示 (matrix representations),因为矩阵能有一个 直观的认识 ^[58,60,61,62]^。 ​ 设 $$\sigma: \mathrm{V} \rightarrow \mathrm{W}$$是向量空间 $$V$$到向量空间W的线性算子,选定向量组 $$\left{\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \cdots,\left|v_{n}\right\rangle\right}$$ 为向量空间 $$V$$的一 个基,向量组 $$\left{\left|w_{1}\right\rangle,\left|w_{2}\right\rangle, \cdots,\left|w_{m}\right\rangle\right}$$ 为向量空间 $$W$$ 的一个基,由于向量空间$$V$$中的任意向量 $$|v\rangle$$ 都可以由基 $$\left{\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \cdots,\left|v_{n}\right\rangle\right}$$线性表示, 根据线性算子的保持加法和数乘的性质,只要确定$$\sigma$$作用在基$$\left{\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \cdots,\left|v_{n}\right\rangle\right}$$上的像,从而也就确定了线性算子$$\sigma$$作用在任意向量 $$| {v}\rangle$$上的像。

​ 根据线性算子的定义可知,线性算子本质上是两个向量空间之间的映射,而映射表示一种对应关系。如果确 定空间V中每一个 $$|v\rangle$$在映射作用到向量空间W中的像,也就确定从向量空间V到向量空间W的对应关系,即 线性算子 $$\sigma: V \rightarrow W$$也就被确定。

​ 而$V$中的每个元素都能被V中的基线性表示,因此将线性算子 $$\sigma$$作用在基的每一个元素上面,得到W中的像 $$\sigma\left|v_{1}\right\rangle, \sigma\left|v_{2}\right\rangle, \cdots, \sigma\left|v_{n}\right\rangle$$都确定,从而基的线性表示的像也被确定,那么线性算子也就被确定。

​ 由于 $$\sigma\left|v_{j}\right\rangle, j=1,2, \cdots, n$$是W中的元素,因此可以由W中的基 $$\left{\left|w_{1}\right\rangle,\left|w_{2}\right\rangle, \cdots,\left|w_{m}\right\rangle\right}$$来线性表示, 即 $$ \sigma\left|v_{j}\right\rangle=a_{1 j}\left|w_{1}\right\rangle+a_{2 j}\left|w_{2}\right\rangle+\cdots+a_{m j}\left|w_{m}\right\rangle=\sum_{i=1}^{m} a_{i j}\left|w_{i}\right\rangle $$

写成矩阵的形式

$$ \left[\sigma\left|v_{1}\right\rangle, \sigma\left|v_{2}\right\rangle, \cdots, \sigma\left|v_{n}\right\rangle\right]=\left[\left|w_{1}\right\rangle, \quad\left|w_{2}\right\rangle, \quad \cdots \quad,\left|w_{m}\right\rangle\right]\left[\begin{array}{cccc} a_{11} & a_{12} & \cdots & a_{1 n} \ a_{21} & a_{22} & \cdots & a_{2 n} \ \vdots & \vdots & \ddots & \vdots \ a_{m 1} & a_{m 2} & \ldots & a_{m n} \end{array}\right] $$ 把上式右端的 $$m \times n$$矩阵记作$$A$$, 称 $$A$$ 是线性算子 $$\sigma$$在$$V$$的基$$\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \ldots,\left|v_{n}\right\rangle$$和$$W$$的基 $$\left|w_{1}\right\rangle,\left|w_{2}\right\rangle, \cdots,\left|w_{m}\right\rangle$$下的矩阵表示(matrix representation) 。

​ 因此,对于给定基下的线性算子都可以找到与之对应的矩阵。并且这种矩阵表示方式是唯一的。

​ 根据矩阵的运算法则以及线性算子的定义,也可以验证矩阵是一个线性算子。因此,在给定向量空间的基 下,线性算子与矩阵作用在同一向量空间上是等价的。

​ 设 $$\sigma$$是域 $$G$$上$$n$$ 维线性空间 $$V$$$$m$$维线性空间$$W$$ 的一个线性算子,它在 $$V$$ 下的一个基 $$\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \ldots,\left|v_{n}\right\rangle$$和$$W$$的一个基 $$\left|w_{1}\right\rangle,\left|w_{2}\right\rangle, \cdots,\left|w_{m}\right\rangle$$下的矩阵为$$A$$, $$V$$中向量$$|v\rangle$$在基 $$\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \ldots,\left|v_{n}\right\rangle$$下的坐标为 $$X$$ ,则有: $$ \begin{aligned} &\sigma|v\rangle=\sigma\left[\left(\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \ldots,\left|v_{n}\right\rangle\right) X\right]=\left[\sigma\left(\left|v_{1}\right\rangle,\left|v_{2}\right\rangle, \ldots,\left|v_{n}\right\rangle\right)\right] X=\left[\left(\left|w_{1}\right\rangle,\left|w_{2}\right\rangle, \ldots,\left|w_{m}\right\rangle\right) A\right] X_{=} \ &\left(\left|w_{1}\right\rangle,\left|w_{2}\right\rangle, \ldots,\left|w_{m}\right\rangle\right)(A X) \end{aligned} $$ 因此 $$\sigma|v\rangle$$在$$W$$的一个基 $$\left|w_{1}\right\rangle,\left|w_{2}\right\rangle, \cdots,\left|w_{m}\right\rangle$$下的坐标为 $$A X$$

​ 线性算子作用于向量空间中的元素所得到的新元素的坐标,实际上就是矩阵乘以向量空间中的元素的坐标。 因此前文矩阵的性质也对应于线性算子的性质。

​ 根据线性算子的定义,可以将向量空间$V$中,两向量 $$| {u}\rangle$$和$$| {v}\rangle$$的内积中的对偶 $$\left\langle {u} \right|$$也可以看作从向量空间 $V$到复数域$C$的线性算子,即 $$ \langle u|(|v\rangle)=\langle u \mid v\rangle=(|u\rangle,|v\rangle)=\sum_{i=1}^{n} u_{i}^{} v_{i}=\left[\begin{array}{lll} u_{1}^{} & \cdots & u_{n}^{*} \end{array}\right]\left[\begin{array}{c} v_{1} \ \vdots \ v_{n} \end{array}\right] $$

​ 而线性算子 $$\left\langle u\right|$$在向量空间$V$中标准正交基下的矩阵表示为1乘n的矩阵 $$\left[\begin{array}{lll}u_{1}^{} & \cdots & u_{n}^{}\end{array}\right] $$ 。

1.7.3 向量外积

​ 一个n维向量可以看作一个1乘n或n乘1的矩阵,反过来,m乘n的矩阵可不可以看作一个向量呢? 本质上向量 和矩阵是一样的,只不过人们在不同的情况下,运用不同的表示方式。类比向量,矩阵的基又是什么呢? 矩 阵是一个线性映射,在给定基下,线性算子与矩阵等价,向量空间中的基与矩阵表示又有什么关系呢?

​ 基于以上的疑问,下面引进向量外积的概念^[61]^。假设 $$| {v}\rangle | {w}\rangle $$是m维内积空间$$W$$ 中的向量,定义 $$| {v}\rangle\left\langle {w}\right|$$是从V到W的线性算子,并且满足运算规则。 $$ (|w\rangle\langle v|)(|\tilde{v}\rangle):=|w\rangle(\langle v \mid \tilde{v}\rangle)=\langle v \mid \tilde{v}\rangle|w\rangle $$

这里借助于内积的运算定义了外积。

​ 设在给定标准正价基下,向量 $$|v\rangle,|w\rangle$$的坐标表示分别为 $$ |v\rangle=\left[\begin{array}{c} v_{1} \ v_{2} \ \vdots \ v_{n} \end{array}\right],|w\rangle=\left[\begin{array}{c} w_{1} \ w_{2} \ \vdots \ w_{m} \end{array}\right] $$

从而线性算子 $$| {w}\rangle\left\langle\left. {v}\right|\right.$$的矩阵表示为

$$ |w\rangle\langle v|=\left[\begin{array}{c}w_{1} \w_{2} \\vdots \w_{m}\end{array}\right]\left[\begin{array}{llll}v_{1}^{} & v_{2}^{} & \cdots & v_{n}^{}\end{array}\right]=\left[\begin{array}{cccc}w_{1} v_{1}^{} & w_{1} v_{2}^{} & \cdots & w_{1} v_{n}^{} \w_{2} v_{1}^{} & w_{2} v_{2}^{} & \cdots & w_{2} v_{n}^{} \\vdots & \vdots & \ddots & \vdots \w_{m} v_{1}^{} & w_{m} v_{2}^{} & \cdots & w_{m} v_{n}^{}\end{array}\right] \text {. } $$

可以看出,在给定标准正交基下,线性算子 $$|w\rangle\left\langle\left. v\right| \right. $$的矩阵表示为向量$$\mid {w}\rangle$$的坐标表示与 $$| {v}\rangle$$的对偶向量的坐标表示的矩阵乘法得到。

1.7.4 对角表示

​ 向量空间$V$上的线性算子$A$的对角表示 (diagonal representation) ^[60,61]^ 是指$A$可以表示成

$$ A=\sum_{i} \lambda_{\rho}|i\rangle\langle i| $$

其中向量 $$|i\rangle$$ 为线性算子A的属于特征值$$\lambda_{i}$$ 的标准正交化的特征向量。

​ 若一个线性算子有对角表示,则该线性算子一定可对角化的 (diagonalizable)。比如,Pauli Z矩阵有对角表示 $$ Z=\left[\begin{array}{cc} 1 & 0 \ 0 & -1 \end{array}\right]=1 \cdot|0\rangle\langle 0|+(-1) \cdot| 1\rangle\langle 1| $$

而线性算子可对角化,不一定有对角表示。

​ 比如,矩阵 $$ \left[\begin{array}{ll} 1 & -2 \ 0 & -1 \end{array}\right] $$

特征值1对应的特征向量为 $$k_{1}\left[\begin{array}{cc}1 & 0\end{array}\right]^{T}$$ ,特征值-1对应的特征向量为 $$k_{2}\left[\begin{array}{cc}1 & 1\end{array}\right]^{T}$$ ,这两个特征向量并不正交, 因此不可以对角表示。

​ 而矩阵 $$ \left[\begin{array}{ll} 1 & 0 \ 1 & 1 \end{array}\right] $$

是不可对角化的。

定理 向量空间V上任意线性算子A是正规算子的充要条件是在 $$V$$ 的某个标准正交基下, 线性算子A有对角表示。

1.7.5 投影算子

​ 假设 $$U$$$$n$$ 维向量空间 $$V$$ 的$k$维子空间,可以从$V$标准正交基中找到 $$k$$ 维子空间 $$U$$ 的标准正交基并标记为 $$|1\rangle, \cdots|k\rangle$$ ,定义

$$ P:=\sum_{i=1}^{k}|i\rangle\langle i| $$

为子空间W上的投影算子 (projector) ^[61]^。定义

$$ Q:=\sum_{i=k+1}^{n}|i\rangle\langle i| $$

为投影算子P的正交补 (orthogonal complement )。可以验证

$$ P+Q=I $$

定理 对于任意投影 $$P$$ ,满足 $$P^{2}=P$$

证明

$$P^{2}=\left(\sum_{i=1}^{k}|i\rangle\langle i|\right)^{2}=\sum_{i, j=1}^{k}|i\rangle\langle i \mid j\rangle\langle j|$$

因为

$$\langle i \mid j\rangle=\delta_{i j}=\left{\begin{array}{l}1,(i=j) \ 0,(i \neq j)\end{array}\right.$$ $$\sum_{ i, j=1}^{k}|i\rangle\langle i \mid j\rangle\left\langle j\left|=\sum_{i=1}^{k}\right| i\right\rangle\langle i|=P$$, 即 $$P^{2}=P$$

​ 证毕。

附录2 量子编程工具的安装与使用

2.1 QPanda

​ 一种功能齐全,运行高效的量子软件开发工具包。

​ QPanda 2是由本源量子开发的开源量子计算框架,它可以用于构建、运行和优化量子算法。QPanda 2作为本源量子计算系列软件的基础库,为QRunes、Qurator、量子计算服务提供核心部件。

2.1.1 编译环境

​ QPanda 2是以C++为宿主语言,其对系统的环境要求如表附2.1.1:

表附2.1.1 环境要求
软件 版本
CMake >= 3.1
GCC >= 5.0
Python >= 3.6.0

2.1.2 下载QPanda 2

​ 如果在您的系统上已经安装了git, 你可以直接输入以下命令来获取QPanda 2:

$ git clone https://github.com/OriginQ/QPanda 2.git

​ 对于一些为安装git的用户来说,也可以直接通过浏览器去下载QPanda 2, 具体的操作步骤如下:

​ (1)在浏览器中输入 https://github.com/OriginQ/QPanda 2 ,进入网页会看到:

图附2.1.1 Github界面

​ (2)点击 Clone or download 看到界面:

图附2.1.2 Github界面

​ (3)然后点击 Download ZIP, 就会完成QPanda 2的下载。

图附2.1.3 下载

2.1.3 编译

​ 我们支持在Windows、Linux、MacOS下构建QPanda 2。用户可以通过CMake的方式来构建QPanda 2。

​ 1)Windows

​ 在Windows下构建QPanda 2。用户首先需要保证在当前主机下安装了CMake环境和C++编译环境,用户可以通过Visual Studio和MinGW方式编译QPanda 2。

​ (1)使用Visual Studio

​ 这里以Visual Studio 2017为例,使用Visual Studio 2017 编译QPanda 2,只需要安装Visual Studio 2017,并需要在组件中安装CMake组件。安装完成之后,用Visual Studio 2017打开QPanda 2文件夹,即可使用CMake编译QPanda 2。

图附2.1.4 使用CMake编译QPanda 2

​ (2)使用MinGW

​ 使用MinGW编译QPanda 2,需要自行搭建CMake和MinGW环境,用户可自行在网上查询环境搭建教程。(注意: MinGW需要安装64位版本)

​ CMake+MinGW的编译命令如下:

​ ①在QPanda 2根目录下创建build文件夹;

​ ②进入build文件夹,打开cmd;

​ ③由于MinGW对CUDA的支持存在一些问题,所以在编译时需要禁掉CUDA,输入以下命令:

1.cmake -G"MinGW Makefiles" -DFIND_CUDA=OFF -DCMAKE_INSTALL_PREFIX=C:/QPanda2 ..  
2.mingw32-make  

​ 2)Linux 和MacOS

​ 在Linux和MacOS下编译QPanda 2,命令是一样的。

​ 编译步骤如下:

​ ①进入QPanda 2根目录;

​ ②输入以下命令:

1.mkdir -p build  
2.cd build  
3.cmake ..  
4.make  

​ 如果有需求,用户通过命令修改QPanda 2的安装路径,配置方法如下所示:

1.mkdir -p build
2.cd build
3.cmake -DCMAKE_INSTALL_PREFIX=/usr/local ..
4.make

2.1.4 安装

​ QPanda 2编译完成后,会以库的形式存在。为了方便调用,大家可以把QPanda 2库安装到指定位置,安装的方式如下所示。

​ 1)Windows

​ (1)使用Visual Studio

​ 同样以Visual Studio 2017为例,在QPanda 2编译完成后,用户可以安装,Visual Studio 2017的安装方式很简单,只需要在Cmake菜单中选择“安装”即可。

图附2.1.5 在Cmake菜单中选择“安装”

​ QPanda 2会安装在用户在CMakeSettings.json中配置的安装目录下。安装成功后会在用户配置的的目录下生成install文件夹,里面安装生成include和lib文件。如果有需求,用户可以在Visual Studio的CMakeSettings.json配置文件修改的安装路径。生成CMakeSettings.json的方法如下图所示:

图附2.1.6 生成CMakeSettings.json的方法

​ 修改QPanda 2的安装路径如下图所示:

图附2.1.7 修改QPanda 2的安装路径

​ 参数修改完成后,cmake选项下执行安装,QPanda 2的lib库文件和include头文件会安装到用户指定的安装位置。(注意:需先进行编译成功后才能进行安装)

​ (2)使用MinGW

​ 在QPanda 2编译完成后,用户可以安装QPanda 2,安装命令如下:

1.mingw32-make install

​ 2)Linux 和MacOS

​ 在Linux和MacOS下安装命令QPanda 2,命令是一样的,安装命令如下:

1.sudo make install

​ 使用不同的平台和不同的IDE在构建C++项目是的方法是不一样的,调用库的方式也不尽相同,大家可以选择用自己的方式调用QPanda 2库, 下面我们以cmake构建项目为例,演示调用QPanda 2库进行量子编程。

​ (1)Visual Studio调用QPanda 2库

​ Visual Studio下调用QPanda 2库的CMakeList的写法为

 1.cmake_minimum_required(VERSION 3.1)  
 2.project(testQPanda)  
 3.SET(CMAKE_INSTALL_PREFIX  "C:/QPanda2") # QPanda2安装的路径  
 4.SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_INSTALL_PREFIX}/lib/cmake")  
 5.  
 6.set(CMAKE_CXX_STANDARD 14)  
 7.set(CMAKE_CXX_STANDARD_REQUIRED ON)  
 8.if (NOT USE_MSVC_RUNTIME_LIBRARY_DLL)  
 9.    foreach (flag  
10.        CMAKE_C_FLAGS  
11.        CMAKE_C_FLAGS_DEBUG  
12.        CMAKE_C_FLAGS_RELEASE  
13.        CMAKE_C_FLAGS_MINSIZEREL  
14.        CMAKE_C_FLAGS_RELWITHDEBINFO  
15.        CMAKE_CXX_FLAGS  
16.        CMAKE_CXX_FLAGS_DEBUG  
17.        CMAKE_CXX_FLAGS_RELEASE  
18.        CMAKE_CXX_FLAGS_MINSIZEREL  
19.        CMAKE_CXX_FLAGS_RELWITHDEBINFO)  
20.  
21.        if (${flag} MATCHES "/MD")  
22.            string(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")  
23.        endif()  
24.        if (${flag} MATCHES "/MDd")  
25.            string(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}")  
26.        endif()  
27.        if (${flag} MATCHES "/W3")  
28.            string(REGEX REPLACE "/W3" "/W0" ${flag} "${${flag}}")  
29.        endif()  
30.    endforeach()  
31.endif()  
32.  
33.set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)  
34.set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)  
35.  
36.find_package(OpenMP)  
37.if(OPENMP_FOUND)  
38.    option(USE_OPENMP "find OpenMP" ON)  
39.    message("OPENMP FOUND")  
40.    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")  
41.    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")  
42.    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")  
43.else(OPENMP_FOUND)  
44.    option(USE_OPENMP "not find OpenMP" OFF)  
45.endif(OPENMP_FOUND)  
46.  
47.find_package(QPANDA REQUIRED)  
48.if (QPANDA_FOUND)  
49.    include_directories(${QPANDA_INCLUDE_DIR})  
50.endif (QPANDA_FOUND)  
51.  
52.add_executable(${PROJECT_NAME} test.cpp)  
53.target_link_libraries(${PROJECT_NAME} ${QPANDA_LIBRARIES})  

​ (2)MinGW调用QPanda 2库

​ MinGW调用QPanda 2库的CMakeList的写法为

 1.cmake_minimum_required(VERSION 3.1)  
 2.project(testQPanda)  
 3.SET(CMAKE_INSTALL_PREFIX  "C:/QPanda2") # QPanda2安装的路径  
 4.SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_INSTALL_PREFIX}/lib/cmake")  
 5.  
 6.  
 7.add_definitions("-w -DGTEST_USE_OWN_TR1_TUPLE=1")  
 8.set(CMAKE_BUILD_TYPE "Release")  
 9.set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -g -ggdb")  
10.set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3")  
11.add_compile_options(-fpermissive)  
12.  
13.set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)  
14.set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)  
15.  
16.find_package(OpenMP)  
17.if(OPENMP_FOUND)  
18.    option(USE_OPENMP "find OpenMP" ON)  
19.    message("OPENMP FOUND")  
20.    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")  
21.    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")  
22.    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")  
23.else(OPENMP_FOUND)  
24.    option(USE_OPENMP "not find OpenMP" OFF)  
25.endif(OPENMP_FOUND)  
26.  
27.find_package(QPANDA REQUIRED)  
28.if (QPANDA_FOUND)  
29.    include_directories(${QPANDA_INCLUDE_DIR})  
30.endif (QPANDA_FOUND)  
31.  
32.add_executable(${PROJECT_NAME} test.cpp)  
33.target_link_libraries(${PROJECT_NAME} ${QPANDA_LIBRARIES})  

​ (3)Linux、MacOS下使用QPanda2

​ Linux、MacOS使用QPanda2的方式是相同的,其CmakeList.txt的写法为:

 1.cmake_minimum_required(VERSION 3.1)  
 2.project(testQPanda)  
 3.SET(CMAKE_INSTALL_PREFIX  "/usr/local") # QPanda2安装的路径  
 4.SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_INSTALL_PREFIX}/lib/cmake")  
 5.  
 6.  
 7.add_definitions("-w -DGTEST_USE_OWN_TR1_TUPLE=1")  
 8.set(CMAKE_BUILD_TYPE "Release")  
 9.set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -g -ggdb")  
10.set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3")  
11.add_compile_options(-fpermissive)  
12.  
13.set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)  
14.set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)  
15.  
16.find_package(OpenMP)  
17.if(OPENMP_FOUND)  
18.    option(USE_OPENMP "find OpenMP" ON)  
19.    message("OPENMP FOUND")  
20.    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")  
21.    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")  
22.    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")  
23.else(OPENMP_FOUND)  
24.    option(USE_OPENMP "not find OpenMP" OFF)  
25.endif(OPENMP_FOUND)  
26.  
27.find_package(QPANDA REQUIRED)  
28.if (QPANDA_FOUND)  
29.    include_directories(${QPANDA_INCLUDE_DIR})  
30.endif (QPANDA_FOUND)  
31.  
32.add_executable(${PROJECT_NAME} test.cpp)  
33.target_link_libraries(${PROJECT_NAME} ${QPANDA_LIBRARIES})  

​ 注解:

​ test.cpp 为使用QPanda2的一个示例。有兴趣的可以试着将其合并在一起形成一个跨平台的CMakeList.txt。

​ 通过一个示例介绍QPanda 2的使用,下面的例子可以在量子计算机中构建量子纠缠态(|00>+|11>),对其进行测量,重复制备1000次。 预期的结果是约有50%的概率使测量结果分别在00或11上。

 1.#include "QPanda.h"  
 2.using namespace QPanda;  
 3.int main()  
 4.{  
 5.    auto qvm = CPUQVM(); 
 6.    auto prog = QProg();  
 7.    auto q = qvm.qAllocMany(2);  
 8.    auto c = qvm.cAllocMany(2);  
 9.    prog << H(q[0])  
10.        << CNOT(q[0],q[1])  
11.        << MeasureAll(q, c);  
12.    auto results = qvm.runWithConfiguration(prog, c, 1000);  
13.    for (auto result : results){  
14.        std::cout << result.first << " : " << result.second << std::endl;  
15.    }  
16.	return 0;
17.}  

​ 编译方式与编译QPanda库的方式基本类似,在这里就不多做赘述。

​ 编译之后的可执行文件会生成在build下的bin文件夹中,进入到bin目录下就可以执行自己编写的量子程序了。

​ 计算结果如下所示:

1.00 : 493
2.11 : 507

2.2 pyQPanda

2.2.1.系统配置和安装

​ 我们通过pybind11工具,以一种直接和简明的方式,对QPanda2中的函数、类进行封装,并且提供了几乎完美的映射功能。 封装部分的代码在QPanda2编译时会生成为动态库,从而可以作为Python的包引入。

2.2.2 系统配置

​ pyqpanda是以C++为宿主语言,其对系统的环境要求如表附2.2.1:

表附2.2.1 环境要求
软件 版本
GCC >= 5.4.0
Python >= 3.6.0

2.2.3 下载pyqpanda

​ 如果你已经安装好了Python环境和pip工具, 在终端或者控制台输入下面命令:

pip install pyqpanda

​ 注解

​ 在linux下若遇到权限问题需要加 sudo

2.3 VQNet

2.3.1 VQNet python包安装

​ 我们提供了Linux,Windows,MacOS上的python预编译包供安装,需要python==3.8。还需要numpy>=1.18.5,pyqpanda>=3.7.8。

pip install pyvqnet

VQNet 测试安装成功

import pyvqnet
from pyvqnet.tensor import *
a = arange(1,25).reshape([2, 3, 4])
print(a)

2.3.2 VQNet 的一个简单例子

​ 这里使用VQNet的经典神经网络模块以及量子模块完成一个机器学习模型的整体流程的例子介绍。该例子参考 Data re-uploading for a universal quantum classifier 。 量子机器学习中的量子计算模块一般有如下几个部分:

​ (1)编码线路(Encoder),用于将经典数据编码到量子数据; (2)可变参数的量子线路(Ansatz),用于训练带参量子门中的参数; (3)测量模块(Measurement),用于检测测量值(也就是某个量子比特的量子态在某些轴上的投影)。

​ 量子计算模块与经典神经网络的运算模块一样是可微分的,是量子经典神经网络混合模型的理论基础。 VQNet支持将量子计算模块与经典计算模块(例如:卷积,池化,全连接层,激活函数等)一起构成混合机器学习模型,提供多种优化算法优化参数。

​ 在量子计算模块,VQNet支持使用本源量子高效的量子软件计算包 pyQPanda 进行量子模块构建。 使用pyQPanda提供的各种常用 量子逻辑门函数接口量子线路接口 , 量子虚拟机函数接口测量函数接口,用户可以快速构建量子计算模块。

​ 接下来的例子我们使用pyQPanda构建了一个量子计算模块。通过VQNet,该量子计算模块可以直接嵌入到混合机器学习模型中进行量子线路参数训练。 本例使用1个量子比特,使用了多个带参数的旋转门 RZ,RY,RZ 对输入x进行编码,并使用 prob_run_dict() 函数观测量子比特的概率测量结果作为输出。

def qdrl_circuit(input,weights,qlist,clist,machine):

        x1 = input.squeeze()
        param1 = weights.squeeze()
        #使用pyqpanda接口构建量子线路实例
        circult = pq.QCircuit()
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RZ门,参数位x1[0]
        circult.insert(pq.RZ(qlist[0], x1[0]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RY门,参数位x1[1]
        circult.insert(pq.RY(qlist[0], x1[1]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RZ门,参数位x1[2]
        circult.insert(pq.RZ(qlist[0], x1[2]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RZ门,参数位param1[0]
        circult.insert(pq.RZ(qlist[0], param1[0]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RY门,参数位param1[1]
        circult.insert(pq.RY(qlist[0], param1[1]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RZ门,参数位param1[2]
        circult.insert(pq.RZ(qlist[0], param1[2]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RZ门,参数位x1[0]
        circult.insert(pq.RZ(qlist[0], x1[0]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RY门,参数位x1[1]
        circult.insert(pq.RY(qlist[0], x1[1]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RZ门,参数位x1[2]
        circult.insert(pq.RZ(qlist[0], x1[2]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RZ门,参数位param1[3]
        circult.insert(pq.RZ(qlist[0], param1[3]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RY门,参数位param1[4]
        circult.insert(pq.RY(qlist[0], param1[4]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RZ门,参数位param1[5]
        circult.insert(pq.RZ(qlist[0], param1[5]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RZ门,参数位x1[0]
        circult.insert(pq.RZ(qlist[0], x1[0]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RY门,参数位x1[1]
        circult.insert(pq.RY(qlist[0], x1[1]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RZ门,参数位x1[2]
        circult.insert(pq.RZ(qlist[0], x1[2]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RZ门,参数位param1[6]
        circult.insert(pq.RZ(qlist[0], param1[6]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RY门,参数位param1[7]
        circult.insert(pq.RY(qlist[0], param1[7]))
        #使用pyqpanda接口在第一个量子比特上插入逻辑门RZ门,参数位param1[8]
        circult.insert(pq.RZ(qlist[0], param1[8]))
        #构建量子程序
        prog = pq.QProg()
        prog.insert(circult)
        #获取概率测量值
        prob = machine.prob_run_dict(prog, qlist, -1)
        prob = list(prob.values())
        return prob

​ 本例子中机器学习的任务是对随机生成的数据根据进行二分类,其中下图是该数据样例,零为圆点,半径为1以内红色的二维点为一类,蓝色的点为另一类。

图附2.3.1 数据样例

​ 训练测试代码流程

#导入必须的库和函数
from pyvqnet.qnn.qdrl.vqnet_model import qdrl_circuit
from pyvqnet.qnn.quantumlayer import QuantumLayer
from pyvqnet.optim import adam
from pyvqnet.nn.loss import CategoricalCrossEntropy
from pyvqnet.tensor import QTensor
import numpy as np
from pyvqnet.nn.module import Module

​ 定义模型Model,其中 init 函数定义内部各个神经网络模块以及量子模块,forward 函数定义前传函数。QuantumLayer 为封装量子计算的抽象类。 您只需将刚才定义的量子计算函数 qdrl_circuit,待训练参数个数 param_num ,运行后端配置 “cpu” , 量子比特数 qbit_num 输入参数,该类就在 VQNet 中自动计算参数梯度。

#待训练参数个数
param_num = 9
#量子计算模块量子比特数
qbit_num  = 1
#定义一个继承于Module的机器学习模型类
class Model(Module):
    def __init__(self):
        super(Model, self).__init__()
        #使用QuantumLayer类,可以把带训练参数的量子线路纳入VQNet的自动微分的训练流程中
        self.pqc = QuantumLayer(qdrl_circuit,param_num,"cpu",qbit_num)
    #定义模型前向函数
    def forward(self, x):
        x = self.pqc(x)
        return x

​ 定义一些训练模型需要的函数

# 随机产生待训练数据的函数
def circle(samples:int,  rads =  np.sqrt(2/np.pi)) :
    data_x, data_y = [], []
    for i in range(samples):
        x = 2*np.random.rand(2) - 1
        y = [0,1]
        if np.linalg.norm(x) < rads:
            y = [1,0]
        data_x.append(x)
        data_y.append(y)
    return np.array(data_x), np.array(data_y)

# 数据载入函数
def get_minibatch_data(x_data, label, batch_size):
    for i in range(0,x_data.shape[0]-batch_size+1,batch_size):
        idxs = slice(i, i + batch_size)
        yield x_data[idxs], label[idxs]

#计算准确率的函数
def get_score(pred, label):
    pred, label = np.array(pred.data), np.array(label.data)
    pred = np.argmax(pred,axis=1)
    score = np.argmax(label,1)
    score = np.sum(pred == score)
    return score

​ VQNet遵循机器学习一般的训练测试流程: 迭代进行载入数据,前传计算,损失函数计算,反向计算,更新参数的操作。

#实例化定义的模型
model = Model()
#定义一个优化器,这里用的是Adam
optimizer = adam.Adam(model.parameters(),lr =0.6)
#定义一个损失函数,这里用的交叉熵损失函数
Closs = CategoricalCrossEntropy()

​ 训练模型部分的函数

def train():

    # 随机产生待训练数据
    x_train, y_train = circle(500)
    x_train = np.hstack((x_train, np.zeros((x_train.shape[0], 1))))
    # 定义每个批次训练的数据个数
    batch_size = 32
    # 最大训练迭代次数
    epoch = 10
    print("start training...........")
    for i in range(epoch):
        model.train()
        accuracy = 0
        count = 0
        loss = 0
        for data, label in get_minibatch_data(x_train, y_train,batch_size):
            # 优化器中缓存梯度清零
            optimizer.zero_grad()
            # 模型前向计算
            output = model(data)
            # 损失函数计算
            losss = Closs(label, output)
            # 损失反向传播
            losss.backward()
            # 优化器参数更新
            optimizer._step()
            # 计算准确率等指标
            accuracy += get_score(output,label)

            loss += losss.item()
            count += batch_size

        print(f"epoch:{i}, train_accuracy:{accuracy/count}")
        print(f"epoch:{i}, train_loss:{loss/count}\n")

​ 验证模型部分的函数

def test():

    batch_size = 1
    model.eval()
    print("start eval...................")
    xtest, y_test = circle(500)
    test_accuracy = 0
    count = 0
    x_test = np.hstack((xtest, np.zeros((xtest.shape[0], 1))))
    predicted_test = []
    for test_data, test_label in get_minibatch_data(x_test,y_test, batch_size):

        test_data, test_label = QTensor(test_data),QTensor(test_label)
        output = model(test_data)
        test_accuracy += get_score(output, test_label)
        count += batch_size

    print(f"test_accuracy:{test_accuracy/count}")

​ 训练测试结果图:

start training...........
epoch:0, train_accuracy:0.6145833333333334
epoch:0, train_loss:0.020432369535168013

epoch:1, train_accuracy:0.6854166666666667
epoch:1, train_loss:0.01872217481335004

epoch:2, train_accuracy:0.8104166666666667
epoch:2, train_loss:0.016634768371780715

epoch:3, train_accuracy:0.7479166666666667
epoch:3, train_loss:0.016975031544764835

epoch:4, train_accuracy:0.7875
epoch:4, train_loss:0.016502128106852372

epoch:5, train_accuracy:0.8083333333333333
epoch:5, train_loss:0.0163204787299037

epoch:6, train_accuracy:0.8083333333333333
epoch:6, train_loss:0.01634311651190122

epoch:7, train_loss:0.016330583145221074

epoch:8, train_accuracy:0.8125
epoch:8, train_loss:0.01629052646458149

epoch:9, train_accuracy:0.8083333333333333
epoch:9, train_loss:0.016270687493185203

start eval...................
test_accuracy:0.826

图附2.3.2 训练测试结果图

2.4 Qurator

​ 一种基于VS Code的量子程序开发工具。

​ qurator-vscode 是本源量子推出的一款可以开发量子程序的 VS Code 插件。其支持 QRunes2 语言量子程序开发,并支持 Python 和 C++ 语言作为经典宿主语言。

​ 在 qurator-vscode 中,量子程序的开发主要分为编写和运行两个部分。

​ ·编写程序:插件支持模块化编程,在不同的模块实现不同的功能,其中量子程序的编写主要在 qcodes 模块中;

​ ·程序运行:即是收集结果的过程,插件支持图表化数据展示,将运行结果更加清晰的展现在您的面前。

2.4.1 设计思想

​ 考虑到目前量子程序的开发离不开经典宿主语言的辅助,qurator-vscode 插件设计时考虑到一下几点:

​ (1)模块编程:

​ qurator-vscode 插件支持模块编程,将整体程序分为三个模块:settings、qcodes 和 script 模块。在不同的模块完成不同的功能。 在 settings 模块中,您可以进行宿主语言类型、编译还是运行等设置;在 qcodes 模块中, 您可以编写 QRunes2 语言程序; 在 script 模块中,您可以编写相应的宿主语言程序。

​ (2)切换简单:

​ qurator-vscode 插件目前支持两种宿主语言,分别为 Python 和 C++。您可以在两种宿主语言之间自由的切换,您只需要在 settings 模块中设置 language 的 类型,就可以在 script 模块中编写对应宿主语言的代码。插件会自动识别您所选择的宿主语言,并在 script 模块中提供相应的辅助功能。

​ (3)图形展示:

​ qurator-vscode 插件提供图形化的结果展示,程序运行后会展示 json 格式的运行结果,您可以点击运行结果,会生成相应的柱状图,方便您对运行结果的分析。

2.4.2 准备工作

​ 使用 qurator-vscode 插件之前需要做一些准备工作,以确保量子程序能够正确的运行。

​ 需要依赖的运行环境有:

​ ·Python (版本 3.6.4 - 3.6.8)

​ ·Pip (版本 10.1 及以上)

​ ·Microsoft Visual C++ Redistributable (Windows)

​ ·MinGw-w64 (Windows 64位版本)

​ 其中,pip 负责下载宿主语言为 Python 时程序运行所依赖的包。Microsoft Visual C++ Redistributable 和 MinGw-w64 是宿主语言为 C++ 时程序运行所依赖的包。

​ (1)安装插件

​ 首先需要您安装 VS Code ,然后打开 VS Code 安装 qurator-vscode 插件: 使用 Ctrl + Shift + X 快捷键打开插件页面,或者您可以在最左侧栏找到 Extensions 点击进入,然后输入 qurator-vscode 来搜索插件,点击 Install 按钮进行插件的安装。

图附2.4.1 插件安装

​ (2)检测运行环境

​ 插件安装好之后,您可以创建以 .qrunes 结尾的文件,此时插件会自动检测是否存在程序运行所依赖的环境。您也可以自己检测程序运行环境,使用 Ctrl + Shift + P 快捷键打开 VS Code 命令行, 输入 qurator-vscode 时您可以看到 qurator-vscode: Check Qurator VSCode Extension dependencies 选择项,点击此项就可以进行运行环境的检测。

图附2.4.2 运行环境检测

​ 检测到运行时所需环境,会在右下角展示软件及版本号:

图附2.3.3 软件及版本号

2.4.3 快速入门

​ 在做好准备工作之后,下面就可以编写属于您自己的量子程序了。

​ (1)项目文件夹中启动 VS Code

​ 在命令提示符或终端上,创建一个名为 “test” 的空文件夹,切换到该文件夹,然后输入命令 code . 在该文件夹中打开 VS Code:

mkdir test
cd test
code .

​ 或者,您可以点击运行 VS Code,然后点击 “File” > “Open File…” 打开项目文件夹。在文件夹中启动 VS Code,该文件夹将成为您的“工作区”。您可以在 .vscode/settings.json 文件中更改工作区的相关设置。

​ (2)创建一个 qrunes 文件

​ 在文件资源管理器工具栏中,单击 “test” 文件夹上的 “New File” 按钮,并命名该文件为 qurator_test.qrunes。

图附2.4.4 创建 qrunes 文件

​ (3)编写量子程序

​ qrunes 文件创建完成之后,便可以编写量子程序了。整个量子程序分为三个部分:settings、qcodes 和 script 三个模块。

​ 其中,settings 模块中可以设置宿主语言,编译还是运行;qcodes 模块中可以编写 QRunes2 量子语言代码; script 模块中可以编写宿主语言代码,目前支持 Python 和 C++ 两种宿主语言。

图附2.4.5 编写量子程序

​ (4)编译运行

​ 点击右上方 Run this QRunes 运行程序,或者使用命令提示符 qurator-vscode: Run this QRunes 来运行程序(快捷键 F5):

图附2.4.6 编译运行

​ 上述示例程序的运行结果如图附2.3.7:

图附2.4.7 运行结果

2.4.4 功能介绍

​ 相信在快速入门步骤之后,您已大体了解插件的整体功能,下面将介绍您在编辑量子程序过程中插件提供的辅助功能:

​ (1)自动补全

​ 对于 QRunes2 语言内设的关键字可以智能提示,根据输入的字符列为您提供当前上下文中适用的最相关符号列表并提示其功能, 以便您可以更快地选择。

图附2.4.8 自动补全

​ (2)验证提示

​ 对于输入进行验证并提示。每当插件检测到您编写的代码发生语法错误时,编辑器中会显示红色波浪线, 鼠标放上去可看到一系列错误信息,您可以准确定位错误发生的位置。

图附2.4.9 验证提示

​ (3)高亮展示

​ 不同的模块有不同的颜色划分,您可以清晰地编写每一个模块的代码,一目了然,快速开发。

图附2.4.10 高亮展示

​ (4)悬浮提示

​ QRunes2 语言中的方法、变量都有详细的解释及用法。每当您编写 QRunes2 语言内设关键字时, 将鼠标放在该关键字上,编辑器将会显示该关键字的功能信息。

图附2.4.11 悬浮提示

​ (5)智能片段

​ 智能片段功能是指用户输入简短的触发指令而生成完整的代码片段,在本插件中内置了自定义代码片段, 可帮助您整理一些重复性代码,提高开发效率。

图附2.4.12 智能片段

​ (6)语言切换

​ 目前 QRunes2 语言可以支持 Python 及 C++ 宿主语言,您可以在 settings 模块的 language 关键字来设置 所需支持的语言类型,就可以在script模块编写相应语言的代码。

图附2.4.13 语言切换

​ (7)编译运行

​ 运行 QRunes2 语言代码,编译器会根据设定的语言去编译该代码,从而实现不同的语言编写生成相同的结构。

图附2.4.14 编译运行

附录3 量子化学工具的安装与使用

​ ChemiQ是在量子计算机或虚拟机上模拟化学分子结构和性质的仿真软件——也是全球首款运用量子算法模拟的仿真软件——接入量子计算机计算速度呈指数增长。ChemiQ利用Jordan-Wigner,Parity等方法将二次量子化的Fermion的Hamiltonian算符转化(mapping)成Qubit的Hamiltonian算符(量子计算机识别的算符),算符间的转换是量子计算模拟化学过程的第一步,不同的转化方法对应着不同的Qubit信息,研究出所转化的算符少的mapping,相应的计算少,可大大简化计算;使用Unitary Coupled Cluster(简称UCC)等拟设构造模拟量子电路,分别代表不同的电路模型,所包含的参数数目和线路深度也不尽相同,构造出参数少、线路浅的线路拟设是量子计算模拟的关键,使得复杂的化学过程得到有效模拟;再结合量子相位评估(QPE),变分量子本征求解(VQE)算法,或量子虚时演化(QITE)算法模拟分子哈密顿量的期望值,进一步预测分子性质。这些算法不仅能保证量子态的相干性,其计算结果还能达到化学精度,在可预见的未来,有着极大的应用前景和优势。

图附3.1.1 ChemiQ软件

3.1 ChemiQ化学软件的安装

​ 1、登录本源量子云官网(https://qcloud.originqc.com.cn/),选择“应用推广云”,如图附3.1.2 所示;选择“生物医药”方向,点击“了解详情”如图附3.1.3所示;点击“Windows进行下载”,如图附3.1.4所示。(直达页面:https://qcloud.originqc.com.cn/chemistryIntroduce)

图附3.1.2 选择“应用推广云”

图附3.1.3 选择“生物医药”

图附3.1.3 下载

​ 2、下载完成后,双击安装该软件,点击“我同意”;

图附3.1.4 点击“我同意”

​ 3、然后点击“下一步”;

图附3.1.5 下一步

​ 4、再安装到默认目录,点击“安装”;

图附3.1.6 点击“安装”

​ 5、安装完成后,运行该软件。

图附3.1.7 安装完成

3.2 ChemiQ软件应用示例

​ 1、 新建项目。先新建一个项目名称——test H2,然后是填好创建人、计算模式、保存路径和项目描述,最后点击确定。

图附3.2.1 新建项目

​ 2、 主界面。该软件左侧显示的是项目下的任务列表;左下显示的是项目或者任务详情;右侧显示分为上下两部分,上部分为分子模型,下部分为结果展示,可上下拖动调节大小。

图附3.2.2 主页面

​ 3、 分子建模。以氢分子势能曲线为例,首先是构建分子模型。点击设置-分子模型,或者工具栏中图标构建分子模型。在这里可使用构建分子快捷工具,如右侧弹出框。

图附3.2.3 分子建模

​ 4、 配置参数。在参数配置框中选择计算类型——势能曲线,基组、电荷、自旋多重度可根据用户对应设置,在这里以STO-3G基组模拟氢分子PES;扫描坐标选择氢分子中键长距离为变量,设置对应的节点个数和扫描区间;映射、拟设和优化器对应选择如下图所示:

图附3.2.4 配置参数

​ 5、任务详情。左下部分显示任务的参数详情,如计算结果中展示的计算列表,其中往下拉会显示20个节点任务;此外为了便于显示,可点击视图中便捷工具,如图展示是分子模型中的元素名称和元素编号。

图附3.2.5 任务详情

​ 6、 计算完成。可以看到计算结果已经展示出来,同时也可以看到每个氢分子坐标计算得到能量如下:

图附3.2.6 计算完成

​ 7、 结果展示。势能曲线中可点击单个节点进入结果详情中,或者点击计算列表/势能曲线切换结果展示。

图附3.2.7 结果展示

3.3 ChemiQ接口介绍与使用

使用封装的ChemiQ计算接口进行实现

表附3.3.1 ChemiQ封装的计算接口
接口名称 描述
initialize 初始化量子化学计算的环境
finalize 释放量子化学计算的环境
setMolecule 设置单个分子模型
setMolecules 设置一组分子模型
setMultiplicity 设置重数
setCharge 设置电荷数
setBasis 设置计算基
setTransformType 设置费米子到泡利算子的转换类型
setUccType 设置UCC模型类型
setOptimizerType 设置优化器类型
setOptimizerIterNum 设置优化器迭代次数
setOptimizerFuncCallNum 设置优化器函数调用次数
setOptimizerXatol 设置优化器参数收敛阈值
setOptimizerFatol 设置优化器函数收敛阈值
setLearningRate 设置学习率
setEvolutionTime 设置演化时间
setHamiltonianSimulationSlices 设置哈密顿量模拟切片数
setSaveDataDir 设置中间数据存放目录
setRandomPara 设置随机优化参数
setDefaultOptimizedPara 设置默认优化参数
setToGetHamiltonianFromFile 设置从文件获取体系哈密顿量
setHamiltonianGenerationOnly 设置只生成体系哈密顿量
exec 执行计算
getLastError 获取最后一条错误日志

​ initialize接口,作用是用来初始化量子化学计算环境,它需要传入一个变量就是量子化学计算包的路径,这里已经把PSi4安装在了python能检索到的环境路径下,使用时只需要传入空的字符串即可。 下面演示一下如何使用ChemiQ计算接口来实现氢分子的基态能量计算。

​ 首先构造一组不同距离下的氢分子模型;然后生成ChemiQ的一个实例,调用setMolecules接口设置一组氢分子模型,设置氢分子的电荷数为0,自旋多重度为1;使用的计算基是sto-3g;UCC模型我们使用的是UCCS,费米子哈密顿量到泡利哈密顿量的转换这里用的是JW变换;这里使用的优化器是Nelder-Mead,优化器迭代次数为200,函数调用次数为200,显示优化器计算的中间结果;最后执行计算。

 1.import matplotlib.pyplot as plt  
 2.  
 3.from pyqpanda import *  
 4.  
 5.if __name__=="__main__":  
 6.  
 7.    distances = [x * 0.1 for x in range(2, 25)]  
 8.    molecule = "H 0 0 0\nH 0 0 {0}"  
 9.  
10.    molecules = []  
11.    for d in distances:  
12.        molecules.append(molecule.format(d))  
13.  
14.    chemiq = ChemiQ()  
15.    chemiq.initialize("")  
16.    chemiq.setMolecules(molecules)  
17.    chemiq.setCharge(0)  
18.    chemiq.setMultiplicity(1)  
19.    chemiq.setBasis("sto-3g")  
20.    chemiq.setUccType(UccType.UCCS)  
21.    chemiq.setTransformType(TransFormType.Jordan_Wigner)  
22.    chemiq.setOptimizerType(OptimizerType.NELDER_MEAD)  
23.    chemiq.setOptimizerIterNum(200)  
24.    chemiq.setOptimizerFatol(200)  
25.    chemiq.exec()  
26.    chemiq.finalize()  
27.      
28.    value = chemiq.getEnergies()  
29.  
30.    plt.plot(distances , value, 'r')  
31.    plt.xlabel('distance')  
32.    plt.ylabel('energy')  
33.    plt.title('VQE PLOT')  
34.    plt.show()

​ 获取优化后的能量,绘制曲线图。这条曲线就是优化得到的氢分子在不同距离下对应的基态能量:

图附3.3.1 氢分子在不同距离下对应的基态能量

3.4 非梯度下降法实现VQE算法代码示例

​ 首先,导入pyQPanda和psi4_wrapper中的所有模块,以及一些其它组件模块准备。

1.from pyqpanda import *  
2.from psi4_wrapper import *  
3.import numpy as np  
4.from functools import partial  
5.from math import pi  
6.import matplotlib.pyplot as plt   

​ 然后,定义非梯度下降优化器使用的损失函数为loss_func,loss_func接受的一组参数为待优化的参数列表,轨道个数,电子个数,体系哈密顿量。这个接口是先用ccsd模型构造的费米子哈密顿量,然后利用JW变换将费米子哈密顿量转换为泡利哈密顿量,再接着将CC转化成UCC,再计算体系哈密顿量在试验态下的期望,最后返回期望值来实现的。

 1.def loss_func(para_list, qubit_number, electron_number, Hamiltonian):  
 2.    '''  
 3.    <𝜓^∗|𝐻|𝜓>, Calculation system expectation of Hamiltonian in experimental state.  
 4.    para_list: parameters to be optimized  
 5.    qubit_number: qubit number  
 6.    electron_number: electron number  
 7.    Hamiltonian: System Hamiltonian  
 8.    '''  
 9.    fermion_cc =get_ccsd(qubit_number, electron_number, para_list)  
10.    pauli_cc = JordanWignerTransform(fermion_cc)  
11.    ucc = cc_to_ucc_hamiltonian(pauli_cc)  
12.    expectation=0  
13.    for component in Hamiltonian:  
14.        expectation+=get_expectation(qubit_number, electron_number, ucc, component)  
15.    expectation=float(expectation.real)  
16.    print(expectation)  
17.    return ("", expectation)  

​ 下面将对loss_func使用到的接口逐个进行讲解:

​ get_ccsd_n_term接口的作用是返回构造CCSD模型需要用到的参数个数,这个接口接收的参数是轨道个数和电子个数。

 1.def get_ccsd_n_term(qn, en):  
 2.    '''  
 3.    coupled cluster single and double model.  
 4.    e.g. 4 qubits, 2 electrons  
 5.    then 0 and 1 are occupied,just consider 0->2,0->3,1->2,1->3,01->23  
 6.    '''  
 7.  
 8.    if n_electron>n_qubit:  
 9.        assert False  
10.      
11.    return int((qn - en) * en + (qn - en)* (qn -en - 1) * en * (en - 1) / 4)  

​ get_ccsd接口则是用来构造普通参数对应的CCSD模型费米子哈密顿量,该接口接收的参数是轨道个数、电子个数和单激发双激发前面对应的系数。

 1.def get_ccsd(qn, en, para):  
 2.    '''  
 3.    get Coupled cluster single and double model.  
 4.    e.g. 4 qubits, 2 electrons  
 5.    then 0 and 1 are occupied,just consider 0->2,0->3,1->2,1->3,01->23.  
 6.    returned FermionOperator like this:  
 7.    { {"2+ 0":var[0]},{"3+ 0":var[1]},{"2+ 1":var[2]},{"3+ 1":var[3]},  
 8.    {"3+ 2+ 1 0":var[4]} }  
 9.  
10.    '''  
11.    if n_electron>n_qubit:  
12.        assert False  
13.    if n_electron==n_qubit:  
14.        return FermionOperator()  
15.  
16.    if get_ccsd_n_term(qn, en) != len(para):  
17.        assert False  
18.  
19.    cnt = 0  
20.    fermion_op = FermionOperator()  
21.    for i in range(en):  
22.        for ex in range(en, qn):  
23.            fermion_op += FermionOperator(str(ex) + "+ " + str(i), para[cnt])  
24.            cnt += 1     
25.      
26.    for i in range(n_electron):  
27.        for j in range(i+1,n_electron):  
28.            for ex1 in range(n_electron,n_qubit):  
29.                for ex2 in range(ex1+1,n_qubit):  
30.                    fermion_op += FermionOperator(  
31.                        str(ex2)+"+ "+str(ex1)+"+ "+str(j)+" "+str(i),  
32.                        para[cnt]  
33.                    )  
34.                    cnt += 1  
35.                      
36.    return fermion_op  

​ JordanWignerTransform接口的作用是将费米子哈密顿量转换成泡利哈密顿量。

1.def JordanWignerTransform(fermion_op):  
2.    data = fermion_op.data()  
3.    pauli = PauliOperator()  
4.    for i in data:  
5.        pauli += get_fermion_jordan_wigner(i[0][0])*i[1]  
6.    return pauli 

​ get_fermion_jordan_wigner接口则是将费米子哈密顿量的子项转换成泡利哈密顿量。

 1.def get_fermion_jordan_wigner(fermion_item):  
 2.    pauli = PauliOperator("", 1)  
 3.  
 4.    for i in fermion_item:  
 5.        op_qubit = i[0]  
 6.        op_str = ""  
 7.        for j in range(op_qubit):  
 8.            op_str += "Z" + str(j) + " "  
 9.  
10.        op_str1 = op_str + "X" + str(op_qubit)  
11.        op_str2 = op_str + "Y" + str(op_qubit)  
12.  
13.        pauli_map = {}  
14.        pauli_map[op_str1] = 0.5  
15.  
16.        if i[1]:  
17.            pauli_map[op_str2] = -0.5j  
18.        else:  
19.            pauli_map[op_str2] = 0.5j  
20.  
21.        pauli *= PauliOperator(pauli_map)  
22.  
23.    return pauli   

​ cc_to_ucc_hamiltonian接口的作用是CC模型对应的哈密顿量转成UCC模型对应的哈密顿量。

1.def cc_to_ucc_hamiltonian(cc_op):  
2.    '''  
3.    generate Hamiltonian form of unitary coupled cluster   
4.    based on coupled cluster,H=1j*(T-dagger(T)),  
5.    then exp(-iHt)=exp(T-dagger(T))  
6.    '''  
7.    return 1j*(cc_op-cc_op.dagger())  

​ get_expectation接口,作用是计算体系哈密顿量在试验态下的期望,接收的参数是轨道个数,电子个数,UCC模型,体系哈密顿量的一个子项。

 1.def get_expectation(n_qubit, n_en, ucc,component):  
 2.    '''  
 3.    get expectation of one hamiltonian.  
 4.    n_qubit: qubit number  
 5.    n_en: electron number  
 6.    ucc: unitary coupled cluster operator  
 7.    component: paolioperator and coefficient,e.g. ('X0 Y1 Z2',0.2)  
 8.    '''  
 9.  
10.    machine=init_quantum_machine(QMachineType.CPU)  
11.    q = machine.qAlloc_many(n_qubit)  
12.    prog=QProg()  
13.  
14.    prog.insert(prepareInitialState(q, n_en))  
15.    prog.insert(simulate_hamiltonian(q, ucc, 1.0, 4))  
16.      
17.    for i, j in component[0].items():  
18.        if j=='X':  
19.            prog.insert(H(q[i]))  
20.        elif j=='Y':  
21.            prog.insert(RX(q[i],pi/2))  
22.      
23.    machine.directly_run(prog)  
24.    result=machine.get_prob_dict(q, select_max=-1)  
25.    machine.qFree_all(q)  
26.      
27.    expectation=0  
28.    #奇负偶正  
29.    for i in result:  
30.        if parity_check(i, component[0]):  
31.            expectation-=result[i]  
32.        else:  
33.            expectation+=result[i]         
34.    return expectation*component[1]  

​ prepareInitialState接口的作用是制备初态,接收的参数是一组量子比特和电子个数。

 1.def prepareInitialState(qlist, en):  
 2.    '''  
 3.    prepare initial state.   
 4.    qlist: qubit list  
 5.    en: electron number  
 6.    return a QCircuit  
 7.    '''  
 8.    circuit = QCircuit()  
 9.    if len(qlist) < en:  
10.        return circuit  
11.  
12.    for i in range(en):  
13.        circuit.insert(X(qlist[i]))  
14.  
15.    return circuit;  

​ simulate_hamiltonian接口,作用是构造哈密顿量的模拟线路,接收的参数是一组量子比特,泡利哈密顿量、演化时间演化次数。

 1.def simulate_hamiltonian(qubit_list,pauli,t,slices=3):  
 2.    '''  
 3.    Simulate a general case of hamiltonian by Trotter-Suzuki  
 4.    approximation. U=exp(-iHt)=(exp(-i H1 t/n)*exp(-i H2 t/n))^n  
 5.    '''  
 6.    circuit =QCircuit()  
 7.  
 8.    for i in range(slices):  
 9.        for op in pauli.data():  
10.            term = op[0][0]  
11.            circuit.insert(  
12.                simulate_one_term(  
13.                    qubit_list,   
14.                    term, op[1].real,   
15.                    t/slices  
16.                )  
17.            )  
18.  
19.    return circuit  

​ simulate_one_term是构造哈密顿量子项的模拟线路。

 1.def simulate_one_term(qubit_list, hamiltonian_term, coef, t):  
 2.    '''  
 3.    Simulate a single term of Hamilonian like "X0 Y1 Z2" with  
 4.    coefficient and time. U=exp(-it*coef*H)  
 5.    '''  
 6.    circuit =QCircuit()  
 7.  
 8.    if not hamiltonian_term:  
 9.        return circuit  
10.  
11.    transform=QCircuit()  
12.    tmp_qlist = []  
13.    for q, term in hamiltonian_term.items():          
14.        if term is 'X':              
15.            transform.insert(H(qubit_list[q]))              
16.        elif term is 'Y':  
17.            transform.insert(RX(qubit_list[q],pi/2))                
18.  
19.        tmp_qlist.append(qubit_list[q])       
20.  
21.    circuit.insert(transform)  
22.  
23.    size = len(tmp_qlist)  
24.    if size == 1:  
25.        circuit.insert(RZ(tmp_qlist[0], 2*coef*t))  
26.    elif size > 1:  
27.        for i in range(size - 1):  
28.            circuit.insert(CNOT(tmp_qlist[i], tmp_qlist[size - 1]))     
29.        circuit.insert(RZ(tmp_qlist[size-1], 2*coef*t))  
30.        for i in range(size - 1):  
31.            circuit.insert(CNOT(tmp_qlist[i], tmp_qlist[size - 1]))    
32.  
33.    circuit.insert(transform.dagger())  
34.  
35.    return circuit  

​ paity_check是对量子态中指定比特1的个数做奇偶校验。

 1.def parity_check(number, terms):  
 2.    '''  
 3.    pairty check   
 4.    number: quantum state  
 5.    terms: a single term of PauliOperator, like"[(0, X), (1, Y)]"  
 6.    '''  
 7.    check=0  
 8.    number=number[::-1]  
 9.    for i in terms:  
10.        if number[i]=='1':  
11.            check+=1  
12.    return check%2  

​ optimize_by_no_gradient是非梯度下降优化算法的主体接口,需要传入的一组参数是体系哈密顿量,轨道个数,电子个数,优化器迭代次数

​ 接口的具体实现步骤是:首先初始化一组待优化的参数,然后构造一个非梯度下降优化器,这里构造的优化器是Nelder-Mead,设置优化器的迭代次数并向优化器注册计算期望的损失函数,然后执行优化器,最后返回优化器优化的最低期望值。

 1.def optimize_by_no_gradient(mol_pauli, n_qubit, n_en, iters):  
 2.    n_para = get_ccsd_n_term(n_qubit, n_electron)  
 3.  
 4.    para_vec = []  
 5.    for i in range(n_para):  
 6.        para_vec.append(0.5)  
 7.  
 8.    no_gd_optimizer = OptimizerFactory.makeOptimizer(OptimizerType.NELDER_MEAD)  
 9.    no_gd_optimizer.setMaxIter(iters)  
10.    no_gd_optimizer.setMaxFCalls(iters)  
11.    no_gd_optimizer.registerFunc(partial(  
12.        loss_func,   
13.        qubit_number = n_qubit,   
14.        electron_number = n_en,  
15.        Hamiltonian=mol_pauli.toHamiltonian(1)),   
16.        para_vec)  
17.  
18.    no_gd_optimizer.exec()  
19.    result = no_gd_optimizer.getResult()  
20.    print(result.fun_val)  
21.  
22.    return result.fun_val  

​ etAtomElectronNum接口作用是返回原子对应的电子个数。

 1.def getAtomElectronNum(atom):  
 2.    atom_electron_map = {  
 3.        'H':1, 'He':2, 'Li':3, 'Be':4, 'B':5, 'C':6, 'N':7, 'O':8, 'F':9, 'Ne':10,   
 4.        'Na':11, 'Mg':12, 'Al':13, 'Si':14, 'P':15, 'S':16, 'Cl':17, 'Ar':18  
 5.    }  
 6.  
 7.    if (not atom_electron_map.__contains__(atom)):  
 8.        return 0  
 9.  
10.    return atom_electron_map[atom]  

​ 该算法演示示例对应的主函数,首先构造一组不同距离下的氢分子模型,然后计算每个氢分子模型对应的基态能量,最后将计算的结果绘制成曲线图。

 1.if __name__=="__main__":      
 2.    distances = [x * 0.1 for x in range(2, 25)]  
 3.    molecule = "H 0 0 0\nH 0 0 {0}"  
 4.  
 5.    molecules = []  
 6.    for d in distances:  
 7.        molecules.append(molecule.format(d))  
 8.  
 9.    chemistry_dict = {  
10.        "mol":"",  
11.        "multiplicity":1,  
12.        "charge":0,  
13.        "basis":"sto-3g",  
14.    }  
15.  
16.    energies = []  
17.  
18.    for d in distances:  
19.        mol = molecule.format(d)  
20.  
21.        chemistry_dict["mol"] = molecule.format(d)  
22.        data = run_psi4(chemistry_dict)  
23.        #get molecule electron number  
24.        n_electron = 0  
25.        mol_splits = mol.split()  
26.        cnt = 0  
27.        while (cnt < len(mol_splits)):  
28.            n_electron += getAtomElectronNum(mol_splits[cnt])  
29.            cnt += 4  
30.  
31.        fermion_op = parsePsi4DataToFermion(data[1])  
32.        pauli_op = JordanWignerTransform(fermion_op)  
33.  
34.        n_qubit = pauli_op.getMaxIndex()  
35.  
36.        energies.append(optimize_by_no_gradient(pauli_op, n_qubit, n_electron, 200))  
37.  
38.    plt.plot(distances , energies, 'r')  
39.    plt.xlabel('distance')  
40.    plt.ylabel('energy')  
41.    plt.title('VQE PLOT')  
42.    plt.show()  

​ 该示例对应的输出结果如下,曲线图是氢分子在不同距离下对应的基态能量:

图附3.3.2 氢分子在不同距离下对应的基态能量