Hello

https://img.shields.io/badge/AIMMS_4.86-ZIP:_MultiSolveHelloWorld-blue

AIMMS 4.86 MultiSolveHelloWorld.zip

This section introduces the multiSolve library via a Hello World example.

The Story

A product is transported from the two supply locations a and b to the two destination locations c and d. There is a capacity limit on the transport from a to d. The transport cost is minimized.

We want to investigate how the transportation cost increases with step by step increases of both the supply and the demand.

The Results

After the page actions Initialize and Run, the various instances are quickly solved. The results are presented in the demo page.

../_images/after-demo-run.png

As expected, when the capacity limit on transport from a to d becomes binding, the cost increases more steeply.

Structure

From the perspective of the application, there are three steps to solve:

  1. Retrieving data and providing the GMP

  2. Actually solving the GMP using a solution algorithm (solver for short)

  3. Retrieving the solution from the GMP and storing it

When there are multiple data instances, the above procedure is executed for each data instance.

Note that step 2 can be executed for multiple data instances in parallel.

To facilitate parallel solving, the multiSolve library packages the handling of the above steps in a single procedure call. This procedure call is presented next.

The call

The essence of the multiSolve library is the procedure: multiSolve::pr_multiSolve. For the example at hand, it is called as follows:

 1Procedure pr_solveMultipleGenerate {
 2    Body: {
 3        multiSolve::pr_multiSolve(
 4            ep_onProvideGMP           :  'pr_generateInstance',
 5            ep_onRetrieveSolution     :  'pr_retrieveSolution',
 6            ep_baseGMP                :  '', ! Using the Generate call back mode.
 7            p_maxParallelGMPs         :  2,
 8            p_maxThreadsPerSolve      :  1,
 9            ep_startingSolutionMethod :  multiSolve::ep_startingSolutionMethod_last);
10    }
11}

Remarks about the above code fragment:

  • Lines 3-9: The entire call to the pr_multiSolve.

    • line 4 the callback for specifying a GMP.

    • line 5 the callback for retrieving the solution.

    • line 6: A base GMP is not needed for this hello world example. The use of this argument is explained in detail in Provide.

    • line 7: p_maxParallelGMPs: Up to this number of solves can be executed in parallel.

    • line 8: p_maxThreadsPerSolve: The maximum number of threads available to a single solve.

    • line 9: p_startingSolutionMethod The method used for supplying a starting solution.

Generate the instance

Next, we discuss an example callback procedure to generate a GMP.

 1Procedure pr_generateInstance {
 2    Arguments: (ep_gmp,ep_handle);
 3    Body: {
 4        p_iter += 1 ;
 5        if p_iter > p_maxNoInstances then
 6            ep_handle := '' ;
 7
 8            ! As there is no more data, this procedure can indicate to
 9            ! the multiSolve library that it can stop new solve sequences.
10            p_procedureReturnCode := 0 ;
11        else
12            ! Which instance are going to solve.
13            ep_handle := element( s_instances, p_iter );
14
15            ! Update model parameters for this variation.
16            p_supply(i_src)  := p_supplyInst(i_src,  ep_handle) ;
17            p_demand(i_trgt) := p_demandInst(i_trgt, ep_handle) ;
18
19            ! Create a new GMP from the new data and ensure that its name is unique.
20            ep_gmp := gmp::Instance::Generate( mp_transport,
21                formatString("Instance %e of mp_transport", ep_handle ) );
22
23            ! Indicating there is data, and a GMP is created ready to solve.
24            p_procedureReturnCode := 1;
25        endif ;
26        return p_procedureReturnCode ;
27    }
28    DeclarationSection Argument_declarations {
29        ElementParameter ep_gmp {
30            Range: AllGeneratedMathematicalPrograms;
31            Property: InOut;
32        }
33        ElementParameter ep_handle {
34            Range: Integers;
35            Property: Output;
36        }
37    }
38    DeclarationSection Local_declarations {
39        Parameter p_procedureReturnCode;
40    }
41}

Remarks:

  • Line 4: A global is used to check where this procedure is in the list of work.

  • Lines 5: First it is checked whether there is any work left to be started. If not, return 0; which is interpreted by the library that no more solve sequences are needed.

  • Lines 6, 13, 35: The ep_handle is a handle to the data instance. Its value can be reused in the procedure to retrieve and store the solution.

  • Lines 15-17: Update the model sets and parameters from the instance data.

  • Lines 19-21: Create a GMP using GMP::Instance::Generate(). Make sure the name of the GMP generated is unique within your application.

  • Lines 10, 24, 26: The procedure return code, via parameter p_procedureReturnCode, signifies to the multiSolve library whether there is data for a new solve sequence; 0 indicates that there is no data.

Retrieve solution

Just as there is a callback to specify the GMP to be solved, there is a callback to retrieve the solution. An example is given below.

 1Procedure pr_retrieveSolution {
 2    Arguments: (ep_gmp,ep_finishedSolverSession,ep_handle,ep_step);
 3    Body: {
 4        ! Translate the handle to index values meaningful for the business.
 5        ep_inst := ep_handle ;
 6
 7        ! Copy the solution in the solver session to all the model variables.
 8        multiSolve::pr_storeSolutionInModelVariables(ep_finishedSolverSession);
 9
10        ! Store solution in the model variables in the data structures of the instance at hand.
11        p_obj(ep_inst) := v_obj ;
12        p_transport(i_src, i_trgt, ep_inst) := v_transport(i_src, i_trgt);
13
14        ! The Operations Research problem at hand contains only one step, so that one and only step was done.
15        ! To indicate there are no next steps:
16        return 0 ;
17    }
18    DeclarationSection Argument_declarations {
19        ElementParameter ep_gmp {
20            Range: AllGeneratedMathematicalPrograms;
21            Property: InOut;
22        }
23        ElementParameter ep_finishedSolverSession {
24            Range: AllSolverSessions;
25            Property: Input;
26        }
27        ElementParameter ep_handle {
28            Range: Integers;
29            Property: Input;
30        }
31        ElementParameter ep_step {
32            Range: Integers;
33            Property: Input;
34        }
35    }
36    DeclarationSection Local_declarations {
37        ElementParameter ep_inst {
38            Range: s_instances;
39        }
40    }
41}

Remarks:

  • Line 8: Retrieve the solution from the solver session and store that solution in the model variables.

  • Line 11,12: Copy the solution of the model variables to the data instance.

  • Line 16: Return 0; this indicates that for this instance, no further solve steps are needed.

Summary

The multiSolve library handles the program logic for solving multiple mathematical programs in parallel. There is a clear separation between this program logic, and the business logic to

  1. Generate GMP’s from the data instances, and

  2. Retrieve solutions and put them in the data instances.