From TomWiki
Jump to navigationJump to search

This guide will introduce you to the very basics associated with solving problems using the TOMLAB Optimization Environment. After this session you will have solved several different problems with a variety of solvers. The solvers you can use will depend on what you are licensed for. The total time required for these exercises has been estimated to about 45 minutes.

Useful commands when using this guide:

   help *Assign (* is lp, qp, con and more)
   help tomRun
   help snoptTL
   help mipSolve
   help minlpBBTL
   help cplexTL
   Prob - view the Problem structure used by the solvers
   Result - view the Result structure


Important Information

Setting patterns is especially important for large-scale problems as memory needs to be managed more properly (a dense problem is normally assumed otherwise). Solver timings and recursive calls primarily applies to smaller problems but could also be important issues for larger test cases.

Passing addition variables

If the user wishes to pass additional variables to the user functions written the parameters need to be included in the Prob structure. The code snippets below illustrates how to do it.

In the main function where TOMLAB is called do:

  Prob = *Assign(...);
  Prob.user.a = a;
  Prob.user.b = b;
  Result = tomRun('solver', Prob, 1);

If for example the objective function needs the additional variables a and b do the following in the file:

  function f = myobjective(x, Prob)
  a = Prob.user.a;
  b = Prob.user.b;
  f = sum(x)*a + sum(x.^3)*b;

Using Patterns

For most problems it is critical to set the proper problem patterns (ConsPattern, HessPattern and d2LPattern) for memory allocation purposes and to speed up numerical differentiation. If analytical derivatives are given only the memory benefit will be seen.

See for example the minlpQG problem and use the following code:

  Prob.ConsDiff = 1;
  Result = tomRun('npsol', Prob, 1);
  Prob.ConsDiff = 11;
  Result = tomRun('npsol', Prob, 1);

As can be seen only 43 constraint evaluations are done for the second run with NPSOL. The reason being that the solver (numerical differentiation routines) can see which variables to perturb at the same time from the ConsPattern.

Solver Timings

Comparing different solvers with solution times under 5-10 seconds may yield incorrect results. When running a problem and a solver for the first time general overhead and loading of dll's consume the majority of the time. The following code illustrates the problem:

  clear all
  Prob = probInit('lp_prob', 1);
  R = tomRun('minos', Prob, 1);
  R = tomRun('minos', Prob, 1);

The first run may report a solution time around 0.3 seconds, while the second run shows that the real time spent on optimization is less than 0.01 seconds. When evaluating different solver solutions, all tests need to be run at least twice (more recommended).

There are ways to avoid the extra overhead associated with the driver routines tomRun. For example one can call the solver directly.

  clear all
  Prob = probInit('lp_prob', 1);
  Prob = ProbCheck(Prob, 'minos');
  R = minosTL(Prob);

This is especially important when recursively calling the solver.

Recursive Calls

When doing recursive calls to a solver and modifying some of the inputs (not the size of the problem) one should call the solver as shown above. This minimizes the overhead during the solver call.

Warm start is commonly used when doing recursive calls. Several of the TOMLAB solvers support warm start.

  clear all
  Prob = probInit('lp_prob', 1);
  R = tomRun('minos', Prob, 1);
  Prob = WarmDefSOL('minos', Prob, R);
  R = tomRun('minos', Prob, 1);

Similar code will work for MINOS (also LP-, QP-MINOS), SNOPT, SQOPT, NPSOL, NLSSOL, LPOPT, QPOPT, LSSOL.

When running the TOMLAB /MINLP solvers the following code is needed. Observe that only BQPD and filterSQP can be warm started, while miqpBB and minlpBB accept a starting point.

  clear all
  Prob = probInit('con_prob', 10);
  R = tomRun('filterSQP', Prob, 1);
  Prob = WarmDefDUNDEE('filterSQP', Prob, R);
  R = tomRun('filterSQP', Prob, 1);

It is also possible to warm start TOMLAB /CPLEX for LP problems (only simplex solvers). When doing this one has to supply a basis. See 'help cplex' for more information.

The global solvers in the TOMLAB Base Module and TOMLAB /CGO are easily warm started. One simply sets Prob.WarmStart = 1 before calling the solver the second round.

Verifying Problems

