IBMQ + Qiskit 使い方まとめ

クラウド量子コンピューターIBMQとインターフェースPythonプログラミングパッケージQiskitの解説 (2019年4月現在)。研究で使ったり使わなかったりしたので諸々を備忘録としてまとめておく。

# IBMQについて
・[実機一覧](https://quantumexperience.ng.bluemix.net/qx/devices) 
現在クラウド上に公開されている量子計算機はこちら
<img width="1160" alt="Screen Shot 2019-04-18 at 14.10.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230477/9d8a1415-c5ff-ce94-7990-8c3fb439fa09.png">
上2つの20qubits計算機は一般人には使えない。5qubitsはIBMQ Experienceで扱えるもの、一番下の16qubitsはQiskitを通してしか扱えない。

・[IBM Q Experience for Researchers](https://quantumexperience.ng.bluemix.net/qx/researchers)
量子計算関連で査読論文を最低1つ持っていると申請出来る。実機への優先的なアクセス権が貰える。

# IBMQ Experience
<img width="988" alt="Screen Shot 2019-04-18 at 14.01.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230477/a927bd15-c00a-0c56-55ff-517f79abb93d.png">
[IBMQ Experience](https://quantumexperience.ng.bluemix.net/qx/editor)
とりあえず動かしてみたい人向け。アカウント作成・ログインは一応必要。量子回路に直接ゲートを埋め込んでいく直感的なUIでわかりやすい。ただし、使える計算機の種類・ゲート操作・shots数などの実行環境に大きな制限がある。
・5qubitsの計算機しか使えない
・MultiqubitゲートはCNOTのみ
・一回の実機実験で選べるshots数は{1,1024,4096,8192}の4種類のみ
<font color="Blue">Simulate</font>ボタンで古典計算機のシミュレーション、<font color="Blue">Run</font>で量子計算機上で動く。実機のほうは結果返ってくるまで結構時間がかかる。実機の方は回数制限があり、ログインすると表示される"MyUnit"(初期値は15)が消費されていき無くなるまで、24時間経つと回復するっぽい(経たなくても回復したりするのでよくわからない)。

# Qiskit
### インストール
こちらの動画[Getting started with Qiskit](https://www.youtube.com/watch?v=V3hXSftZuoc)を参照にインストール及びテストを行った。Python3,Jupyterがインストールされている環境で
`sudo pip install qiskit`
`sudo pip install msgpack`
で終わり。

### アカウントのload

```Python:load_account
from qiskit import IBMQ
IBMQ.save_account("API")
IBMQ.load_accounts()
```
"API"の部分はMy Account -> Advanced -> API Token をコピーしたものを貼り付ける。これで自分のアカウントの読み込みが完了し、実機を動かすことが出来る。

### 実機の情報取得
アカウントloadが終わった状態で次のコマンドを打つと利用可能な実機一覧の配列が返ってくる。

```python
IBMQ.backends()
```

```:Output
[<IBMQBackend('ibmqx4') from IBMQ()>,
 <IBMQBackend('ibmqx2') from IBMQ()>,
 <IBMQBackend('ibmq_16_melbourne') from IBMQ()>,
 <IBMQBackend('ibmq_qasm_simulator') from IBMQ()>]
```


さらに、詳しい情報は

```Python
from qiskit.tools.monitor import backend_overview
# このモジュールのimportはなぜか1回目にエラー吐くのでもう一度繰り返す

backend_overview()
```

```:Output
ibmq_16_melbourne            ibmqx2                      ibmqx4
-----------------            ------                      ------
Num. Qubits:  14             Num. Qubits:  5             Num. Qubits:  5
Pending Jobs: 1              Pending Jobs: 0             Pending Jobs: 0
Least busy:   False          Least busy:   True          Least busy:   False
Operational:  True           Operational:  True          Operational:  True
Avg. T1:      55.1           Avg. T1:      55.8          Avg. T1:      46.0
Avg. T2:      73.1           Avg. T2:      42.8          Avg. T2:      26.2
```
で取得出来る。Pending Jobsが現在の待ち計算数を表す。

### 量子回路の作成

```Python
import numpy as np
import math
import matplotlib.pyplot as plt
import qiskit as qk
from qiskit import IBMQ, BasicAer
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, execute, Aer
from qiskit.tools.visualization import plot_histogram
import random

IBMQ.save_account("API")
IBMQ.load_accounts()

def Create_circuits(P_qubits=2):

    # 量子ビット数と古典ビット数を決める
    q = QuantumRegister(P_qubits, "q")
    c = ClassicalRegister(P_qubits, "c")
    
    # middle
    middle = QuantumCircuit(q, c)
    for i in range(P_qubits):
        middle.h(q[i])
    middle.barrier()

    # 量子フーリエ変換 QFT
    def Qft(circ, q, n):
        """n-qubit QFT on q in circ."""
        for j in range(n):
            for k in range(j):
                circ.cu1(math.pi/float(2**(j-k)), q[k], q[j]) 
            circ.h(q[P_qubits-1-j])
    qft3 = QuantumCircuit(q, c, name="qft3")
    Qft(qft3, q, P_qubits)

    # 測定 meas_QFT
    meas_QFT = QuantumCircuit(q, c)
    meas_QFT.barrier()
    for i in range(P_qubits):
        meas_QFT.measure(q[i],c[i])
    meas_QFT.barrier()
    
    return middle + qft3 + meas_QFT

Circuits = Create_circuits(2)
Circuits.draw(output='mpl')
```
Output:
![download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230477/bf756901-5939-2dd7-3c0e-7d17c7e93fb8.png)


### 量子計算の実行
上記のように作成した量子回路は一回の実験で75個分まで登録出来る。`execute(量子回路の配列, 使用する計算機, 一つの量子回路を実行する回数)`で計算が実行される。

```Python
from qiskit.tools.monitor import job_monitor # このモジュールはインポート失敗した場合もう一度行う

def Execute(circuits, shots, backend):
    print("The backend is " + backend.name())
    
    # 量子回路circuits[0~74]を順に実機に投げる
    #job = execute(circuits, backend, shots)                                    # 実機
    job = execute(circuits, backend, shots=shots, seed=random.randint(0,10000)) # シミュレータ  
    job_monitor(job) # jobの進捗をモニターする
    
    # jobの結果を取得
    result = job.result()
    for i in range(3):
        print(result.get_counts(circuits[i]))

Circuits = []
for i in range(3): # 量子回路は75個で追加出来る
    Circuits.append(Create_circuits(P_qubits=i+2))
backend = Aer.get_backend('qasm_simulator')  # シミュレータ   
#backend = IBMQ.backends()[1]                # 実機 IBMQ 5 Yorktown
Execute(Circuits, 100, backend)
```

`job_monitor(job)`により計算の進捗状況が表示され、次のように変化する

```
Job Status: job is being initialized
Job Status: job is queued (37)
Job Status: job has successfully run
```
計算が無事終了すると各量子状態がいくつ観測されたかをget_countsメソッドで習得出来る。

```
{'00': 100}
{'010': 12, '011': 17, '001': 10, '000': 61}
{'0010': 14, '0011': 15, '0001': 10, '0000': 61}
```

## その他
・メインユーザーは欧米っぽいので、日本時間での昼間(12時~18時)はほぼ人が居ない。逆に夜(19時~6時)はめちゃ混んでいて(常時Job Pendingが10以上)まともに計算を回せない傾向にあった。

・IBM Q 16 Melbourne はかなり不安定ぽい。[質問フォーラム](https://quantumexperience.ng.bluemix.net/qx/community/question?questionId=5bba32044a0ce7004f133854)でもいくつかコメントがあった。研究にはちょっと使えないかなという感じ。

・他にも、Multiqubitsゲートの精度が悪すぎ(公式のErrorは$5*10^{-2}$で、Singlequbitsゲートより一桁大きい)て、CZゲート5回ぐらい使っただけでほとんどランダムみたいな結果が出ます。

・Controlledゲートについては、実機のqubitのarchitectureを考慮する必要あり。例えばYorktownでは0->4や1->3などのControlledゲートは使えない。
<img width="220" alt="Screen Shot 2019-04-18 at 15.32.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230477/4a266af3-bd25-1823-b360-f50bad811a8e.png">

・計算機のCalibrationが2日に1回ぐらい入る。30分ぐらい使えなくなる。(Calibration後はちょっと結果が良くなったりする気がする。)