量子コンピュータ

【量子コンピュータ入門】Bloch球×Qiskitで理解する万能ゲートと量子回路シミュレーション

量子コンピュータシリーズ第3弾です。

前回は、量子コンピュータとは量子状態を自由自在にユニタリ変換する装置であるということを説明し、次回(つまり今回です)は量子コンピュータにおける万能ゲートについて説明するという旨の予告をしました。

前回
量子コンピュータのための量子論基礎【一体系篇】

こんにちは皆さん、量子コンピュータシリーズ第2弾です。 前回は量子コンピュータの概要について見ました。 今回の記事では、より詳しく量子コンピュータを理解するために必要な最小限の数学と量子論を学んでいこ ...

続きを見る

そこで今回は量子回路のシミュレーションを行いつつ、量子万能ゲートを理解することを目標とします。

早速始めていきましょう。

 

メモ

・前回の内容

 

備考

今回は量子状態及び量子回路のシミュレータとしてQiskitというPythonライブラリを用いるつもりなので、これらを使えるようにしておくとより理解が深まるかと思います。

また前回と同様に光学系による実装を仮定しているので、諸々の定義やセットアップなどは前回を参照してください。

 

量子回路のシミュレーション

始めに用語の定義ですが、「量子回路」とは量子コンピュータの内部で行われる一連のユニタリ変換のセットのことを言います。

そして量子回路は「量子ゲート」という特定のユニタリ変換を物理的に実装した素子を組み合わせることで実現されます。

以下ではBloch球の概念を用いることで、量子ゲート及び量子回路の作用を視覚的に分かりやすい形で表現してみたいと思います。

Bloch球

まずは前回のおさらいを兼ねてBloch(ブロッホ)球を定義し直しましょう。

Bloch球とは、二準位量子系が取り得る全ての状態を球面上の点と対応させて表現したものです。

前回はBloch球の各点に光学由来の記号をつけましたが、今回はコンピュータらしく\(0, 1\)をベースにした記号をつけました。

向きを\(0 \circ\)に固定した偏光板を通過する状態、通過しない状態をそれぞれ\(| 0 \rangle, | 1 \rangle\)とし、それらをBloch球の北極と南極にそれぞれ対応させます。

これらは古典コンピュータにおける真理値\(0, 1\)に対応しており、量子系における情報の最小単位ということで「量子ビット」と呼ばれます。

任意の量子状態は\(| 0 \rangle, | 1 \rangle\)の適当な重ね合わせで作ることができ、それはブロッホ球に関するパラメータ\(\phi, \delta\)を用いて

$$ | \psi \rangle = \cos \frac{\phi}{2} | 0 \rangle + e^{i \delta} \sin \frac{\phi}{2} | 1 \rangle $$

と表現できます。

前回とは量子状態の表現が違うことに注意してください。

前回は多準位系への拡張も視野に入れて、\(\phi_1, \phi_2\)という各固有状態からの角度を用いて量子状態を表しましたが(こうしておくとパーセヴァルの等式という、多準位系で一般に成り立つ関係が使えます)、今回のように二準位系のみを取り扱う場合には二つのパラメータのみで事足りるのです。

また前回は記号の混乱を避けるために角度の表記として度数法を用いましたが、今回は全面的に弧度法を用いることにします。

ではBloch球上の量子状態をQiskitを使って図示してみましょう。

from qiskit.quantum_info import Statevector
from qiskit.visualization import plot_bloch_multivector
import numpy as np

phi = np.pi/6 # φに対応
delta = np.pi/4 # δに対応

alpha = np.cos(phi/2) # |0>の係数に対応
beta = np.exp(1j*delta) * np.sin(phi/2) # |1>の係数に対応
state = Statevector([alpha, beta]) # ベクトル(リスト)を量子状態に変換

plot_bloch_multivector(state) # 量子状態を図示

>>

 

環境の整っている方はphi, deltaを色々変えて遊んでみてください。

以下ではこの状態に量子ゲートを作用させたときの変化を見ていくことにします。

 

量子ゲート

次に入力された量子状態に対して、それをユニタリ変換して出力する素子である量子ゲートについて見ていきましょう。

一つの量子ビットのみに作用する量子ゲートとしては、メジャーなもので大体以下のものがあります。

