$$
\def\bra#1{\mathinner{\left\langle{#1}\right|}}
\def\ket#1{\mathinner{\left|{#1}\right\rangle}}
\def\braket#1#2{\mathinner{\left\langle{#1}\middle|#2\right\rangle}}
$$
はじめに
これまで、
- 表面符号によるユニバーサル量子計算(Braiding)
- 表面符号によるユニバーサル量子計算(1)〜Braidingで論理CNOT演算〜
-
表面符号によるユニバーサル量子計算(2)〜Braidingで論理アダマール演算〜
という3つの記事を通して、Braidingによる「論理パウリ演算」「論理CNOT演算」「論理アダマール演算」の構成法が理解できましたので、今回は「論理位相シフト演算」です。代表的な位相シフト演算として$S$と$T$(および、そのエルミート共役$S^{\dagger}$と$T^{\dagger}$)がありますが、その論理演算バージョンの構成法について勉強します。ユニバーサル量子計算のためには、特に非クリフォード演算である論理$T$演算が重要なのですが、それを実現するためには論理$S$演算も必要になりますので、併せて説明します。一通り理解できたところで、論理$T$演算の動作を量子計算シミュレータqlazyを使って確認します1。
参考にさせていただいたのは、以下の文献です。
理論説明
定義
まず念の為のおさらいから始めます。任意に$\theta$だけ位相を回転させる位相シフト演算子$P(\theta)$は、
P(\theta) =
\begin{pmatrix}
1 & 0 \\
0 & e^{i\theta}
\end{pmatrix} \tag{1}
と定義されます2。
$S$および$T$は、この$\theta$を各々$\pi/2$、$\pi/4$にしたものとして定義されています。すなわち、
S =
\begin{pmatrix}
1 & 0 \\
0 & e^{i\pi/2}
\end{pmatrix}, \space
T =
\begin{pmatrix}
1 & 0 \\
0 & e^{i\pi/4}
\end{pmatrix} \tag{2}
です。また、エルミート共役である$S^{\dagger}$および$T^{\dagger}$は、言わずもがなですが、
S^{\dagger} =
\begin{pmatrix}
1 & 0 \\
0 & e^{-i\pi/2}
\end{pmatrix}, \space
T^{\dagger} =
\begin{pmatrix}
1 & 0 \\
0 & e^{-i\pi/4}
\end{pmatrix} \tag{3}
です。
これらの論理演算子バージョンをこれから構成していくのですが、前提として物理的な1量子ビットに対する位相シフトゲートは、他のパウリ$X,Z$ゲートやアダマールゲートと比べて高い精度で制御することが難しい(らしい)ので、単体の$S$ゲートや$T$ゲートを使わないで構成することを考えます。が、そんなことは不可能なので、さらにもう一つ、十分に精度の高い特別な状態を用意することができるという前提を置きます。
論理S演算
まず論理$S$演算の構成法ですが、いきなり天下ります。以下のような回路で$S$演算は実現できることがわかっています。
ここで、$\ket{Y}$は、
\ket{Y} = \ket{0} + e^{i\pi/2} \ket{1} = \ket{0} + i \ket{1} \tag{4}
のように定義される特別な状態です(規格化定数は面倒なので省略します。以下同様)。このようにある演算を実現するために用意される補助的な状態のことを「マジック状態(magic state)」と言います。先ほど「十分に精度の高い特別な状態を用意することができるという前提を置きます」と言ったのは、このことです。さて、これで本当に$S$ゲートが実現できているでしょうか?一応確認してみます。
まず1番目の量子ビットに関する最初の状態が、
\ket{\psi} = a \ket{0} + b \ket{1} \tag{5}
だったとして、1番目の量子ビット(すなわち、CNOTの制御側)が$\ket{0}$の場合と$\ket{1}$の場合に場合分けして考えます。
1番目の量子ビットがが$\ket{0}$だった場合、2番目の量子ビットにはCNOTが作用しないので、
\ket{Y} \rightarrow HH \ket{Y} = \ket{Y} = \ket{0} + i \ket{1} \tag{6}
のように全く変化しません。一方、1番目の量子ビットが$\ket{1}$だった場合、2番目の量子ビットにはCNOTが作用して、
\ket{Y} \rightarrow HXHX \ket{Y} = ZX \ket{Y} = -\ket{1} + i \ket{0} \tag{7}
のように変化します。総合すると出力側の2量子ビット状態は、
\begin{align}
& a \ket{0} (\ket{0} + i \ket{1}) + b \ket{1} (-\ket{1} + i \ket{0}) \\
&= a \ket{0} (\ket{0} + i \ket{1}) + ib \ket{1} (\ket{0} + i \ket{1}) \\
&= (a \ket{0} + ib \ket{1}) (\ket{0} + i \ket{1}) \\
&= (S \ket{\psi}) \ket{Y} \tag{8}
\end{align}
となり、確かに出力側の1番目の量子ビットの状態は$S \ket{\psi}$になっていることがわかりました。この出力式からもわかるように、1番目と2番目の量子ビットはエンタングルしていない(テンソル積状態になっている)ので、1番目の量子ビットをそのまま引っ張り出せば、所望の1量子ビット状態を得ることができます。
さて、この回路は単なる2量子ビットの普通の量子回路でしたが、これの各パートを論理状態および論理演算に置き換えたものを考えることができます(下図)。各論理量子ビットを表す1本の線は1量子ビットではなく、例えば格子上に定義された欠陥対を表しているものとイメージしてください。
ここで、量子状態を表す記号の上にバーをつけたものを論理状態、演算子を表す記号の上にハットをつけたものを論理演算子を表すものとします(以下同様)3。
この回路に含まれる論理アダマールも論理CNOTもbraidingで実現できることはすでにわかっています。前々回の記事で見たように、論理CNOTはチューブが絡み合った現代アート風のオブジェのようなもので表現することができました。また、前回の記事で、論理アダマールは適用したい欠陥対の周りにお掘りを作って孤立させておいてから物理的なアダマールゲートを適用すれば良いということもわかりました。ということで、誤り訂正を用いれば、原理的にはこの回路は誤差なしで実行することができます。
ただし、論理的な$\ket{Y}$状態が曲者です。すなわち、
\ket{\bar{Y}} = \ket{\bar{0}} + e^{i\pi/2} \ket{\bar{1}} \tag{9}
をどうやって用意すれば良いか、です。式(9)からわかるように$\ket{\bar{Y}}$は$\ket{\bar{+}}$に$\hat{S}$を適用すれば得られます。が、そもそも$\hat{S}$を実現したいのに、それに$\hat{S}$を使うことはできません。では、どうするか?
まず、平面格子の真空状態(面演算子と頂点演算子がびっしり敷き詰められた状態)から、欠陥対を作って、それを$\ket{\bar{+}}=\ket{\bar{0}}+\ket{\bar{1}}$にするプロセスを思い出してください。下図左に示したように平面上の量子ビットのどれかを$X$測定します。そうすると、測定した量子ビットを共有する2つの面演算子がスタビライザーから消えて、代わりに測定した量子ビットに関する$X$演算子(測定値に応じてプラスかマイナスの符号が前に付く)と2つの欠陥の周りを囲むループ上の$Z$演算子が加わります。測定した$X$演算子を論理$X$演算子とみなせば、これで論理的な$\ket{+}$状態(測定値が-1だった場合は$\ket{-}$)が出来上がったことになります。いま測定値が+1だったとします($-1$だった場合は$+1$になるまで再度測定し直します)。このようにできた論理状態$\ket{\bar{+}}$は、実質的には物理的な$\ket{+}$そのものです。これに普通の1量子ビットの$S$ゲートを演算させれば、下図中に示したように、とりあえず$\ket{Y} = \ket{0} + \exp{(i\pi/2)} \ket{1}$という状態になります。これは最も近接した最小限の欠陥対なので、下図右に示すように、欠陥対を拡大・移動することができて、それで任意の符号距離をもった論理状態を実現することができます。つまり、これで論理的な$\ket{\bar{Y}} = \ket{\bar{0}} + \exp{(i\pi/2)} \ket{\bar{1}}$が出来上がったことになります。マジック状態を準備するこのプロセスのことを「マジック状態注入(magic state injection)」と言います。
これで、めでたし、めでたし、と言いたいところなのですが、実はひとつ問題が残っています。上図中で物理的な$S$ゲートを使ってしまっています。$S$ゲートは十分に信頼できる精度で制御するのが難しいということなので、得られた$\ket{Y}$状態が定義式に示したとおりの係数できれいに得られないかもしれないということです。したがって、何も工夫しなければ、上図右の論理状態もきたない状態になります。せっかく誤差なしの論理CNOTや論理アダマールができたとしても、これでは、きれいな論理$S$演算を実現できません。では、どうするか?
これには「マジック状態蒸留(magic state distillation)」というテクニックが使えることが知られています。が、ちゃんと説明し出すと1本の記事になりそうなので、今回は省略して機会を改めたいと思います(というか、自分自身まだ十分に理解できていないので、汗)。ここでは、そうやってできた「きれいなマジック状態」があるものとして議論を先に進めます(悪しからず)。
論理$S$演算ができたので、ここから論理$S^{\dagger}$演算は簡単に導けます。$S^{\dagger} = Z S$という公式があるので4、上で示した回路の2番目の論理量子ビットの一番最後に$\hat{Z}$を追加すれば良いだけです。
これで論理$S$演算の話は完了しましたので、次は論理$T$演算の説明に移ります。
論理T演算
こちらも、まず天下ります。以下の回路で論理的な$T$演算は実現できます。
ここで、$\ket{\bar{A}}$は、
\ket{\bar{A}} = \ket{\bar{0}} + e^{i\pi/4} \ket{\bar{1}} \tag{10}
のように定義されるマジック状態です。先ほどの論理$S$演算とは異なり、測定が入っていてその測定値によって論理$S$演算をオン/オフする形になっており、出力論理状態も測定値に応じて、パウリ演算子の付加項が含まれています5。
さて、これで本当に$T$ゲートが実現できているでしょうか?一応確認してみます。
先ほどと同様に、まず2番目の論理量子ビットへの入力状態が、
\ket{\bar{\psi}} = a \ket{\bar{0}} + b \ket{\bar{1}} \tag{11}
だったとして、1番目の論理量子ビット(すなわち、CNOTの制御側)が$\ket{\bar{0}}$の場合と$\ket{\bar{1}}$の場合に場合分けして考えます。
1番目の論理量子ビットが$\ket{\bar{0}}$だった場合、CNOT直後の2番目の論理量子状態は変わりません。すなわち、
\ket{\bar{\psi}} \rightarrow \ket{\bar{\psi}} = a \ket{\bar{0}} + b \ket{\bar{1}} \tag{12}
です。一方、1番目の論理量子ビットが$\ket{\bar{1}}$だった場合、2番目の量子ビットは、
\ket{\bar{\psi}} \rightarrow X \ket{\bar{\psi}} = a \ket{\bar{1}} + b \ket{\bar{0}} \tag{13}
のように変化します。総合するとCNOT直後の状態は、
\begin{align}
& \ket{\bar{0}} (a \ket{\bar{0}} + b \ket{\bar{1}}) + e^{i\pi/4} \ket{\bar{1}} (a \ket{\bar{1}} + b \ket{\bar{0}}) \\
&= a \ket{\bar{0}\bar{0}} + b \ket{\bar{0}\bar{1}} + b e^{i\pi/4} \ket{\bar{1}\bar{0}} + a e^{i\pi/4} \ket{\bar{1}\bar{1}} \\
&= (a \ket{\bar{0}} + b e^{i\pi/4} \ket{\bar{1}}) \ket{\bar{0}} + (b \ket{\bar{0}} + a e^{i\pi/4} \ket{\bar{1}}) \ket{\bar{1}} \tag{14}
\end{align}
となります。次に2番目の論理量子ビットに対する$Z$測定の結果を場合分けします。測定値が$+1$だった場合、1番目の量子状態は、
a \ket{\bar{0}} + b e^{i\pi/4} \ket{\bar{1}} = \hat{T} \ket{\bar{\psi}} \tag{15}
となり、所望の論理量子状態が得られます。測定値が$-1$だった場合、1番目の量子状態は、
\begin{align}
b \ket{\bar{0}} + a e^{i\pi/4} \ket{\bar{1}}
&= e^{i\pi/4} (a \ket{\bar{1}} + b e^{-i\pi/4} \ket{\bar{0}}) \\
&= e^{i\pi/4} \hat{X} \hat{T}^{\dagger} \ket{\bar{\psi}} \tag{16}
\end{align}
となり、グローバル位相を無視したとしても、
\hat{X} \hat{T}^{\dagger} \ket{\bar{\psi}} \tag{17}
なので、所望の論理量子状態になっていません。そこで、この状態に対して$\hat{S}$を演算すると、
\begin{align}
\hat{S} \hat{X} \hat{T}^{\dagger} \ket{\bar{\psi}}
&= \hat{X} \hat{S}^{\dagger} \hat{T}^{\dagger} \ket{\bar{\psi}} \\
&= \hat{X} (\hat{Z} \hat{S}) \hat{T}^{\dagger} \ket{\bar{\psi}} \\
&= (\hat{X} \hat{Z}) \hat{T} \ket{\bar{\psi}} \tag{18}
\end{align}
ということになるので、これで上の回路図が正しいことが確かめられました。所望の$\hat{T} \ket{\bar{\psi}}$を得たい場合は、この状態に$\hat{Z}\hat{X}$を作用させます。
マジック状態$\ket{\bar{A}}$の準備(マジック状態注入)は、先ほどの論理$S$演算のときと同様の考え方で$S$ゲート適用のところを$T$ゲート適用に置き換えれば良いです。きれいなマジック状態$\ket{\bar{A}}$を得るためのマジック状態蒸留の方法も知られていますが、詳細説明については機会を改めます。
論理$T^{\dagger}$演算の構成は、少しだけ難しいです。つまり、測定値に応じた場合分けが必要です。測定値が$+1$だった場合、出力は$\hat{T}\ket{\bar{\psi}}$なので$\bar{S}$をかければ、$\hat{S} \hat{T} \ket{\bar{\psi}} = \bar{Z} \bar{T}^{\dagger}$となり、$\hat{T} \ket{\bar{\psi}}$に$\bar{Z}$を演算した結果が得られます。一方、測定値が$-1$だった場合、出力は$\bar{X} \bar{T}^{\dagger} \ket{\bar{\psi}}$なので、$\bar{T}^{\dagger}$に$\bar{X}$を演算した結果が得られます。これで論理パウリ演算子を一番後ろに持っていく形での$\bar{T}$および$\bar{T}^{\dagger}$を得ることができました6。
これで論理$T$演算の話は完了です。論理$T$演算に含まれる論理$S$演算は論理アダマールと論理CNOTで実現できるので、結局、論理$T$演算は論理アダマールと論理CNOTと測定および論理パウリ演算だけで実現できることがわかりました。ただし、2種類のきれいなマジック状態を補助的に用意しておく必要はあります。
本記事を含め4回分の記事を費やしましたが、これでユニバーサル量子計算に必要なすべての要素をbraidingによって構成できることがわかりました(マジック状態蒸留という積み残しがありますが、、)。お疲れ様でした。
動作確認
それでは、ユニバーサル量子計算の大トリ!ということで、論理$T$演算の動作確認です。が、braidingによる本当の論理演算はたくさんの量子ビットを消費し、かつ、非クリフォード演算が含まれるので、スタビライザーで計算できる範囲に収まりません。かと言って、まともに状態ベクトルで計算しようとするとメモリが全く足りません。ということで、論理演算ではなく物理量子ビットに対する普通の量子回路で、今回説明した$T$ゲート演算をシミュレートしてみます。アダマール、CNOT、パウリ、測定およびマジック状態だけで、ちゃんと$T$ゲートが実現できるという確認を目的とします。つまり、お茶を濁そうというわけです(汗)。大トリ!なんて勢い込んで言った割に、ちょっとしょぼいシミュレーションになりますが悪しからず7。
さて、上で説明した$T$ゲート回路の中に含まれる$S$ゲート回路の中身も合わせて量子回路を書き下すと、以下のようになります。
ここで任意の$\ket{\psi}$を入力にした出力結果が正しく$T\ket{\psi}$になっているかどうかを確認します。
実装
全体のPythonコードを示します。
【2021.9.6追記】qlazy最新版でのソースコードはここに置いてあります。
import random
from qlazypy import QState
def main():
# parameters for generating random state: |psi>
alpha, beta, gamma = random.random(), random.random(), random.random()
# reference state: T|psi>
qs_expect = QState(1)
qs_expect.u3(0, alpha=alpha, beta=beta, gamma=gamma).t(0)
# prepare initial state
qs = QState(3)
qs.h(0).s(0) # |Y>
qs.h(1).t(1) # |A>
qs.u3(2, alpha=alpha, beta=beta, gamma=gamma) # |psi>
# T gate (only with X,Z,H,CNOT and measurement)
qs.cx(1,2)
mval = qs.m(qid=[2]).last
if mval == '1':
qs.cx(1,0).h(0).cx(1,0).h(0)
qs.x(1).z(1)
qs_actual = qs.partial(qid=[1])
# show the result
print("== expect ==")
qs_expect.show()
print("== actual ==")
qs_actual.show()
print("== fidelity ==")
print("{:.6f}".format(qs_actual.fidelity(qs_expect)))
QState.free_all(qs, qs_expect, qs_actual)
if __name__ == '__main__':
main()
ざっくり説明します。まず、
# parameters for generating random state: |psi>
alpha, beta, gamma = random.random(), random.random(), random.random()
で、初期状態をランダムに用意するためのパラメータを設定します。
# reference state: T|psi>
qs_expect = QState(1)
qs_expect.u3(0, alpha=alpha, beta=beta, gamma=gamma).t(0)
で、$U3$ゲート適用して作成したランダム状態に対して、$T$ゲートを作用させた1量子ビット状態qs_expectを作ります。これが正解の状態です。最後に結果評価するときに使います。
# prepare initial state
qs = QState(3)
qs.h(0).s(0) # |Y>
qs.h(1).t(1) # |A>
qs.u3(2, alpha=alpha, beta=beta, gamma=gamma) # |psi>
で、上の回路図で示した3量子ビットの入力状態を設定します8。3番目の量子ビット状態は、先ほどと同じパラメータでランダム状態を作っています。
# T gate (only with X,Z,H,CNOT and measurement)
qs.cx(1,2)
mval = qs.m(qid=[2]).last
if mval == '1':
qs.cx(1,0).h(0).cx(1,0).h(0)
qs.x(1).z(1)
qs_actual = qs.partial(qid=[1])
で、上の回路を実行します。1番目の量子ビットに所望の結果が反映されているはずなので、partialメソッドで部分系を取り出します9。
# show the result
print("== expect ==")
qs_expect.show()
print("== actual ==")
qs_actual.show()
print("== fidelity ==")
print("{:.6f}".format(qs_actual.fidelity(qs_expect)))
で、正解状態と上の回路を実行した結果の状態を表示して、両者の忠実度を表示します。
実行結果
以下に実行結果例を示します。
== expect ==
c[0] = +0.7991+0.0000*i : 0.6386 |+++++++
c[1] = +0.2549+0.5445*i : 0.3614 |+++++
== actual ==
c[0] = +0.7991-0.0000*i : 0.6386 |+++++++
c[1] = +0.2549+0.5445*i : 0.3614 |+++++
== fidelity ==
1.000000
何度実行してもランダムに準備される状態は変わるのですが、fidelityは必ず1.0になりました。というわけで、正しく計算できていることが確認できました。
おわりに
今回、タイトルにもあるように「Braidingで論理位相シフト演算」を確認するという主旨だったのですが、実はほとんどBraidingを使っていません。マジック状態注入だけBraidingで行いました。この部分を考えている表面符号方式に応じて変えれば、他の部分はそのまま置き換えることができるはずです。具体的に他方式でどうやるかは自分自身よくわかっていないので、追々理解していきたいと思います。さて、本文でも述べましたが、とりあえず直近の積み残し課題としてマジック状態蒸留の説明があります。次回はこのあたりを勉強してみたいと思います(例によって予定は未定ですが)。
以上
-
ただし、後でも言いますが、1論理量子ビットあたり大量の量子ビットが必要なbaidingで非クリフォード演算をシミュレーションするのが難しかったため、論理$T$ゲート演算をやっているつもりで(汗)、普通の$T$ゲート演算のシミュレーションを行いました。 ↩
-
ちなみに、$Z$軸周りの回転ゲート$R_{z}(\theta)$をこの$P(\theta)$のように定義している文献もあるのですが(というか、今回の参考文献1がそうでした)、ニールセン・チャンでは、$R_{z}(\theta)=\exp{(i\theta Z/2)}$と定義されているので、$R_{z}(\theta)=\exp{(-i\theta/2)} P(\theta)$という関係になります。どっちの定義を採用したとしてもグローバル位相の違いだけなので実用上は気にしないでも良いのですが、文献を見ながら数式確認する際に少し混乱することがあるかもしれないので、ご注意ください。 ↩
-
論理CNOTを表す適当な記号がないのでCNOTはそのままですが論理CNOTだと思ってください。 ↩
-
蛇足ですが、これが本当かどうか紙と鉛筆で行列計算して確かめなくても良いです。$S$も$Z$もそれから$T$も(それらのエルミート共役も含めて)同じ$P(\theta)$の仲間です。つまり、すべてZ軸周りの回転演算でその回転角が各々異なっているだけの違いです。当然ですが各々可換です。$S^{\dagger}$は$-\pi/2$回転で、$S Z$は$\pi/2$回転と$\pi$回転の合成で$3\pi/2$回転=$-\pi/2$回転ということなので、$S^{\dagger} = Z S$が成り立つのは頭の中で一瞬で確かめられますね。 ↩
-
ニールセン・チャンを一生懸命勉強した人は、ここで「ん?」となったかもしれません(ちなみに自分がそうでした)。日本語版だと3巻のp.185に同じことを実現する回路が書かれているのですが、そこでは測定値に応じて$S$ではなく$SX$を演算する形になっています。かつ、出力結果の場合分けはなく、きれいに$T\ket{\psi}$の形になっています。が、実は、$ZXS$と$SX$はグローバル位相を除いて全く同じものなので、両者が等価回路であることはすぐにわかります。今回の記事本文で示した回路は参考文献1の記載に従っているのですが、なぜこのようなややこしい書き方をするのか?これには理由があります。それは、パウリ演算子を回路の一番後ろに持っていった方が、実用上の利点があるからです。パウリ演算子の連鎖は逐次量子ビットに適用しなくても量子回路実行前の回路最適化の段階で簡単に高々2個のパウリ演算子($\hat{X}$と$\hat{Z}$)に置き換えることができます。さらにそうして置き換えた先には大抵測定があります。高々2個にまとめたパウリ演算子の最後が何かに応じて測定方向を切り替えることにすれば、パウリ演算子の適用回数を最低限(運が良ければ全く不要)に抑えることができます。 ↩
-
言わずもがなですが、純粋な$\bar{T}^{\dagger}$を得るには、測定値が$+1$だった場合は出力状態に$\bar{Z}$を作用させ、測定値が$-1$だった場合は$\bar{X}$を作用させれば良いです。 ↩
-
テンソルネットワークを使えば近似的に計算できるかもしれないのですが、未対応なので(そのうち何とかできるようにしたいです)。 ↩
-
本来であれば、$\ket{Y}$と$\ket{A}$をマジック状態蒸留で用意したいところなのですが、未勉強なので不本意ながら卑怯な手を使っています。 ↩
-
正しく計算できていれば0番目と1番目の量子ビットはエンタングルしていないはずなので、結果は確定的になります(なるはずです)。 ↩