量子叠加与纠缠实例分析
大家在第一篇文章中已经对量子叠加态和量子间互相纠缠有了一定的理解,在此篇文章中,我们将通过量子编程代码的形式来深入理解量子这两个特性:
PS:在此文章中,我们将通过微软官方文档的案例还深入理解
链接如下:https://learn.microsoft.com/en-us/azure/quantum/tutorial-qdk-explore-entanglement?pivots=ide-local
在探究量子叠加与纠缠之前,需要明确的是,我们已经知道了由于量子叠加态这一特性的存在,一个量子比特的观测值虽然是一个确定的态(Zero or One),但是这一量子比特将会被测量为其中任意态我们是不知道的。所以,为了方便探究量子的叠加态和量子间的纠缠,我们首先要将一个量子的态确定下来,也就是通过测量来初始化量子比特。
我们先来查看下述代码
1 operation SetQubitState(desired : Result, target : Qubit) : Unit { 2 if desired != M(target) { 3 X(target); 4 } 5 }
我们可以看到SetQubitState方法的功能如下
- 采用两个参数:一个“Result”类型的desired参数,用来表示我们想要将量子比特初始化的状态 (Zero or One),以及一个“Qubit”类型的参数,作为目标测量量子比特。
- 标准运算
M
,用来测量量子比特的状态(Zero or One),并将结果与“desired”中的值进行比较。 - 如果测量结果与比较值不匹配,则运行标准运算X,用来将量子比特的状态进行反转。
通过上述方法即可将一个量子比特初始化为我们想要设定的初始态(Zero or One)。
接下来我们来查看下述代码:
1 operation TestBellState(count : Int, initial : Result) : (Int, Int, Int, Int) { 2 mutable numOnesQ1 = 0; 3 mutable numOnesQ2 = 0; 4 5 use (q1, q2) = (Qubit(), Qubit()); 6 for test in 1..count { 7 SetQubitState(initial, q1); 8 SetQubitState(Zero, q2); 9 10 let resultQ1 = M(q1); 11 let resultQ2 = M(q2); 12 13 if resultQ1 == One { 14 set numOnesQ1 += 1; 15 } 16 if resultQ2 == One { 17 set numOnesQ2 += 1; 18 } 19 } 20 21 SetQubitState(Zero, q1); 22 SetQubitState(Zero, q2); 23 24 Message($"Q1 - Zeros: {count - numOnesQ1}"); 25 Message($"Q1 - Ones: {numOnesQ1}"); 26 Message($"Q2 - Zeros: {count - numOnesQ2}"); 27 Message($"Q2 - Ones: {numOnesQ2}"); 28 return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 ); 29 30 }
让我们探究一下TestBellState方法的功能:
- 首先调用“use”语句以初始化两个量子比特。
- 循环 count 次迭代。 对于每次循环,它将
- 调用SetQubitState()方法以便对第一个量子比特设置指定的initial值(Zero or One)。
- 再次调用SetQubitState()方法以将第二个量子比特设置为“Zero”状态。
- 使用
M
运算来测量每个量子比特。 - 最后将量个量子比特返回“One”的测量数目保存在numOnesQ1和numOnesQ2中。
- 循环完成后,它会再次调用SetQubitState()方法以将量子比特重置为已知状态(Zero态),目的是让其他对象能够以已知状态分配量子比特。
- 最后,通过Message()函数输出指定格式的结果。
由于该方法需要传入指定参数值,所以我们在终端启动的时候就要赋予该函数所需要的函数值:
dotnet run --count 1000 --initial One
在终端按上述形式启动程序即可将第一个量子比特初始化为(One)并且迭代循环1000次。
我们可以看到我们已经成功将第一个量子比特初始化为“One”,第二个量子比特初始化为“Zero”了。
接下来我们就可以开始探索量子叠加与纠缠这两个特性了:
首先,叠加态:
探索叠加态需要用到一个老朋友:H门。还记得在真正随机那篇文章H门第一次出现。他都作用是使一个量子比特置于叠加状态,在此状态下,量子比特的测量会在 50% 的时间返回“Zero”,在 50% 的时间返回“One”。
我们探究叠加态的思路是:首先,我们使两个量子比特中的一个量子比特通过H门的作用,使其处于叠加态中,而保持另一个量子比特处于“Zero”的初始态,然后经过迭代循环,不断测量两个量子比特的具体态,最后输出两个量子比特的测量值并进行观察。
通过上述思路,我们可以实现下述代码:
1 namespace Bell { 2 open Microsoft.Quantum.Intrinsic; 3 open Microsoft.Quantum.Canon; 4 5 operation SetQubitState(desired : Result, target : Qubit) : Unit { 6 if desired != M(target) { 7 X(target); 8 } 9 } 10 11 @EntryPoint() 12 operation TestBellState(count : Int, initial : Result) : (Int, Int, Int, Int) { 13 mutable numOnesQ1 = 0; 14 mutable numOnesQ2 = 0; 15 16 use (q1, q2) = (Qubit(), Qubit()); 17 for test in 1..count { 18 SetQubitState(initial, q1); 19 SetQubitState(Zero, q2); 20 21 //叠加 22 H(q1); 23 24 let resultQ1 = M(q1); 25 let resultQ2 = M(q2); 26 27 if resultQ1 == One { 28 set numOnesQ1 += 1; 29 } 30 if resultQ2 == One { 31 set numOnesQ2 += 1; 32 } 33 } 34 35 SetQubitState(Zero, q1); 36 SetQubitState(Zero, q2); 37 38 Message($"Q1 - Zeros: {count - numOnesQ1}"); 39 Message($"Q1 - Ones: {numOnesQ1}"); 40 Message($"Q2 - Zeros: {count - numOnesQ2}"); 41 Message($"Q2 - Ones: {numOnesQ2}"); 42 return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 ); 43 44 } 45 }
按照上述启动方法,在终端按上形式启动程序即可将第一个量子比特初始化为(One)并且迭代循环1000次。
我们可以看到,针对第一个量子比特,通过H门的作用已经显示出 Zero 和 One 概率各50%的叠加态。而结果不是 Zeros 和 Ones 各为精确的500次也是因为量子计算中绝大多数问题都是以概率的形式进行表现。运用概率论的思想,一件事务发生的频率是接近于其发生的概率的,但不可能绝对相等。
接下来,让我们一起探索量子比特间的相互纠缠:
通过第一篇文章的介绍,量子间纠缠是量子间的特性。纠缠是量子系统之间的量子关联。 当量子比特纠缠时,它们会形成一个全局系统,因此无法相互独立地描述各个子系统的量子状态。 同时,当我们无法将全局系统的状态写入为子系统状态的组合时,两个系统也就纠缠在一起了。也就是说,无论一个量子比特发生了什么运算,纠缠的量子比特也会发生这种运算。 通过这种特性,我们只需测量一个量子比特的状态,就能知道另一个量子比特的最终状态,从而无需测量它的态。
我们探究量子间纠缠的思路大致与量子叠加相似,:首先,我们使两个量子比特中的一个量子比特通过H门的作用,使其处于叠加态中,然后通过某一手段使处于叠加态的第一个量子比特与另一个量子比特相互纠缠,然后经过迭代循环,不断测量两个量子比特的具体的态,最后输出两个量子比特的测量值并进行观察。
PS:和H门一样,Q# 提供了CNOT运算来实现纠缠。 该运算的实质是:对于两个量子比特,运行此操作的结果为,在第一个量子比特是“One”的情况下翻转第二个量子比特。
有了上述思路,让我们查看以下代码:
1 namespace Bell { 2 open Microsoft.Quantum.Intrinsic; 3 open Microsoft.Quantum.Canon; 4 5 operation SetQubitState(desired : Result, target : Qubit) : Unit { 6 if desired != M(target) { 7 X(target); 8 } 9 } 10 11 @EntryPoint() 12 operation TestBellState(count : Int, initial : Result) : (Int, Int, Int, Int) { 13 mutable numOnesQ1 = 0; 14 mutable numOnesQ2 = 0; 15 16 use (q1, q2) = (Qubit(), Qubit()); 17 for test in 1..count { 18 SetQubitState(initial, q1); 19 SetQubitState(Zero, q2); 20 21 //叠加 22 H(q1); 23 //纠缠 24 CNOT(q1, q2); 25 26 let resultQ1 = M(q1); 27 let resultQ2 = M(q2); 28 29 if resultQ1 == One { 30 set numOnesQ1 += 1; 31 } 32 if resultQ2 == One { 33 set numOnesQ2 += 1; 34 } 35 } 36 37 SetQubitState(Zero, q1); 38 SetQubitState(Zero, q2); 39 40 Message($"Q1 - Zeros: {count - numOnesQ1}"); 41 Message($"Q1 - Ones: {numOnesQ1}"); 42 Message($"Q2 - Zeros: {count - numOnesQ2}"); 43 Message($"Q2 - Ones: {numOnesQ2}"); 44 return (count - numOnesQ1, numOnesQ1, count - numOnesQ2, numOnesQ2 ); 45 46 } 47 }
实际上就是在探究叠加态的基础上,在第一个量子比特经过H门操作后,通过CNOT(q1, q2);运算来使两个量子比特处于相互纠缠的状态。
接下来,我们一起观察一下纠缠的结果:
我们可以看到,虽然我们没有对第二个量子比特叠加态处理(使其作用于H门),但是由于第二个量子比特与第一个量子比特处于相互纠缠的状态,所以第一个量子比特的信息也会赋予第二个量子比特中,这就是我们观测到第二个量子比特的测量值与第一个量子比特的测量值相同的原因了。
大家看到这,量子比特的叠加态和量子比特间的相互纠缠的特性都已经通过代码形式显现出来了,大家是否觉得很神奇呢?我认为量子计算基础的部分到这里就可以了,如果大家感兴趣的话可以跟着我一起学习后续的量子算法部分吧!