これらは特定のユニタリ変換を記号化したもので、左側から入力された量子状態が、記号に対応したユニタリ変換を受けて右側から出力されることを図示しています。

これらをどんどん繋いでいったものが量子回路です。

それではそれぞれのゲートについて、対応する物理的な操作と行列による表現、量子状態に与える変化を見てみましょう。

\(T\)ゲート

\(T\)ゲートは上の行列で表されるユニタリ変換を施す素子です。

Qiskitでは先のコードに以下のコードを合わせることでこのゲートの作用をシミュレートすることができます。

from qiskit import QuantumCircuit
from qiskit.quantum_info.operators.operator import Operator

T = Operator([[1, 0], [0, np.e ** (1j*np.pi/4)]]) # Tゲートを定義

qc = QuantumCircuit(1) # 一つの量子ビットに対する量子回路を定義
qc.initialize(state, 0) # 入力の状態を指定のものに初期化
qc.append(T, [0]) # 0番目の回路にゲートを追加

qc.draw(output='mpl') # 量子回路を図示

>>

 

state = Statevector(qc) # 量子回路から出力される状態を取得
alpha = state[0] # |0>の係数を取得
beta = state[1] # |1>の係数を取得
phi = 2*np.arccos(np.abs(alpha)) # 変換後の状態のφを算出
delta = np.angle(beta) - np.angle(alpha) # 変換後の状態のδを算出

print(f"cos({round(phi/np.pi, 2)}\u03c0)|0>"
f"+exp({round(delta/np.pi, 2)}i\u03c0)"
f"sin({round(phi/np.pi, 2)}\u03c0)|1>")
plot_bloch_multivector(state) # 変換後の量子状態を図示

>>cos(0.17π)|0>+exp(0.5iπ)sin(0.17π)|1>

>>

 

上の結果を見れば明らかなように、\(T\)ゲートは\(z\)軸の周りに\(\pi / 4\)だけ回転させる変換を量子状態に施します。

Qiskitにはあらかじめ\(T\)ゲートが組み込まれており、qc.t(0)というコードで0番目の回路にTゲートを追加することができます。

同じ図が表示されると思うので試してみてください。

このゲートは量子状態に\(\pi / 4\)の位相差を与えるということなので、物理的には前回見たように\(\lambda / 4\)位相板を通すという操作で実現できます。

\(S\)ゲート

\(S\)ゲートは上の行列で表されるユニタリ変換を施す素子です。

Qiskitでは以下のようにシミュレートすることができます。

from qiskit import QuantumCircuit
from qiskit.quantum_info.operators.operator import Operator

S = Operator([[1, 0], [0, np.e ** (1j*np.pi/2)]]) # Sゲートを定義

qc = QuantumCircuit(1) # 一つの量子ビットに対する量子回路を定義
qc.initialize(state, 0) # 入力の状態を指定のものに初期化
qc.append(S, [0]) # 0番目の回路にゲートを追加

qc.draw(output='mpl') # 量子回路を図示

>>

 

state = Statevector(qc) # 量子回路から出力される状態を取得
alpha = state[0] # |0>の係数を取得
beta = state[1] # |1>の係数を取得
phi = 2*np.arccos(np.abs(alpha)) # 変換後の状態のφを算出
delta = np.angle(beta) - np.angle(alpha) # 変換後の状態のδを算出

print(f"cos({round(phi/np.pi, 2)}\u03c0)|0>"
f"+exp({round(delta/np.pi, 2)}i\u03c0)"
f"sin({round(phi/np.pi, 2)}\u03c0)|1>")
plot_bloch_multivector(state) # 変換後の量子状態を図示

>>cos(0.17π)|0>+exp(1.0iπ)sin(0.17π)|1>

>>

 

上の結果を見れば明らかなように、\(S\)ゲートは\(z\)軸の周りに\(\pi / 2\)だけ回転させる変換を量子状態に施します。

\(S\)ゲートも同様にQiskitに組み込まれており、qc.s(0)というコードで実装できるので試してみてください。

このゲートは量子状態に\(\pi / 2\)の位相差を与えるということなので、物理的には\(\lambda / 4\)位相板を二回通すという操作で実現できます。

\(Z\)ゲート

\(Z\)ゲートは上の行列で表されるユニタリ変換を施す素子です。

