Pythonで量子コンピュータを動かしたい


はじめに

Googleが量子超越性を実証したとのNewsが出て最近量子コンピュータが何かと話題だったので軽く調べていたのですが、誰でもお試しで量子コンピュータ(後述しますが、量子アニーリング方式の方でGoogleか開発を進めている方式とは異なる)を誰でもお試しで動かせる方法があったのでこちらにまとめました。
筆者は本領域の専門家ではないので、説明に誤りがある箇所があるかもしれません。その点はご了承ください。

参考

量子コンピュータの理解と、実際に量子コンピュータを動かすに当たって下記を参考にさせていただきました。

量子コンピュータとは何か

量子コンピュータの説明について日経新聞に出ていた説明が完結でわかりやすかったため、
まずはそのまま引用させていただきます。

▼量子コンピュータ
物質を構成する原子や電子など、極微の世界で成り立つ物理法則「量子力学」を応用したコンピューター。従来のコンピューターは「0」と「1」のビットという単位で情報を表して計算するが、0と1の並び方によって膨大な量の計算が必要になる。これに対し、量子コンピューターは0と1のどちらでもある「重ね合わせ」という特殊な状態を利用して計算する。この原理を応用すれば、従来は難しかった計算が短時間でできると期待されている。
2019/10/19 日経新聞 「量子コンピューターとは グーグルなど参入、開発活発」

量子コンピュータというのは、0と1の重ね合わせの状態をもつことのできる量子ビットの存在が非常に肝になっており、これを使って全ての組み合わせから1番良い組み合わせを瞬時に見つけてくれるマシンが量子コンピュータである、とのことです。

現在開発が進んでいる量子コンピュータは2つの方式があります。

方式 概要     開発ベンダー    
量子アニーリング方式 組み合わせ最適化のタスク処理に特化した方式 D-wave Systemsなど
量子ゲート方式 従来のコンピュターのような何でも計算できる汎用的な方式 Google,IBMなど

現在企業による実証実験が進んでいるのは量子アニーリング方式のマシン方です。
2011年にカナダのD-wave Systemsという会社が量子アニーリングマシンの商用販売を開始し様々な企業で実証実験が行われています。

日本の企業だとリクルートコミュニケーションズが量子コンピュータの広告最適化への適用を目指して研究開発を行なっているようです。

今回、Pythonで動かすのはD-wave Systemsの量子アニーリングマシンです。2019年11月現在、登録するだけで誰でも1分間無料で量子アニーリングマシンを動かすことができます。

準備

量子コンピュータを動かす準備

こちらのサイトからまずは利用者登録を行います。名前とメールアドレスと職業程度の情報を入力するだけで登録可能で、クレジットカード情報とかも不要です。

ログインするとまずトップにこのような画面が表示されます。一番左が、各種説明ムービーでこの量子アニーリングマシンによって何ができるか説明がなされています。真ん中は量子コンピュータのデモを見ることができますが、お試しの1分間の中から時間を消費されてしまうので注意です。一番右にはPythonライブラリで量子アニーリングマシンを動かす方法の説明が書かれています。

スクロールするとこのようなダッシュボードも表示されています。
こちらには残りどの程度の時間、量子コンピュータを動かすことができるかが表示されています。

使用するとこんな感じで時間が減っていきます。

Pythonライブラリの準備

ライブラリですが、普通にpipでインストールすることが可能です。
ただ自分がいつも使用している環境では何故かインストール時にエラーが頻発したため、Dockerでmachine learning用のイメージからコンテナを立ち上げでそこでインストールを行いました。

pip install dwave-ocean-sdk

こちらのインストールが完了したら下記コマンドを実行してください。

dwave config create

すると下記が上から順に表示されていくのですが、基本的にはそのままEnterを押していただき、
「Authentication token」のところには自分のAPItokenを入れてください。
自分のAPItokenはマイページトップからコピーができます。

Confirm configuration file path [/home/jane/.config/dwave/dwave.conf]:
Profile (create new) [prod]:
API endpoint URL [skip]:
Authentication token [skip]: 自分のAPItokenが記載
Default client class (qpu or sw) [qpu]:
Default solver [skip]:
Configuration saved.

こちらで事前準備は完了です。
正常に接続できていることを確認するためには下記コマンドを実行します。

dwave ping

このような感じ表示されればOKです。

Using endpoint: https://my.dwavesys.url/
Using solver: My_DWAVE_2000Q

Wall clock time:
 * Solver definition fetch: 2007.239 ms
 * Problem submit and results fetch: 1033.931 ms
 * Total: 3041.171 ms

QPU timing:
 * total_real_time = 10493 us
 * anneal_time_per_run = 20 us
 * post_processing_overhead_time = 128 us
 * qpu_anneal_time_per_sample = 20 us

量子コンピュータでタスクを解く

それでは量子コンピュータを用いて実際にタスクを解いていきます。

量子コンピュータで解くタスク

今回はAPIリファレンスのサンプル問題として用意されている、
制約条件付きのスケジューリングタスクを解いていきます。

問題

