見出し画像

QAP.03:Hello,D-Wave Leap【量子コンピュータ/アニーリング@Python/D-Wave】

【はじめに】

第一回、第二回では「Fixstars Amplify」を使った。
今回は「D-Wave Leap」の使い方をざっとまとめていく。

■D-Wave Leap

Fixstars Amplifyと同じように、ユーザ登録をして「アクセストークン」を取得しておく。

【開発ツール・用語など】

■開発ツール:Ocean

「D-Wave」では開発ツールとして「Oceanライブラリ(dwave-ocean-sdk)」を使う。

■用語:Modelオブジェクト(計算モデル)

「D-Wave(Ocean SDK)」では、計算させたい問題の種類にあわせて、いい感じに取り扱ってくれる「Model(計算モデルオブジェクト)」を用意している。大きく分けて「3つ」ある。

・BQM:Binary Quadratic Models
・CQM:Constrained Quadratic Models
・DQM:Discrete Quadratic Models

▲Ocean SDKが用意する主な計算モデル(Modelオブジェクト)

■用語:Samplerオブジェクト

「D-Wave(Ocean SDK)」では、「解きたい問題に対するパラメータを設定したModel」を「Samplerオブジェクト」に渡す。これは大きく分けて5つある。

■全体の流れ

「Model」を用意して必要なパラメータを設定したら、「Samplerオブジェクト」経由でD-Wave上にある「所定のSolver」宛にデータを渡すことで(通信して)量子アニーリング計算ができる。

計算結果は「SampleSetオブジェクト」として返ってくる。

▲Model→Samplerを経由してD-Wave上のSolverに量子アニーリング計算をさせる


以上をふまえて、実際にプログラムしてみる。

【例題】:x + 2y - 3zを最小にするx, y, zを探す

実行環境は「D-Wave Leap」+「Google Colab」でやっていく。

【1】ライブラリのインストール

#ライブラリのインストール
!pip install dwave-ocean-sdk

(※補足:ネット上を検索すると「dwave-system」というよく似たライブラリも出てくるので困惑するかもしれないが、「dwave-ocean-sdk」の「pip」時に一緒に入るので気にしなくてよい。)

【2】トークンの設定について

トークンを使ったD-Waveへのアクセスについては以下の通り

上記ドキュメント記載の通り、本来はアクセストークン漏洩防止など、セキュリティの観点から「コンフィグファイル」や「環境変数」に仕込む。

【注意】
今回は簡単なプログラムをちょっと試してみるだけなので、「Samplerオブジェクトに仕込む」というやり方で手抜きをしている。

リリースアプリ、実運用ではSamplerへのトークン埋め込みはしないこと。

■トークン設定

# Sampler埋め込み用トークン(本番では行わないこと)
# 各自登録して取得したアクセストークンを指定する
MY_DWAVE_TOKEN = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

トークンを使った接続確認として、使用可能なSolver情報を出力してみる。

from dwave.cloud import Client

# トークンを使った接続確認
# 使用可能なSolver情報を出力する
client = Client.from_config(token=MY_DWAVE_TOKEN)
print(client.get_solvers())

【実行結果例】
[BQMSolver(id='hybrid_binary_quadratic_model_version2'), DQMSolver(id='hybrid_discrete_quadratic_model_version1'), CQMSolver(id='hybrid_constrained_quadratic_model_version1'), StructuredSolver(id='DW_2000Q_6'), StructuredSolver(id='Advantage_system4.1')]

▲トークンを使ったアクセスができていれば、solver情報が出力される。

【3】変数を用意する(D-Wave版)

「Fixstars Amplify」で「QUBO変数/イジング変数」と呼ばれていたものは、「D-Wave」では次のように呼ばれている。

Spin:「-1」 または「1」をとる (※イジング変数相当)
Binary:「0」または「1」をとる (※QUBO変数相当)

今回の例題では、「Binaryオブジェクト」を使い変数を生成、BQMオブジェクトを作ることにする。


※補足
「D-Wave」では、最終的に目的関数に対応する「QUBO(行列フォーマット)」と呼ばれる「dict型のデータオブジェクト」を作ることができればいい。


【Note】Binaryオブジェクトについて

Binaryオブジェクトには2種類ある
 ・pyqubo版
 ・dimod版

どっちを使ってもいい。

今回は「dimod版のBinaryオブジェクト」を使用して変数を生成し、「BQMオブジェクト(目的関数)」を作っていく。
(※pyqubo版はcompile()をコールしてOcean用に若干変換処理を記述するなどがあるぐらい)

import dimod

# dimod版のBinaryオブジェクトを3つ作成
q0 = dimod.Binary('q0')
q1 = dimod.Binary('q1')
q2 = dimod.Binary('q2')

【4】Model(目的関数)の作成

目的関数は数式通り記述する。

# 目的関数を作成
bqm_model = q0 + 2*q1 - 3*q2
print(bqm_model)

【ここまでの実行結果】
BinaryQuadraticModel({'q0': 1.0, 'q1': 2.0, 'q2': -3.0}, {}, -0.0, 'BINARY')

▲目的関数に対するBQMオブジェクトが生成されている。

【5】Sampler経由で量子アニーリング計算する

ここでは「Sampler」として「DWaveSampler」を使用してみる。

(※なお、今の段階では細かいことは気にせず「DWaveSampler」を使う時は「EmbeddingComposite」と組み合わせて使う、ということをごま塩程度に覚えておいてくれ。組み合わせずに実行すると組み合わせて使え、とエラーを吐く。)

from dwave.system.samplers import DWaveSampler
from dwave.system.composites import EmbeddingComposite

# DWaveSampler+EmbeddingCompositeでsamplerを生成する
sampler = EmbeddingComposite(DWaveSampler(token=MY_DWAVE_TOKEN))

