7.7 Progress and data callback

Callbacks are a very useful mechanism that allow the caller to track the progress of the MOSEK optimizer. A callback function provided by the user is regularly called during the optimization and can be used to

  • obtain a customized log of the solver execution,

  • collect information for debugging purposes or

  • ask the solver to terminate.

Optimizer API for .NET has the following callback mechanisms:

  • progress callback, which provides only the basic status of the solver.

  • data callback, which provides the solver status and a complete set of information items that describe the progress of the optimizer in detail.

  • integer solution callback, for reporting progress on a mixed-integer problem.

Warning

The callbacks functions must not invoke any functions of the solver, environment or task. Otherwise the state of the solver and its outcome are undefined. The only exception is the possibility to retrieve an integer solution, see below.

Retrieving mixed-integer solutions

If the mixed-integer optimizer is used, the callback will take place, in particular, every time an improved integer solution is found. In that case it is possible to retrieve the current values of the best integer solution from within the callback function. It can be useful for implementing complex termination criteria for integer optimization. Note that there is a specialized callback class for retrieving only the integer solution anyway.

7.7.1 Data callback

In the data callback MOSEK passes a callback code and values of all information items to a user-defined function. The callback function is called, in particular, at the beginning of each iteration of the interior-point optimizer. For the simplex optimizers iparam.log_sim_freq controls how frequently the call-back is called.

The callback is set by calling the method Task.set_InfoCallback. The callback function must be implemented by extending the abstract class DataCallback and implementing the method DataCallback.callback.

Non-zero return value of the callback function indicates that the optimizer should be terminated.

7.7.2 Progress callback

In the progress callback MOSEK provides a single code indicating the current stage of the optimization process.

The callback is set by calling the method Task.set_Progress. The callback function must be implemented by extending the abstract class Progress and implementing the method Progress.progressCB.

Non-zero return value of the callback function indicates that the optimizer should be terminated.

7.7.3 Integer solution callback

In this type of callback the user-defined callback function receives an updated solution every time the mixed-integer optimizer improves the objective value. It can be useful for implementing complex termination criteria for integer optimization.

Syntax

The callback is set by calling the method Task.set_ItgSolutionCallback. The callback function must be implemented by extending the abstract class ItgSolutionCallback and implementing the method ItgSolutionCallback.callback.

7.7.4 Working example: Data callback

The following example defines a data callback function that prints out some of the information items. It interrupts the solver after a certain time limit.

Listing 7.5 An example of a data callback function. Click here to download.
  class myCallback : mosek.DataCallback
  {
    double maxtime;
    
    public myCallback(double maxtime_)
    {
      maxtime = maxtime_;
    }
    
    public override int callback( callbackcode caller, 
                                  double[]     douinf,
                                  int[]        intinf,
                                  long[]       lintinf )
    {
      double opttime = 0.0;
      int itrn;
      double pobj, dobj, stime;

      switch (caller)
      {
        case callbackcode.begin_intpnt:
          Console.WriteLine("Starting interior-point optimizer");
          break;
        case callbackcode.intpnt:
          itrn    = intinf[(int) iinfitem.intpnt_iter      ];
          pobj    = douinf[(int) dinfitem.intpnt_primal_obj];
          dobj    = douinf[(int) dinfitem.intpnt_dual_obj  ];
          stime   = douinf[(int) dinfitem.intpnt_time      ];
          opttime = douinf[(int) dinfitem.optimizer_time   ];
          
          Console.WriteLine("Iterations: {0,-3}",itrn);
          Console.WriteLine("  Elapsed: Time: {0,6:F2}({1:F2})",opttime,stime);
          Console.WriteLine("  Primal obj.: {0,-18:E6}  Dual obj.: {1,018:E6}e",pobj,dobj);
          break;
        case callbackcode.end_intpnt:
          Console.WriteLine("Interior-point optimizer finished.");
          break;
        case callbackcode.begin_primal_simplex:
          Console.WriteLine("Primal simplex optimizer started.");
          break;
        case callbackcode.update_primal_simplex:
          itrn    = intinf[(int) iinfitem.sim_primal_iter  ];
          pobj    = douinf[(int) dinfitem.sim_obj          ];
          stime   = douinf[(int) dinfitem.sim_time         ];
          opttime = douinf[(int) dinfitem.optimizer_time   ];
          
          Console.WriteLine("Iterations: {0,-3}}", itrn);
          Console.WriteLine("  Elapsed time: {0,6:F2}({1:F2})",opttime,stime);
          Console.WriteLine("  Obj.: {0,-18:E6}", pobj );
          break;
        case callbackcode.end_primal_simplex:
          Console.WriteLine("Primal simplex optimizer finished.");
          break;
        case callbackcode.begin_dual_simplex:
          Console.WriteLine("Dual simplex optimizer started.");
          break;
        case callbackcode.update_dual_simplex:
          itrn    = intinf[(int) iinfitem.sim_dual_iter    ];
          pobj    = douinf[(int) dinfitem.sim_obj          ];
          stime   = douinf[(int) dinfitem.sim_time         ];
          opttime = douinf[(int) dinfitem.optimizer_time   ];
          Console.WriteLine("Iterations: {0,-3}}", itrn);
          Console.WriteLine("  Elapsed time: {0,6:F2}({1:F2})",opttime,stime);
          Console.WriteLine("  Obj.: {0,-18:E6}", pobj );
          break;
        case callbackcode.end_dual_simplex:
          Console.WriteLine("Dual simplex optimizer finished.");
          break;
        case callbackcode.begin_bi:
          Console.WriteLine("Basis identification started.");
          break;
        case  callbackcode.end_bi:
          Console.WriteLine("Basis identification finished.");
          break;
        default:
          break;
      }

      if (opttime >= maxtime)
        // mosek is spending too much time. Terminate it.
        return 1;
                
      return 0;
    }
  }

Assuming that we have defined a task task and a time limit maxtime, the callback function is attached as follows:

Listing 7.6 Attaching the data callback function to the model. Click here to download.
          task.set_InfoCallback(new myCallback(maxtime));