Use the Progress Window in WebUI

Introduction

While a solve procedure is running, we are curious about the estimated time left for completion - are we going to get the results back soon or is there enough time to go grab a cup of coffee? In essence, we want to keep track of the progress of the solve procedure. We can do this by using the Progress Window (Ctrl + P) in the Developer mode, and this article will show you how to present this progress information to the end user of a WebUI application.

Approach

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

../../_images/ThreeLevelsOfExecutionTimeCB.png
  1. The solver execution on the solver session.

    The solver passes on status information periodically, as part of the time callback mechanism.

  2. The AIMMS execution on the solver session.

    Retrieves the information provided by the solver in the previous step, also as part of the time callback mechanism.

  3. The AIMMS execution on the data session.

    Execute a procedure to retrieve the information from the solver session to the data session and display it in the WebUI widgets.

The implementation of the information stream represented by the two arrows will be discussed in the next section.

Implementation

The AIMMS project for the current running example with the steps implemented can be downloaded from: 6. Flow Shop - Progress Communication.

The Gap curve linechart widget in the below image is updated every second with the gap between the best bound and incumbent objective value of the mathematical program in the project.

../../_images/BB06_WebUI_screen.PNG

You can implement the same in your project by communicating the data from the solver (level 1) to the data session (level 2), which is done in two steps as explained in detail below.

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

Step 1A Instruct the solver to provide the progress information periodically.

We use the mathematical program suffix CallbackTime for this purpose. In the context of the current running example, the mathematical program is FlowShopModel and the user defined procedure, NewTimeCallback is assigned to the CallbackTime.

The predefined option statement lets you alter the project options in a procedure. We set the interval to update the progress information as 1 second by referring to the progress_time_interval option. You can also change this option by, Settings → Project Options → AIMMS → Progress Options

If included before the solve statement in your project, the procedure pr_NewTimeCallback is executed every 1 second.

FlowShopModel.CallbackTime := 'pr_NewTimeCallback';
option progress_time_interval := 1 ;

Step 1B Retrieve the information passed on by the solver to the AIMMS solver session.

In our example, we want to display only the best bound and incumbent objective value of the MIP. So, the body of pr_NewTimeCallback consists of a procedure with two arguments - FlowShopModel.bestbound and FlowShopModel.Incumbent. You can retrieve values of any of the mathematical program suffices which are listed and explained in Mathematical Program Suffices.

pr_UpdateGapToClient(FlowShopModel.bestbound,FlowShopModel.Incumbent);

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

As we are only passing small amounts of data and executing some simple arithmetic, the procedure pr_UpdateGapToClient can be executed on the data session i.e., on the end user’s browser. To do this, we use the call pro::DelegateToClient. This is very similar to the earlier used call, pro::DelegateToServer and the difference is evident as their names suggest - in pro::DelegateToClient, we are delegating a procedure to the client (or data) session and in the other one, we are delegating a procedure to the solver session.

This procedure contains two arguments as input parameters, bb and icb which take on the values of the best bound and Incumbent suffices specified in the previous step.

Procedure pr_UpdateGapToClient {
    Arguments: (bb,icb);
    Body: {
        if pro::GetPROEndPoint() then
            if pro::DelegateToClient(flags: pro::PROMFLAG_LIVE) then
                return 1;
            endif ;
        endif ;

    }
    Parameter bb {
        Property: Input;
    }
    Parameter icb {
        Property: Input;
    }
}

In our running example, the body of this procedure contains other data manipulation statements to update a set of observations and calculate the gap percentage between the best bound and incumbent objective value. These statements are not discussed in this article.

Further reading

Some closing remarks about the pr_UpdateGapToClient procedure to give you a better understanding of what is happening.

  1. The pro::DelegateToClient code is protected by pro::GetPROEndPoint() to make the procedure executable on Developer mode too. This IF statement is optional but is generally recommended as it allows for a smooth development and debugging workflow.

  2. The second IF statement containing pro::DelegateToClient checks and returns if there is an active data session available. The statements in the body of the procedure are executed on the data session only if this IF statement returns a TRUE or 1 status.

You can read more about the pro::PROMFLAG_LIVE and other flag arguments in a separate article

Now that end users know the state of the solution process, they might want to interrupt it when they see that further improvements are not worth waiting for. The article Interrupt the solver session shows you how to do it.