7.1 Accessing the solution

This section contains important information about the status of the solver and the status of the solution, which must be checked in order to properly interpret the results of the optimization.

7.1.1 Solver termination

The optimizer provides two status codes relevant for error handling:

  • Response code of type MSKrescodee. It indicates if any unexpected error (such as an out of memory error, licensing error etc.) has occurred. The expected value for a successful optimization is MSK_RES_OK.
  • Termination code: It provides information about why the optimizer terminated, for instance if a predefined time limit has been reached. These are not errors, but ordinary events that can be expected (depending on parameter settings and the type of optimizer used).

When using the method MSK_optimize, the response code or termination code most relevant for the user will be returned. To receive both codes separately call the function MSK_optimizetrm.

If a runtime error causes the program to crash during optimization, the first debugging step is to enable logging and check the log output. See Sec. 7.3 (Input/Output).

If the optimization completes successfully, the next step is to check the solution status, as explained below.

7.1.2 Available solutions

MOSEK uses three kinds of optimizers and provides three types of solutions:

  • basic solution (BAS, from the simplex optimizer),
  • interior-point solution (ITR, from the interior-point optimizer),
  • integer solution (ITG, from the mixed-integer optimizer).

Under standard parameters settings the following solutions will be available for various problem types:

Table 3 Types of solutions available from MOSEK
  Simplex optimizer Interior-point optimizer Mixed-integer optimizer
Linear problem MSK_SOL_BAS MSK_SOL_ITR  
Nonlinear continuous problem   MSK_SOL_ITR  
Problem with integer variables     MSK_SOL_ITG

For linear problems the user can force a specific optimizer choice making only one of the two solutions available. For example, if the user disables basis identification, then only the interior point solution will be available for a linear problem. Numerical issues may cause one of the solutions to be unknown even if another one is feasible.

Not all components of a solution are always available. For example, there is no dual solution for integer problems.

The user will always need to specify which solution should be accessed.

7.1.3 Problem and solution status

Assuming that the optimization terminated without errors, the next important step is to check the problem and solution status. There is one for every type of solution, as explained above.

Problem status

Problem status (MSKprostae, retrieved with MSK_getprosta) determines whether the problem is certified as feasible. Its values can roughly be divided into the following broad categories:

  • feasible — the problem is feasible. For continuous problems and when the solver is run with default parameters, the feasibility status should ideally be MSK_PRO_STA_PRIM_AND_DUAL_FEAS.
  • primal/dual infeasible — the problem is infeasible or unbounded or a combination of those. The exact problem status will indicate the type of infeasibility.
  • unknown — the solver was unable to reach a conclusion, most likely due to numerical issues.

Solution status

Solution status (MSKsolstae, retrieved with MSK_getsolsta) provides the information about what the solution values actually contain. The most important broad categories of values are:

  • optimal (MSK_SOL_STA_OPTIMAL) — the solution values are feasible and optimal.
  • near optimal (MSK_SOL_STA_NEAR_OPTIMAL) — the solution values are feasible and they were certified to be at least nearly optimal up to some accuracy.
  • certificate — the solution is in fact a certificate of infeasibility (primal or dual, depending on the solution).
  • unknown/undefined — the solver could not solve the problem or this type of solution is not available for a given problem.

The solution status determines the action to be taken. For example, in some cases a suboptimal solution may still be valuable and deserve attention. It is the user’s responsibility to check the status and quality of the solution.

Typical status reports

Here are the most typical optimization outcomes described in terms of the problem and solution statuses. Note that these do not cover all possible situations that can occur.

Table 4 Continuous problems (solution status for MSK_SOL_ITR or MSK_SOL_BAS)
Outcome Problem status Solution status
Optimal MSK_PRO_STA_PRIM_AND_DUAL_FEAS MSK_SOL_STA_OPTIMAL
Primal infeasible MSK_PRO_STA_PRIM_INFEAS MSK_SOL_STA_PRIM_INFEAS_CER
Dual infeasible MSK_PRO_STA_DUAL_INFEAS MSK_SOL_STA_DUAL_INFEAS_CER
Uncertain (stall, numerical issues, etc.) MSK_PRO_STA_UNKNOWN MSK_SOL_STA_UNKNOWN
Table 5 Integer problems (solution status for MSK_SOL_ITG, others undefined)
Outcome Problem status Solution status
Integer optimal MSK_PRO_STA_PRIM_FEAS MSK_SOL_STA_INTEGER_OPTIMAL
Infeasible MSK_PRO_STA_PRIM_INFEAS MSK_SOL_STA_UNKNOWN
Integer feasible point MSK_PRO_STA_PRIM_FEAS MSK_SOL_STA_PRIM_FEAS
No conclusion MSK_PRO_STA_UNKNOWN MSK_SOL_STA_UNKNOWN

