% % Optical Imaging and Spectroscopy % % David J. Brady % Duke University % www.opticalimaging.org % % function [x,w] = nnls(A,b,tol) % function [x,w] = nnls(A,b,tol) % NNLS Non-negative least-squares. % % x = nnls(A,b) returns the vector X that solves x = pinv(A)*b % in a least squares sense, subject to x >= 0. % Differently stated it solves the problem min ||y - Xx|| if % A = X'*X and b = X'*y. % % A default tolerance of TOL = MAX(SIZE(A)) * NORM(A,1) * EPS % is used for deciding when elements of x are less than zero. % This can be overridden with x = nnls(A,b,TOL). % % [x,w] = nnls(A,b) also returns dual vector w where % w(i) < 0 where x(i) = 0 and w(i) = 0 where x(i) > 0. % Adapted from NNLS of Mathworks, Inc. % % L. Shure 5-8-87 % Revised, 12-15-88,8-31-89 LS. % (Partly) Copyright (c) 1984-94 by The MathWorks, Inc. % Modified by R. Bro 5-7-96 according to % Bro R., de Jong S., Journal of Chemometrics, 1997, 11, 393-401 % Corresponds to the FNNLSa algorithm in the paper % % Modified by N. P. Pitsianis 9/23/04 % to accomodate rectangular matrices, % cleanup the handling of the zero and non-zero index sets. % Reference: % Lawson and Hanson, "Solving Least Squares Problems", Prentice-Hall, 1974. % initialize variables if nargin < 3 tol = 10*eps*norm(A,1)*max(size(A)); end [m,n] = size(A); % if m ~= n b = A'*b; A = A'*A; % end x = zeros(n,1); r = b-A*x; P = zeros(n,1); z = zeros(n,1); Z = 1:n; ZZ = 1:n; % set up iteration criterion iter = 0; itmax = 30*n; % outer loop to put variables into set to hold positive coefficients while any(Z) & any(r(ZZ) > tol) [rt,t] = max(r(ZZ)); t = ZZ(t); P(t) = t; Z(t) = 0; PP = find(P); ZZ = find(Z); z(PP) = A(PP,PP) \ b(PP); z(ZZ) = 0; % inner loop to remove elements from the positive set which no longer belong while any((z(PP) <= tol)) & iter < itmax iter = iter + 1; QQ = find((z <= tol) & P); alpha = min(x(QQ)./(x(QQ) - z(QQ))); x = x + alpha*(z - x); ij = find(abs(x) < tol & P); Z(ij) = ij'; P(ij) = 0; PP = find(P); ZZ = find(Z); z(PP) = A(PP,PP) \ b(PP); z(ZZ) = 0; end x = z; r = b-A*x; end