AmplifyのモデルをOpenJijのSASamplerに投入する
TL;DR
Amplifyはイジングマシンを手軽に扱うことのできるSDKです。
イジングマシンを使用するとき、古典マシン(一般的なCPU)でのシミュレーションと性能を比較したいケースが多々あります。
構築したイジングモデルに対してシミュレーテッドアニーリング (SA)でさくっと最適化を試したいなどが想定されます。
D-Wave Ocean SDKやPyQUBO(内部的にはdwave-neal)、OpenJijには、イジングモデル/QUBOに対するSAのソルバーが実装されています。
しかし、Amplifyでは特にSAなどの古典ソルバーは実装されていません。
(無料でイジングマシンが使用できるのでなくても全く問題ないですが)
そこで、今回はAmplifyで構築したモデルをOpenJijの古典ソルバーに投入する流れをまとめます。
Amplifyのモデル
Amplifyでは多項式や論理式の数式オブジェクトを用いて記述し、入力模型を構築していきます。
from amplify import BinaryPoly, SymbolGenerator
gen = SymbolGenerator(BinaryPoly)
q = gen.array(2)
f = 1 - q[0] * q[1]
その後、構築した入力模型をイジングマシンが取り扱うことが可能な「論理模型」として抽象化します。
from amplify import BinaryQuadraticModel
model = BinaryQuadraticModel(f)
論理模型への変換にはBinaryQuadraticModel
IsingQuadraticModel
といったクラスを使用します。
イジングマシンを利用する場合は、この論理模型をイジングマシンに投入することになりますが、今回はOpenJijのソルバーに投入するために変換していきます。
OpenJij用の変換
OpenJijのインターフェースはイジングモデルの相互作用 と縦磁場 のリスト(QUBOの場合はQUBO行列)を渡すものになっています。
以下の関数でAmplifyの論理模型から必要な形式に変換します。
from amplify import BinaryQuadraticModel, IsingQuadraticModel
def amplify_bqm_to_qubo_dict(model: IsingQuadraticModel):
Q = {}
const = 0
for k, v in model.logical_model_poly.asdict().items():
if len(k) == 1:
Q[(k[0], k[0])] = v
elif len(k) == 2:
Q[k] = v
else:
const = v
return Q, const
def amplify_iqm_to_ising_dict(model: BinaryQuadraticModel):
h = {}
J = {}
const = 0
for k, v in model.logical_model_poly.asdict().items():
if len(k) == 1:
h[k[0]] = v
elif len(k) == 2:
J[k] = v
else:
const = v
return h, J, const
実際に変換関数を用いてOpenJijでSAを実行する流れは以下のようになります。
import openjij as oj
from dataclasses import dataclass
@dataclass
class Solution():
# amplify.SolverSolution と同様のインターフェース
energy: float
frequency: int
is_feasible: bool
values: Dict[int, int]
sampler = oj.SASampler()
params = {'num_reads': 10}
# Ising/QUBOを変換してSASamplerで計算実行
if isinstance(model, BinaryQuadraticModel):
Q, const = self.amplify_bqm_to_qubo_dict(model)
result = sampler.sample_qubo(Q, **params)
elif isinstance(model, IsingQuadraticModel):
h, J, const = self.amplify_iqm_to_ising_dict(model)
result = sampler.sample_ising(h, J, **params)
# 結果の解析
solutions = []
for k, s in enumerate(result.states):
# 制約違反をチェック
c_status = list(filter(lambda c: not c[1], model.check_constraints(s)))
values = {}
for i in result.indices:
values[i] = s[i]
solution = Solution(
energy=result.energies[k] + const,
frequency=1,
is_feasible=len(c_status) == 0,
values=values,
)
solutions.append(solution)
print(solutions)
ここではAmplifyでイジングマシンを利用した場合に得られる結果のクラス SolverSolution
と同等のインターフェースになるように Solution
クラスを定義して利用しています。
以上でAmplifyで構築したモデルに対して手軽にSAでシミュレーションすることができます。
このコンテンツにコメントはありません。