更多电路标识
from qiskit import QuantumCircuit
from qiskit.circuit import Gate
from math import pi
qc = QuantumCircuit(2)
c = 0
t = 1
当我们为量子计算机编程时,我们的目标总是从基本的构件中构建有用的量子电路。但有时,我们可能没有我们想要的所有基本构件。在本节中,我们将看看如何将基本的门相互转换,以及如何使用它们来构建一些稍微复杂一些的门(但仍然相当基本)。
本章中讨论的许多技术都是由Barenco及其合作者在1995年的一篇论文[1]中首次提出的。
[toc]
1.用CNOT制作一个受控Z门
受控 Z 门或cz门是另一种常用的双量子比特门。就像CNOT在其控制处于状态|1⟩时将 X 应用于其目标量子比特一样,受控 Z 在相同情况下应用 Z 。在Qiskit中,它可以直接调用
# a controlled-Z
qc.cz(c,t)
qc.draw()
其中c和t是控制量子比特和目标量子比特。然而,在IBM Q设备中,唯一一种可以直接应用的双量子比特门是CNOT。因此,我们需要一种方法将两者转换为另一种。
这个过程非常简单。我们知道,哈达玛将状态 |0⟩ 和 |1⟩ 分别转换为状态 |+⟩ 和 |-⟩ 。我们还知道,Z门对状态 |+⟩ 和 |-⟩ 的影响与X对状态 |0⟩ 和 |1⟩ 的影响相同。从这个推理,或者简单的矩阵乘法,我们发现
同样的技巧可以用于将CNOT转换为受控 Z 。我们需要做的是在CNOT之前和之后都在目标量子比特上添加哈达玛。这将把应用于该量子比特的任何 X 转换为 Z 。
qc = QuantumCircuit(2)
# also a controlled-Z
qc.h(t)
qc.cx(c,t)
qc.h(t)
qc.draw()
更一般地说,我们可以通过简单地在其前后进行正确的旋转,将单个CNOT转换为围绕布洛赫球体的任意旋转的角度 \pi 的控制版本。例如,受控 Y :
qc = QuantumCircuit(2)
# a controlled-Y
qc.sdg(t)
qc.cx(c,t)
qc.s(t)
qc.draw()
和一个受控 H
qc = QuantumCircuit(2)
# a controlled-H
qc.ry(pi/4,t)
qc.cx(c,t)
qc.ry(-pi/4,t)
qc.draw()
2.交换量子比特
a = 0
b = 1
有时我们需要在量子计算机中移动信息。对于某些量子比特实现,这可以通过物理移动它们来完成。另一种选择是简单地在两个量子比特之间移动状态。这是由交换门完成的。
qc = QuantumCircuit(2)
# swaps states of qubits a and b
qc.swap(a,b)
qc.draw()
上面的命令直接调用此门,但让我们看看如何使用我们的标准门集来制作它。为此,我们需要考虑几个示例。
首先,我们将看看量子比特a处于状态的情况 |1⟩ 并且量子比特B处于状态 |0⟩ .为此,我们将应用以下门:
qc = QuantumCircuit(2)
# swap a 1 from a to b
qc.cx(a,b) # copies 1 from a to b
qc.cx(b,a) # uses the 1 on b to rotate the state of a to 0
qc.draw()
这具有将量子比特b置于状态 |1⟩ 和量子比特a置于状态的效果 |0⟩ 。至少在这个例子中,我们做了一次交换。
现在让我们把这个状态换回原来的状态。你可能已经猜到了,我们可以用上述过程的反向来实现:
# swap a q from b to a
qc.cx(b,a) # copies 1 from b to a
qc.cx(a,b) # uses the 1 on a to rotate the state of b to 0
qc.draw()
注意,在这两个过程中,一个的第一个门不会影响另一个的初始状态。例如,当我们将 |1⟩ b交换到a时,第一个门是cx(b,a)
。如果将此应用于最初在b上没有 |1⟩ 的状态,则它将没有效果。
还要注意,对于这两个进程,一个进程的最终状态不会影响另一个进程的最终状态。例如,当我们将 |1⟩ 从a交换到b时,最终的cx(b,a)
对b上没有 |1⟩ 的状态没有影响。
有了这些观察结果,我们可以通过在两个过程之间添加一个无效的门来组合这两个过程。例如,
qc = QuantumCircuit(2)
qc.cx(b,a)
qc.cx(a,b)
qc.cx(b,a)
qc.draw()
我们可以认为这是一个将 |1⟩ 从a交换到b的过程,但开始时是一个无用的qc.cx(b,a)
。我们也可以认为它是一个将 |1⟩ 从b交换到a的过程,但最后是一个无用的qc.cx(b,a)
。无论哪种方式,结果都是一个可以以两种方式进行交换的进程。
它还对 |00⟩ 状态具有正确的影响。这是对称的,因此交换状态应该没有影响。由于CNOT门在其控制量子比特为 |0⟩ 时没有效果,因此该过程正确地什么都不做。
|11⟩ 状态也是对称的,因此需要从交换中获得微不足道的影响。在这种情况下,上述过程中的第一个CNOT门将导致第二个没有影响,第三个消除第一个。因此,整个效果确实微不足道。
因此,我们找到了一种方法,将交换门分解为单量子比特旋转的标准门集合和CNOT门。
qc = QuantumCircuit(2)
# swaps states of qubits a and b
qc.cx(b,a)
qc.cx(a,b)
qc.cx(b,a)
qc.draw()
它对各状态 |00⟩、|01⟩、|10⟩ 和 |11⟩ 有效,如果它在计算基础上对所有状态都有效,那么它肯定对所有状态都有效。因此,这个电路交换了所有可能的双量子比特状态。
如果我们改变CNOT门的顺序,也会产生相同的效果:
qc = QuantumCircuit(2)
# swaps states of qubits a and b
qc.cx(a,b)
qc.cx(b,a)
qc.cx(a,b)
qc.draw()
这也是获取交换门的一种同样有效的方法。
这里使用的推导在很大程度上基于z基状态,但也可以通过思考在状态 |+⟩ 和 |−⟩ 中交换量子比特需要什么来完成。因此,实现交换门的方法与这里的完全相同。
快速练习
找到一个不同的电路,在状态 |+⟩ 和 |−⟩ 中交换量子比特,并表明这等同于上面所示的电路。
3.受控旋转
我们已经看到了如何从单个CNOT门构建受控的 π 旋转。现在我们来看看如何构建任何可控的旋转。
首先,让我们考虑绕y轴的任意旋转。具体来说,考虑下面的门序列。
qc = QuantumCircuit(2)
theta = pi # theta can be anything (pi chosen arbitrarily)
qc.ry(theta/2,t)
qc.cx(c,t)
qc.ry(-theta/2,t)
qc.cx(c,t)
qc.draw()
如果控制量子比特处于状态 |0⟩ ,我们在这里拥有的是一个 R_y(\theta/2) ,紧跟着是它的逆 R_y(-\theta/2) 。端部效应是微不足道的。然而,如果控制量子比特处于 |1⟩| 状态,则ry(-theta/2)
有效地前后有一个X门。这具有翻转y旋转方向的效果,并产生第二个 R_y(\theta/2) 。因此,在这种情况下,最终的效果是创建一个受控版本的旋转函数 R_y(\theta) 。
这个方法可行是因为x轴和y轴是正交的,这导致x门翻转旋转的方向。因此,同样可以控制 R_z(\theta) 。受控的 R_x(\theta) 同样可以使用CNOT门制作。
我们还可以制作任何单量子比特旋转的受控版本 V 。为此,我们只需要找到三个旋转A, B和C,以及相位 α B,以便
然后,我们使用受控 Z 门使第一个关系在控制处于状态 |0⟩ 时发生,第二个关系在控制处于状态 |1⟩ 时发生。 R_z(2\alpha) 旋转也用于控件以获得正确的相位,这在有叠加状态时非常重要。
A = Gate('A', 1, [])
B = Gate('B', 1, [])
C = Gate('C', 1, [])
alpha = 1 # arbitrarily define alpha to allow drawing of circuit
qc = QuantumCircuit(2)
qc.append(C, [t])
qc.cz(c,t)
qc.append(B, [t])
qc.cz(c,t)
qc.append(A, [t])
qc.p(alpha,c)
qc.draw()
这里A、B和C分别是实现 A、B 和 C 的门。
4.托佛利门
托佛利门是一个三量子比特门,有两个控制和一个目标。仅当两个控件都处于|1⟩状态时,它才对目标执行X。然后,目标的最终状态等于两个控件的AND或NAND,这取决于目标的初始状态是|0⟩还是|1⟩。托佛利也可以被认为是受控-受控-非,也被称为CCX门。
qc = QuantumCircuit(3)
a = 0
b = 1
t = 2
# Toffoli with control qubits a and b and target t
qc.ccx(a,b,t)
qc.draw()
为了了解如何从单量子比特门和双量子比特门构建它,首先展示如何构建更通用的东西是有帮助的:任意单量子比特旋转U的任意受控-受控-U。为此,我们需要定义 V = \sqrt{U} 和 V^\dagger 的受控版本。在下面的代码中,我们使用cp(theta,c,t)
和cp(-theta,c,t)
分别代替未定义的子程序cv
和cvdg
。控制是量子比特 a 和 b ,目标是量子比特 t 。
qc = QuantumCircuit(3)
qc.cp(theta,b,t)
qc.cx(a,b)
qc.cp(-theta,b,t)
qc.cx(a,b)
qc.cp(theta,a,t)
qc.draw()
通过跟踪两个控制量子比特的每个值,您可以说服自己,当且仅当两个控制都为1时,U门应用于目标量子比特。使用我们已经描述过的想法,你现在可以实现每个受控V门,以到达双控u门的某些电路。结果表明,实现托佛利门所需的CNOT门的最小数量是6[2]。
这是一个具有3个量子比特(q0,q1,q2)的托佛利。在这个电路示例中,q0与q2连接,但q0与q1不连接。
托佛利并不是在量子计算中实现AND门的唯一方法。我们还可以定义其他具有相同效果的门,但也会引入相对的阶段。在这种情况下,我们可以用更少的CNOTs来实现门。
例如,假设我们同时使用受控哈达玛和受控-Z门,它们都可以用单个CNOT实现。有了这些,我们可以创建以下电路:
qc = QuantumCircuit(3)
qc.ch(a,t)
qc.cz(b,t)
qc.ch(a,t)
qc.draw()
对于两个控件上的状态 |00⟩ ,这对目标没有任何作用。对于 |11⟩ ,目标经历一个 Z 门,它前后都有一个H。对目标的净影响是一个 X 。对于状态 |1⟩ 和 |10⟩ ,目标要么只经历两个哈达玛(相互抵消),要么只经历Z(只诱导一个相对阶段)。因此,这也重现了AND的效果,因为目标的值只对控制上的 |11⟩ 状态进行更改——但它只使用相当于3个CNOT门的值。
5.从H和T任意旋转
当前器件中的量子比特会受到噪声的影响,噪声基本上由错误完成的门组成。一些简单的事情就可能会导致我们意想不到的事情发生,如温度、杂散磁场或邻近量子比特的活动,
对于量子计算机的大型应用,有必要以一种保护量子比特免受这种噪声影响的方式编码我们的量子比特。这是通过使盖茨更难以错误地执行,或以一种稍微错误的方式执行。
这对于单量子比特旋转 R_x(\theta) , R_y(\theta) 和 R_z(\theta) 来说是不幸的。完全精确地实现角度 θ 是不可能的,这样你就不会不小心实现 \theta + 0.0000001 这样的值。我们所能达到的精度总是有限制的,当我们考虑大电路上的缺陷累积时,它总是大于我们所能容忍的范围。因此,我们不能直接在容错量子计算机中实现这些旋转,而是需要以一种更深思熟虑的方式来构建它们。
容错方案通常只使用两个门的多个应用程序来执行这些旋转: H 和 T 。
T门在Qiskit中表示为.t()
:
qc = QuantumCircuit(1)
qc.t(0) # T gate on qubit 0
qc.draw()
它是绕z轴旋转 \theta = \pi/4 ,因此数学上表示为 R_z(\pi/4) = e^{i\pi/8~ z} 。
在下文中,我们假设 H 和 T 门实际上是完美的。这可以通过适当的错误纠正和容错方法来实现。
使用哈达玛函数和上一章讨论的方法,我们可以使用T门创建类似的绕x轴的旋转。
qc = QuantumCircuit(1)
qc.h(0)
qc.t(0)
qc.h(0)
qc.draw()
现在让我们把两者放在一起。让我们制作门 R_z(\pi/4)~R_x(\pi/4) 吧.
qc = QuantumCircuit(1)
qc.h(0)
qc.t(0)
qc.h(0)
qc.t(0)
qc.draw()
由于这是一个单量子比特门,我们可以将其视为围绕布洛赫球的旋转。这意味着它是绕某个轴旋转某个角度。这里我们不需要过多考虑轴,但它显然不是简单的x, y或z,更重要的是角度。
这个旋转角度的关键性质是它是 π 的无理数倍。你可以自己用一堆数学来证明这一点,但你也可以通过应用门来看到其中的不合理性。请记住,每当我们应用大于 2π 的旋转时,我们将对旋转角度计算 2π 的隐模。因此,重复上述 n 次的组合旋转,将导致围绕同一轴旋转不同的角度。作为一个严格证明的提示,回想一下无理数不能被写成什么?
我们可以利用这一点。每个角度将介于 0 和 2π 之间。让我们将这个区间划分为 n 的切片,宽度为 2π/n 。对于每次重复,产生的角度将落在这些切片中的一个。如果我们观察前 n+1 重复的角度,根据鸽子洞原理,至少有一个切片包含两个这样的角度,这肯定是正确的。我们用 n_1 表示第一个所需的重复次数,用 n_2 表示第二个所需的重复次数。
有了这个,我们可以证明 n_2 - n_1 重复的角度。这实际上与进行 n_2 重复相同,然后是 n_1 重复的倒数。由于它们的角度不相等(这是不合理的),而且它们之间的差异也不大于 2π/n (因为它们对应于同一个切片),因此 n_2 - n_1 重复的角度满足要求
因此,我们有能力围绕小角度进行旋转。我们可以用它来旋转任意小的角度,只需要增加重复这个门的次数。
通过使用许多小角度旋转,我们也可以旋转任何我们喜欢的角度。这并不总是精确的,但可以保证在 2π/n 以内是精确的,并且可以使其尽可能小。我们现在可以控制旋转中的不准确性。
到目前为止,我们只能绕一个轴做任意的旋转。对于第二个轴,我们只需按相反的顺序进行 R_z(\pi/4) 和 R_x(\pi/4) 的旋转。
qc = QuantumCircuit(1)
qc.t(0)
qc.h(0)
qc.t(0)
qc.h(0)
qc.draw()
这个旋转对应的轴与之前考虑的门不一样。因此,我们现在可以围绕两个轴进行任意旋转,这可以用于生成围绕布洛赫球的任意旋转。我们又可以做任何事情了,尽管花费了很多 T 门。
正是因为这种应用, T 门在量子计算中才如此突出。事实上,容错量子计算机算法的复杂性经常被引用为它们需要多少 T 门。这促使人们追求用尽可能少的 T 门来实现目标。请注意,上面的讨论只是为了证明 T 门可以以这种方式使用,并不是我们所知道的最有效的方法。
6.参考文献
import qiskit.tools.jupyter
%qiskit_version_table
Qiskit Software | Version |
---|---|
qiskit-terra | 0.18.1 |
qiskit-aer | 0.8.2 |
qiskit-ignis | 0.6.0 |
qiskit-ibmq-provider | 0.16.0 |
qiskit-aqua | 0.9.4 |
qiskit | 0.29.0 |
qiskit-nature | 0.1.5 |
qiskit-finance | 0.2.0 |
qiskit-optimization | 0.2.1 |
qiskit-machine-learning | 0.2.0 |
System information | |
Python | 3.8.5 (default, Sep 4 2020, 07:30:14) [GCC 7.3.0] |
OS | Linux |
CPUs | 2 |
Memory (Gb) | 7.521877288818359 |