量子ゲート実機で回路深さの限界を調べる

# 量子ゲート実機で回路深さの限界を調べる

量子ゲート実機で簡単な回路をやってみて、どれぐらいの深さまで出来るのか試してみます。
使うのはIBMの ibmqx2 とします。(5量子ビット)

- なお、深さを変えながら何度も実行するので、単純にjobを投げると大変なことになります。
なので、複数の回路を同時に投げることができる　IBMQJobManager　という関数を使っています。


## 1量子ビットゲート
1量子ビットゲートとして、今回はNOTゲート(Xゲート)を使います。
"0"にNOTを二連続で作用させると、元の状態"0"に戻ってくることを利用して、エラーの度合いを調べます。

```python
#initialization
import matplotlib.pyplot as plt
import numpy as np
import math

# importing Qiskit
from qiskit import IBMQ, Aer
from qiskit.providers.ibmq.managed import IBMQJobManager
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister, execute

# import basic plot tools
from qiskit.visualization import plot_histogram

def Not_Circuit(n_depth):
  circ = QuantumCircuit(1)
  for i in range(n_depth):
    circ.x(0)
    circ.barrier()

  circ.measure_all()
  return circ

circs = []
depth_list = range(0,40,2)
n_circ = len(depth_list)
for i in depth_list:
  circs.append(Not_Circuit(i))

backend = provider.get_backend('ibmqx2')
job_manager = IBMQJobManager()
job_set = job_manager.run(circs, backend=backend)
results = job_set.results()

x = []
y = []
for i in range(n_circ):
  x.append(depth_list[i])
  y.append(results.get_counts(i).get('0')/1024)

fig, ax = plt.subplots()

ax.set_xlabel('Num of X gate')  # x軸ラベル
ax.set_ylabel('Prob. of 1')  # y軸ラベル
# ax.set_aspect('equal') # スケールを揃える
ax.grid()            # 罫線
ax.set_ylim([0, 0.5])    # y方向の描画範囲を指定
ax.plot(x, y)

fig.tight_layout()  # レイアウトの設定
# plt.savefig('hoge.png') # 画像の保存
plt.show()
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/4aeea27c-e35a-e41e-5e85-cbd3349170bd.png)


NOTゲートが増えると、望まない状態"1"が出る確率が増加します。
最悪はランダムに0/1が出る状態なので、0.5が上限になります。
これをみると、単一ゲート(NOT)の深さとしては100連続がいいところかと思います。

なお、単一ゲートでも任意回転角ゲート(Ry,Rx,Rz)はもっとずっと悪いと思います。

## 2量子ビットゲート

2量子ビットゲートとしては、最も基本的なCNOTゲートを使います。
CNOTは、古典論理ゲートでいうとXORに似たものです。（実際、XORを可逆にしようとするとCNOTが導出されます）
"00"にCNOTを二回作用させると"00"に戻ってきますので、エラーの度合いを調べます。

- やった後に気づきましたが、"10"が"10"に戻るのを見るべきだった気はします

プログラムとしては、ゲートをCNOTに書き換えるだけです。

```python
def Not_Circuit(n_depth):
  circ = QuantumCircuit(2)
  for i in range(n_depth):
    circ.cnot(0,1)    
    circ.barrier()

  circ.measure_all()
  return circ
```


```python
x = []
y = []
for i in range(n_circ):
  x.append(depth_list[i])

  count_sucess = results.get_counts(i).get('00')
  y.append((1024-count_sucess)/1024)

fig, ax = plt.subplots()

ax.set_xlabel('Num of CNOT gate')  # x軸ラベル
ax.set_ylabel('Prob. of 00')  # y軸ラベル
# ax.set_aspect('equal') # スケールを揃える
ax.grid()            # 罫線
ax.set_ylim([0, 1])    # y方向の描画範囲を指定
ax.plot(x, y)

fig.tight_layout()  # レイアウトの設定
# plt.savefig('hoge.png') # 画像の保存
plt.show()
```

- CNOTの場合、たまに実機からよくわからない値(None)が返ってきてバグるようです。

CNOTの場合、失敗率を　1 - "00"/総shot数$N$ としました。
最悪ケースでは"00"が確率25%で出るので、失敗率の上限は75%です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878664/8a96a7af-6054-eff7-d94c-eda53c6aeb75.png)


CNOTゲートが10も連続すると、厳しいようです。
深くなると、だいたい75%に収束しています。


# まとめ

単一ゲート(NOT)の場合は100個連続、二量子ゲート(CNOT)の場合は10個連続がいいところとなりました。
一般の回路ではこの混ぜ合わせですから、数十の量子ゲートが上限と思いました。
これまでの実行経験からも、「まぁ、そうだろうな」という結果でした。
単一ゲートの場合でも、任意回転角度ゲートなどは誤り率が高いことが知られているので、
なかなか厳しいです。


今回はみやすさのためにNOTゲートやCNOTゲートを用いました。
実際のところ、量子コンピューターではNOTは更に基本的なゲートに分解されて実行されています。
その粒度でエラー率と深さの関係を調べるのも面白いと思います。