2. JijZeptのSamplerについて
この章では、JijZeptを使う際に必要となるsamplerに関する次の説明を行います。
- 基本的な使い方
- 設定可能なオプション (同期オプション、timeoutオプション)
- JijZeptの計算ステータス、エラーメッセージの取得
- 利用可能なSampler
2.1 基本的な使い方
JijZeptを用いて計算を行う (サンプリングする)手順は
- samplerオブジェクトを初期化
.sample_qubo、.sample_model等を呼び出してサンプリングを実行
の2つとなります。
2.1.1 QUBOモデルのサンプリング
のようなQUBOモデルをサンプリングする際には、次のようにQUBO行列を辞書で指定することで可能となります。
import jijzept as jz
# samplerオブジェクトの初期化
sampler = jz.JijSASampler(config='config.toml')
Q = {}
N = 500
for i in range(N):
for j in range(i+1, N):
Q[i,j] = 1.0
# sample_quboでサンプリング
response = sampler.sample_qubo(Q)
print(response)
戻り値の形式については、OpenJijと同じ形式となるので、こちらのOpenJij tutorialをご覧ください。
2.1.2 JijModelingを用いたサンプリング
JijModelingを用いることで、構築した数式、制約条件を直接JijZeptへ送信することができます。 計算を行う際には、次の4つのオプションが使用できます。
| parameters | 説明 |
|---|---|
feed_dict | JijModelingのPlaceholderに指定するインスタンスのデータ |
multipliers | JijModelingに制約条件を指定する際に利用する、ラベル名と、制約条件の係数に相当する初期パラメータ |
search | パラメータサーチを有効にするかを設定 |
num_search | パラメータサーチの更新回数 |
from jijmodeling import Problem, Placeholder, Binary, Element, Sum, Constraint
# 1次元ベクトルを用意します
d = Placeholder('d', dim=1)
N = d.shape[0]
# 1次元ベクトルと同じ長さのバイナリ変数列を用意します
x = Binary('x', shape=N)
# 総和 (Sum)のindexを設定します
i = Element('i', N)
problem = Problem('test_problem')
cost = Sum(i, d[i]*x[i])
problem += cost
# ペナルティの未定乗数はConstraintを使うと自動で付与されます
problem += Constraint('one-hot', x[:] == 1)
from jijzept import JijSASampler
# インスタンス d となる具体的なベクトルを設定します
data_d = [1.0, 0.1, 2, 1]
sampler = JijSASampler(config='config.toml')
response = sampler.sample_model(
problem,
feed_dict={'d': data_d},
multipliers={'one-hot': 1.0},
search=True,
num_search=10
)
JijModelingを用いたモデリングの方法に関しては、こちらのドキュメントを参照してください。
JijModelingの場合、戻り値に対して.decodeを用いることで得られた解の詳細を調べることができます。
.decode関数には、それぞれ、JijZeptからのresponseと.sample_modelのfeed_dictに相当するインスタンスのデータを指定する必要があります。
decodeの詳細は、こちらのリファレンスを参照してください。
decoded = problem.decode(response, {'d': data_d})
# 得られた解を表示します。
print(decoded.solutions)
# 制約条件の評価値を表示します。
print(decoded.constraint_violations)
2.2 設定可能なオプション
.sample_qubo、.sample_modelなどの関数には、次の引数を設定することができます。
2.2.1 同期オプション (sync)
デフォルトの設定だと、JijZeptに問題を投げた後、答えが返ってくるまでに処理がブロックされますが、処理に時間がかかる際には不便になる場合があります。
パラメータを非同期モードであるsync=Falseに設定すると、問題を投げた直後に制御が返ります。
response = sampler.sample_model(
problem,
feed_dict={'d': data_d},
multipliers={'one-hot': 1.0},
search=True,
num_search=10,
sync=False, # 非同期モードに設定
)
# output
# Your solution_id is b6ed5fddaebd41caa9bf242311550eef.
# You can access the solution by
# >>> a = XXXSampler(config=...)
# >>> a.get_result("b6ed5fddaebd41caa9bf242311550eef")
送信した問題の解は、表示されたsolution_idを用いて別途.get_resultで取得することが可能です。
sampler = JijSASampler(config='config.toml')
response = sampler.get_result("b6ed5fddaebd41caa9bf242311550eef")
2.2.2 timeout設定 (timeout)
timeoutオプションを設定することで、Solverでの動作時間に制限をかけることができます。計算時間をオーバーするとFAILEDが返ってきます。
response = sampler.sample_model(
problem,
feed_dict={'d': data_d},
multipliers={'one-hot': 1.0},
search=True,
num_search=10,
timeout=10, # Solverの利用可能時間を10秒間に制限します。
)
!!! note
timeoutを設定しない場合、デフォルト値として1時間 (3600秒)が指定されます。
2.3 戻り値のステータス、エラー表示について
JijZeptで.sample_qubo、.sample_modelの戻り値であるresponseにはJijZeptの計算ステータスも格納されており、以下の5種類があります。
| status | 説明 |
|---|---|
SUCCESS | 求解が成功したことを表します |
PENDING | 問題がsubmitされ、まだSolverに渡っていない状態を表します。 |
RUNNING | 問題がsubmitされ、Solverに渡った状態を表します。 |
FAILED | 問題の求解に失敗したことを表します。 |
UNKNOWNERROR | 想定外の原因により問題の求解に失敗したことを表します。 |
response.statusで上のステータス情報が取得できます。また、FAILEDの場合、response.error_messageによりエラーの詳細を取得することができます。
2.4 利用可能なsampler
チュートリアルで使用していたJijSASamplerの他のSamplerも用いることができ、SamplerもUpdateに伴い随時追加されます。
各samplerの仕様については、こちらをご覧ください
!!! note
ポータルサイトのDashboardにある available solvers に対応するソルバーが記述されていない場合、そのソルバーの利用はできませんのでご注意ください。
2.4.1 JijAmazonBraketDWaveSampler
JijAmazonBraketDWaveSamplerを用いることで、Amazon Braket上のDWaveデバイスを用いることができます。
from jijzept import JijAmazonBraketDWaveSampler
sampler = JijAmazonBraketDWaveSampler(config='config.toml')
# `sample_model` 関数でJijModelingでモデリングされた問題を送信できます。利用方法は `JijSASampler`と同じです。
response = sampler.sample_model(...)
2.4.2 JijSwapMovingSampler
複雑な制約条件を持つ問題をイジングマシンで取り扱う際、全ての制約条件を見たす解が出にくい状況がよく発生します。JijSwapMovingSampler を用いることで、JijModelingで記述された数式のうち等式で記述された制約を抽出し、その制約を必ず満たすように解を探索します。これにより、全ての制約条件を見たす解が発見されやすくなります。
from jijmodeling import Problem, Placeholder, Binary, Element, Sum, Constraint
# 1次元ベクトルを用意します
d = Placeholder('d', dim=1)
N = d.shape[0]
# 1次元ベクトルと同じ長さのバイナリ変数列を用意します
x = Binary('x', shape=N)
# 総和 (Sum)のindexを設定します
i = Element('i', N)
problem = Problem('test_problem')
cost = Sum(i, d[i]*x[i])
problem += cost
# JijSwapMovingSamplerを用いると、この等式制約条件が必ず満たされる解が返ります。
problem += Constraint('one-hot', x[:] == 1)
from jijzept import JijSASampler
# インスタンス d となる具体的なベクトルを設定します
data_d = [1.0, 0.1, 2, 1]
sampler = JijSwapMovingSampler(config='config.toml')
response = sampler.sample_model(
problem,
feed_dict={'d': data_d},
search=True,
)
!!! note 複数の等式制約条件が存在する場合、その等式制約の中の1つを必ず満たすように動作します。