ソルバーの並列実行

parallel_solve() を使用すると、複数のクライアントやモデルに対して同時にリクエストを送ることができます。これにより、複数回の実行が必要な場合に、モデル変換やリクエストデータの処理時間、ソルバーへのネットワークアクセスによる転送時間などの隠蔽が期待出来ます。また、複数の問題を同時に実行できるソルバーに対しても、並列実行による実行効率の向上が期待出来ます。

並列実行の例

まず、solve() 関数を使用するときと同様に、モデルを構築します。
あとで複数のモデルを用いる例も示すため、ここでは 2 つのモデルを構築します。

from amplify import VariableGenerator, one_hot, solve

gen = VariableGenerator()
q = gen.array("Binary", 3)

objective = q[0] * q[1] - q[2]
constraint = one_hot(q)

model1 = objective + constraint
model2 = objective + 2 * constraint

次に、複数のソルバークライアントを構築します。

from amplify import AmplifyAEClient, DWaveSamplerClient
from datetime import timedelta

amplify_client = AmplifyAEClient()
# amplify_client.token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
amplify_client.parameters.time_limit_ms = timedelta(milliseconds=1000)

dwave_client = DWaveSamplerClient()
# dwave_client.token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
dwave_client.parameters.num_reads = 100

parallel_solve() 関数を用いて、複数のクライアントにリクエストを送ります。parallel_solve()solve() と同様のインターフェースを持ちますが、引数にリストを与えることができます。

from amplify import parallel_solve

amplify_result, dwave_result = parallel_solve(model1, [amplify_client, dwave_client])

上記のコードは、以下の for ループを並列で実行したのと同じ効果を持ちます。

from amplify import solve

for client in [amplify_client, dwave_client]:
    result = solve(model1, client)

parallel_solve() はモデル引数とクライアント引数の両方にリストを与えることもできます。
例えば、次のように複数のモデルと複数のクライアントに対して、parallel_solve() を用いて同時実行できます。

この時、上記は以下の for ループを並列で実行した場合と同じ効果を持ちます。

for model, client in zip([model1, model2], [amplify_client, dwave_client], strict=True):
    result = solve(model, client)

注釈

モデル引数とクライアント引数の両方にリストを与えた場合、それぞれのリストの要素数は同じでなければなりません。

もし片方の引数がスカラー値であれば、もう一方の引数のリストの各要素に対して同じ値が繰り返されたリストとして扱われます。最初の例では、単一のモデルに対して複数のクライアントが使用されましたが、次のように複数のモデルに対して単一のクライアントを使用することもできます。

# 以下は parallel_solve([model1, model2], [amplify_client] * 2) と同じ意味です。
result1, result2 = parallel_solve([model1, model2], amplify_client)

# 以下は parallel_solve([model1] * 2, [amplify_client, dwave_client]) と同じ意味です。
result1, result2 = parallel_solve(model1, [amplify_client, dwave_client])

並列実行のパラメータ

parallel_solve()solve() と同様のキーワード引数を受け取ることができます。通常はキーワード引数は全ての並列実行で共通で使用されますが、キーワード引数にもリストを与えることで、複数のモデル、複数のクライアントと同様に、複数のキーワード引数を同時に指定することができます。
この場合についても、リスト型のキーワード引数の要素数はモデル引数やクライアント引数の要素数と同じでなければなりません。

例として、以下のリストを用いた次のパラメータの指定を考えます。

amplify_result, dwave_result = parallel_solve(
    model1,
    [amplify_client, dwave_client],
    dry_run=[False, True],
    num_solves=2,
)

上記は、以下を並列で実行したのと同じ効果を持ちます。

for client, dry_run in zip([amplify_client, dwave_client], [False, True], strict=True):
    result = solve(model1, client, dry_run=dry_run, num_solves=2)

ソルバーの種類や契約内容によっては、同一のクライアントに複数のリクエストを同時に送ることができない場合があります。parallel_solve()concurrency パラメータを指定することで、並列実行数の最大値を設定することができます。デフォルトは 0 で、この場合は動作させているマシンの CPU 数に応じて並列実行数が自動で決定されます。

amplify_result, dwave_result = parallel_solve(
    model1,
    [amplify_client, dwave_client],
    concurrency=2,
)