QAP.08:「CQM:Constrained Quadratic Models」の基本【量子コンピュータ/アニーリング@Python/D-Wave】
【はじめに】
繰り返しになるが、D-Waveでは計算させたい問題の種類にあわせて、いい感じに取り扱ってくれる「Model(計算モデルオブジェクト)」を用意している
今回はこの中の「CQM:Constrained Quadratic Models」の使い方についてざっとまとめていく。
【CQMの特徴】
「CQM」の特徴をざっくりいうと
というもの。CQMで想定している数式は以下を参照。
以上を踏まえてさっそく例題でCQMの使い方をまとめていく。
【例題】
つまり
をみたす(x, y)の組み合わせをさがす、ということ。
【1】ライブラリのインストール
#ライブラリのインストール
!pip install dwave-ocean-sdk
(※再掲:ネット上を検索すると「dwave-system」というよく似たライブラリも出てくるので困惑するかもしれないが、「dwave-ocean-sdk」の「pip」時に一緒に入るので気にしなくてよい。)
【2】トークン設定
※再掲:
トークンを使ったD-Waveへのアクセスについては以下の通り
上記ドキュメント記載の通り、本来はアクセストークン漏洩防止など、セキュリティの観点から「コンフィグファイル」や「環境変数」に仕込む。
■トークン設定
# Sampler埋め込み用トークン(本番では行わないこと)
# 各自登録して取得したアクセストークンを指定する
MY_DWAVE_TOKEN = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
トークンを使った接続確認として、使用可能なSolver情報を出力してみる。
from dwave.cloud import Client
# トークンを使った接続確認
# 使用可能なSolver情報を出力する
client = Client.from_config(token=MY_DWAVE_TOKEN)
print(client.get_solvers())
【3】整数を取り扱える変数を用意する(dimod版)
「整数を取り扱える変数」として「dimod.Integer」を使うことができる。
※これは次のように定義されている(2022/2/17時点)
これを踏まえて「変数:x、変数:y」は次のように書ける。
■整数を取り扱える変数を用意する
import dimod
# 変数の定義
x = dimod.Integer('x',upper_bound=4) # 下限デフォルト値0以上なので省略
y = dimod.Integer('y',upper_bound=4)
▲「変数」定義の時点で、「変数単体」に「値のとる範囲」を設定することができる。
【4】目的関数:fの作成
変数が用意出来たら「目的関数:f」を用意する。ここで気をつけることは
ということ。
■目的関数:fの作成
f = -(x*y)
print(f)
【5】CQMオブジェクトの生成と目的関数のセット
「CQMオブジェクト」を作成し、作成した「目的関数:f」をセットする。
■CQMオブジェクトの生成と目的関数の設定
# CQMオブジェクトの作成
cqm = dimod.ConstrainedQuadraticModel()
# 作成した目的関数をセットする
cqm.set_objective( f )
※CQMオブジェクトの詳細は以下参照。
【6】CQMに制約条件を設定する
「CQM」では「制約条件の表記のままで設定」する。制約条件に対応する数式(ペナルティ関数)にする必要はない。
■CQMに制約条件を設定する
# CQMに制約条件を設定する
# 制約条件の表記のまま設定してOK
cqm.add_constraint(2*x + 2*y <= 8, label="my constraint")
▲今回は「add_constraint()」で設定した。
※これは「add_constraint_from_model()」「add_constraint_from_comparison()」「add_constraint_from_iterable()」のwrapper関数。
ここまでで、「CQMオブジェクト」に対して「目的関数」と「制約条件」の設定が完了した。あとはSampler経由で量子アニーリング計算をすればいい。
【7】Sampler経由で量子アニーリング計算する
※再掲:Samplerオブジェクト
「D-Wave(Ocean SDK)」では、「解きたい問題に対するパラメータを設定したModel」を「Samplerオブジェクト」に渡す。これは大きく分けて5つある。
作成した「CQM」に対応する「Sampler」は「LeapHybridCQMSampler」である。
■LeapHybridCQMSampler
これを使って量子アニーリング計算をする
from dwave.system.samplers import LeapHybridCQMSampler # CQM系で使うSamplerオブジェクト
# トークンを仕込んだSamplerにmodelを投げ込んで計算する
sampler = LeapHybridCQMSampler(token=MY_DWAVE_TOKEN )
sampleset = sampler.sample_cqm(cqm)
【8】結果を確認する
「Sampler」経由で「D-Wave上のSolver」が計算した結果は「SampleSetオブジェクト」として返ってくる。
■SampleSetオブジェクトについて
print(sampleset.first)
▲一辺の長さがそれぞれ(x, y) = (2, 2)、面積:4と計算された(正解)
【9】全体コード
最後に全体コードを示しておく
【例題】
・目的関数: x * y ← できるだけ大きくしたい
・制約条件:
2 * x + 2 * y ≦ 8 ※紐の長さの上限
0 ≦ x ≦ 4 ※横1辺の長さの上限
0 ≦ y ≦ 4 ※縦1辺の長さの上限
【実行環境】
D-Wave Leap + Google Colab
■事前準備:ライブラリのインストール
#ライブラリのインストール
!pip install dwave-ocean-sdk
■ここからが全体コード
import dimod
from dwave.system.samplers import LeapHybridCQMSampler # CQM系で使うSamplerオブジェクト
from dwave.cloud import Client
# Sampler埋め込み用トークン(本番では行わないこと)
# 各自登録して取得したアクセストークンを指定する
MY_DWAVE_TOKEN = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
# トークンを使った接続確認
# 使用可能なSolver情報を出力する
client = Client.from_config(token=MY_DWAVE_TOKEN)
print(client.get_solvers())
# 変数の定義
x = dimod.Integer('x',upper_bound=4) # 下限デフォルト値0以上なので省略
y = dimod.Integer('y',upper_bound=4)
# 目的関数の作成(dimodの変数利用)
f = -(x*y)
print(f)
# CQMオブジェクトの作成
cqm = dimod.ConstrainedQuadraticModel()
# 作成した目的関数をセットする
cqm.set_objective( f )
# トークンを仕込んだSamplerにmodelを投げ込んで計算する
sampler = LeapHybridCQMSampler(token=MY_DWAVE_TOKEN )
sampleset = sampler.sample_cqm(cqm)
# 結果の確認
print(sampleset.first)