The new Qiskit Textbook beta is now available. Try it out now
さらなる回路の等価性
from qiskit import QuantumCircuit
from qiskit.circuit import Gate
from math import pi
qc = QuantumCircuit(2)
c = 0
t = 1

量子コンピューターをプログラムするとき、私たちの目標は常に、基本的なパーツから有用な量子回路を構築することです。ただし、必要とする基本的なパーツがすべて揃っていない場合もあります。このセクションでは、基本的なゲートを相互に変換する方法と、ゲートを使用して少し複雑な(ただしかなり基本的な)ゲートを構築する方法について説明します。

この章で説明する手法の多くは、1995年にバレンコと共著者による論文で最初に提案されました[1]。

目次

  1. 制御ZをCNOTから作成する
  2. 量子ビットのスワップ
  3. 制御回転
  4. トフォリゲート
  5. HとTによる任意の回転
  6. 参考文献

1. 制御ZをCNOTから作成する

制御Zまたはczゲートは、よく使用されるまた別の2量子ビットゲートです。 CNOTは、その制御量子ビットが $ |1\rangle $の状態にあるときはその標的量子ビットに$X$を適用しますが、同じように、制御$Z$は、同じ場合に𝑍を適用します。 Qiskitでは、制御$Z$を直接呼び出すことができます:

# 制御Z
qc.cz(c,t)
qc.draw()

ここで、cとtは制御量子ビットと標的量子ビットです。ただし、IBM Qデバイスでは、直接適用できる2量子ビットゲートはCNOTだけです。したがって、変換する方法が必要です。

このプロセスは非常に簡単です。アダマールが$|0\rangle$および$|1\rangle$の状態を$|+\rangle$および$|-\rangle$の状態に変換することはわかっています。 $|+\rangle$と$|-\rangle$の状態に対する𝑍ゲートの影響は、$|0\rangle$と$|1\rangle$の状態に対する$X$の作用と同じであることもわかっています。このことから、または単純に行列を乗算することから、

$$ H X H = Z,\\\\ H Z H = X. $$

同じトリックを使用して、CNOTを制御$Z$に変換できます。私たちがしなければならないのは、CNOTの前と後で、アダマールを標的量子ビットに作用させるだけです。これにより、その量子ビットに適用された$X$が$Z$に変換されます。

qc = QuantumCircuit(2)
# こちらも制御Z
qc.h(t)
qc.cx(c,t)
qc.h(t)
qc.draw()

より一般的には、単一のCNOTの前後に、正しい回転を配置することにより、ブロッホ球での角度$\pi$の任意の回転の制御バージョンに変換できます。たとえば、制御$Y$は:

qc = QuantumCircuit(2)
# 制御Y
qc.sdg(t)
qc.cx(c,t)
qc.s(t)
qc.draw()

そして、制御$H$は:

qc = QuantumCircuit(2)
# 制御H
qc.ry(pi/4,t)
qc.cx(c,t)
qc.ry(-pi/4,t)
qc.draw()

2. 量子ビットのスワップ

a = 0
b = 1

量子コンピューター上で情報を移動する必要なときがあります。これを物理的に移動することで実行できるように、実装された量子ビットもありますが、別のオプションとしては、2つの量子ビット間で状態を移動することで情報の移動を実現します。これはSWAPゲートによって行われます。

qc = QuantumCircuit(2)
# 量子ビットaとbの状態をスワップする
qc.swap(a,b)
qc.draw()

上記のコマンドはこのゲートを直接呼び出しますが、標準のゲートセットを使用してこれを作成する方法を見てみましょう。このためには、いくつかの例を検討する必要があります。

まず、量子ビットaが$|1\rangle$の状態で、量子ビットbが$|0\rangle$の状態である場合を見てみましょう。これには、次のゲートを適用します:

qc = QuantumCircuit(2)
# aの1をaからbに交換
qc.cx(a,b) # aからbへ1をコピーする
qc.cx(b,a) # bの1を使用してaの状態を0に回転
qc.draw()

これは、量子ビットbを状態$|1\rangle$にし、量子ビットaを状態$|0\rangle$にする効果があります。この場合、少なくともSWAPを実行したことになります。

次に、この状態を元の状態に戻します。ご想像のとおり、上記のプロセスの逆でこれを行うことができます:

# qをbからaに入れ替える
qc.cx(b,a) # 1をbからaにコピーする
qc.cx(a,b) # aの1を使用してbの状態を0に回転
qc.draw()

