[練習20200705] qiskitでCHSH不等式の破れを検証してみた

# CHSH不等式とは?

説明もtex打ちも面倒なので、ひとまず外部資料などにお任せします。
一言で言えば、この不等式が実験で成り立たないことが示せると、局所実在論の否定につながります。
(つまり量子系の非局在性の証明になります。)

# qiskitで実装

### モデル
今回使用するベル状態は$\frac{1}{\sqrt{2}}(|01\rangle-|10\rangle)$とします。
- Aliceは$\{|0\rangle,|1\rangle\}$基底または$\{|+\rangle,|-\rangle\}$基底で測定します。
- Bobは$\{\cos (\theta)|0\rangle+\sin (\theta)|1\rangle,-\sin (\theta)|0\rangle+\cos (\theta)|1\rangle\}$基底または$\{\sin (\theta)|0\rangle+\cos (\theta)|1\rangle,-\cos (\theta)|0\rangle+\sin (\theta)|1\rangle\}$基底で測定します。
この時、$\theta = \frac \pi 8$で理論的には相関が最大になるので、今回は$\theta = \frac \pi 8$とします。

### 実装パート

愚直に実装しました。

```python
import numpy as np
import qiskit
from qiskit import *
from qiskit.tools.monitor import job_monitor
qiskit.__qiskit_version__
```
実行環境は
{'qiskit-terra': '0.14.1',
 'qiskit-aer': '0.5.2',
 'qiskit-ignis': '0.3.0',
 'qiskit-ibmq-provider': '0.7.2',
 'qiskit-aqua': '0.7.1',
 'qiskit': '0.19.3'}
です。次に、アカウントのロードをします。IBM Quantum Experienceでは16qubitデバイスを公開しています。
たまたまライセンスがあったので、今回はibmq_johannesburg(20qubit)と、ibmq_rochester(53qubit)を使用しました。

```python
IBMQ.load_account()
provider = IBMQ.get_provider(hub="ibm-q-utokyo")
print(provider)
```

まず、上記のベル状態を作る関数を定義します。

```python
def make_bell_state(qubits, n=16):
    qc = QuantumCircuit(n, 2)
    qc.x(qubits[0])
    qc.h(qubits[0])
    qc.x(qubits[1])
    qc.cx(qubits[0], qubits[1])
    qc.z(qubits[1])
    return qc
```
次に、AliceとBobの観測結果から、それらの積の期待値を計算する関数を以下に定義します。

```python
def E(shots, count):
    cs = [count[i + j] if i + j in count else 0 for i in ["0", "1"] for j in ["0", "1"]]
    return (cs[0] + cs[3] - cs[1] - cs[2]) / shots
```

そして、以下の関数がCHSH相関を計算するメインパートです。
解説は時間があれば今後つけたします。


```python
def real_chsh(theta, qubits, shots=1024, backend="qasm_simulator", n=16):
    qcs = [make_bell_state(qubits, n) for _ in range(4)]
    counts = []
    for i in range(4):
        if i >= 2:
            qcs[i].h(qubits[0])
        qcs[i].ry(-theta, qubits[1]) if i % 2 else qcs[i].ry(-theta - np.pi / 2, qubits[1])
        qcs[i].measure(qubits, [0,1])
        if backend == "qasm_simulator":
            counts.append(execute(qcs[i], backend=Aer.get_backend(backend), shots=shots).result().get_counts())
        else:
            job = execute(qcs[i], backend=provider.get_backend(backend), shots=shots, max_credits=10)
            job_monitor(job, interval = 2)
            counts.append(job.result().get_counts())
    return E(shots, counts[2]) + E(shots, counts[3]) + E(shots, counts[0]) - E(shots, counts[1])
```

パラメタは以下のようにします。

```python
theta = np.pi / 4
shots = 8192
```

さて、まずシミュレータで実験すると、

```python
n = 20
sim_backend="qasm_simulator"
print("correlation of [0, 1] by simulation:", real_chsh(theta, [0,1], shots, sim_backend, n))
print("correlation of [0,12] by simulation:", real_chsh(theta, [0,12], shots, sim_backend, n))
print("correlation of [0,19] by simulation:", real_chsh(theta, [0,19], shots, sim_backend, n))
```
結果は
correlation of [0, 1] by simulation: 2.849365234375
correlation of [0,12] by simulation: 2.804931640625
correlation of [0,19] by simulation: 2.814453125
のように、おおよそ$2\sqrt 2$になることがわかります。
一方、実機で実機すると、

```python
n = 20
real_backend="ibmq_johannesburg"
print("correlation of [0, 1] on real device:", real_chsh(theta, [0,1], shots, real_backend, n))
print("correlation of [0,12] on real device:", real_chsh(theta, [0,12], shots, real_backend, n))
print("correlation of [0,19] on real device:", real_chsh(theta, [0,19], shots, real_backend, n))

n=53
real_backend="ibmq_rochester"
print("correlation of [0,36] on real device:", real_chsh(theta, [0,36], shots, real_backend, n))
print("correlation of [0,52] on real device:", real_chsh(theta, [0,52], shots, real_backend, n))
```
以下のように、使用するqubitが離れると相関は減少してしまいます。
Job Status: job has successfully run
Job Status: job has successfully run
Job Status: job has successfully run
Job Status: job has successfully run
correlation of [0, 1] on real device: 2.308349609375
Job Status: job has successfully run
Job Status: job has successfully run
Job Status: job has successfully run
Job Status: job has successfully run
correlation of [0,12] on real device: 2.014892578125
Job Status: job has successfully run
Job Status: job has successfully run
Job Status: job has successfully run
Job Status: job has successfully run
correlation of [0,19] on real device: 1.94970703125
Job Status: job has successfully run
Job Status: job has successfully run
Job Status: job has successfully run
Job Status: job has successfully run
correlation of [0,36] on real device: 0.775634765625
Job Status: job has successfully run
Job Status: job has successfully run
Job Status: job has successfully run
Job Status: job has successfully run
correlation of [0,52] on real device: 0.205810546875

### qubitが離れると相関が小さくなる理由

これは実機の物理的実装の制約に拠ります。
IBMQの実機では全てのqubit素子が連結されているわけではありません。
そのため、CNOTなど、系にエンタングルした状態を含ませる演算子を作用させるためには隣接するqubit同士で演算を行うために回路を等価変形しなければなりません。
この最適化の段階でSWAPゲートを用いてqubitを交換するわけですが、SWAPゲートはCNOTゲート3つで構成されており、このCNOTゲートの実行は現在のIBMQデバイスではわりかし雑音が乗ってしまいます。
そのため、離れたqubit同士の相関は雑音によってかき乱されてしまうというわけです。

### 実用的な意義
この実験はある意味でqubit同士のエンタングルメントの強さを数値化することができていると言えます。
CNOTゲートに対してどれだけ頑強なのかといった、量子デバイスの性能を評価するベンチマークとして使われることがそうです。

## おわりに
大昔にqiskitのdocumentでもっと賢い検証方法を見かけたんですが、リンクを忘れてしまったので、知ってる人がいたらおしえてください。

加えて、はじめての記事なので至らない点はご容赦ください。