% CPLEX - linear programming by the simplex method.
% Package written in C-language.
% Sparsity is preserved.
%
% CPLEX solves a linear program on the form
%
%       min  c'x
%       s.t  Ax | b
%            l <= x <= u
%
% where | is any of =, <= , >=.
%
% Calling syntax: [obj,x,lambda,status,cstat,it] = cplex(c,A,b,l,u,le,ge,opts)
%
% where 'le' ('ge') are indices corresponding to constraints 
% with <=  ( >= ) and can be omitted.
% 'opts' is a structure that contains option pairs, eg struct('lpmethod',1)
% see cplex manual for more details
%
% If 'l','u' are omitted, x is assumed non-negative.
%
% On exit 'status' has the following interpretation:
%
%                 1 optimal solution found
%                 2 problem unbounded
%                 3 problem infeasible
%                 4 problem infeasible or unbounded
%                 9 problem non-optimal, singularities in Phase II
%                10 problem non-optimal, singularities in Phase I
%
% 'cstat' tells the status of the columns:
%
%                  cstat[i] = 0   variable at lower bound
%                  cstat[i] = 1   variable is basic
%                  cstat[i] = 2   variable at upper bound
%                  cstat[i] = 3   variable free and non-basic
%
% 'it' is the total number of iterations.
%
function [obj,x,lambda,status,cstat,it] = rcplex(c,A,b,l,u,le,ge,opts)

if nargin < 3
  error('must have 3 input arguments');
end

[m,n]=size(A);

[m1,n1]=size(c);

if(n1 ~= 1)
  c = c';
  if(n1 ~= n | m1 ~=1)
    error('Input arguments are of incompatible sizes');
  end % if
elseif (m1 ~= n)
  error('Input arguments are of incompatible sizes');
end % if

[m1,n1]=size(b);
if(n1 ~= 1)
  b = b';
  if(n1 ~= m | m1 ~=1)
    error('Input arguments are of incompatible sizes');
  end % if
elseif (m1 ~= m)
  error('Input arguments are of incompatible sizes');
end % if


%%%%%%%%%%  Call with appropriate arguments  %%%%%%%%
if nargin < 4,
  l = zeros(size(c));
  u = Inf*ones(size(c));
  [obj , x, lambda, status, cstat, it] = cplexlp(c, A, b, l, u);
elseif nargin < 5,

  if isempty(l)
    l = zeros(size(c));
  end
  [m1,n1]=size(l);
  if(n1 ~= 1)
    l = l';
    if(n1 ~= n | m1 ~=1)
      error('Input arguments are of incompatible sizes');
    end % if
  elseif (m1 ~= n)
    error('Input arguments are of incompatible sizes');
  end % if
  
  u = Inf*ones(size(c));
  [obj , x, lambda, status, cstat, it] = cplexlp(c, A, b, l, u);
elseif nargin < 6
  
  if isempty(l)
    l = zeros(size(c));
  end
  [m1,n1]=size(l);
  if(n1 ~= 1)
    l = l';
    if(n1 ~= n | m1 ~=1)
      error('Input arguments are of incompatible sizes');
    end % if
  elseif (m1 ~= n)
    error('Input arguments are of incompatible sizes');
  end % if
  
  if isempty(u)
    u = Inf*ones(size(c));
  end
  [m1,n1]=size(u);
  if(n1 ~= 1)
    u = u';
    if(n1 ~= n | m1 ~=1)
      error('Input arguments are of incompatible sizes');
    end % if
  elseif (m1 ~= n)
    error('Input arguments are of incompatible sizes');
  end % if
  
  [obj , x, lambda, status, cstat, it] = cplexlp(c, A, b, l, u);
elseif nargin < 7
  
  if isempty(l)
    l = zeros(size(c));
  end
  [m1,n1]=size(l);
  if(n1 ~= 1)
    l = l';
    if(n1 ~= n | m1 ~=1)
      error('Input arguments are of incompatible sizes');
    end % if
  elseif (m1 ~= n)
    error('Input arguments are of incompatible sizes');
  end % if
  
  if isempty(u)
    u = Inf*ones(size(c));
  end
  [m1,n1]=size(u);
  if(n1 ~= 1)
    u = u';
    if(n1 ~= n | m1 ~=1)
      error('Input arguments are of incompatible sizes');
    end % if
  elseif (m1 ~= n)
    error('Input arguments are of incompatible sizes');
  end % if
  
  [m1,n1]=size(le);
  if(n1 ~= 1)
    le = le';
    if(n1 > m | m1 > 1)
      error('Input arguments are of incompatible sizes');
    end % if
  elseif (m1 > m)
    error('Input arguments are of incompatible sizes');
  end % if
  
  [obj,x,lambda,status,cstat,it] = cplexlp(c, A, b, l, u, le);
  
else
  
  if isempty(l)
    l = zeros(size(c));
  end
  [m1,n1]=size(l);
  if(n1 ~= 1)
    l = l';
    if(n1 ~= n | m1 ~=1)
      error('Input arguments are of incompatible sizes');
    end % if
  elseif (m1 ~= n)
    error('Input arguments are of incompatible sizes');
  end % if
  
  if isempty(u)
    u = Inf*ones(size(c));
  end
  [m1,n1]=size(u);
  if(n1 ~= 1)
    u = u';
    if(n1 ~= n | m1 ~=1)
      error('Input arguments are of incompatible sizes');
    end % if
  elseif (m1 ~= n)
    error('Input arguments are of incompatible sizes');
  end % if
  
  
  [m1,n1]=size(ge);
  if(n1 ~= 1)
    ge = ge';
    if(n1 > m | m1 > 1)
      error('Input arguments are of incompatible sizes');
    end % if
  elseif (m1 > m)
    error('Input arguments are of incompatible sizes');
  end % if
 
  [m1,n1]=size(le);
  if(n1 ~= 1)
    le = le';
    if(n1 > m | m1 > 1)
      error('Input arguments are of incompatible sizes');
    end % if
  elseif (m1 > m)
    error('Input arguments are of incompatible sizes');
  end % if
  if ~isempty(intersect(le,ge))
    eqs = intersect(le,ge);
    le = setdiff(le,eqs);
    ge = setdiff(ge,eqs);
  end
  
  if nargin < 8 | isempty(opts)
    opts = struct();
  end
  [obj, x, lambda, status, cstat, it] = cplexlp(c, A, b, l, u, le, ge, opts);
  
end % if