# num_reads:アニーリングサイクルは500(QPUが試行する回数、問題を解く回数のこと)
response = sampler.sample(bqm_model,num_reads=500)

■EmbeddingComposite

■DWaveSampler

【6】計算結果を確認する

「Sampler」経由で「D-Wave上のSolver」が計算した結果は「SampleSetオブジェクト」として返ってくる。

■SampleSetオブジェクトについて


print(response)

【ここまでの実行結果例】
   q0 q1 q2 energy num_oc. chain_.
0   0   0   1     -3.0          500       0.0
['BINARY', 1 rows, 500 samples, 3 variables]

※Colab上でprintを使わずに吐き出すと次のようになる

response

SampleSet(rec.array([([0, 0, 1], -3., 500, 0.)], dtype=[('sample', 'i1', (3,)), ('energy', '<f8'), ('num_occurrences', '<i8'), ('chain_break_fraction', '<f8')]), Variables(['q0', 'q1', 'q2']), {'timing': {'qpu_sampling_time': 47420.0, 'qpu_anneal_time_per_sample': 20.0, 'qpu_readout_time_per_sample': 54.3, 'qpu_access_time': 55870.6, 'qpu_access_overhead_time': 15128.4, 'qpu_programming_time': 8450.6, 'qpu_delay_time_per_sample': 20.54, 'total_post_processing_time': 1736.0, 'post_processing_overhead_time': 1736.0}, 'problem_id': 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'}, 'BINARY')

※掲載上problem_idはXXXでマスキングしてます

▲いずれにせよ、「x + 2y - 3zを最小にするx, y, z」は
(x, y, z)=(q0, q1, q2):(0, 0, 1)で最小値:-3
であると計算された。(正解)

※本来はこの後、「SampleSet」から必要なデータ部分だけを取得したり、複数の答えが求められた場合にフィルタリングをしたりするが、今回は省略。

【7】全体コード

最後にコード全体を示しておく。

【例題】
x + 2y - 3zを最小にするx, y, zを探す

【実行環境】
・D-Wave Leap + Google Colab

■事前準備:ライブラリのインストール

#ライブラリのインストール
!pip install dwave-ocean-sdk

■ここからが全体コード

import dimod
from dwave.system.samplers import DWaveSampler
from dwave.system.composites import EmbeddingComposite
from dwave.cloud import Client



# Sampler埋め込み用トークン(本番では行わないこと)
# 各自登録して取得したアクセストークンを指定する
MY_DWAVE_TOKEN = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"


# トークンを使った接続確認
# 使用可能なSolver情報を出力する
client = Client.from_config(token=MY_DWAVE_TOKEN)
print(client.get_solvers())



# dimod版のBinaryオブジェクトを3つ作成
q0 = dimod.Binary('q0')
q1 = dimod.Binary('q1')
q2 = dimod.Binary('q2')


# 目的関数を作成
bqm_model = q0 + 2*q1 - 3*q2
print(bqm_model)



# DWaveSampler+EmbeddingCompositeでsamplerを生成する
sampler = EmbeddingComposite(DWaveSampler(token=MY_DWAVE_TOKEN))

# num_reads:アニーリングサイクルは500(QPUが試行する回数、問題を解く回数のこと)
response = sampler.sample(bqm_model,num_reads=500)


print(response)

【実行結果】
   q0 q1 q2 energy num_oc. chain_.
0   0   0   1     -3.0          500       0.0
['BINARY', 1 rows, 500 samples, 3 variables]

【おまけ】LeapHybridSamplerを使う

最後に「LeapHybridSampler(LeapHybridBQMSampler)」を使った書き方を掲載しておく。このSamplerは「D-Wave Leap」提供のサービス経由で動くもの。

文字通り、いい感じに古典コンピューティングと量子アニーリングを組み合わせて計算を行うハイブリッドSampler

違いとしては、
「EmbeddingComposite」と組み合わせなくていい
「num_reads(アニーリングサイクル)」の指定はできない
…などがある。

import dimod
#from dwave.system.samplers import DWaveSampler
#from dwave.system.composites import EmbeddingComposite

#from dwave.system.samplers import LeapHybridSampler
from dwave.system.samplers import LeapHybridBQMSampler # LeapHybridSamplerのエイリアス
from dwave.cloud import Client



# Sampler埋め込み用トークン(本番では行わないこと)
# 各自登録して取得したアクセストークンを指定する
MY_DWAVE_TOKEN = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"


# トークンを使った接続確認
# 使用可能なSolver情報を出力する
client = Client.from_config(token=MY_DWAVE_TOKEN)
print(client.get_solvers())



# dimod版のBinaryオブジェクトを3つ作成
q0 = dimod.Binary('q0')
q1 = dimod.Binary('q1')
q2 = dimod.Binary('q2')


# 目的関数を作成
bqm_model = q0 + 2*q1 - 3*q2
print(bqm_model)



# DWaveSampler+EmbeddingCompositeでsamplerを生成する
#sampler = EmbeddingComposite(DWaveSampler(token=MY_DWAVE_TOKEN))

# LeapHybridBQMSamplerでSamplerを作成
# EmbeddingCompositeは無しでよい
sampler2 = LeapHybridBQMSampler(token=MY_DWAVE_TOKEN)

# LeapHybridBQMSamplerには「num_reads:アニーリングサイクル」はない
response2 = sampler.sample(bqm_model)



print(response2)

【実行結果】
   q0 q1 q2 energy num_oc. chain_.
0   0   0   1     -3.0          500       0.0
['BINARY', 1 rows, 500 samples, 3 variables]

もっと応援したいなと思っていただけた場合、よろしければサポートをおねがいします。いただいたサポートは活動費に使わせていただきます。