Skip to main content

2. JijZeptのSamplerについて

この章では、JijZeptを使う際に必要となるsamplerに関する次の説明を行います。

  • 基本的な使い方
  • 設定可能なオプション (同期オプション、timeoutオプション)
  • JijZeptの計算ステータス、エラーメッセージの取得
  • 利用可能なSampler

2.1 基本的な使い方

JijZeptを用いて計算を行う (サンプリングする)手順は

  • samplerオブジェクトを初期化
  • .sample_qubo.sample_model等を呼び出してサンプリングを実行

の2つとなります。

2.1.1 QUBOモデルのサンプリング

E=i<jQijqiqj (qi=0 or 1)E = \sum_{i < j} Q_{ij} q_i q_j \ (q_i = 0\ \mathrm{or}\ 1)

のような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_dictJijModelingのPlaceholderに指定するインスタンスのデータ
multipliersJijModelingに制約条件を指定する際に利用する、ラベル名と、制約条件の係数に相当する初期パラメータ
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_modelfeed_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つを必ず満たすように動作します。