The new Qiskit Textbook beta is now available. Try it out now
位相キックバック

1. Exploring the CNOT-Gate

前のセクションでは、CNOTゲートを使用したいくつかの非常に基本的な結果を確認しました。ここでは、さらに興味深い結果をいくつか見ていきます。

制御量子ビットを状態$|+\rangle$におくことで、2つの量子ビットをエンタングルできました:

$$ \text{CNOT}|0{+}\rangle = \tfrac{1}{\sqrt{2}}(|00\rangle + |11\rangle) $$

しかし、2番目の量子ビットも重ね合わせの状態にするどうなるでしょうか?

from qiskit import QuantumCircuit, Aer, assemble
from math import pi
import numpy as np
from qiskit.visualization import plot_bloch_multivector, plot_histogram, array_to_latex
qc = QuantumCircuit(2)
qc.h(0)
qc.h(1)
qc.cx(0,1)
qc.draw()

上の回路について、CNOTを作用させます:

$$ |{+}{+}\rangle = \tfrac{1}{2}(|00\rangle + |01\rangle + |10\rangle + |11\rangle) $$

CNOTは$|01\rangle$と$|11\rangle$の振幅をスワップするため、結果に変わりが無いことが分かります:

qc = QuantumCircuit(2)
qc.h(0)
qc.h(1)
qc.cx(0,1)
display(qc.draw())  # `display` is a command for Jupyter notebooks
                    # similar to `print`, but for rich content

# Let's see the result
svsim = Aer.get_backend('aer_simulator')
qc.save_statevector()
qobj = assemble(qc)
final_state = svsim.run(qobj).result().get_statevector()
display(array_to_latex(final_state, prefix="\\text{Statevector} = "))
plot_bloch_multivector(final_state)
$\displaystyle \text{Statevector} = \begin{bmatrix} \tfrac{1}{2} \\ \tfrac{1}{2} \\ \tfrac{1}{2} \\ \tfrac{1}{2} \end{bmatrix} $

標的量子ビットの状態を$|-\rangle$にすると、マイナスの位相をもちます:

qc = QuantumCircuit(2)
qc.h(0)
qc.x(1)
qc.h(1)
qc.draw()

この状態はこちらです:

$$ |{-}{+}\rangle = \tfrac{1}{2}(|00\rangle + |01\rangle - |10\rangle - |11\rangle) $$
qc = QuantumCircuit(2)
qc.h(0)
qc.x(1)
qc.h(1)
display(qc.draw())
# See the result
qc1 = qc.copy()
qc1.save_statevector()
final_state = svsim.run(qc1).result().get_statevector()
display(array_to_latex(final_state, prefix="\\text{Statevector} = "))
plot_bloch_multivector(final_state)
$\displaystyle \text{Statevector} = \begin{bmatrix} \tfrac{1}{2} \\ \tfrac{1}{2} \\ -\tfrac{1}{2} \\ -\tfrac{1}{2} \end{bmatrix} $

CNOTをこの状態に作用させる場合、$|01\rangle$ と $|11\rangle$ の振幅がスワップされて、次の状態になります:

$$ \begin{aligned} \text{CNOT}|{-}{+}\rangle & = \tfrac{1}{2}(|00\rangle - |01\rangle - |10\rangle + |11\rangle) \\ \text{CNOT}|{-}{+}\rangle & = |{-}{-}\rangle \end{aligned} $$

これは興味深いものです。なぜなら、標的量子ビットの状態を変更せずに、制御量子ビットの状態に影響を与えるからです。

qc.cx(0,1)
display(qc.draw())

qc.save_statevector()
qobj = assemble(qc)
final_state = svsim.run(qobj).result().get_statevector()
display(array_to_latex(final_state, prefix="\\text{Statevector} = "))
plot_bloch_multivector(final_state)
$\displaystyle \text{Statevector} = \begin{bmatrix} \tfrac{1}{2} \\ -\tfrac{1}{2} \\ -\tfrac{1}{2} \\ \tfrac{1}{2} \end{bmatrix} $

