# Serial Solver Execution You may want to run the solver several times iteratively when evaluating performance. Also, some solvers are more likely to find a good solution by running several iterations with a short timeout than by running a single iteration with a long timeout.Amplify SDK allows running the same combinatorial optimization problem multiple times in a row with the same solver for such needs. ```{seealso} [](parallel.md) may be more appropriate for obtaining statistics from multiple runs for formulation, solver performance studies, etc. ``` ## Example of multiple runs First, create a model and solver client as in a usual {py:func}`~amplify.solve` function execution. ```{testcode} 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) ``` By passing an integer as the `num_solves` keyword argument to {py:func}`~amplify.solve`, the solver is executed iteratively for `num_solves` times. ```{testcode} result = solve(model, client, num_solves=3) ``` As in a usual {py:func}`~amplify.solve` call, the solver returns an instance of the {py:class}`~amplify.Result` class. The return value contains the results of the num_solves iterations. ```{doctest} >>> len(result) 3 ``` Using the {py:class}`~amplify.Result.best` attribute, you can obtain the best solution among those returned by the `num_solves` runs. ```{doctest} >>> print(f"objective = {result.best.objective}, q = {q.evaluate(result.best.values)}") objective = -1.0, q = [0. 0. 1.] ``` ## Fetching results When {py:func}`~amplify.solve` is called with the `num_solves` keyword, the return value is an instance of the {py:class}`~amplify.Result` class, as usual. The Amplify SDK determines the number of times of the solver executions by the {py:attr}`~amplify.Result.num_solves` attribute of the {py:class}`~amplify.Result` class. This attribute usually yields the same value as the value specified to {py:func}`~amplify.solve` as the `num_solves` keyword argument. Still, it may be less than the value specified as the `num_solves` keyword argument, if some of the solver runs, fail for some reason. ```{doctest} >>> result.num_solves 3 ``` Index or iteration access allows you to aggregate all the solutions the solver returns for the `num_solves` runs. By default, the Amplify SDK sorts them in order of preferred solution, and there is no distinction regarding the number of executions the solution was found. ```{doctest} >>> print(f"objective = {result[0].objective}, q = {q.evaluate(result[0].values)}") objective = -1.0, q = [0. 0. 1.] ``` Use the {py:attr}`~amplify.Result.split` property to get only the solutions returned by a particular run. ```{doctest} >>> first_result = result.split[0] # extract only the part of the `result` that was obtained at the first run >>> type(first_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.] ``` The following are included for each property of the {py:class}`~amplify.Result` object returned by {py:func}`~amplify.solve` when `num_solves` is specified, and the {py:attr}`~amplify.Result` object represents the result of the `i`-th run obtained by using the {py:attr}`~amplify.Result.split` property on it. ```{list-table} :header-rows: 1 :width: 100% :widths: 1 4 4 * - Property name - {py:class}`~amplify.Result` returned by {py:func}`~amplify.solve` - {py:class}`~amplify.Result` after applying {py:attr}`~amplify.Result.split` * - {py:attr}`~amplify.Result.best` - The best solution for the {py:attr}`~amplify.Result.num_solves` runs - The best solution for the `i`-th run * - {py:attr}`~amplify.Result.solutions` - All solutions obtained for the {py:attr}`~amplify.Result.num_solves` runs - All solutions obtained for the `i`-th run * - {py:attr}`~amplify.Result.intermediate` - Same as usual {py:func}`~amplify.solve` execution - Same as usual {py:func}`~amplify.solve` execution * - {py:attr}`~amplify.Result.embedding` - Same as usual {py:func}`~amplify.solve` execution - Same as usual {py:func}`~amplify.solve` execution * - {py:attr}`~amplify.Result.client_result` - Property obtained for the first run - Property obtained for the `i`-th run * - {py:attr}`~amplify.Result.execution_time` - The sum of the {py:attr}`~amplify.Result.num_solves` runs - Property obtained for the `i`-th run * - {py:attr}`~amplify.Result.response_time` - The sum of the {py:attr}`~amplify.Result.num_solves` runs - Property obtained for the `i`-th run * - {py:attr}`~amplify.Result.total_time` - Time from the start to the end of {py:func}`~amplify.solve` - Time used for the `i`-th run ```