There are several routines and functionality in TOMLAB for verifying problem setup. checkDerivs can be used to check the absolute error of user supplied derivatives. checkFuncs make general user function checking and problem validation. One can also check the derivatives with for example SNOPT, MINOS and NPSOL. The code below illustrates how to generate a print file for further analysis.

  clear all
  Prob = probInit('con_prob', 10);
  Prob.SOL.optPar(1)  = 111111;        % Major print level
  Prob.SOL.optPar(2)  = 10;            % Minor print level
  Prob.SOL.optPar(13) = 3;             % Verify level
  Prob.SOL.PrintFile  = 'snoptP.txt';  % SNOPT print file name
  Prob.SOL.SummFile   = 'snoptS.txt';  % SNOPT summary file name
  R = tomRun('snopt', Prob, 1);

The print file snoptP.txt will provide details on the user supplied derivatives. Observe that this checking should never be done for production code. Once the derivatives have been verified it is recommended to set Prob.SOL.optPar(13) = -1 to avoid one extra function call.

Optimization Toolbox

There is an optimization toolbox interface included in /tomlab/optim. These routines can be used for quick testing of the TOMLAB capabilities when problems are setup for use with optimization toolbox. In general, the routines should be avoided as unnecessary overhead is introduced from the format conversion. If one has embedded calls they should be used as is.

Matlab functions

TOMLAB supports all types of Matlab functions; anonymous, nested and general sub-functions.

The following file illustrates various combinations of the options:

File: tomlab/quickguide/funchandleQG.m

Open the file for viewing, and execute funchandleQG; in Matlab.

 % funchandleQG is a small example for defining and solving problems
 % using nested functions, anonymous functions and subfunctions.
 function [R1, R2, R3] = funchandleQG
 x_L = [0 0 0 0 0 ]';
 x_U = [inf inf 1 1 1 ]';
 A = [1 0     1  0 0 ; ...
     0 1.333 0  1 0 ; ...
     0 0    -1 -1 1 ];
 b_L = [];
 b_U = [1.6 ; 3 ; 0];
 c_L = [1.25;3];
 c_U = c_L;
 x_0 = ones(5,1);
 HessPattern = spalloc(5,5,0);
 ConsPattern = [ 1 0 1 0 0; ...
     0 1 0 1 0 ];
 % Example with local sub functions
 Prob1 = minlpAssign(@my_f, @my_g, @my_H, HessPattern, ...
     x_L, x_U, Name, x_0, [], [], [], [], ...
     A, b_L, b_U, @my_c, @my_dc, @my_d2c, ...
     ConsPattern, c_L, c_U);
 R1 = tomRun('knitro', Prob1, 1);
 constr = @(x) [ x(1)^2+x(3) ; sqrt(x(2)^3)+1.5*x(4)];
 % Example with local sub functions and anonymous function
 % One directly into assign routine and one as variable input
 Prob2 = minlpAssign(@(x) [2 3 1.5 2 -0.5]*x, @my_g, @my_H, HessPattern, ...
     x_L, x_U, Name, x_0, [], [], [], [], ...
     A, b_L, b_U, constr, @my_dc, @my_d2c, ...
     ConsPattern, c_L, c_U);
 R2 = tomRun('knitro', Prob2, 1);
 % Example with local sub functions, anonymous function
 % and nested function
 Prob3 = minlpAssign(@mynested_f, @my_g, @my_H, HessPattern, ...
     x_L, x_U, Name, x_0, [], [], [], [], ...
     A, b_L, b_U, constr, @my_dc, @my_d2c, ...
     ConsPattern, c_L, c_U);
     function f = mynested_f(x)
         f = [2 3 1.5 2 -0.5]*x;
 R3 = tomRun('knitro', Prob3, 1);
 function f = my_f(x)
 f = [2 3 1.5 2 -0.5]*x;
 function g = my_g(x)
 g = [2 3 1.5 2 -0.5]';
 function H = my_H(x)
 H = spalloc(5,5,0);
 function c = my_c(x)
 c = [ x(1)^2+x(3) ; sqrt(x(2)^3)+1.5*x(4)];
 function dc = my_dc(x)
 dc = [2*x(1) 0.0  1.0  0.0  0.0 ; ...
       0.0  1.5*sqrt(x(2))  0.0  1.5  0.0];
 function d2c = my_d2c(x,lam)
 d2c      = spalloc(5,5,2);
 d2c(1,1) = lam(1)*2;
 d2c(2,2) = lam(2)*3/(4*sqrt(x(2)));