Hゲートが$|{+}\rangle \rightarrow |0\rangle$ と $|{-}\rangle \rightarrow |1\rangle$ の変換をすることを覚えていたら、CNOTをHゲートでラップすると、向きが反対のCNOTと同じ作用になることが分かると思います。

cnot_identity

これは、Qiskitのユニタリーシミュレーターを使って確認できます:

qc = QuantumCircuit(2)
qc.h(0)
qc.h(1)
qc.cx(0,1)
qc.h(0)
qc.h(1)
display(qc.draw()) 
# `display` is an IPython tool, remove if it causes an error

qc.save_unitary()
usim = Aer.get_backend('aer_simulator')
qobj = assemble(qc)
unitary = usim.run(qobj).result().get_unitary()
array_to_latex(unitary, prefix="\\text{Circuit = }\n")
$\displaystyle \text{Circuit = } \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \\ \end{bmatrix} $$ $
qc = QuantumCircuit(2)
qc.cx(1,0)
display(qc.draw())
qc.save_unitary()

qobj = assemble(qc)
unitary = usim.run(qobj).result().get_unitary()
array_to_latex(unitary, prefix="\\text{Circuit = }\n")
$\displaystyle \text{Circuit = } \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \\ \end{bmatrix} $$ $

この等価性は位相キックバックの一例であり、説明は次のセクションに続きます。。。

2. 位相キックバック

2.1 CNOT回路の等価性の説明

前のセクションでこの等価性を確認しました:

cnot_identity

これはキックバック(または位相キックバック)の一例であり、ほとんどすべての量子アルゴリズムで使用されているほど、とても重要です。キックバックは、ゲートによって量子ビットに追加された固有値が、制御操作によって別の量子ビットに「キックバック」されることです。例えば、$|{-}\rangle$ の量子ビットにXゲートを実行すると、位相 $-1$が得られます:

$$ X|{-}\rangle = -|{-}\rangle $$

制御量子ビットが$|0\rangle$ または$|1\rangle$のいずれかにある場合、この位相は状態全体に影響しますが、グローバル位相であるため、観測されません:

$$ \begin{aligned} \text{CNOT}|{-}0\rangle & = |{-}\rangle \otimes |0\rangle \\ & = |{-}0\rangle \\ \quad & \\ \text{CNOT}|{-}1\rangle & = X|{-}\rangle \otimes |1\rangle \\ & = -|{-}\rangle \otimes |1\rangle \\ & = -|{-}1\rangle \\ \end{aligned} $$

興味深い効果は、制御量子ビットが重ね合わせの場合です。この位相因子は、状態$|1\rangle$の場合にのみ、標的量子ビットに適用されます。これにより、制御量子ビットに相対位相が追加されます:

$$ \begin{aligned} \text{CNOT}|{-}{+}\rangle & = \tfrac{1}{\sqrt{2}}(\text{CNOT}|{-}0\rangle + \text{CNOT}|{-}1\rangle) \\ \text{CNOT}|{-}{+}\rangle & = \tfrac{1}{\sqrt{2}}(|{-}0\rangle + X|{-}1\rangle) \\ \text{CNOT}|{-}{+}\rangle & = \tfrac{1}{\sqrt{2}}(|{-}0\rangle -|{-}1\rangle) \\ \end{aligned} $$

これは、2つの分離可能な量子ビット状態として書き込むことができます:

$$ \begin{aligned} \text{CNOT}|{-}{+}\rangle & = |{-}\rangle \otimes \tfrac{1}{\sqrt{2}}(|{0}\rangle - |1\rangle )\\ \text{CNOT}|{-}{+}\rangle & = |{-}{-}\rangle \\ \end{aligned} $$

