はじめに
お久しぶりの記事となってしまいました。
そこで、Qiskitの復習がてら量子ランダムアクセス符号を実装してみることとしました。ちなみに次がBB84を実装する予定です。
ランダムアクセス符号とは
ランダムアクセス符号(Random Access Code)とは次のような2者間の通信プロトコルのことです。
ランダムアクセス符号
AさんとBさんがおり、それぞれに下記の入力が与えられます。なお、AとBは互いの入力を知りません。
- Aへの入力として、長さ$m$のビット列$x=x_1 x_2 \dots x_m$が与えられる
- Bへの入力として添字$j \in \lbrace 1,2,\dots m \rbrace$が与えられる
この時、AがBに$1$ビット($1$量子ビット)をメッセージとして送ることで、Bが常に確率$p$以上で$x_j$を得ることができるような、Aによる$m$ビットから$1$ビットへの符号化を$(m,1,p)$古典(量子)ランダムアクセス符号という。
$(2,1,p)$古典ランダムアクセス符号は$p=\frac{1}{2}$しか達成できないことが示されています。Aから送られてきたビットをBはあてずっぽうで答えることしか出来ません。
一方で、$(2,1,p)$量子ランダムアクセス符号では、
p=\cos^2(\frac{\pi}{8}) \approx 0.85
という古典と比較して高い確率を達成することができます。
量子ランダムアクセス符号
$(2,1,p)$量子ランダムアクセス符号で考えていきます。
Aの符号化
以下の各$|\phi(x_1x_2)>$はAが入力$x_1x_2$を持つときにBへ送る量子ビットの状態になります。
\begin{align}
|\phi(00)> &= \cos(\frac{\pi}{8})|0> + \sin(\frac{\pi}{8})|1> \\
|\phi(10)> &= \cos(\frac{3\pi}{8})|0> + \sin(\frac{3\pi}{8})|1> \\
|\phi(01)> &= \cos(\frac{-\pi}{8})|0> + \sin(\frac{-\pi}{8})|1> \\
|\phi(11)> &= \cos(\frac{5\pi}{8})|0> + \sin(\frac{5\pi}{8})|1> \\
\end{align}
Bの復号化
Bは$x_j$を復号するために
- $j=1$の時は計算基底$\lbrace|0>,|1>\rbrace$で測定する。
- $j=2$の時は正規直交基底$\lbrace|+>,|->\rbrace$で測定する。ここで、測定値$+$は0、$-$は1と解釈する。
解説
Aの送ったベクトル$|\phi(x_1x_2)>$は、Bの選んだ測定をなす二つの基底ベクトルのうち、測定値として$x_j$を出す方のベクトルにより近いことがわかります。
例えば。$x=01$の場合を考えると、AはBに$|\phi(01)>$を送る。Bは$j=1$の時、計算基底で測定するが、$|\phi(01)>$は$|0>$により近いので、
|<0|\phi(01)>|^2 = \cos^2(\frac{\pi}{8})
の確率で$x_1=0$が得られる。
一方で,$j=2$の場合は、基底$\lbrace|+>,|->\rbrace$で測定するが、$|\phi(01)>$は$|->$により近いので、
|<-|\phi(01)>|^2 = \cos^2(\frac{\pi}{8})
の確率で$x_2=1$が得られる。
したがって、古典ランダムアクセス符号では$p=\frac{1}{2}$であったが、量子ランダムアクセス符号ではそれより高い確率を達成できる。(量子の優位性)
Qiskitでの実装
必要なライブラリのimport
from qiskit import QuantumCircuit
from qiskit import QuantumRegister
from qiskit import ClassicalRegister
from qiskit import Aer, execute
from math import pi
初期設定
backendとしてqasm_simulatorを使い、shot数は$1024$としました。
backend = Aer.get_backend('qasm_simulator')
shots = 1024
その他、あらかじめ設定しておく内容を記載しておきます。
# 入力2ビットリスト
inputbitlist = ["00", "10", "01", "11"]
rotationangles = {"00": pi/4, "10": 3*pi/4, "01":-1*pi/4, "11":5*pi/4}
# 量子レジスター
qr = QuantumRegister(1)
# 古典レジスター
cr = ClassicalRegister(1)
# QuantumCirtcuits
EncodeCircuits = {}
DecodeCircuits = {}
Encode(Aの作業)
$8$通りの回路を一気に作っていきます。まずはAがBへ送る量子ビットの状態を$4$通り作成していきます。
$ry$ゲートを使って状態を作成していきます。
# エンコードしていく
for input in inputbitlist:
circuitname = "Encode" + input
EncodeCircuits[circuitname] = QuantumCircuit(qr, cr, name=circuitname)
EncodeCircuits[circuitname].ry(rotationangles[input], 0)
EncodeCircuits[circuitname].barrier()
Decode(Bの作業)
$j=1$の時の回路と、$j=2$の時の回路を作成していきます。$j=2$では基底$\lbrace|+>,|->\rbrace$で測定を行うためにアダマールゲートを作用させています。
# デコードしていく
position = ["First", "Second"]
for pos in position:
circuitname = "Decode" + pos
DecodeCircuits[circuitname] = QuantumCircuit(qr, cr, name=circuitname)
if pos == "Second":
DecodeCircuits[circuitname].h(0)
DecodeCircuits[circuitname].measure(qr[0], cr[0])
実行
実行の前にEncodeとDecodeでそれぞれ作成した回路を合体させていきます。
# 組み合わせていく
Circuits = {}
for encode in EncodeCircuits.keys():
for decode in DecodeCircuits.keys():
circuitname = encode + decode
Circuits[circuitname] = EncodeCircuits[encode] + DecodeCircuits[decode]
実行します。
# 実行していく
job = execute(list(Circuits.values()), backend=backend, shots=shots)
results = job.result()
結果を確認します。ここで正規直交基底$\lbrace|+>,|->\rbrace$で測定場合、測定値$+$は0、$-$は1と解釈していることに気をつける必要があります。概ね$0.85$の確率で得たい結果を得ることができていることがわかります。
# 結果の確認
for name in Circuits.keys():
counts = results.get_counts(Circuits[name])
print("result of {}: {}".format(name, counts))
"""
result of Encode00DecodeFirst: {'1': 141, '0': 883}
result of Encode00DecodeSecond: {'0': 876, '1': 148}
result of Encode10DecodeFirst: {'0': 152, '1': 872}
result of Encode10DecodeSecond: {'1': 159, '0': 865}
result of Encode01DecodeFirst: {'1': 154, '0': 870}
result of Encode01DecodeSecond: {'1': 873, '0': 151}
result of Encode11DecodeFirst: {'0': 146, '1': 878}
result of Encode11DecodeSecond: {'0': 140, '1': 884}
"""
最後に
Qiskitのリハビリのために量子ランダムアクセス符号の実装を行ってみました。この後は、量子鍵配送プロトコルとして有名なBB84プロトコルについて実装を行う予定です。