Qiskitでは以下のようにシミュレートすることができます。

from qiskit import QuantumCircuit
from qiskit.quantum_info.operators.operator import Operator

Z = Operator([[1, 0], [0, -1)]]) # Zゲートを定義

qc = QuantumCircuit(1) # 一つの量子ビットに対する量子回路を定義
qc.initialize(state, 0) # 入力の状態を指定のものに初期化
qc.append(Z, [0]) # 0番目の回路にゲートを追加

qc.draw(output='mpl') # 量子回路を図示

>>

 

state = Statevector(qc) # 量子回路から出力される状態を取得
alpha = state[0] # |0>の係数を取得
beta = state[1] # |1>の係数を取得
phi = 2*np.arccos(np.abs(alpha)) # 変換後の状態のφを算出
delta = np.angle(beta) - np.angle(alpha) # 変換後の状態のδを算出

print(f"cos({round(phi/np.pi, 2)}\u03c0)|0>"
f"+exp({round(delta/np.pi, 2)}i\u03c0)"
f"sin({round(phi/np.pi, 2)}\u03c0)|1>")
plot_bloch_multivector(state) # 変換後の量子状態を図示

>>cos(0.17π)|0>+exp(-0.75iπ)sin(0.17π)|1>

>>

 

上の結果を見れば明らかなように、\(Z\)ゲートは\(z\)軸の周りに\(\pi\)だけ回転させる変換を量子状態に施します。

\(Z\)ゲートも同様にQiskitに組み込まれており、qc.z(0)というコードで実装できるので試してみてください。

このゲートは量子状態に\(\pi\)の位相差を与えるということなので、物理的には\(\lambda / 4\)位相板を四回通すという操作で実現できます。

\(H\)ゲート

\(H\)ゲートは上の行列で表されるユニタリ変換を施す素子です。

Qiskitでは以下のようにシミュレートすることができます。

from qiskit import QuantumCircuit
from qiskit.quantum_info.operators.operator import Operator

H = Operator([[1/2**0.5, 1/2**0.5], [1/2**0.5, -1/2**0.5]]) # Hゲートを定義

qc = QuantumCircuit(1) # 一つの量子ビットに対する量子回路を定義
qc.initialize(state, 0) # 入力の状態を指定のものに初期化
qc.append(H, [0]) # 0番目の回路にゲートを追加

qc.draw(output='mpl') # 量子回路を図示

>>

 

state = Statevector(qc) # 量子回路から出力される状態を取得
alpha = state[0] # |0>の係数を取得
beta = state[1] # |1>の係数を取得
phi = 2*np.arccos(np.abs(alpha)) # 変換後の状態のφを算出
delta = np.angle(beta) - np.angle(alpha) # 変換後の状態のδを算出

print(f"cos({round(phi/np.pi, 2)}\u03c0)|0>"
f"+exp({round(delta/np.pi, 2)}i\u03c0)"
f"sin({round(phi/np.pi, 2)}\u03c0)|1>")
plot_bloch_multivector(state) # 変換後の量子状態を図示

>>cos(0.38π)|0>+exp(-0.12iπ)sin(0.38π)|1>

>>

 

少しわかりづらいですが、\(H\)ゲートは\(z\)軸と\(x\)軸の間に位置する\((1 / \sqrt{2}, 0, 1/ \sqrt{2})\)という軸の周りに\(\pi\)だけ回転させる変換を量子状態に施します。

これは特定の状況を考えた方がわかりやすく、例えば状態\(| 0 \rangle\)対しては\((| 0 \rangle + | 1 \rangle) / \sqrt{2}\)という\(| 0 \rangle\)と\(| 1 \rangle\)が同位相で重なった状態に変換し、逆に状態\(| 1 \rangle\)に対しては\((| 0 \rangle - | 1 \rangle) / \sqrt{2}\)という\(| 0 \rangle\)と\(| 1 \rangle\)が逆位相で重なった状態に変換します。

\(H\)ゲートも同様にQiskitに組み込まれており、qc.h(0)というコードで実装できるので試してみてください。

このゲートは量子状態を同位相で重ね合わせた状態と逆位相で重ね合わせた状態に変換するということだったので、物理的には以下のようなセットアップで実現できます。

(図)

 

