EPR Pairを変更して量子テレポーテーションを行う

#量子テレポーテーション
理学系研究科、情報理工研究科共通の「量子計算論」という授業で提出したレポートをもとに書いています。量子テレポーテーションの説明やQiskitを用いた実装については[Qiskit Textbook](https://qiskit.org/textbook/ch-algorithms/teleportation.html)に書かれているのでそちらを参考にしてください。日本語(自動翻訳)は[こちら](https://qiskit.org/textbook/ja/ch-algorithms/teleportation.html)。

#EPR Pairの変更
$$
\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}}
$$[Qiskit Textbook](https://qiskit.org/textbook/ch-algorithms/teleportation.html)にもある通りEPR Pairとしては
$$
\frac{\ket{00}+\ket{11}}{\sqrt{2}}
$$が用いられますが、
$$
\frac{\ket{10}+\ket{01}}{\sqrt{2}}
$$を用いた場合にどうすれば量子テレポーテーションを行うことができるのか考えます。アリスは未知の状態$\ket{\psi}$を持ち、$\Psi^+$をボブと共有するとします。
$$
\begin{eqnarray}
  \ket{\psi} &=& \alpha\ket{0} + \beta\ket{1} \\\
  \Psi^+ &=& \frac{\ket{10}+\ket{01}}{\sqrt{2}}
\end{eqnarray}
$$量子テレポーテーション・プロトコルに従って、アリスは先ずCNOTゲートを用いて$\ket{\psi}$と$\Psi^+$をエンタングルします。$\ket{\psi_1}$がエンタングルする前、$\ket{\psi_2}$がエンタングルした後です。
$$
\begin{eqnarray}
  \ket{\psi_1} &=& (\alpha\ket{0} + \beta\ket{1})\otimes
  \frac{1}{\sqrt{2}}(\ket{10}+\ket{01}) \\\
  \ket{\psi_2} &=& \frac{1}{\sqrt{2}}(\alpha\ket{010} + 
  \alpha\ket{001} + \beta\ket{100} + \beta\ket{111} ) \\\
  &=& \frac{1}{\sqrt{2}}\left[
    \alpha\ket{0}(\ket{10} + \ket{01}) 
    + \beta\ket{1}(\ket{00}+ \ket{11}) 
  \right]
\end{eqnarray}
$$そしてアリスは$\psi$に$H$ゲートを適用します。$\ket{\psi_3}$は$H$ゲート適用後の状態です。
$$
\begin{eqnarray}
  \ket{\psi_3} &=& \frac{1}{\sqrt{2}}\left[
    \alpha H \ket{0}(\ket{10} + \ket{01}) 
    + \beta H \ket{1}(\ket{00}+ \ket{11}) 
  \right] \\\
  &=& \frac{1}{2}[
   \ket{00}(\alpha\ket{1}+\beta\ket{0})
  +\ket{01}(\alpha\ket{0}+\beta\ket{1})
  +\ket{10}(\alpha\ket{1}-\beta\ket{0})
  +\ket{11}(\alpha\ket{0}-\beta\ket{1})
  ]
\end{eqnarray}
$$ボブが$\ket{\psi}$を得るためには、アリスから受け取る観測結果が<ul><li>$\ket{00}$の時、$X$ゲート</li><li>$\ket{01}$の時、何もしない </li><li>$\ket{10}$の時、$Z$ゲートと$X$ゲート</li><li>$\ket{11}$の時、$Z$ゲート</li></ul>を適用すればいいことがわかります。しかし、2つ目のqubit(EPR Pairのアリス側)が$\ket{0}$の時に$X$ゲートを適用することになり、通常のCNOTゲートとは逆です。そのためアリスが観測する前に2つ目のqubitを反転させておきます。
$$
\begin{eqnarray}
  &&I\otimes X \otimes I \ket{\psi_3} \\\
  &=& 
  \frac{1}{2}[
   \ket{00}(\alpha\ket{0}+\beta\ket{1})
  +\ket{01}(\alpha\ket{1}+\beta\ket{0})
  +\ket{10}(\alpha\ket{0}-\beta\ket{1})
  +\ket{11}(\alpha\ket{1}-\beta\ket{0})
  ]
\end{eqnarray}
$$するとアリスから測定結果を受け取ったボブが適用すべきゲートはEPR pairが$\frac{\ket{00}+\ket{11}}{\sqrt{2}}$の時と全く同じになります。以下にQiskitでシミュレーターを使った時の結果と実際の量子コンピュータを使った時の結果を置いておきます。

```python
import numpy as np
import matplotlib.pyplot as plt

from qiskit import QuantumCircuit, execute, Aer, IBMQ
from qiskit.quantum_info import random_statevector
from qiskit.visualization import plot_histogram
from qiskit.extensions import Initialize
from qiskit.providers.ibmq import least_busy
from qiskit.tools.monitor import job_monitor

IBMQ.load_account()
provider = IBMQ.get_provider(hub="ibm-q")
real_backend = least_busy(provider.backends(filters= lambda x: x.configuration().n_qubits > 3
                                            and not x.configuration().simulator))
sim_backend = Aer.get_backend("qasm_simulator")
print("The backend as a real device is " + real_backend.name())
print("The backend as a simulator is " + sim_backend.name())
```

    The backend as a real device is ibmq_athens
    The backend as a simulator is qasm_simulator



```python
psi = random_statevector(2, 1)
init_gate = Initialize(psi)
init_gate.label = "init"
inverse_init_gate = init_gate.gates_to_uncompute()
```
$$
\Psi^+ = \frac{\ket{10}+\ket{01}}{\sqrt{2}} = X\otimes I\frac{\ket{00}+\ket{11}}{\sqrt{2}}
$$なので、$\frac{\ket{00}+\ket{11}}{\sqrt{2}}$の状態を構成してから、片方のqubitに$X$ゲートを適用すれば$\Psi^+$を構成できます。Qiskitの場合qubitは$\ket{0}$で初期化されています。したがって片方のqubitに$H$ゲートを適用してからCNOTゲートを適用することで$\frac{\ket{00}+\ket{11}}{\sqrt{2}}$を構成することができます。
$$
\ket{0}\otimes\ket{0} \xrightarrow[H\otimes I]{} \frac{\ket{0}+\ket{1}}{\sqrt{2}}\otimes\ket{0}\xrightarrow[CNOT]{}\frac{\ket{00}+\ket{11}}{\sqrt{2}}
$$

```python
def create_psiplus(qc, a, b):
    qc.h(a)
    qc.cx(a, b)
    qc.x(a)
    
def alice_gates(qc, psi, a):
    qc.cx(psi, a)
    qc.h(psi)
    qc.x(a)
    
def bob_gates(qc, a, b, c):
    qc.cz(a, c)
    qc.cx(b, c)
    
```


```python
qc = QuantumCircuit(3, 1)

qc.append(init_gate, [0])
qc.barrier()

create_psiplus(qc, 1, 2)
qc.barrier()

alice_gates(qc, 0, 1)
qc.barrier()

bob_gates(qc, 0, 1, 2)
qc.barrier()

qc.append(inverse_init_gate, [2])
qc.measure(2, 0)

qc.draw(output="mpl")
```

![output_3_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/975018/5306cf83-2754-98c7-294c-ff5aa3a85fa3.png)

```python
#results using simulator
counts = execute(qc, sim_backend, shots=1000).result().get_counts()
plot_histogram(counts)
```

![output_4_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/975018/636c7c09-a3b8-75e4-2829-4830d606c67e.png)

```python
#results using real device
job = execute(qc, real_backend)

job_monitor(job)

real_result = job.result()
plot_histogram(real_result.get_counts(qc))
```

    Job Status: job has successfully run

![output_5_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/975018/542f763b-a304-cabf-f24d-9a80e6408623.png)

```python
error_rate_percent = sum([
    real_result.get_counts(qc)[result] for result in real_result.get_counts(qc).keys() if result[0]=="1"
]) * 100 / sum(list(real_result.get_counts(qc).values()))
print("The experimental error rate: ", error_rate_percent, "%")
```

    The experimental error rate:  10.05859375 %