これらの2つのプロセスでは、一方の最初のゲートが他方の初期状態に影響を与えないことに注意してください。たとえば、bの$|1\rangle$をaに交換する場合、最初のゲートはcx(b,a)です。代わりに、これが最初にbに$|1\rangle$がなかった状態に適用された場合、効果はありません。

また、これらの2つのプロセスでは、一方の最終ゲートが他方の最終状態に影響を与えないことに注意してください。たとえば、$|1\rangle$をaからbにスワップするときに必要な最後のcx(b,a)は、$|1\rangle$がbにない状態には影響しません。

これらの観察結果を元に、一方のゲートからもう一方のゲートに無効なゲートを追加して、2つのプロセスを組み合わせることができます。例えば、

qc = QuantumCircuit(2)
qc.cx(b,a)
qc.cx(a,b)
qc.cx(b,a)
qc.draw()

これは、aからbに$|1\rangle$を交換するプロセスと考えることができますが、最初は役に立たない qc.cx(b,a)があります。また、$|1\rangle$をbからaに交換するプロセスと考えることもできますが、最後に無用なqc.cx(b,a)があります。どちらにしても、結果は、双方向でスワップを実行できるプロセスです。

また、状態$|00\rangle$に対して正しく効果を発揮します。これは対称的であるため、状態を入れ替えても影響はありません。制御量子ビットが$|0\rangle$の場合、CNOTゲートは効果がないため、プロセスは何もしません。

状態$|11\rangle$も対称的であるため、スワップによる効果はないに等しいです。この場合、上記のプロセスの最初のCNOTゲートは2番目のゲートに影響を与えず、3番目のゲートは最初のゲートを元に戻します。したがって、全体の効果は確かにないに等しいです。

このようにして、SWAPゲートを標準ゲートセットである単一量子ビットの回転ゲートとCNOTゲートに分解する方法を見つけました。

qc = QuantumCircuit(2)
# 量子ビットaとbの状態のスワップ
qc.cx(b,a)
qc.cx(a,b)
qc.cx(b,a)
qc.draw()

これは、$|00\rangle$、 $|01\rangle$、 $|10\rangle$、 $|11\rangle$、およびそれらのすべての重ね合わせに対して機能します。したがって、可能なすべての2量子ビット状態をスワップします。

CNOTゲートの順序を変更した場合も、同じ効果が得られます:

qc = QuantumCircuit(2)
# 量子ビットaとbの状態を入れ替えます
qc.cx(a,b)
qc.cx(b,a)
qc.cx(a,b)
qc.draw()

これは、SWAPゲートを取得するための同様に有効な方法です。

ここでの導出には、z基底状態に基づいていましたが、状態 $|+\rangle$ と $|-\rangle$でも同じように量子ビットのスワップができ、SWAPゲートを実装する方法は、完全に同じです。

練習問題:

  • 状態$|+\rangle$ と $|-\rangle$ で量子ビットをスワップする回路を作り、それが上記の回路と等価であることを示してください。

3. 制御回転

制御$\pi$回転を単一のCNOTゲートから構築する方法についてをみてきました。 次に、任意の制御回転を構築する方法をみていきます。

まず、y軸を中心とした任意の回転を考えてみましょう。 具体的には、次の一連のゲートを考えてみてください。

qc = QuantumCircuit(2)
theta = pi # thetaは何でもよい (任意の値としてpiを選択)
qc.ry(theta/2,t)
qc.cx(c,t)
qc.ry(-theta/2,t)
qc.cx(c,t)
qc.draw()

この回路は、制御量子ビットが状態 $|0\rangle$の場合、$R_y(\theta/2)$の後にその逆の $R_y(-\theta/2)$ が続くだけです。この最終的な効果は、ないに等しいです。しかし、制御量子ビットが $|1\rangle$ の場合、ry(-theta/2)の前後にXゲートが適用されます。これは、y回転の方向を反転し、2番目の $R_y(\theta/2)$ を作成する効果があります。したがって、この場合の正味の作用は、制御バージョンの回転 $R_y(\theta)$ を作ることと同じになります。

この方法が機能するのは、xとy軸が直行し、そのためにxゲートが回転の方法を反転させるためです。したがって、制御$R_z(\theta)$を作るのも同じように機能します。制御 $R_x(\theta)$ は、CNOTゲートを使って同じように作ることができます。

