量子力学导论
艾伦·图灵(Alan Turing)于1936年发明了可编程计算机(请参阅参考资料 ),这是一种思想实验,旨在证明某些数学问题是不可计算的。 在他的论点中隐含的想法是,拥有足够资源的计算机能够实现任何合理的算法。
自那时以来,计算机行业不仅设法构建可编程计算机,而且每18个月左右将功能翻一番,它们也变得过时了。 尽管计算机技术取得了疯狂的进步,但是现代计算机仍然无法在棘手的问题上发挥重大作用。 需要指数资源(与问题本身的大小相比)的问题在今天仍然和1936年一样棘手。
1982年,理查德·费曼(Richard Feynman)提出,这种古老的图灵机可能没有人们想象的那么强大。 Feynman试图用量子力学模拟N粒子的相互作用。 尽他所能,如果不使用指数资源就无法找到通用的解决方案。
然而,自然地,自然能够仅使用N个粒子来模拟这个数学问题。 结论是不可避免的:自然界有能力构建根本上优越的计算设备,这表明Turing机器并不是人们认为的通用计算机。
QC算法涉及根据概率因素进行思考,这是当前程序员的一种概念变化。 在某些方面,这就像是第一次使用OOP,函数编程或多线程所涉及的概念转变。 从另一种意义上说,这种转变更为根本,因为它带来了一类全新的(可能)非对等问题。
让我们想象以下问题。 我们需要找到一条穿过复杂迷宫的道路。 每次我们走一条路,我们很快就会遇到新的分支。 即使知道有一些出路,也很容易迷路。 可以说,走迷宫时,众所周知的算法是右手法则-沿着右手墙直到出门(包括死胡同)。 这可能不是很短的路,但是至少您不会重复相同的走廊。 用计算机术语来说,此规则也称为递归树下降。
现在让我们想象另一个解决方案。 站在迷宫的入口处,并释放出足够数量的有色气体,以同时填充迷宫的每个通道。 在出口处有一个合作者。 当她看到一股有色气体发出来时,她只是问那些气体颗粒经过了什么路径。 她查询的第一个粒子很可能已走过迷宫的最短路径。
自然,气体颗粒并不能完全告诉我们它们的行程。 但是,质量控制的行为与我们的情况非常相似。 也就是说,它们会填满整个问题空间,然后只管去问一个正确的解决方案(将所有死胡同都留在答案空间之外)。
在传统的经典计算机上模拟量子计算机是一个难题。 所需要的资源随着仿真中量子存储器的数量呈指数增长,以至于用几十个量子位(qubit)来模拟QC远远超出了当今制造的任何计算机的能力。
qcl只能模拟非常小的量子计算机,但幸运的是,它的功能足以证明一些有用的QC算法背后的概念。
像过去的超级计算机一样,明天的第一个QC可能将在核心中包含一些奇特的硬件,这些硬件用于存储和操作量子状态机。 围绕它的将是维持生命的硬件,并为用户提供合理的编程环境。 qcl通过提供具有量子数据类型和特殊功能以对其执行操作的经典程序结构来模拟这种环境。
让我们从使用qcl进行的经典计算中的一些熟悉的操作开始。 由于qcl是一种交互式解释器,语法类似于C,因此我们可以启动它并开始在其中输入命令。 为了使示例更具可读性,我们将模拟下的量子位数限制为5。
$ qcl --bits=5
[0/8] 1 |00000>
qcl> qureg a[1];
qcl> dump a
: SPECTRUM a: |....0>
1 |0>
在这里,我们从qcl量子堆中分配了一个1 qubit(布尔)变量。 机器的量子状态|00000>
被初始化为全零。 |>
字符表示这是一个量子状态(有时称为ket),而5 0的字符串(量子堆中的每一位一个)构成该状态的标签。 这就是量子力学的狄拉克(Dirac)表示法(又名Bra-ket)。 与线性代数的传统数学符号相比,它的主要优点是它更容易键入。
“ qureg a [1]”从量子堆分配一个位变量a
。 dump a
命令可为我们提供有关a
信息。 SPECTRUM
行向我们显示了量子堆中a
的量子位的分配位置; 在这种情况下, a
的0位是堆中最右边的qubit。 下一行告诉我们,如果我们测量a
,则将看到概率为“ 1”的“ 0”。
当然,仅由于qcl是模拟器,才有可能窥视量子内存。 如果不改变其值,就无法观察到真实的量子位。 稍后再详细介绍。
qcl提供的许多原始量子算符是经典计算所熟悉的。 例如, Not()
函数翻转一位的值。
qcl> Not(a);
[2/8] 1 |00001>
再次将Not()
应用于相同的qubit将取消第一个的效果,这正是我们期望从经典计算中获得的效果。
CNot(x,y)
运算符测试CNot(x,y)
的值,如果它是“ 1”,它将翻转x的值。 这等效于C中的语句x^=y
。
qcl> qureg b[2];
qcl> Not(b[1]);
[3/8] 1 |00100>
qcl> CNot(b[0], b[1]);
[3/8] 1 |00110>
qcl> dump b[0];
: SPECTRUM b[0]: |...0.>
1 |1>
qcl> dump b[1];
: SPECTRUM b[1]: |..0..>
1 |1>
像Not()
运算符一样, CNot()
运算符是其自身的逆。 再次应用它,它会反转第一次的效果,使您处于与开始时相同的状态。
可逆性这一思想对于理解量子计算至关重要。 理论物理学告诉我们,对量子位的每个操作(测量除外)都必须是不可撤销的。 我们必须始终保留足够的信息,以便进行任何反向操作。 这意味着像赋值(x = y),AND( x&=y
)和OR( x|=y
)之类的操作(我们在经典计算中认为是必须的)必须进行修改才能在QC中使用。 幸运的是,有一个简单的公式可以将不可逆的经典运算转换为量子运算。
首先,除了将其初始化为“ 0”外,我们从不覆盖量子位。 因此,在我们要完成分配(x = y)的地方,我们改为初始化目标(x = 0)并使用上例或(x ^ = y),如上例所示。
nomadic$ qcl --bits=5
[0/8] 1 |00000>
qcl> qureg c[3];
qcl> Not(c[1]);
[3/8] 1 |00010>
qcl> Not(c[2]);
[3/8] 1 |00110>
qcl> dump c
: SPECTRUM c: |..210>
1 |110>
qcl> CNot(c[0], c[1] & c[2]);
[3/8] 1 |00111>
qcl> dump c
: SPECTRUM c: |..210>
1 |111>
如果y和z为“ 1” CNot(x, y & z)
将翻转x的值。 因此,如果在开始之前将x
初始化为“ 0”,则实际上与计算y&z
并将值存储在x
。 这是一个微妙的区别,但在量子计算中至关重要。
现在让我们看一些没有经典类似物的操作。 Hadamard函数是最引人注目,同时也是最有用的函数之一,并通过qcl适当地标记了Mix()
。 Mix()
采用计算基础状态,如|0>
或|1>
,并将其转换为量子叠加。 这是一个量子比特的例子:
[0/8] 1 |00000>
qcl> qureg a[1];
qcl> dump a;
: SPECTRUM a: |....0>
1 |0>
qcl> Mix(a);
[1/8] 0.707107 |00000> + 0.707107 |00001>
qcl> dump a;
: SPECTRUM a: |....0>
0.5 |0> + 0.5 |1>
在这个例子中,我们利用了叠加的量子力学原理。 根据dump a
,如果要测量a
,则将看到等价概率为0.5(0.707107 2)的“ 0”或“ 1”。
如果您从未接触过这种叠加概念,则可能会有点困惑。 量子力学告诉我们,小的粒子,例如电子,可以同时位于两个位置。 类似地,一个量子位可以同时具有两个不同的值。 理解这一切的关键是矢量算法。
与经典计算机不同,传统计算机的状态仅是一个单一的1和0字符串,而QC的状态是一个向量,其中每个可能的1和0字符串都具有分量。 换句话说,一和零的字符串构成了机器状态所驻留的向量空间的基础。 我们可以通过写出这样的总和来写下质量控制的状态:
a|X> + b|Y> + ...
其中X
, Y
等是一元和零的字符串, a
, b
等是各个分量X,Y等的振幅。 |X>
表示法只是物理学家表示“矢量(或状态)”的方式称为X”。
如上例所示,将Mix()
运算符(Hadamard运算符)应用于|0>
状态的位时,会将状态转换为sqrt(0.5)(|0>+|1>)
。 但是,如果将Mix()
应用于|1>
状态的位,则会得到sqrt(0.5)(|0>-|1>)
。 因此,如果我们将Mix()
两次应用于任何qubit(处于任何状态),我们将回到开始的位置。 换句话说, Mix()
是它自己的逆。
如果我们有两个量子位a
和b
(被初始化为零),并且我们对a
进行了一系列量子运算,然后对b
进行了同样的运算,那么我们期望a
和b
最终具有相同的值,然后我们做。
qcl> qureg a[1];
qcl> Not(a);
[1/8] 1 |00001>
qcl> Mix(a);
[1/8] 0.707107 |00000> + -0.707107 |00001>
qcl> qureg b[1];
qcl> Not(b);
[2/8] 0.707107 |00010> + -0.707107 |00011>
qcl> Mix(b);
[2/8] 0.5 |00000> + -0.5 |00010> + -0.5 |00001> + 0.5 |00011>
qcl> dump a
: SPECTRUM a: |....0>
0.5 |0> + 0.5 |1>
qcl> dump b
: SPECTRUM b: |...0.>
0.5 |0> + 0.5 |1>
在此示例中, a
和b
是完全独立的。 如果我们测量一个,它就不会影响另一个。
qcl> measure a;
[2/8] -0.707107 |00001> + 0.707107 |00011>
qcl> dump b
: SPECTRUM b: |...0.>
0.5 |0> + 0.5 |1>
如预期的那样,通过测量a
, b
的光谱不变。
如果操作比简单的Not();Mix()
更复杂,我们可能会被诱惑只对a
执行一次,然后将值从a
复制到b
。 好的,我们不能真正复制(因为它不是可逆的操作),但是我们可以将b
初始化为零,并且CNot(b,a)
可以实现相同的目标。
las,这并没有达到我们的预期。 但是,让我们尝试一下,看看我们能得到什么:
qcl> qureg a[1];
qcl> Not(a);
[1/8] 1 |00001>
qcl> Mix(a);
[1/8] 0.707107 |00000> + -0.707107 |00001>
qcl> qureg b[1];
qcl> CNot(b,a);
[2/8] 0.707107 |00000> + -0.707107 |00011>
qcl> dump a;
: SPECTRUM a: |....0>
0.5 |0> + 0.5 |1>
qcl> dump b;
: SPECTRUM b: |...0.>
0.5 |0> + 0.5 |1>
a
和b
的光谱看起来正确。 确实,如果我们仅测量a
或b
我们将得到与上述相同的结果。 区别在于当我们同时测量a和b时会发生什么。
请记住,测量结果是随机的,因此,如果您重复此实验,则里程可能会有所不同。
qcl> measure a;
[2/8] -1 |00011>
qcl> dump b
: SPECTRUM b: |...0.>
1 |1>
通过测量a
,我们折叠了b
的叠加。 这是因为a
和b
缠结在爱因斯坦,波多尔斯基和罗森之后的物理学家所说的EPR对中,所有这些人都试图以此来证明量子力学是不完整的理论。 然而,约翰·贝尔后来通过对贝尔不等式的实验性反驳(正式将EPR思想实验正式化)证明了真实粒子中的纠缠。
当您尝试将一个量子变量复制到另一个量子变量时会发生什么? 纠缠在一起而不是真正的副本。
假设我们给了一个接受一位参数并返回一位的函数。 为了使事情不断发展,我们要求这是一个伪古典函数。 如果我们将经典位(0或1)作为参数传递,它将返回经典位。
完全有4种可能的功能可以满足此要求。
f(x) -> 0Â Â Â Â Â Â Â Â Â Â Â Â # constant zero result
f(x) -> 1Â Â Â Â Â Â Â Â Â Â Â Â # constant one result
f(x) -> x            # identity function
f(x) -> ~x           # boolean negation
前两个是常数,这意味着无论输入如何,它们输出相同的值。 后两个是平衡的,这意味着输出是一半时间的0和一半时间的1。 传统上,如果不对函数进行两次评估,就无法确定f()
是恒定的还是平衡的。
离合器问题要求我们仅通过评估f()
来确定f()是恒定的还是平衡的。 运作方式如下。
首先,我们必须在qcl中构造一个伪经典运算符,用于评估f(x)
。 为此,我们将定义一个带输入和输出参数的qufunct。 例如:
qufunct F(qureg out, quconst in) {
   CNot(out, in);
   Not(out);
   print "f(x)= ~x";
}
如果out初始化为“ 0”,则调用此函数将变为f(x)=~x
。 您可以注释掉CNot()
或Not()
行以获得其他三个可能的函数之一。 将上面的代码片段放入一个名为f_def.qcl的文件中之后,我们可以测试F()
以确保它可以实现我们想要的功能:
qcl> include "f_def.qcl";
qcl> qureg in[1];
qcl> qureg out[1];
qcl> F(out,in);
: f(x)= ~x
[2/8] 1 |00010>
qcl> dump out;
: SPECTRUM out: |...0.>
1 |1>
qcl> reset
[2/8] 1 |00000>
qcl> Not(in);
[2/8] 1 |00001>
qcl> dump in
: SPECTRUM in: |....0>
1 |1>
qcl> F(out,in);
: f(x)= ~x
[2/8] 1 |00001>
qcl> dump out
: SPECTRUM out: |...0.>
1 |0>
现在,让我们重置量子内存,并运行Deutches算法。 它通过首先将输入和输出位放入四个基本状态的叠加中来工作。
(01)Â qcl> reset;
(02)Â qcl> int result;
(03)Â qcl> Not(out);
(04)Â [2/8] 1 |00010>
(05)Â qcl> Mix(out);
(06)Â [2/8] 0.707107 |00000> + -0.707107 |00010>
(07)Â qcl> Mix(in);
(08)Â [2/8] 0.5 |00000> + 0.5 |00001> + -0.5 |00010> + -0.5 |00011>
(09)Â qcl> F(out,in);
(10)Â : f(x)= ~x
(11)Â [2/8] 0.5 |00010> + 0.5 |00001> + -0.5 |00000> + -0.5 |00011>
(12)Â qcl> Mix(in);
(13)Â [2/8] 0.707107 |00011> + -0.707107 |00001>
(14)Â qcl> Mix(out);
(15)Â [2/8] -1 |00011>
(16)Â qcl> measure in, result;
(17)Â [2/8] -1 |00011>
(18)Â qcl> if (result == 0) { print "constant"; } else { print "balanced"; }
(19)Â : balanced
在第1-7行中,我们将输入/输出位叠加为四个基本状态的叠加,其中“ out = 0”的状态为+0.5的正振幅,而“ out = 1”的状态为-0.5的负振幅。 请注意,即使我们有四个非零振幅,振幅绝对值的平方和也总是相加一。
在第9行,我们运行量子函数F()
,将f(in)
的值与out
量子位异或。 函数F()
是伪古典的,这意味着它在不改变任何振幅的情况下交换基向量。 因此,在应用F()
我们仍然有两个振幅值为“ +0.5”的振幅和两个振幅值为“ -0.5”。
通过将F()
函数应用于叠加状态,我们可以一次有效地将F()
有效地应用于所有四个基本状态。 这就是所谓的“量子并行性”,它是质量控制的关键要素。 当然,我们的模拟器必须将F()
依次应用于每个基本状态,但是真正的QC会将F()
作为单个操作应用于组合状态。
第14和16行的Mix()
函数将机器状态翻转出叠加状态,然后返回到计算基础状态( |00011>
)。 如果我们没有在第9行运行F()
,这会使我们回到第4行的状态(这是因为Mix()
是其自身的逆函数)。 但是因为我们用F()
交换了振幅,所以取消叠加会使我们进入与第9行不同的状态。具体而言,现在将qubit中的in
设置为“ 1”而不是“ 0”。
注意第15行中-1的幅度并不重要,这也很有启发性。 量子态是一个矢量,其总长度对我们来说并不重要(只要它不为零)。 仅矢量的方向(分量振幅之间的比率)很重要。 通过将量子态保持为单位向量,这些转换都是单一的。 这不仅使理论数学变得更加容易,而且还使经典计算机上进行数值计算时出现的错误不会滚滚而来。
量子计算的最初目标是使用一小组基本组件来模拟任意量子系统的行为。 到目前为止,我们已经讨论了Not()
, CNot()
和Mix()
函数。 为了完善集合并允许通用量子计算,我们需要控制相位函数CPhase()
。
CPhase()
将(经典)浮点数作为其第一个参数,将qubit作为其第二个参数。 CPhase(a,x)
更改机器基本状态的分量幅度:
|0>
基本状态的幅度不变,而 |1>
基态的振幅乘以exp(i * a)= cos(a)+ i * sin(a)。 在复数平原中,x = 1时,通过a弧度旋转的机器状态的系数。 例如:
$ qcl --bits=5
[0/5] 1 |00000>
qcl> qureg a[1];
qcl> Mix(a);
[1/5] 0.707107 |00000> + 0.707107 |00001>
qcl> CPhase(3.14159265, a);
[1/5] 0.707107 |00000> + -0.707107 |00001>
qcl> reset
[1/5] 1 |00000>
qcl> Mix(a);
[1/5] 0.707107 |00000> + 0.707107 |00001>
qcl> CPhase(0.01, a);
[1/5] 0.707107 |00000> + (0.707071,0.00707095) |00001>
qcl> dump a
: SPECTRUM a: |....0>
0.5 |0> + 0.5 |1>
由于exp(i * pi)=-1, CPhase(pi,x)
将翻转|1>
分量的符号。 CPhase(0.01, x)
在复平面中将|1>
分量的相位旋转弧度的百分之一。 带括号的元组(0.707071,0.00707095)是复数exp(0.01 * i)= 0.707071 + i * 0.00707095的qcl表示。
Deutches问题及其N位泛化,即Deutch-Jozsa问题,可能很有趣,但是它们没有太多实用价值。 幸运的是,还有其他量子算法有望带来更大的回报。
例如,Shor的算法能够找到多项式时间内N位的函数的周期。 虽然这听起来没什么大不了,但是分解和找到离散对数的困难构成了大多数(即使不是全部)公共密钥密码系统的基础。
不太引人注目,但更容易实现的是格罗弗算法,该算法在O(sqrt(N))时间内搜索N个项目的无序列表。 最佳经典算法平均需要N / 2次迭代来搜索此类列表。
自从出现以来,经典计算机的任务之一就是模拟电路以帮助设计更快的计算机。 这种反馈回路帮助推动了计算机行业半个世纪的爆炸性增长。 量子计算有潜力将这种爆炸性增长转变为更高的速度,因为QC用于创建更快,更强大的量子计算元素。
2000年8月,IBM Almaden研究中心的Isaac L. Chuang宣布他和他的合作者使用具有5个Fl原子的分子构建了一个5量子位的机器(请参阅参考资料 )。 不幸的是,这项技术可能无法扩展到可用的大小。
那么什么时候建造第一台可扩展量子计算机呢? 存在几种用于存储,操纵和移动量子位的候选技术。 完整的列表不在本文的讨论范围之内,但是可以肯定地说,第一个有用的质量控制还需要一到二十年的时间。
翻译自: https://www.ibm.com/developerworks/opensource/library/l-quant/index.html
量子力学导论