7.1.4 Retrieving solution values

After the meaning and quality of the solution (or certificate) have been established, we can query for the actual numerical values. They can be accessed with methods such as:

and many more specialized methods, see the API reference.

7.1.5 Source code example

Below is a source code example with a simple framework for assessing and retrieving the solution to a conic quadratic optimization problem.

Listing 14 Sample framework for checking optimization result. Click here to download.
#include <stdio.h>
#include "mosek.h"

/* Log handler */
void MSKAPI printlog(void *ptr,
                     const char s[])
{
  printf("%s", s);
} 

int main(int argc, char const *argv[])
{
  MSKenv_t    env;
  MSKtask_t   task;
  MSKrescodee r;
  char        symname[MSK_MAX_STR_LEN];
  char        desc[MSK_MAX_STR_LEN];
  int         i, numvar;
  double      *xx = NULL;
  const char  *filename;

  if ( argc >= 2 ) filename = argv[1];
  else             filename = "../data/cqo1.mps";

  // Create the environment
  r = MSK_makeenv(&env, NULL);

  if ( r == MSK_RES_OK )
  {
    // Create the task
    r = MSK_makeemptytask(env, &task);

    // (Optionally) attach the log handler to receive log information
    // if ( r == MSK_RES_OK ) MSK_linkfunctotaskstream(task, MSK_STREAM_LOG, NULL, printlog);

    // (Optionally) uncomment this line to most likely see solution status Unknown
    // MSK_putintparam(task, MSK_IPAR_INTPNT_MAX_ITERATIONS, 1);

    // In this example we read an optimization problem from a file
    r = MSK_readdata(task, filename);

    if ( r == MSK_RES_OK )
    {
      MSKrescodee trmcode;
      MSKsolstae  solsta;

      // Do the optimization, and exit in case of error
      r = MSK_optimizetrm(task, &trmcode); 
      if ( r != MSK_RES_OK ) {
        MSK_getcodedesc(r, symname, desc);
        printf("Error during optimization: %s %s\n", symname, desc);
        exit(r);
      }

      /* Expected result: The solution status of the interiot-point solution is optimal. */

      if ( MSK_RES_OK == MSK_getsolsta(task, MSK_SOL_ITR, &solsta) )
      {
        switch ( solsta )
        {
          case MSK_SOL_STA_OPTIMAL:
          case MSK_SOL_STA_NEAR_OPTIMAL:
            printf("An optimal interior-point solution is located.\n");

            /* Read a print the variable values in the solution */
            MSK_getnumvar(task, &numvar);
            xx = calloc(numvar, sizeof(double));
            MSK_getxx(task, MSK_SOL_ITR, xx);
            for(i = 0; i < numvar; i++)
              printf("xx[%d] = %.4lf\n", i, xx[i]);
            free(xx);
            break;

          case MSK_SOL_STA_DUAL_INFEAS_CER:
          case MSK_SOL_STA_NEAR_DUAL_INFEAS_CER:
            printf("Dual infeasibility certificate found.\n");
            break;

          case MSK_SOL_STA_PRIM_INFEAS_CER:
          case MSK_SOL_STA_NEAR_PRIM_INFEAS_CER:
            printf("Primal infeasibility certificate found.\n");
            break;

          case MSK_SOL_STA_UNKNOWN:
            /* The solutions status is unknown. The termination code
               indicating why the optimizer terminated prematurely. */
            printf("The solution status is unknown.\n");
            if ( r != MSK_RES_OK )
            {
              /* Optimization error */
              MSK_getcodedesc(r, symname, desc);
              printf("  Response code: %s %s\n", symname, desc);
            }
            else
            {
              /* No-error cause of termination e.g. an iteration limit is reached.  */
              MSK_getcodedesc(trmcode, symname, desc);
              printf("  Termination code: %s %s\n", symname, desc);
            }
            break;

          default:
            MSK_solstatostr(task, solsta, desc);
            printf("An unexpected solution status %s with code %d is obtained.\n", desc, solsta);
            break;
        }
      }
      else
        printf("Could not obtain the solution status for the requested solution.\n");
    }
    else {
      MSK_getcodedesc(r, symname, desc);
      printf("Optimization was not started because of error %s(%d): %s\n", symname, r, desc);
    }

    MSK_deletetask(&task);
  }

  MSK_deleteenv(&env);
  return r;
}