function [x,z,u,basic,status,it] = simple(c,A,b,basic,printlvl,maxit) % % SIMPLE - linear programming by the primal simplex method. % % Assumes problem on standard form: % % minimize c'x % s.t. Ax = b (b >= 0) % x >= 0 % % Calling syntax: % [x,z,u,basis,status,it] = simple(c,A,b,basic,printlvl,maxit) % % Input: c - cost vector % A - constraint matrix % b - right-hand side % basic - variable index for initial basis (optional) % printlvl - if > 0, output is printed (optional) % maxit - iteration limit (optional) % % Output: x - primal solution % z - objective value % u - dual solution % basis - indices corr. to final basic solution % % status = 0 optimal solution found % = 1 no feasible solution found % = 2 unbounded problem % = 3 iteration limit reached % % it(1) - number of iterations in Phase I % it(2) - number of iterations in Phase II % % CAUTION: No anti-cycling strategy employed! % Please see documentation and comments in code for details. % % Author: Stefan Feltenmark % Optimization & Systems Theory % Dept. of Mathematics, KTH % SE-100 44 Stockholm % % Last modified 2000/04/27 by SF % % % % Constants % tol = sqrt(eps); MAXIT = 1000; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% [m1,n]=size(A); m = m1; if( nargin < 6) maxit = MAXIT; end % % Check input data % if m > n, error('Overdetermined system (unless rank deficient): Use x = A\b instead!'); end %if if length(c) ~= n | length(b) ~= m, error('Data of incompatible size'); end % if if any(b < -tol), error('Right-hand side must be non-negative.'); end % Default printlvl = 0 if nargin <= 4, printlvl = 0; end if printlvl > 0, disp(sprintf('SIMPLE execution begins.')); end % % Check suggested start basis % if nargin > 3 B = A(:,basic); % a bit coarse but short... if rank(full(B)) == m, Bi = inv(B); y0 = Bi*b; if y0 >= 0, phase = 2; q = zeros(n,1); q(basic) = ones(m,1); nonbasic = find(~q); else if printlvl > 0, disp('Initial basis not feasible!'); end % if phase = 1; end % if else if printlvl > 0, disp('Initial basis not invertible...doing phase I'); end % if phase = 1; end % if else phase = 1; end % if if phase == 1, cc = c; c = [zeros(n,1) ; ones(m,1)]; A = [ A speye(m)]; B = speye(m); Bi = B; nonbasic = (1:n)'; basic = n+1:n+m'; y0 = b; z = c(basic)'*y0; end % if rows = 1:m; % number of rows may decrease ndel = 0; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % Iterate until some termination criteria satisfied % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% it = 0; it1 = 0; it2 = 0; while 1, % % Same loop both phases % if printlvl > 0, disp(sprintf('Phase %d',phase)); disp(sprintf(' It out in red. cost step objective')); end % rowcnt = 0; while it < maxit, it = it + 1; if printlvl > 0 & rowcnt == 20, disp(sprintf(' It out in red. cost step objective')); rowcnt = 0; end % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % Compute dual solution and reduced costs % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% u = c(basic)'*Bi; r = c(nonbasic)' - u*A(rows,nonbasic); % fix if phase == 1, artind = find(nonbasic > n); r(artind) = 1.0; end % Leaving variable index i = 0; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % Determine entering variable % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% nind = find(r < -tol); if ~isempty(nind), % Dantzig's rule [rj,j]=min(r); j = j(1); % Steepest edge pricing %Y = Bi*A(rows,nonbasic); %nd = sqrt(1+diag( Y'*Y )); %[rj,j]=min(r'./nd); %j = j(1); elseif phase == 1, % Infeasibility left? Then (primal) problem infeasible. if( z > tol ) flag = 1; break; end % Are there artificial variables left? artind = find( basic > n ); if ~isempty( artind ), % % Find original variables that can be pivoted into the basis % or conclude that there are redundant equations. % ind = find( nonbasic' <= n ); if isempty( ind ), % This cannot happen since we check m <= n flag = 1; break; else % % Check if we can replace artificial variables % with original ones, and still maintain a bfs. % Y = Bi*A(rows,nonbasic(ind)); Y = Y(artind,:); j = 0; for k = 1:length( artind ), for l = 1:length(ind), if abs(Y(k,l)) > tol, % Choose l'th nonbasic to enter j = ind(l); % Choose k'th basic artificial to leave i = artind(k); break; end % if end % for l if j > 0, break; else % We can cross out a row! col = artind(k); row = basic(col)-n; % row = find(row == rows); if printlvl > 0, disp(sprintf('Linear dependence detected: deleting row %d.',rows(col))); end % Delete row index rows(row:m-1) = rows(row+1:m); rows = rows(1:m-1); % Delete from list of basics basic(col:m-1) = basic(col+1:m); basic = basic(1:m-1); % Can cross out row/column in Bi! Bi = Bi([1:col-1 col+1:m], [1:row-1 row+1:m]); % position of artificial variables in basic is shifted artind(k:length(artind)) = artind(k:length(artind)) - 1; % Delete from y0 y0(col:m-1) = y0(col+1:m); y0 = y0(1:m-1); m = m - 1; ndel = ndel + 1; end % if end % for k if j == 0, flag = 0; break; end % if end % if ind else % no artificial variables left in basis! flag = 0; break; end % if artind else % optimal solution found! flag = 0; break; end % if %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % Determine leaving variable % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% yj = Bi*A(rows,nonbasic(j)); if i == 0, pind = find(yj > tol); if isempty( pind ), % Problem unbounded! flag = 2; break; end % if % % Max steplength, and basics that hit zero % [alpha,i] = min( y0(pind)./yj(pind) ); i = pind(i); i = i(1); else alpha = 0; end % if % Update solution. y0 = y0 - alpha*yj; y0(i) = alpha; % Update basis. temp = basic(i); basic(i) = nonbasic(j); nonbasic(j) = temp; piv = yj(i); yj(i) = piv-1; Bi = Bi-(yj./piv)*Bi(i,:); % M = speye(size(Bi)); % M(:,i) = -yj./yj(i); % M(i,i) = 1/yj(i); % Pivot % Bi = M*Bi; z = c(basic)'*y0; if printlvl > 0, disp(sprintf('%4.0d %4.0d %4.0d %12.3f %12.3f %12.3f', ... it,nonbasic(j),basic(i),rj,alpha,z)); rowcnt = rowcnt + 1; end % if end % while if it >= maxit, flag = 3; end % if if flag == 0, if phase == 1, it1 = it; phase = 2; c = cc; q = zeros(n,1); q(basic) = ones(m,1); nonbasic = find(~q); else it2 = it - it1; if printlvl > 0, disp('Solution is optimal.'); end % if x = zeros(n,1); x(basic) = y0; z = c'*x; status = 0; break; end % if elseif flag == 1, if printlvl > 0, disp('Problem infeasible.'); end % if x = zeros(n,1); x(basic) = y0; z = Inf; status = 1; it1 = it; break; elseif flag == 2, if printlvl > 0, disp('Problem unbounded.'); end % if x = zeros(n,1); x(basic) = yj; x(j) = 1; z = -Inf; status = 2; it2 = it-it1; break; elseif flag == 3, if printlvl > 0, disp('Iteration limit reached.'); end % if x = zeros(n,1); if phase == 1, it1 = it; ind = find(basic <= n); x(basic(ind)) = y0(ind); z = c(basic)'*y0; basic = basic(ind); else x(basic) = y0; z = c'*x; it2 = it-it1; end status = 3; break; end % if end % while % assign output arguments it = [it1 it2]'; % consider case when rows deleted u1 = zeros(m1,1); u1(rows) = u; u = u1; if printlvl > 0, disp(sprintf('SIMPLE execution finished.')); end