また、単一量子ビット回転$U$の制御バージョンも作ることができます。そのためには、3つの回転A、B、Cと、次のような位相 $\alpha$ を見つけるだけです。

$$ ABC = I, ~~~e^{i\alpha}AZBZC = U $$

制御Zゲートを使うことで、上の左の式を制御ビットが$|0\rangle$の状態の際に発生させ、右の式を制御ビットが$|1\rangle$の状態のときに発生させます。正しい位相を得るために制御ビット側で$R_z(2\alpha)$回転も使われ、これは、重ね合わせ状態がある場合に重要です。

A = Gate('A', 1, [])
B = Gate('B', 1, [])
C = Gate('C', 1, [])
alpha = 1 # 回路描写のために任意のalphaを設定
qc = QuantumCircuit(2)
qc.append(C, [t])
qc.cz(c,t)
qc.append(B, [t])
qc.cz(c,t)
qc.append(A, [t])
qc.u1(alpha,c)
qc.draw()

A controlled version of a gate V

ここで、ABCはそれぞれ、$A$ 、$B$ 、$C$を実装するゲートです。

4. トフォリ

トフォリゲートは、2つの制御と1つの標的を持つ3量子ビットゲートです。両方の制御ビットが $|1\rangle$ の状態の時のみ標的ビットにXを適用します。標的ビットの最終状態は、標的ビットの初期状態が $|0\rangle$ または $|1\rangle$ のどちらであったかに応じて、2つの制御ビットのANDまたはNANDのいずれかに等しくなります。トフォリは、制御・制御NOTとも考えることもでき、CCXゲートとも呼ばれます。

qc = QuantumCircuit(3)
a = 0
b = 1
t = 2
# 制御ビットa、b、標的ビットtのトフォリ
qc.ccx(a,b,t)
qc.draw()

単一量子ビットゲートと2量子ビットゲートからこれを構築する方法を確認するために、まず、より一般的なものを構築する方法を示します:任意の単一量子ビット回転Uについての、任意の制御・制御Uです。そのためには、制御バージョンの $V = \sqrt{U}$ と $V^\dagger$ の定義が必要です。以下のコードでは、未定義のサブルーチン cvcvdg の代わりに、それぞれ cu1(theta,c,t)cu1(-theta,c,t) を使っています。制御ビットは量子ビット $a$ と $b$で、標的ビットは量子ビット $t$ です。

qc = QuantumCircuit(3)
qc.cu1(theta,b,t)
qc.cx(a,b)
qc.cu1(-theta,b,t)
qc.cx(a,b)
qc.cu1(theta,a,t)
qc.draw()

A doubly controlled version of a gate V

2つの制御ビットの各値をみていくことで、両方の制御ビットが1の場合にのみ、Uゲートが標的ビットに適用されることを確認できます。すでに説明したアイディアを使って、二重制御されたUゲートのある回路を使って、各制御Vゲートを実装することができるでしょう。これから、トフォリゲートを実装するために必要なCNOTゲートの数は最小で6であることがわかります[2]。

A Toffoli

トフォリは、量子コンピューティングでANDゲートを実装するための唯一の方法ではありません。同じ効果があり、相対位相を持つ他のゲートも定義することができます。これらの場合、より少ないCNOTでゲートを実装できます。

例えば、制御アダマールゲートと制御$Z$ゲートを使うとします。これらのゲートは、両方とも1つのCNOTで実装できます。これらのゲートから次の回路を作成できます:

qc = QuantumCircuit(3)
qc.ch(a,t)
qc.cz(b,t)
qc.ch(a,t)
qc.draw()

2つの制御ビットの状態が $|00\rangle$ の場合、標的ビットに対して何も行いません。$|11\rangle$ の場合、標的ビットには、前後にHゲートのある$Z$ゲートが適用されます。$|01\rangle$ と $|10\rangle$ の状態の時には、標的ビットには2つのアダマール(相互に打ち消しあう)だけ、または$Z$(相対位相のみ変化させる)が適用されます。また、標的ビットは制御ビットが$|11\rangle$状態でのみ変更されるため、制御ビットのANDの効果も生じます(ただしCNOTゲート3つのときのみの効果)。

5. HとTによる任意の回転

現在のデバイスの量子ビットはノイズの影響を受けやすく、基本的にはエラーを起こすゲートで構成されています。温度、磁場のゆらぎ、隣の量子ビットの動きなどのような単純なことが、意図していないことを引き起こす可能性があります。

