function [x,lambda,mu,status,it] = alps(c,A,b,l,u,sense,maxit,printlvl) % % alps - a linear program solver % % alps assumes problem on the form % % min z = c'x % s.t. Ax | b % l<=x<=u % where | is any of =, <=, >= % % Calling syntax % [x,lambda,mu,status,it] = alps(c,A,b,l,u,sense,maxit,printlvl); % % input arguments: c cost vector % A coefficient matrix % b right-hand side % l lower bounds on x (default: 0) % u upper bound on x (default: inf) % sense sense(i)=0 means | -> = in row i (default) % sense(i)=1 means | -> <= -"- % sense(i)=2 means | -> >= -"- % maxit iteration limit (default: 10000) % printlvl if > 0, iteration information is printed % % output arguments: x solution if status = 0 % lambda multipliers for linear constraints % mu multipliers for bounds (one per variable) % status = 0 optimal solution found % = 1 problem infeasible % = 2 problem unbounded % = 3 iteration limit reached % it(1) number of iterations in Phase I % it(2) number of iterations in Phase II % % NB: * Calls subroutine "simple". % * Handles sparse matrices properly. % * Use column vectors. % % CAUTION: No anti-cycling strategy employed! % % Author: Stefan Feltenmark % Optimization & Systems Theory % Dept. of Mathematics, KTH % SE-100 44 Stockholm % % (1999/09/10) % % Revisions: % 990312 added mu as output, removed basis % 060322 fixed bug sign of lambda with negative rhs, UB % Tolerance to define e.g. zero tol = sqrt(eps); MAXIT = 10000; % problem dimensions [m,n] = size(A); % Defaults if nargin < 4 | isempty(l), l = zeros(n,1); end if nargin < 5 | isempty(u), u = inf*ones(n,1); end if nargin < 6 | isempty(sense), sense = zeros(m,1); end if nargin < 7 | isempty(maxit), maxit = MAXIT; end if nargin < 8 | isempty(printlvl), printlvl = 0; end % Check sizes if any( size(c) ~= [n 1]) | ... any( size(b) ~= [m 1]) | ... any( size(l) ~= [n 1]) | ... any( size(u) ~= [n 1]) | ... any( size(sense) ~= [m 1]), whos c A b l u sense error('Wrong input data dimensions: check above'); end % Check bounds if any( u-l <= -tol ), error('There are bounds with l > u'); end %%%%% Convert bounds to general constraints % Reverse negative unbounded variables: % l= -inf, u < inf => l = -u, u = inf m1 = m; n1 = n; rev = find(l <= -inf); revub = find( u(rev) <= inf ); reversed = []; if ~isempty(revub), reversed = rev(revub); l(reversed) = -u(reversed); u(reversed) = inf*ones(size(reversed)); c(reversed) = -c(reversed); A(:,reversed) = -A(:,reversed); if printlvl > 0, disp(sprintf('ALPS: Reversed %5d variables',length(revub))); end end % Replace free variables with diff. of two positive: % x free (l = -inf, u = inf) => x = x+ - x-, l- = l+ = 0, u- = u+ = inf nub = find( l <= -inf ); nubfree = find( u(nub) >= inf ); free = nub(nubfree); if ~isempty(free), % add columns for negative variables A = [A -A(:,free)]; c = [c' -c(free)']'; l(free) = zeros(size(free)); l = [l ; zeros(size(free))]; u = [u ; inf*ones(size(free))]; n1 = n1 + length(free); if printlvl > 0, disp(sprintf('ALPS: Replaced %5d free variables',length(free))); end end % Now all variables have finite lower bounds. % Translate by l > -inf: x := x-l, u : = u-l, l := 0, b = b - A*l; u = u - l; % Now all variables have lower bound 0. % Transform finite upper bounds to general inequality % constraints: fub = find( u < inf); if ~isempty(fub), lfub = length(fub); A1 = sparse(lfub, n1); A1(:,fub) = speye(lfub); A = [A ; A1]; sense = [sense' ones(1,lfub)]; b = [b' u(fub)']'; m1 = m1 + lfub; u(fub) = inf*ones(lfub,1); if printlvl > 0, disp(sprintf('ALPS: %5d upper bounded variables',lfub)); end end % Add slack eq = find( sense == 0 ); le = find( sense == 1 ); ge = find( sense == 2 ); I = speye(m1); A = [A I(:,le) -I(:,ge)]; lle = length(le); lge = length(ge); c = [c ; zeros(lle,1) ; zeros(lge,1)]; if printlvl > 0, disp(sprintf('ALPS: # slack vars.: %d # surplus vars.: %d',lle,lge)); end % Reverse sign to get b >= 0 as required by % simple: negind = find(b < -tol); A(negind,:) = -A(negind,:); b(negind) = -b(negind); %%% Now problem is on standard form: solve with simple! [x,z,lambda,basis,status,it] = simple(c,A,b,[],printlvl,maxit); %%% compute multipliers for bounds mu = zeros(n,1); %%% compute reduced costs cbar = c - A'*lambda; mu = cbar(1:n); %% lambda for upper bound constraints; if ~isempty(fub), lamub = lambda(m1-lfub+1:m1); ind = find(lamub < -tol); mu(fub(ind)) = lamub(ind); end %%%% Transform problem back to original form % reverse sign back A(negind,:) = -A(negind,:); b(negind) = -b(negind); % strip slack variables A = A(:,1:n1); c = c(1:n1); x = x(1:n1); % strip upper bound rows A = A(1:m,:); b = b(1:m); lambda = lambda(1:m); lambda(negind) = -lambda(negind); % add on lower bounds x = x + l; % reconvert free variables lfree = length(free); if lfree > 0, x(free) = x(free) - x((n+1):(n+lfree)); end x = x(1:n); % unreverse variables x(reversed) = -x(reversed);