MTGを開催する条件として下記規則が定められています。
この規則を反しない形でMTGを開催できる条件を網羅的に抽出することを試みます。
規則
- 定時内かつオフィスに居る時は、直接MTGに参加しなければならない(電話会議はだめ)
- 定時内に開かれるMTGには必ず参加しなければならない(強制参加)
- 定時外のMTGは必ず電話会議で行わなければならない
- 定時外のMTGは30分を超えてはならない

タスクを解く

問題の変換

まず、上記の条件をコンピュータに読み込ませることができるように0と1で変換していきます。

  • timeが1の時は「定時内」0の時は「定時外」
  • locationが1の時は「オフィス内」0の時は「オフィス外」
  • lengthが1の時は「MTG時間が30分以下」0の時は「MTG時間が30分以上」
  • mandatoryが1の時は「強制参加」0の時は「任意参加」

それでは規則に対して上記の0,1変換を落とし込んだ関数を作成します。

def scheduling(time, location, length, mandatory):
    if time:                                 # 定時内
        return (location and mandatory)      # オフィス内で強制参加
    else:                                    # 定時外
        return ((not location) and length)   # 30分以下の電話会議

この関数からライブラリを用いて制約条件を作成します。

import dwavebinarycsp
csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY)
csp.add_constraint(scheduling, ['time', 'location', 'length', 'mandatory'])

さらにこちらをイジイングモデル(二次形式最小化問題)という形式に変換します。
量子コンピュータに問題を解かせるためにはこの形式に問題を変換することが必須となります。
下記引数で指定しているmin_classical_gapですが公式のサンプルコードでは指定されていません。デフォルトのままだとうまくいかず、こちらで指定しましたが原因は調査してもわかりませんでした...分かる方いらっしゃれば教えていただけると幸いです。

bqm = dwavebinarycsp.stitch(csp, min_classical_gap=2.1)
print(bqm)
BinaryQuadraticModel({'a': -1.0, 'aux0': -2.0, 'aux1': 0.0, 'b': 2.0, 'c': 1.0, 'aux2': -1.0}, {('aux0', 'a'): 1.0, ('aux1', 'a'): 1.0, ('aux1', 'aux0'): -1.0, ('b', 'a'): -1.0, ('b', 'aux0'): -1.0, ('b', 'aux1'): -1.0, ('c', 'a'): 0.0, ('c', 'aux0'): -1.0, ('c', 'aux1'): -1.0, ('c', 'b'): 1.0, ('aux2', 'a'): 1.0, ('b', 'aux2'): -1.0, ('c', 'aux2'): 1.0}, 0.0, Vartype.SPIN)

上記の出力は数式的にはこちらに対応しています。
$\sum_i^N q_ix_i + \sum_{i<j}^N q_{i,j}x_i x_j$

量子コンピュータに問題を解かせる

from dwave.system.samplers import DWaveSampler
from dwave.system.composites import EmbeddingComposite
sampler = EmbeddingComposite(DWaveSampler(endpoint='https://cloud.dwavesys.com/sapi', token='自分のAPItokenを記載', solver='DW_2000Q_2_1'))

量子コンピュータにサンプリングを要求します。
サンプリングされた結果は確率的なので、1つではなく多くのサンプルを要求することで複数の「最適」な解を呼び出し、「最適」でない解に落ち着くことを防ぎます。以下では引数で5000個のサンプルを要求しています。
※ここの工程で量子コンピュータの使用時間を消費します。

response = sampler.sample(bqm, num_reads=5000)
#energyの値が最も小さい解が最適解
min_energy = next(response.data(['energy']))

それではサンプリング結果を見てみます。

total = 0
for sample, energy, occurrences in response.data(['sample', 'energy', 'num_occurrences']):
    total = total + occurrences 
    if energy == min_energy:
        time = '定時内' if sample['time'] else '定時外'
        location = 'オフィス' if sample['location'] else '電話会議'
        length = '30分以下の' if sample['length'] else '30分より長い'
        mandatory = '強制参加' if sample['mandatory'] else '任意参加'
        sub = str(sample['mandatory'])
#         print("{}: During {} at {}, you can schedule a {} meeting that is {}::{}".format(occurrences, time, location, length, mandatory, sub))
        print(" {}は{}で、{}MTGを{}で開催することができます。".format(time, location, length, mandatory))
定時外は電話会議で、30分以下のMTGを任意参加で開催することができます。
定時内はオフィスで、30分以下のMTGを強制参加で開催することができます。
定時内はオフィスで、30分より長いMTGを強制参加で開催することができます。
定時内はオフィスで、30分より長いMTGを強制参加で開催することができます。
定時内はオフィスで、30分より長いMTGを強制参加で開催することができます。
定時外は電話会議で、30分以下のMTGを強制参加で開催することができます。
定時内はオフィスで、30分より長いMTGを強制参加で開催することができます。

重複している解が複数ありますが、全て制約条件を満たした解を抽出できています。

Next

取り敢えず量子コンピュータを動かしてはみたものの、QUBO行列やらイジイングモデルやら、わからないところが一杯あったので時間があれば勉強していきたいと思います。
また今回はテストで実施したデータ量が少なかったのと、この量子コンピュータ自体もクラウドで接続したものなので、中々その話題の計算スピードを実感するには至りませんでした。この領域は日進月歩で進んでいく領域だと思うのでちゃんと追っていきたいです。