量子コンピューターの大規模なアプリケーションでは、このノイズから量子ビットを保護するように量子ビットをエンコードする必要があります。これは、ゲートを間違って実行することを難しくするか、またはわずかに間違った方法で実装することによって行われます。

単一量子ビットの回転$R_x(\theta)$、 $R_y(\theta)$ 、 $R_z(\theta)$ は残念ですが、角度 $\theta$ を完璧な精度で実装するのは不可能です。これは、あなたが、角度 $\theta + 0.0000001$ のようなものを間違って実装することがないのと同じです。達成できる精度には常に限界があり、大きな回路ではエラーの積み重ねがあることを考慮すると、その精度は許容範囲を常に超えています。したがって、これらの回転をフォールトトレラントな量子コンピューターに直接実装することはできませんが、代わりに、より工夫した方法で回転を構築する必要があります。

フォールトトレラントのスキームでは、通常、2つのみのゲート、$H$ と $T$ を複数適用することによってこれらの回転を実行します。

Tゲートは、Qiskitでは.t()として表現されます:

qc = QuantumCircuit(1)
qc.t(0) # 量子ビット0へTゲートを適用
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()

では、2つを組み合わせてみましょう。$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の回転になることはありません。より重要なのは角度です。

この回転の角度の重要な特性は、それが無理数であることです。これは、たくさんの数学で自分で証明できますが、ゲートを適用することで、動作から無理数であることを確認することもできます。 𝑛回繰り返すと、同じ軸を中心に異なる角度で回転します。無理数性により、異なる繰り返しから生じる角度は同じになることはありません。

これを有利に利用できます。各角度は$0$ から $2\pi$の間のどこかになります。この間隔を幅 $2\pi/n$ の $n$個のスライスに分割してみましょう。繰り返す度に、その角度はこれらのスライスのどこか1つになります。最初の $n+1$ 回の繰り返しの角度を見ると、少なくとも1つのスライスにこれらの角度が2つ含まれていることは事実です。 $n_1$ を最初の繰り返し数、 $n_2$ を2番目の繰り返し数とします。

これにより、$n_2-n_1$ 回の繰り返しの際の角度について何かを証明できます。これは実質的に $n_2$ 回の繰り返しの後に $n_1$ 回の逆向きの繰り返しをするのと同じです。これらの角度は等しくない(無理数のため)だけでなく、 $2\pi/n$ 以下の差(同じスライスに対応するため)であるため、 $n_2-n_1$ 回の繰り返しの角度は、

$$ \theta_{n_2-n_1} \neq 0, ~~~~-\frac{2\pi}{n} \leq \theta_{n_2-n_1} \leq \frac{2\pi}{n} . $$

したがって、小さな角度で回転させることができます。 これを使用して、このゲートを繰り返す回数を増やすだけで、好きなだけ小さい角度で回転できます。

小さな角度の回転を多用することで、好きな角度で回転させることもできます。 これは常に正確であるとは限りませんが、最大$2\pi/n$まで正確であることが保証されています。これは、好きなだけ小さくすることができます。 これで、ローテーションの不正確さを管理できるようになりました。

これまでのところ、私たちはこれらの任意の回転を1つの軸を中心に行う力しか持っていません。 2番目の軸については、$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()

この回転に対応する軸は、以前に検討したゲートの軸と同じではありません。 したがって、2つの軸を中心とした任意の回転が得られ、ブロッホ球を中心とした任意の回転を生成するために使用できます。 $T$ ゲートのコストがかなりかかりますが、すべてを実行できるようになりました。

$T$ ゲートが量子計算でよく見られるのは、このようなアプリケーションのためです。 実際、フォールトトレラントな量子コンピューターのアルゴリズムの複雑さは、 $T$ ゲートがいくつ必要かという点でしばしば引用されます。 これは、できるだけ少ない $T$ ゲートで達成するための探求の動機になります。 上記の説明は、 $T$ ゲートをこのように使用できることを証明するためのものであり、私たちが知っている最も効率的な方法を表すものではないことに注意してください。

import qiskit
qiskit.__qiskit_version__
{'qiskit-terra': '0.14.1',
 'qiskit-aer': '0.5.1',
 'qiskit-ignis': '0.3.0',
 'qiskit-ibmq-provider': '0.7.1',
 'qiskit-aqua': '0.7.1',
 'qiskit': '0.19.2'}