HゲートでCNOTをラップすると、量子ビットが計算基底から$(|+\rangle, |-\rangle)$ 基底に変換され、この効果がわかります。一部のハードウェアは2つの特定の量子ビット間の一方向のCNOTしか許されないため、この等価性はハードウェアレベルで非常に有益です。この等価性を使ってこのハードウェアの問題を克服し、双方向のCNOTを実現できるようになります。

2.2 Tゲートでのキックバック

別の制御オペレーションである、制御Tゲートを見てみましょう:

qc = QuantumCircuit(2)
qc.cp(pi/4, 0, 1)
qc.draw()

Tゲートは、以下の行列です:

$$ \text{T} = \begin{bmatrix} 1 & 0 \\ 0 & e^{i\pi/4}\\ \end{bmatrix} $$

そして、制御Tゲートは以下の行列です:

$$ \text{Controlled-T} = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & e^{i\pi/4}\\ \end{bmatrix} $$

これはQiskitのユニタリーシミュレーターで確認できます:

qc = QuantumCircuit(2)
qc.cp(pi/4, 0, 1)
display(qc.draw())
# See Results:
qc.save_unitary()
qobj = assemble(qc)
unitary = usim.run(qobj).result().get_unitary()
array_to_latex(unitary, prefix="\\text{Controlled-T} = \n")
$\displaystyle \text{Controlled-T} = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & \tfrac{1}{\sqrt{2}}(1 + i) \\ \end{bmatrix} $$ $

より一般的には、次の規則を使用して、制御Uオペレーションの行列を見つけることができます:

$$ \begin{aligned} \text{U} & = \begin{bmatrix} u_{00} & u_{01} \\ u_{10} & u_{11}\\ \end{bmatrix} \\ \quad & \\ \text{Controlled-U} & = \begin{bmatrix} I & 0 \\ 0 & U\\ \end{bmatrix} = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & u_{00} & u_{01} \\ 0 & 0 & u_{10} & u_{11}\\ \end{bmatrix} \end{aligned} $$

または、Qiskitの量子ビット配列では:

$$ \text{Controlled-U} = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & u_{00} & 0 & u_{01} \\ 0 & 0 & 1 & 0 \\ 0 & u_{10} & 0 & u_{11}\\ \end{bmatrix} $$

状態 $|1\rangle$ の量子ビットにTゲートを適用すると、この量子ビットに $e^{i\pi/4}$ の位相が追加されます:

$$ T|1\rangle = e^{i\pi/4}|1\rangle $$

これはグローバル位相であり、観測することはできませんが、$|{+}\rangle$状態の別の量子ビットを使用してこの操作を制御すると、位相はグローバルではなく相対になり、制御ビットの相対位相が変化します:

$$ \begin{aligned} |1{+}\rangle & = |1\rangle \otimes \tfrac{1}{\sqrt{2}}(|0\rangle + |1\rangle) \\ & = \tfrac{1}{\sqrt{2}}(|10\rangle + |11\rangle) \\ & \\ \text{Controlled-T}|1{+}\rangle & = \tfrac{1}{\sqrt{2}}(|10\rangle + e^{i\pi/4}|11\rangle) \\ & \\ \text{Controlled-T}|1{+}\rangle & = |1\rangle \otimes \tfrac{1}{\sqrt{2}}(|0\rangle + e^{i\pi/4}|1\rangle) \end{aligned} $$

これは、標的量子ビットを変化させずに、制御量子ビットをブロッホ球のZ軸回りに回転させる作用があります。これをQiskitで見てみましょう:

qc = QuantumCircuit(2)
qc.h(0)
qc.x(1)
display(qc.draw())
# See Results:
qc.save_statevector()
qobj = assemble(qc)
final_state = svsim.run(qobj).result().get_statevector()
plot_bloch_multivector(final_state)
qc = QuantumCircuit(2)
qc.h(0)
qc.x(1)
# Add Controlled-T
qc.cp(pi/4, 0, 1)
display(qc.draw())
# See Results:
qc.save_statevector()
qobj = assemble(qc)
final_state = svsim.run(qobj).result().get_statevector()
plot_bloch_multivector(final_state)