% CPLEXMIP - Solves a mip program (MIP) using the CPLEX solver.
% CPLEXMIP solves the mip programming problem:
%
%       min  c'*x
%       s.t  A*x ? b
%            l <= x <= u
%            x_j =0,1  j in binvar
%            x_k general integer  k in genvar
%
% where ? can be =, <= , or >=.
%
% Syntax:
% [obj,x,slack,status,colstat,it] = cplexmip(c,A,b,l,u,le,ge,binvar,genvar,maxIter,verbose)
% verbose = 0 no display solution   1=display solution
%
% c, A, and b are required arguments.
% If l and u are omitted, x is assumed non-negative.
% le and ge are indices corresponding to constraints with <= and >=,
%   respectively.
% maxiter is 10000 by default.

% compile with mex -I/.../cplex8.1 -L/.../cplex8.1 -lcplex mip_cplex_mex.c

function [obj,x,lambda,status,colstat,it] =...
  cplexmip(c,A,b,l,u,le,ge,binvar,genvar,maxIter,verbose)

  % Initial error checking
  [m,n]=size(A);
  
  
  c = ColumnVector(c);
  mc = length(c);
  if (mc ~= n)
    error('A and c are of incompatible sizes.');
  end;
  
  b = ColumnVector(b);
  mb = length(b);
  if (mb ~= m)
    error('A and b are of incompatible sizes.');
  end;
  
  % Assign default values if not provided
  if ~exist('l','var')
    l = zeros(mc,1);
  else
    l = ColumnVector(l);
  end;

  if ~exist('u','var')
    u = inf*ones(mc,1);
  else
    u = ColumnVector(u);
  end;

  if ~exist('le','var')
    le = [];
  else
    le = ColumnVector(le);
  end;
  
  if ~exist('ge','var')
    ge = [];
  else
    ge = ColumnVector(ge);
  end;
  if ~exist('binvar','var')
    binvar = [];
  else
    binvar = ColumnVector(binvar);
  end;
  if ~exist('genvar','var')
    genvar = [];
  else
    genvar = ColumnVector(genvar);
  end;
    
  if ~exist('maxIter','var')
    maxIter = 5000000;
  end;

  % More error checking
  if length(l) ~= n,
    error('A and l are of incompatible sizes');
  end;

  if length(u) ~= n,
    error('A and u are of incompatible sizes');
  end;

  if max(le) > m | length(le) > m,
    error('A and le are incompatible');
  end;

  if max(ge) > m | length(ge) > m,
    error('A and ge are incompatible');
  end;

  % Make the CPLEX call
  [obj,x,lambda,status,colstat,it] = cplexmipmex(c,A,b,l,u,le,ge,binvar,genvar,maxIter);
  % Output based on status
  switch(status)
   case 101,
    disp(sprintf('Optimal solution found.'));
   case 103,
    disp(sprintf('Problem infeasible'));
   case 102,
    disp(sprintf('Problem solved within tolerances.'));
   case 105,
    disp(sprintf('Node limit exceeded, int soln found.'));
   case 106,
    disp(sprintf('Node limit exceeded, no int soln found.'));
   case 107,
    disp(sprintf('Time limit exceeded, int soln found.'));
   case 108,
    disp(sprintf('Time limit exceeded, no int soln found.'));
   otherwise,
    disp(sprintf('Cplex failed.'));
  end;

if (verbose)
  if status < 109,
    fprintf('\nMIP Succesfully Solved with CPLEX');
  end;
  fprintf('\nNumber of iterations : %d',it);
  fprintf('\nBest objective       : %f',obj);
end

function [vec] = ColumnVector(oldVec)
  vec = oldVec;
  [m,n] = size(vec);
  if n>1
    vec = vec';
    [m,n] = size(vec);
  end;
  if n>1
    error('One of the input vectors is of the wrong size.');
  end;
  return;
