Show Intermediate Solutions


During a long running solver session (job), we may want to compute intermediate results and show them to the end user as soon as they are available. Consider the following use cases:

  1. The submitted job contains multiple decision subproblems, all of which are solved in one batch. Why wait for providing the solution of the first subproblem, while the job is already working on the second subproblem?

  2. The optimization of a significant Mixed Integer Problem will compute several intermediate incumbents, and perhaps these incumbents are worth visualizing and studying further.

  3. By showing intermediate solutions, the end user may decide that the last shown solution is good enough and decide to terminate the job.

Difference with passing progress information

The differences between progress information and intermediate solutions are:

  1. The intermediate solutions will be stored as cases such that they can be retrieved upon demand.

  2. There is no limit to the amount of information that can be passed back to the data session.

  3. The messages about the presence of the intermediate solutions are guaranteed to arrive at the data session; even if the data session is temporarily unreachable.


The approach here involves passing information through three levels of execution.

  1. The solver execution on the solver session.

    Construct a new incumbent containing the entire solution. This is done as part of the incumbent callback mechanism.

  2. The AIMMS execution on the solver session.

    Retrieve incumbent solution or intermediate result from the solver, also as part of the incumbent callback mechanism. Store this retrieved solution as a case file on the AIMMS PRO storage.

  3. The AIMMS execution on the data session.

    Execute a procedure to retrieve the name of the case file generated in the previous step, and load the data from the case file into the data session for the end user’s viewing.

This approach is possible because both the data session and the solver session have access to the AIMMS PRO storage and storing all the different incumbent solutions as case files allows the user to access them when required to conduct further studies. The following image illustrates how AIMMS PRO storage is organized:


We will use the folder pro:/UserData/<environment>/<User>/Cases/<app>/ on AIMMS PRO storage.


There are two steps to communicate the information from the first to the third level.

Step 1. From Solver (level 1) to solver session (level 2)

Step 1A Construct the incumbent solution on the solver session.

As we want to display/update a new incumbent solution as it becomes available, we use the mathematical program suffix CallbackNewIncumbent. A callback procedure is assigned to this suffix as below, and this executes the assigned procedure whenever a new incumbent solution is found by the solver. Include the below statement before the solve statement in your project.

FlowShopModel.CallbackNewIncumbent := 'NewIncumbentCallback';

Step 1B Retrieve the incumbent solution generated by the solver to the AIMMS solver session.

In the running example, the procedure NewIncumbentCallback first retrieves the incumbent solution from the solver session, transforms it to be displayed in the Ganttchart, creates a case file containing this data and saves it on the AIMMS PRO storage. The intermediate data transformation steps are specific to this example and hence are not explained here.

The predefined procedure RetrieveCurrentVariableValues retrieves the current values of the variables as the name suggests. It takes an argument specifying which variable values are to be retrieved and we use the predefined set AllVariables to get the values of all the variables in the model. TimeSpan is the objective function of the model and we are storing the current incumbent value with the assignment statement.

! Transfer the solution from the solver to AIMMS
empty JobSchedule;

TimeSpan := FlowShopModel.Incumbent;

Create a case file containing this solution.

AllCaseFileContentTypes += 'sIncumbentSolutionIdentifiers' ;
CurrentCaseFileContentType := 'sIncumbentSolutionIdentifiers' ;
sp_CaseFileName := FormatString( "", pIncumbentNumber );
P_IncumbentNumber += 1 ;
sp_FullCaseFileName := "data/" + spCaseFileName ;
CaseFileSave( spCaseFileName, sIncumbentSolutionIdentifiers );

Now, save the case file on PRO storage and store the name of the case file (including location path) in a string parameter.

! Transfer the case from the data folder of the solver session to the AIMMS PRO storage user data folder.
! Transfer the GC solution from AIMMS to a case.
spFullProStorageName := "pro:/userdata/" + pro::GetPROEnvironment() +
                    "/" + pro::GetPROUserName() + "/Cases/" + pro::ModelName + "/" + spCaseFileName ;
Pro::SaveFileToCentralStorage(spCaseFileName, spFullProStorageName );

The AIMMS execution side is now triggered using the previously updated string parameters as arguments.

! Run the AIMMS execution on the data session

Step 2. From solver session (level 2) to data session (level 3)

The procedure UpdateIncumbentToClient is a simple loading case file execution using the predefined procedure, CaseFileLoad.

if pro::DelegateToClient(flags: 0) then
    return 1;
endif ;

! From here on, only the client (data) session is running.

CaseFileLoad( spArgFullProStorageName );

! Comment out the next line if you want to retain intermediate solutions.
pro::DeleteStorageFile( spArgFullProStorageName );

A copy of the flowshop model that is the result of this answer: Flow Shop - share intermediate.


Further reading

Now that end users know the state of the solution process, they also want to interrupt it when they see that further improvements are not worth waiting for. This is handled in Interrupt the solver session.