D-Wave Leapで量子アニーリングマシンの実機に触れる

# はじめに

D-Wave Leapを利用することで実機のD-Waveに処理を投げられることが確認できましたので、D-Wave LeapのデモとPythonで実機のD-Waveへリクエストを投げるまでの手順を紹介します。

量子コンピュータは従来の古典コンピュータと異なり、まだ直感的な操作ができる状態ではありません。
実機を使い、小規模な足し算を量子コンピュータへどう投げれば良いかも簡単に紹介します。

# D-Wave Leapとは

クラウド上からD-Waveの実機へ無料(上限あり)で量子アニーリングを行わせることができるサービスです。
2018/10/04にD-Wave社から発表され、発表当初はアメリカとカナダ限定のサービスでしたが、2019/03/26に日本でも利用可能になるとアナウンスがありました。

# ダッシュボード

[ユーザー登録](https://cloud.dwavesys.com/leap/signup/)後、ログインするとダッシュボード画面が表示されます。そこで、あとどのくらいD-Waveで計算できるかを知ることができます。
![d-wave_leap_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316064/0b79175d-5132-8a29-9fee-910e451a6cbf.png)
一ヶ月につき1分間QPUが無料で利用可能となっています[^1]。QPUとは、量子アニーリングを行うプロセッサであり、この処理時間はmsecオーダーなので最大4000回ほどD-Waveに処理を投げることができるようです。
![d-wave_leap_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316064/02a78886-ee46-7441-d44c-5e16b2adc8ae.png)
D-Waveマシンのステータスも表示されています。現時点で実機ソルバーは`DW_2000Q_2_1`と`DW_2000Q_5`の2台がリストに表示されていました。
[^1]: 初月のみ条件無しで無料、次月からはDeveloper Planに登録が必要なようです。ソースコードの公開も条件になっていました。

# デモを実行する

![d-wave_leap_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316064/60c815f6-93fc-fc58-7a49-290992ed24b6.png)
デモがあるのでそれを実行してみます。
![d-wave_leap_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316064/e3a05f4a-b471-0242-c657-0b9f71965d5c.png)
因数分解とソーシャルネットワーク解析のデモが実行できます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316064/4d1af9e6-cac1-388f-1a42-7971e8c81b41.png" width=30%>　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316064/bae0eb7a-77d1-f044-54b3-57b7724b78ee.png" width=30%>　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316064/d9b977b5-f861-a93a-d090-9426b46eb00d.png" width=30%>
因数分解のデモを見てみます。
3ビットの乗算回路を制約充足の観点から定式化すると、回路を逆方向に実行することが可能となるため、出力(因数分解の結果)を設定すると入力(因数のペア)を得ることができるようです。
![d-wave_leap_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316064/e6ac2616-3daf-319f-90e0-6edefb1d07fb.png)
`RUN`ボタンを押下すると、実機で計算してくれます。
![d-wave_leap_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316064/af8b8177-bd99-13c4-396a-c352998b4de5.png)
因数分解の結果、`3`と`4`が得られました。
`12`の因数分解なので理論的には`(3,4)`、`(4,3)`、`(2,6)`、`(6,2)`がそれぞれ25%の確率で得られることになります。
![d-wave_leap_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316064/1ecc817e-dd8e-ebe6-32ad-cd181c2e0a9c.png)
ダッシュボード画面を再度見てみると、実機での実行可能時間が減っているのが分かります。
一度の実行でQPUを26msec利用したようです。

# Pythonから実機ソルバー(D-Wave 2000Q)を動かしてみる

コード上から実機ソルバーへ量子アニーリングを実行させてみます。

まずはD-Wave社が提供しているOceanというSDKをインストールします。
Ocean SDKはもともとD-Wave社が提供していた`dwave-system`をより簡単に利用できるようにしたもののようです。

```bash:dwave-ocean-sdkのインストール
$ pip install dwave-ocean-sdk
```

実機に接続するため、トークンを取得します。D-Wave Leapにトークンが表示されているのでそれを取ってきます。
![token.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316064/a529f120-6045-0aed-beb3-459d31407b9d.png)
今回は[D-Wave Cloud Client](https://docs.ocean.dwavesys.com/projects/cloud-client/en/latest/index.html)を使います。
まずは実機ソルバーのリストを取ってみます。

```python:solver.py
from dwave.cloud import Client

client = Client.from_config(token='ABC-123456789123456789123456789')
print(client.get_solvers())
```

```bash
$ python solver.py
[Solver(id='DW_2000Q_5'), Solver(id='DW_2000Q_2_1')]
```

実機ソルバーが2台稼働していることが確認できました。

トークンをコードに含めたくない場合、設定ファイルに書き出すことができます。
設定ファイルの保存場所など、色々聞かれますが、とりあえずはトークンの設定だけでOKです。

```bash
$ dwave config create
Configuration file not found; the default location is: /home/user-name/.config/dwave/dwave.conf
Configuration file path [/home/user-name/.config/dwave/dwave.conf]: 
Configuration file path does not exist. Create it? [y/N]: y
Profile (create new) [prod]: 
API endpoint URL [skip]: 
Authentication token [skip]: ABC-123456789123456789123456789
Default client class (qpu or sw) [qpu]:  
Default solver [skip]: 
Configuration saved.
```

この設定をしておくと、コマンドラインからソルバーの情報を取得できるようになります。

```
$ dwave solvers
Solver: DW_2000Q_5
  Parameters:
    anneal_offsets: A list of anneal offsets for each working qubit (NaN if u...
...略...
Solver: DW_2000Q_2_1
  Parameters:
    anneal_offsets: A list of anneal offsets for each working qubit (NaN if u...
...略...
```

各ソルバーへの`ping`も叩けます。

```
$ dwave ping -s DW_2000Q_2_1
Using endpoint: https://cloud.dwavesys.com/sapi
Using solver: DW_2000Q_2_1
Submitted problem ID: 49519939-a023-4d29-b649-85a2c503df28

Wall clock time:
 * Solver definition fetch: 1172.703 ms
 * Problem submit and results fetch: 1293.948 ms
 * Total: 2466.652 ms

QPU timing:
 * qpu_sampling_time = 164 us
 * qpu_anneal_time_per_sample = 20 us
 * qpu_readout_time_per_sample = 123 us
 * qpu_access_time = 7711 us
 * qpu_access_overhead_time = 1680 us
 * qpu_programming_time = 7547 us
 * qpu_delay_time_per_sample = 21 us
 * total_post_processing_time = 175 us
 * post_processing_overhead_time = 175 us
 * total_real_time = 7711 us
 * run_time_chip = 164 us
 * anneal_time_per_run = 20 us
 * readout_time_per_run = 123 us
```

設定ファイルを作ったので、先程のソルバーを取得するPythonはトークンを省いてこう書けます。

```python:solver.py
from dwave.cloud import Client

with Client.from_config() as client:
    solvers = client.get_solvers()
    print(solvers)
```

### 1+1を量子アニーリングで解いてみる

詳しい説明は割愛しますが、量子アニーリングでは問題をQUBOという形式にする必要があり、最小値問題に落とし込む必要があります。ですので1+1は、$$E = (x - 2)^2 $$というコスト関数で表すことができます。

途中の計算は省きますが、2量子ビットで上記コスト関数をQUBOとして表現すると

```math
{\begin{align*}
H &= \left(
    \begin{array}{c}
      q_0 & q_1 
    \end{array}
  \right)
\left(
    \begin{array}{cc}
      -3 & 4 \\
      0 & -4
    \end{array}
  \right)
\left(
    \begin{array}{c}
      q_0 \\
      q_1 
    \end{array}
  \right)
\end{align*}
}
```

と表すことができます。このQUBOをD-Waveに解かせてみます。

```python:solve.py
from dwave.cloud import Client

with Client.from_config() as client:
    solver = client.get_solver()
    print('solver: ' + solver.data['id'])

    u, v = next(iter(solver.edges))
    print('edges: ' + str([u, v]))
    Q = { 
        (u, u): -3, 
        (u, v): 4,
        (v, u): 0,
        (v, v): -4, 
    }   

    computation = solver.sample_qubo(Q, num_reads=5)

    for sample in computation.samples:
        print('result: ' + str([int(sample[u]), int(sample[v])]))

    print('timing: ' + str(computation.timing))
```

実行結果です。

```
 $ python solver.py
solver: DW_2000Q_5
edges: [711, 707]
result: [0, 1]
timing: {'qpu_sampling_time': 1575, 'qpu_anneal_time_per_sample': 20, 'qpu_readout_time_per_sample': 274, 'qpu_access_time': 11246, 'qpu_access_overhead_time': 3028, 'qpu_programming_time': 9672, 'qpu_delay_time_per_sample': 21, 'total_post_processing_time': 3788, 'post_processing_overhead_time': 3788, 'total_real_time': 11246, 'run_time_chip': 1575, 'anneal_time_per_run': 20, 'readout_time_per_run': 274}
```

`result: [0, 1]`となっており、1量子ビット目が0、2量子ビット目が1なので解は`2`となり、量子コンピュータで1+1を解くことができました！

コードを詳しく見てみます。

```python
solver = client.get_solver()
```

この行はD-Waveへアクセスして、利用可能な実機ソルバーを取得しています。設定でデフォルトのソルバーを指定することもできます。

```python
u, v = next(iter(solver.edges))
```

ここでは実機で相互接続されている量子ビットのインデックスを取得しています。
今回は2量子ビットで解くため、このペアは一つだけあれば良いです。

```python
computation = solver.sample_qubo(Q, num_reads=5)
```

D-Waveへ処理を投げています。`num_reads`はD-Waveでの測定回数です。この値を大きくすると1分のQPU無料枠をたくさん消費することになるのでお試しの場合は少なめにした方が良いです。
といっても一回のアニーリング時間は`20usec`とかなり小さいので回数を`100`にしても`2msec`くらいしかQPUを消費しません。

```python
for sample in computation.samples:
```

D-Waveからの結果を取得しています。
測定回数は5回ですが、今回は一つしか結果が返りませんでした。これは、5回とも同じ値に収束したからだと考えられます。

ちなみにD-Waveのサイトでは以下のように結果を取っていますが、これだと領域外アクセスが起きますので注意してください。おそらくドキュメントがライブラリのアップデートに対応できていないです。

```python
for i in range(5):
```

```python
print('timing: ' + str(computation.timing))
```

最後の出力は処理に要した時間を返しています。QPUを使用した時間は `qpu_anneal_time_per_sample[usec] × 測定回数`でおおよそ求められます。`timing`の詳細については[こちら](https://docs.dwavesys.com/docs/latest/c_timing_5.html#timing-cloud-client)に記載があるのですが、厳密にはどの値をQPUの処理時間としてカウントするのか、といった情報は見つけられませんでした…

# まとめ

以前は実機での実行にはD-Waveとの契約が必要でしたが、D-Wave Leapによってかなりカジュアルに量子アニーリングマシンの実機で実行できることが分かりました。
今回のような、デモの確認や小規模な足し算などのちょっとしたことを試す程度であれば1ヶ月1分のQPU利用時間は十分すぎるほどあるので色々と問題を解いてみようと思います。

# 参考URL

### D-Wave
https://www.dwavesys.com/take-leap
https://ocean.dwavesys.com/
https://docs.ocean.dwavesys.com/en/latest/overview/dwavesys.html
https://docs.ocean.dwavesys.com/projects/cloud-client/en/latest/reference/index.html
https://docs.dwavesys.com/docs/latest/c_timing_5.html#timing-cloud-client

### その他
https://spectrum.ieee.org/tech-talk/computing/hardware/dwave-launches-free-quantum-cloud-service
https://gigazine.net/news/20181005-d-wave-leap/
https://jp.techcrunch.com/2019/03/26/d-wave-leap/
https://own-search-and-study.xyz/2018/12/24/d-wave%E3%81%AEleap%E3%81%AE%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%82%92python%E3%81%A7%E5%8B%95%E4%BD%9C%E3%81%95%E3%81%9B%E3%81%A6%E3%81%BF%E3%81%9F/
https://qiita.com/abenben/items/1ccc51cd5d9ba18b30c1
https://qiita.com/YuichiroMinato/items/57cb8504ab61930eb479