この notebook では量子コンピューティングにおける超密度符号化(Superdense Coding: SDC)を紹介します。まず初めに作成した量子回路を Qiskit のシミュレーターを使ってテストし、実際の量子コンピューターで動かしてみます。
目次
- 超密度符号化と量子テレポーテーション
- 処理手順
2.1 Step 1
2.2 Step 2
2.3 Step 3 - 超密度符号化プロトコルのシミュレーション
3.1 3.1 測定の可視化 - 実際の量子コンピューターにおける超密度符号化
1. 超密度符号化と量子テレポーテーションの違い
量子テレポーテーションと超密度符号化は密接に関係しているので、適切に説明・区別なしには混乱を引き起こすでしょう。
量子テレポーテーションとは、2ビットの古典通信と Bell pair を利用して、量子ビット ($|\psi\rangle$) の状態をある場所から他の場所へ送信するプロトコルの事です。言い換えれば、共有されたエンタングルメントを利用してある場所に存在する量子ビットの量子状態を破壊し、離れた場所に作り直すプロトコルとも言えます。対して超密度符号化とは、1つの量子ビット通信を使用して、2つの古典ビットを誰かが別のグループに送信できるようにする手続きの事です。
量子テレポーテーション | 超密度符号化 |
---|---|
2つの古典ビットを使って 1つの量子ビットを転送 |
1つの量子ビットを使って 2つの古典ビットを転送 |
つまり、テレポーテーション・プロトコルは超密度符号化の反転バージョンであり、アリスとボブが最初の持ち物を交換しただけ、ともみなせます。
2. 処理手順
2.1 Step 1
手順はある第三者、チャーリーから始まります。チャーリーはエンタングルした状態にある2量子ビットを用意します。まず彼は、基底状態 $|0\rangle$ の2量子ビットから始めます。そして1つ目の量子ビットにアダマールゲート( $H$ )を作用させて重ね合わせ状態を作ります。その後、1つ目の量子ビットをコントロール・ビット、2つめをターゲット・ビットとして CNOT ゲート( $CX$ )を作用させます。このエンタングルした状態が、以前私たちが触れた Bell pair です。
出力結果
チャーリーは初めにアダマールゲートを作用させます。
$H$ ゲートが1つ目の量子ビットに作用すると重ね合わせ状態に遷移し、次の状態が得られることになります:
$$|0+\rangle = \tfrac{1}{\sqrt{2}}(|00\rangle + |01\rangle)$$その後、チャーリーは CNOT ゲートを作用させます。CNOT ゲートは2つの量子ビットをエンタングルさせるので、もしコントロール・ビットが $|1\rangle$ ならばターゲット・ビットが反転します。 ケットの右側の量子ビットがコントロール・ビットである事に注意しましょう。
$$\text{CNOT} \tfrac{1}{\sqrt{2}}(|00\rangle + |01\rangle) = \tfrac{1}{\sqrt{2}}(|00\rangle + |11\rangle)$$2.2 Step 2
チャーリーは1つ目の量子ビットをアリスに、2つ目をボブに送ります。この手順の目標は、アリスが彼女の持っている量子ビットを使って、2つの古典ビット情報をボブに送信することです。しかしその前にアリスは、彼女が送信したい2ビットの情報に応じて、彼女の持つ量子ビットにいくつかのゲートの組を作用させる必要があります。
超密度符号化の変換規則(アリスの手順)
従って、もしアリスが 00 を送りたいならば、彼女は自分の量子ビットには何も作用させません(恒等ゲート( $I$ )を作用させます)し、10 ならば、$X$ ゲートを作用させます。何を送りたいかによって、それに応じたゲートを作用させればよいのです。それが完了したら、アリスは彼女の量子ビットをボブに送り、手順の最終ステップに進みます。
2.3 Step 3
ボブは(右側の量子ビットである)アリスの量子ビットを受け取り、彼の量子ビットを使ってアリスのメッセージを復号します。復号の際、ボブは何の情報も必要としない事に注意してください。彼に必要なのは、つぎに示す復号手順の知識だけです。
ボブは、右側の量子ビットをコントロール・ビット、左側をターゲット・ビットとして CNOT ゲートを作用させます。そしてアダマールゲートを作用させ、最後に両方の量子ビットを観測する事で、アリスのメッセージを取り出すことが出来ます。
ボブが観測を行うと、彼はアリスが彼に送ったメッセージを確実に受け取ります。この最後の結果は実際には $-|11\rangle$ ですが $|11\rangle$ と書かれていることに注意してください。グローバル位相は観測に影響しないからです。
3. 超密度符号化プロトコルのシミュレーション
# 必要なすべてのライブラリをインポートします
from qiskit import QuantumCircuit
from qiskit import IBMQ, Aer, transpile, assemble
from qiskit.visualization import plot_histogram
量子エンタングルのペアを作るには、$H$ ゲートの後に CNOT ゲートが必要である事はわかっています。なので、QuantumCircuit
を引数にもち、インデックス a
, b
で表される2つの量子ビットをエンタングルさせる関数を作りましょう。
# QuantumCircit (qc) と2つの整数 (a,b) を引数にとる関数を定義します。
def create_bell_pair(qc, a, b):
qc.h(a) # 1つめの量子ビットに H ゲートを作用させます。
qc.cx(a, b) # 1つめの量子ビットをコントロール・ビットとして、CNOT ゲートを作用させます。
次に、メッセージを符号化しましょう。次の4つのメッセージ(00
, 10
, 01
, 11
)が送信できる事はわかっています。なので、このメッセージを引数に取り、対応するゲートを作用させるような関数を作りましょう。
# QuantumCircuit (qc)、量子ビットの添え字( qubit )、
# メッセージの文字列( msg )を引数にとる関数を定義します
def encode_message(qc, qubit, msg):
if msg == "00":
pass # 00 を送信するには何もしません
elif msg == "10":
qc.x(qubit) # 10 を送信するには X-ゲートを作用させます
elif msg == "01":
qc.z(qubit) # 01 を送信するには Z-ゲートを作用させます
elif msg == "11":
qc.z(qubit) # 11 を送信するには、Zゲートを作用させた後に
qc.x(qubit) # Xゲートを作用させます
else:
print("Invalid Message: Sending '00'")
最後に、メッセージを復号します。CNOT ゲートの後に $H$ ゲートを作用させれば復号できる事はわかっているので、これについても関数を作りましょう。
def decode_message(qc, a, b):
qc.cx(a,b)
qc.h(a)
これらを使って最終的な手順を完成させましょう。
# 2量子ビット回路を作成します
qc = QuantumCircuit(2)
# まず、イブがアリスとボブに渡す量子エンタングルペアを作ります
# First, Charlie creates the entangled pair between Alice and Bob
create_bell_pair(qc, 0, 1)
qc.barrier() # ここでは回路に「バリア(仕切り)」を挿入します。
#「バリア」はダイアグラム内のゲートを分離し、
# 回路のどの部分がどのようなものかを明確にします
# (回路をビジュアライズするとどのようなものかわかるでしょう)
# ここで、量子ビット_0 をアリスへ、量子ビット_1 をボブに送ります
# 次に、アリスは彼女のメッセージを 量子ビット_0 上に符号化します。
# 今回は '10' を送りたいしましょう。
# 読者自身でこの値を変更し、それが回路にどう影響するかを見ることもできます
message = "10"
encode_message(qc, 0, message)
qc.barrier()
# そうしたら、アリスは自分の量子ビットをボブに送ります。
# ボブは 量子ビット_0 を受け取ったら、復号手順を適応します。
decode_message(qc, 0, 1)
# 最後に、ボブが彼の量子ビットを測定することでアリスのメッセージを取得します
qc.measure_all()
# 出力を描画しましょう
qc.draw(output = "mpl")
aer_sim = Aer.get_backend('aer_simulator')
qobj = assemble(qc)
result = aer_sim.run(qobj).result()
counts = result.get_counts(qc)
print(counts)
plot_histogram(counts)
シミュレーターでは完全な量子コンピューターがシミュレートされます。正しいメッセージが、エラーなしに 100% の確率で測定できる事がわかります。
from qiskit import IBMQ
from qiskit.providers.ibmq import least_busy
shots = 1024
# ローカルアカウントの情報を取得します
IBMQ.load_account()
# 最も空いているバックエンドを取得します
provider = IBMQ.get_provider(hub='ibm-q')
backend = least_busy(provider.backends(filters=lambda x: x.configuration().n_qubits >= 2
and not x.configuration().simulator
and x.status().operational==True))
print("least busy backend: ", backend)
# 回路を実行します
t_qc = transpile(qc, backend, optimization_level=3)
job = backend.run(t_qc)
# ジョブをモニタリングします
from qiskit.tools.monitor import job_monitor
job_monitor(job)
# 結果をプロットします
result = job.result()
plot_histogram(result.get_counts(qc))
このように実際の量子コンピューターで実行すると、他の3つの状態も観測結果として現れます。量子ゲートのエラーと量子ビットのデコヒーレンスによるエラーが原因で起こるものです。これらのエラーについては後の章で詳しく学習することになるでしょう。
correct_results = result.get_counts(qc)[message]
accuracy = (correct_results/shots)*100
print(f"Accuracy = {accuracy:.2f}%")
import qiskit.tools.jupyter
%qiskit_version_table