\(X\)ゲート

\(X\)ゲートは上の行列で表されるユニタリ変換を施す素子です。

Qiskitでは以下のようにシミュレートすることができます。

from qiskit import QuantumCircuit
from qiskit.quantum_info.operators.operator import Operator

X = Operator([[0, 1], [1, 0)]]) # Xゲートを定義

qc = QuantumCircuit(1) # 一つの量子ビットに対する量子回路を定義
qc.initialize(state, 0) # 入力の状態を指定のものに初期化
qc.append(X, [0]) # 0番目の回路にゲートを追加

qc.draw(output='mpl') # 量子回路を図示

>>

 

state = Statevector(qc) # 量子回路から出力される状態を取得
alpha = state[0] # |0>の係数を取得
beta = state[1] # |1>の係数を取得
phi = 2*np.arccos(np.abs(alpha)) # 変換後の状態のφを算出
delta = np.angle(beta) - np.angle(alpha) # 変換後の状態のδを算出

print(f"cos({round(phi/np.pi, 2)}\u03c0)|0>"
f"+exp({round(delta/np.pi, 2)}i\u03c0)"
f"sin({round(phi/np.pi, 2)}\u03c0)|1>")
plot_bloch_multivector(state) # 変換後の量子状態を図示

>>cos(0.83π)|0>+exp(-0.25iπ)sin(0.83π)|1>

>>

 

上の結果を見れば明らかなように、\(X\)ゲートは\(x\)軸の周りに\(\pi\)だけ回転させる変換を量子状態に施します。

これは\(| 0 \rangle\)の係数と\(| 1 \rangle\)の係数を逆転させる変換であるので、古典コンピュータにおけるNOTゲートになぞらえて量子NOTゲートなどと呼ばれます。

\(X\)ゲートも同様にQiskitに組み込まれており、qc.x(0)というコードで実装できるので試してみてください。

行列の積を計算してみると、このゲートは実は\(H Z H\)と等しいことがわかるので、物理的には先ほど実装した\(H\)ゲートを通した後に\(Z\)ゲートを通し、その後再び\(H\)ゲートを通すという操作で実現できます。

\(Y\)ゲート

\(Y\)ゲートは上の行列で表されるユニタリ変換を施す素子です。

Qiskitでは以下のようにシミュレートすることができます。

from qiskit import QuantumCircuit
from qiskit.quantum_info.operators.operator import Operator

Y = Operator([[0, -1j], [1j, 0)]]) # Yゲートを定義

qc = QuantumCircuit(1) # 一つの量子ビットに対する量子回路を定義
qc.initialize(state, 0) # 入力の状態を指定のものに初期化
qc.append(Y, [0]) # 0番目の回路にゲートを追加

qc.draw(output='mpl') # 量子回路を図示

>>

 

state = Statevector(qc) # 量子回路から出力される状態を取得
alpha = state[0] # |0>の係数を取得
beta = state[1] # |1>の係数を取得
phi = 2*np.arccos(np.abs(alpha)) # 変換後の状態のφを算出
delta = np.angle(beta) - np.angle(alpha) # 変換後の状態のδを算出

print(f"cos({round(phi/np.pi, 2)}\u03c0)|0>"
f"+exp({round(delta/np.pi, 2)}i\u03c0)"
f"sin({round(phi/np.pi, 2)}\u03c0)|1>")
plot_bloch_multivector(state) # 変換後の量子状態を図示

>>cos(0.83π)|0>+exp(0.75iπ)sin(0.83π)|1>

>>

 

上の結果を見れば明らかなように、\(Y\)ゲートは\(y\)軸の周りに\(\pi\)だけ回転させる変換を量子状態に施します。

\(Y\)ゲートも同様にQiskitに組み込まれており、qc.y(0)というコードで実装できるので試してみてください。

行列の積を計算してみると、このゲートは実は\(S H Z H S\)と等しいことがわかるので、物理的には\(S\)ゲート、\(H\)ゲートを通した後に\(Z\)ゲートを通し、その後再び\(H\)ゲート、\(S\)ゲートを通すという操作で実現できます。

 

万能ゲートセット

これまで基本的な量子ゲートについて見て来ましたが、実の所それらは\(H\)ゲートと\(T\)ゲートの組み合わせで表すことができました。

