7.3 Errors and exceptions

Response codes

Almost every function in Optimizer API for C returns a response code, which is an integer (implemented as the enum MSKrescodee), informing if the requested operation was performed correctly, and if not, what error occurred. The expected response, indicating successful execution, is always MSK_RES_OK. It is a good idea to check the response code every time to avoid silent fails such as for instance:

  • referencing a nonexisting variable (for example with too large index),

  • defining an invalid value for a parameter,

  • accessing an undefined solution,

  • repeating a variable name, etc.

The one case where it is extremely important to check the response code is during optimization, when MSK_optimizetrm is invoked. We will say more about this in Sec. 7.2 (Accessing the solution).

A numerical response code can be converted into a human-readable description using MSK_getcodedesc. A full list of response codes, error, warning and termination codes can be found in the API reference. For example, the following code

  res = MSK_putdouparam(task, MSK_DPAR_INTPNT_CO_TOL_REL_GAP, -1.0e-7);
  if (res != MSK_RES_OK) {
    MSK_getcodedesc(res, symb, str);
    printf("Error %s(%d): %s\n", symb, res, str); 
  }

will produce as output:

Error MSK_RES_ERR_PARAM_IS_TOO_SMALL(1216): A parameter value is too small.

Optimizer errors and warnings

The optimizer may also produce warning messages. They indicate non-critical but important events, that will not prevent solver execution, but may be an indication that something in the optimization problem might be improved. Warning messages are normally printed to a log stream (see Sec. 7.4 (Input/Output)). A typical warning is, for example:

MOSEK warning 53: A numerically large upper bound value  6.6e+09 is specified for constraint 'C69200' (46020).

Warnings can also be suppressed by setting the MSK_IPAR_MAX_NUM_WARNINGS parameter to zero, if they are well-understood.

The user can also register a dedicated callback function to handle all errors and warnings. This is done with MSK_putresponsefunc.

Error and solution status handling example

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

Listing 7.2 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);
      }

      MSK_solutionsummary(task, MSK_STREAM_LOG);

      /* 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:
            printf("An optimal interior-point solution is located.\n");

            /* Read and 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:
            printf("Dual infeasibility certificate found.\n");
            break;

          case MSK_SOL_STA_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");
            /* 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;
}