はじめに
GWの量子コンピューター入門第二弾です。
今日は量子テレポーテーションをBlueqatで実装してみます。
まず、チュートリアルにある2者間エンタングルメントを使った量子テレポーテーションを実装してみます。
Blueqat/012_algo_teleportation.ipynb at master · Blueqat/Blueqat · GitHub
その次に、3者間エンタングルメントによる量子テレポーテーションネットワークを実装します。
量子テレポーテーションとは
量子テレポーテーションとは、量子状態を伝送することである。
「任意の量子状態は複製できない」という要請を満たして量子状態を伝送するためには、送信側でオリジナルの量子状態が消滅し、受信側で再生される必要がある。
量子テレポーテーション
以下に示しているのは、ベネットらによって提案された量子ビットのテレポーテーション回路である。
Vの状態 はAへと渡されて、Bのところで再生される。
0, 1, 2ではわかりにくいので、それぞれV, A, Bとしている。
この回路では、AとBの間で2者間エンタングルメントを共有し、Vの情報をAからBへと状態を送っている。
赤線で囲んだ箇所で、AとBの量子ビットはエンタングルされる。
c1 = Circuit().h[1].cx[1,2] c1.m[:].run(shots=1000) ## Counter({'011': 493, '000': 507})
重要なのは、青線で囲んだ箇所である。ここで、量子複製不可能定理を回避するために、ベル測定という方法を用いる。
ベル測定とは、ベル基底の射影を測定することである。ベル基底とは、2量子系がエンタングルした基底のことで、以下の4つがある。
それぞれのベル基底に対するベル測定の出力は以下のように1:1対応する。
# ベル測定の回路 c2 = Circuit().cx[0, 1].h[0].m[0, 1] # |Φ>+ (Circuit().h[0].cx[0, 1] + c2).run(shots=1000) ## Counter({'00': 1000}) # |Φ>- (Circuit().x[0].h[0].cx[0, 1] + c2).run(shots=1000) ## Counter({'10': 1000}) # |Ψ>+ (Circuit().h[0].cx[0, 1].x[0] + c2).run(shots=1000) ## Counter({'01': 1000}) # |Ψ>- (Circuit().x[0].h[0].cx[0, 1].x[0] + c2).run(shots=1000) ## Counter({'11': 1000})
つまり、赤線で囲んだ箇所からの出力は と書ける。
ベル測定前の全体は、送りたい量子状態 と の直積であるから、以下のように変形できる。
この状態でベル測定を行うと、状態は4つのうちのどれかに収束する。つまり、Bの状態はベル測定によって
のどれかに収束する。
Bで状態を再生させるためには、ベル測定の結果(V, A)をBに送って、適切なユニタリー変換を行う必要がある。
これはCXゲート(Aが1の場合Xを適用)とCZゲート(Vが1の場合Zを適用)で実現できる。
c3 = Circuit().cx[1,2].cz[0,2]
A, Bをエンタングルさせる回路(c1)、ベル測定回路 (c2)、ユニタリー変換を行う回路 (c3)をつなげると、量子テレポーテーションの回路が完成する。
c1 = Circuit().h[1].cx[1,2] c2 = Circuit().cx[0, 1].h[0].m[0, 1] c3 = Circuit().cx[1,2].cz[0,2] c = c1 + c2 + c3 # Vが1であれば、必ずBでも1が再生される (Circuit().x[0] + c).m[:].run(shots=100) ## Counter({'001': 20, '101': 29, '111': 25, '011': 26}) # Vの状態は|0>と|1>が3:1 c4 = Circuit().ry(np.pi / 3)[0] c4.m[:].run(shots=10000) ## Counter({'0': 7555, '1': 2445}) out = (c4 + c).m[:].run(shots=10000) counts = [0, 0] for bits, count in out.items(): counts[int(bits[2])] += count # Bも|0>と|1>が3:1になる counts ## [7544, 2456]
というわけでVの状態をBにテレポーテーションさせることができた。
量子テレポーテーションネットワーク
次に、3者間でエンタングルメントを共有し、相互に状態を送り合う量子テレポーテーションネットワークを構築する。
A, B, Cの3者間でエンタングルメントを共有(赤線で囲んだ箇所で生成する)し、Vの情報はAからBへと送られる。テレポーテーションを成功させるためには、Cの情報が必要である。
ここで、最後のZはCCZであるが、令和元年5月3日(使ってみたかった)現在、pip経由でインストールしたBlueqat (v0.3.7)ではCCZGateは使えない。ただし、すでに実装済みっぽいので、すぐに使えるようになると思われる。
Add numpy backend ccx implementation to improve performance · Blueqat/Blueqat@9db46fd · GitHub
とりあえず、これで無理くり使えるようにした。
import blueqat class CCZGate(blueqat.gate.Gate): lowername = "ccz" class MyBackend(blueqat.backends.numpy_backend.NumPyBackend): def gate_ccz(self, gate, ctx): c1, c2, t = gate.targets qubits = ctx.qubits n_qubits = ctx.n_qubits i = ctx.indices indices = (i & (1 << c1)) != 0 indices &= (i & (1 << c2)) != 0 indices &= (i & (1 << t)) != 0 qubits[indices] *= -1 return ctx blueqat.circuit.BACKENDS["my_backend"] = MyBackend blueqat.circuit.DEFAULT_BACKEND_NAME = "my_backend" blueqat.circuit.GATE_SET["ccz"] = CCZGate
上の回路図の通りに量子回路を組むと、以下のようになる。
c1 = Circuit().h[1].cx[1, 2].cx[1, 3] c2 = Circuit().cx[0,1].h[0].m[0,1] c3 = Circuit().h[3].m[3] c4 = Circuit().cx[1,2].ccz[0,3,2] c = c1 + c2 + c3 + c4 # Vを1にすると、Bも1になる (Circuit().x[0] + c).m[:].run(shots=1000) ## Counter({'0010': 120, ## '0111': 143, ## '1010': 121, ## '0011': 112, ## '1110': 124, ## '0110': 131, ## '1011': 123, ## '1111': 126}) # Vの状態を|0>と|1>が3:1になるように c5 = Circuit().ry(np.pi / 3)[0] out = (c5 + c).m[:].run(shots=10000) counts = [0, 0] for bits, count in out.items(): counts[int(bits[2])] += count counts ## [7558, 2442]
というわけで、量子テレポーテーションと、量子テレポーテーションネットワークを実装できた。
はてなブログで数式を書くのがつらいので、数式を書くのもうやめたい。