これは偶然ではなく、古典コンピュータにおいてNANDゲートさえあれば他の論理ゲートを用意する必要がないのと同じように、量子コンピュータにも万能ゲートという概念があり、\(H\)ゲートと\(S\)ゲートはそれに該当しているのです。

このような任意のユニタリ変換を再現できるような量子ゲートの集合を「万能ゲートセット」と言います。

このセットが万能である根拠は「Solovay-Kitaevの定理」により与えられています。

Solovay-Kitaevの定理

任意の1量子ユニタリ変換は、SU(2)を稠密に覆うことのできる有限種類の1量子ビットゲートを\(O(\log^c(1 / \epsilon))\)個使用することで、精度\(\epsilon\)で近似できる。ただし\(c\)は定数である。

ここで定理中の\(\mathrm{SU}(2)\)とは、量子系に対するユニタリ変換が属している演算付きの集合のことです。

ここで厳密な証明を与えることはできませんので、代わりに感覚的に理解することを目指したいと思います。

唐突ですが、\(T\)ゲートと\(H\)ゲートを組み合わせた\(THTH\)というユニタリ変換について考えます。

これは

$$
THTH =
\frac{1}{2\sqrt{2}}
\begin{pmatrix}
\sqrt{2}+1-i  & -\sqrt{2}+1-i \\
\sqrt{2}-1+i & \sqrt{2}+1+i
\end{pmatrix}
=\frac{1}{2 \sqrt{2}}((\sqrt{2}+1) I - i X - (\sqrt{2}-1)i Y - i Z)
$$

と表せます。

これはあるパラメータ\(\theta\)を導入することで

$$THTH = cos \frac{\theta}{2} I + i sin \frac{\theta}{2} (X + (\sqrt{2}+1)Y + Z)$$

と書くことができ、軸\(1, \sqrt{2}+1, 1\)の周りに\(\theta\)だけ回転させるユニタリ変換であることを表している。

両式を見比べると

$$
cos \frac{\theta}{2} = \frac{\sqrt{2}+1}{2 \sqrt{2}}
\qquad \text{ゆえに} \theta = \arccos(\frac{\sqrt{2}+1}{2 \sqrt{2}})
$$

であることがわかります。

この角は\(\pi\)の無理数倍であることがわかっているので、\(THTH\)を繰り返すことで軸\(1, \sqrt{2}+1, 1\)周りの円周を稠密に埋め尽くすことができます。

同様に\(HTHT\)も

$$
\begin{aligned}
H T H T
&= \frac{e^{i \pi / 4}}{2 \sqrt{2}}
\begin{pmatrix}
\sqrt{2}+1 - i & \sqrt{2}-1 - i \\
-\sqrt{2}+1 - i & \sqrt{2}+1 + i
\end{pmatrix} \\[6pt] &= \frac{e^{i \pi / 4}}{2 \sqrt{2}}\Bigl((\sqrt{2}+1)\,I \;-\; i\,X \;+\; (\sqrt{2}-1)\,i\,Y \;-\; i\,Z\Bigr) \\[6pt] &= e^{i \pi / 4}\,\cos\!\biggl(\frac{\theta}{2}\biggr)\,I
\;+\;
i\,\sin\!\biggl(\frac{\theta}{2}\biggr)
\Bigl(X \;-\; (\sqrt{2}+1)\,Y \;+\; Z\Bigr).
\end{aligned}
$$

から軸\(1, -\sqrt{2}+1, 1\)の周りに\(\pi \)の無理数倍の角である\(\theta\)だけ回転させるユニタリ変換であることがわかります。

二つの独立な軸について、それぞれの周りの回転角が稠密であることがわかったので、これらを合わせることでBloch球の表面を覆い尽くすことができます。

これで\({T, H}\)のセットが万能性を持つことがわかりました。

 

これで一体系の任意のユニタリ変換を再現することができるようになった訳ですが、これだけでは加算器すら作れません。

というのも今回の話は複数のビットの入力を受けて新しい状態を出力するという、古典的なコンピュータが当たり前に行っている処理に相当する量子的な操作を全く念頭に置いていないからです。

次回は「テンソル」という概念を導入することで複数の量子ビットに対する処理について考えていきましょう。

 

-量子コンピュータ