ソルバーの直列実行#

性能の評価を行いたい場合、ソルバーを何回か繰り返し実行したい場合があります。また、ソルバーによっては、長時間のタイムアウトを指定して 1 回実行するよりも短時間のタイムアウトで何回か繰り返し実行したほうが良い解を見つける可能性が高くなることもあります。Amplify SDK は、そのようなニーズのために、同じ組合せ最適化問題を同じソルバーで複数回連続して実行する機能を提供しています。

参考

定式化やソルバーの性能調査などのために複数回を実行した統計を取る場合には ソルバーの並列実行 の方が適していることもります。そちらも参照してください。

複数実行の例#

まず、通常の solve() 関数の実行と同様に、モデルとソルバークライアントを作成します。

from amplify import VariableGenerator, one_hot, FixstarsClient, solve
from datetime import timedelta

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

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

model = objective + constraint

client = FixstarsClient()
# client.token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
client.parameters.timeout = timedelta(milliseconds=1000)

solve()num_solves キーワード引数に整数を与えることで、ソルバーがその回数だけ繰り返し実行されます。

result = solve(model, client, num_solves=3)

通常の solve() の実行と同様に、Result クラスのインスタンスが返ります。返り値には、num_solves 回の実行結果がフラットに入っています。

>>> len(result)
3

best アトリビュートを用いることにより、num_solves 回の実行で返ってきた中で最も良い解を取得することができます。

>>> print(f"objective = {result.best.objective}, q = {q.evaluate(result.best.values)}")
objective = -1.0, q = [0. 0. 1.]

結果の取得#

solve()num_solves キーワードを指定して実行した場合、返り値は通常と同様に Result クラスのインスタンスとなっています。

ソルバーが実行された回数は、Result クラスの num_solves アトリビュートにより知ることができます。これは通常 solve()num_solves キーワード引数として指定した値と同一ですが、ソルバー実行のうち何回かが何らかの理由により失敗した場合、num_solves キーワード引数として指定した値よりも小さくなることがあります。

>>> result.num_solves
3

インデックスアクセスやイテレートアクセスにより、ソルバーが num_solves 回の実行で返した全ての解を集約して得ることができます。デフォルトでは、良い解の順にソートされて入っており、何回目の実行で返されたかの区別はありません。

>>> print(f"objective = {result[0].objective}, q = {q.evaluate(result[0].values)}")
objective = -1.0, q = [0. 0. 1.]

特定の実行により返された解のみを取得するには、split プロパティを使用します。

>>> first_result = result.split[0] # `result` から初回の実行にかかった部分のみを抽出
>>> type(first_result)
<class 'amplify.Result'>
>>> len(first_result)
1
>>> print(f"objective = {first_result.best.objective}, q = {q.evaluate(first_result.best.values)}")
objective = -1.0, q = [0. 0. 1.]

num_solves が指定された場合に solve() から返される Result オブジェクト、およびそれに split プロパティを使用して得られる i 回目の実行結果を表す Result オブジェクトの各プロパティについては、以下の通りのものが入ります。

プロパティ名

solve() 関数が返す Result

split 適用後の Result

best

num_solves 回の実行のうち最も良い解

i 回目の実行のうち最も良い解

solutions

num_solves 回の実行で得たすべての解

i 回目の実行で得たすべての解

intermediate

通常の solve() 実行と同様

通常の solve() 実行と同様

embedding

通常の solve() 実行と同様

通常の solve() 実行と同様

client_result

最初の実行で得られたもの

i 回目の実行で得られたもの

execution_time

num_solves 回の実行の合計値

i 回目の実行で得られたもの

response_time

num_solves 回の実行の合計値

i 回目の実行で得られたもの

total_time

solve() を始めてから終わるまでの時間

i 回目の実行のために費やされた時間