function [x,fval,flag,output]=milp_solve_tomlab_cplex(M,options)
% Syntax:  [x,fval,flag,output]=milp_solve_tomlab_cplex(M,options)
%
% Purpose: Solves the MILP problem
%             min_x  f^T x + offset
%             s.t. A x  <= b
%                  Aeq x = beq
%                  lb <= x <= ub
%                  x(vartype) in {0,1} or integer between lb(vartype)
%                                         and ub(vartype)
%          using the Tomlab cplex solver.
%          M is an MILP structure with the following fields:
%             M.f        nx by 1 real matrix
%             M.A        nc by nx real matrix
%             M.b        nc by 1 real matrix
%             M.Aeq      ne by nx real matrix
%             M.beq      ne by 1 real matrix
%             M.intvars  integer vector (see help cplex)
%             M.lb       nx by 1 real matrix
%             M.ub       nx by 1 real matrix
%             M.offset   scalar
%          milp_solve_tomlab_cplex allows the following options fields (the
%          first field value is the default):
%             options.display = 'off'|'on'
%             options.PriLev = 0 (silent)|1 (warnings & errors)|
%                              2 (summary info)| 3 (more detailed) | 11 (debug)
%          The other options are passed through to cplex (see help cplex).
%          x is the optimal solution and fval is the corresponding function
%          value (offset included). If flag equals 1, the optimization was
%          succesful. output is a structure containing the additional output
%          of cplex.
%
% Inputs:  M        MILP structure
%          options  structure, optional
%
% Outputs: x       nx by 1 real matrix
%          fval    real number
%          flag    integer
%          output  structure

% Created: Mar 31, 2005       by Bart De Schutter
% Last revised: Jan  6, 2007  by Bart De Schutter

% Warning: No further checking is done on the input arguments.

if ( nargin < 2 )
   options=[];
end;
if (  ( nargin >= 2 )  &&  isfield(options,'display')  )
   PriLev=2*strcmp(options.display,'on');
   % 0 : silent
   % 2 : summary information
   % 3 : more detailed information
else
   PriLev=0;
end;
if ( isfield(options,'PriLev') )
   PriLev=options.PriLev;
end;

if ( ~isfield(M,'b') || ~isfield(M,'A') || ~isfield(M,'f') )
     error('The structure M should contain f, A, and b fields.');
end;
if ( ~isfield(M,'beq') )
   M.beq=[];
end;
if ( ~isfield(M,'Aeq') )
   M.Aeq=[];
end;
if ( ~isfield(M,'offset') )
   M.offset=0;
end;
if ( ~isfield(M,'intvars') )
   M.intvars=[];
end;

big_number=1e13;
if ( ~isfield(M,'lb') || isempty(M.lb) )
   x_L=repmat(-big_number,size(M.f));
else
   x_L=M.lb;
   x_L(isinf(x_L))=-big_number;  % We silently assume that M.lb contains
                                 % no +Inf's
end;
if ( ~isfield(M,'ub') || isempty(M.ub) )
   x_U=repmat(big_number,size(M.f));
else
   x_U=M.ub;
   x_U(isinf(x_U))=big_number;   % We silently assume that M.ub contains
                                 % no -Inf's
end;


b_L=[repmat(-big_number,size(M.b));M.beq];
b_L(isinf(b_L))=-big_number;   % We silently assume that M.beq contains no
                               % +Inf's
b_U=[M.b;M.beq];
b_U(isinf(b_U))=big_number;    % We silently assume that M.b and M.beq
                                % contain no -Inf's

[x,slack,v,rc,fval,ninf,sinf,Inform]=...
    cplex(M.f,[M.A;M.Aeq],x_L,x_U,b_L,b_U,options,[],PriLev,[],...
          M.intvars,[], ...
          [],[],[],[],[]); %#ok

global cpxRetVec

output.cpxRetVec=cpxRetVec;
output.Inform=Inform;

if ( isfield(M,'offset') )
   fval=fval+M.offset;
end;

if ( any(Inform==[1,6,101,102]) )
   flag=1;
else
   flag=-1;
end;

