⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spgl1.m

📁 Spectral Projected L1 solver
💻 M
📖 第 1 页 / 共 2 页
字号:
function [x,r,g,info] = spgl1( A, b, tau, sigma, x, options )%SPGL1  Solve basis pursuit, basis pursuit denoise, and LASSO%% [x, r, g, info] = spgl1(A, b, tau, sigma, x0, options)%% ---------------------------------------------------------------------% Solve the basis pursuit denoise (BPDN) problem%% (BPDN)   minimize  ||x||_1  subj to  ||Ax-b||_2 <= sigma,%% or the l1-regularized least-squares problem%% (LASSO)  minimize  ||Ax-b||_2  subj to  ||x||_1 <= tau.% ---------------------------------------------------------------------%% INPUTS% ======% A        is an m-by-n matrix, explicit or an operator.%          If A is a function, then it must have the signature%%          y = A(x,mode)   if mode == 1 then y = A x  (y is m-by-1);%                          if mode == 2 then y = A'x  (y is n-by-1).%% b        is an m-vector.% tau      is a nonnegative scalar; see (LASSO).% sigma    if sigma != inf or != [], then spgl1 will launch into a%          root-finding mode to find the tau above that solves (BPDN).%          In this case, it's STRONGLY recommended that tau = 0.% x0       is an n-vector estimate of the solution (possibly all%          zeros). If x0 = [], then SPGL1 determines the length n via%          n = length( A'b ) and sets  x0 = zeros(n,1).% options  is a structure of options from spgSetParms. Any unset options%          are set to their default value; set options=[] to use all%          default values.%% OUTPUTS% =======% x        is a solution of the problem% r        is the residual, r = b - Ax% g        is the gradient, g = -A'r% info     is a structure with the following information:%          .tau     final value of tau (see sigma above)%          .rNorm   two-norm of the optimal residual%          .rGap    relative duality gap (an optimality measure)%          .gNorm   Lagrange multiplier of (LASSO)%          .stat    = 1 found a BPDN solution%                   = 2 found a BP sol'n; exit based on small gradient%                   = 3 found a BP sol'n; exit based on small residual%                   = 4 found a LASSO solution%                   = 5 error: too many iterations%                   = 6 error: linesearch failed%                   = 7 error: found suboptimal BP solution%                   = 8 error: too many matrix-vector products%          .time    total solution time (seconds)%          .nProdA  number of multiplications with A%          .nProdAt number of multiplications with A'%% OPTIONS% =======% Use the options structure to control various aspects of the algorithm:%% options.fid         File ID to direct log output%        .verbosity   0=quiet, 1=some output, 2=more output.%        .iterations  Max. number of iterations (default if 10*m).%        .bpTol       Tolerance for identifying a basis pursuit solution.%        .optTol      Optimality tolerance (default is 1e-4).%        .decTol      Larger decTol means more frequent Newton updates.%        .subspaceMin 0=no subspace minimization, 1=subspace minimization.%% EXAMPLE% =======%   m = 120; n = 512; k = 20; % m rows, n cols, k nonzeros.%   p = randperm(n); x0 = zeros(n,1); x0(p(1:k)) = sign(randn(k,1));%   A  = randn(m,n); [Q,R] = qr(A',0);  A = Q';%   b  = A*x0 + 0.005 * randn(m,1);%   opts = spgSetParms('optTol',1e-4);%   [x,r,g,info] = spgl1(A, b, 0, 1e-3, [], opts); % Find BP sol'n.%% AUTHORS% =======%  Ewout van den Berg (ewout78@cs.ubc.ca)%  Michael P. Friedlander (mpf@cs.ubc.ca)%    Scientific Computing Laboratory (SCL)%    University of British Columbia, Canada.%% BUGS% ====% Please send bug reports or comments to%            Michael P. Friedlander (mpf@cs.ubc.ca)%            Ewout van den Berg (ewout78@cs.ubc.ca)% 15 Apr 07: First version derived from spg.m.%            Michael P. Friedlander (mpf@cs.ubc.ca).%            Ewout van den Berg (ewout78@cs.ubc.ca).% 17 Apr 07: Added root-finding code.% 18 Apr 07: sigma was being compared to 1/2 r'r, rather than%            norm(r), as advertised.  Now immediately change sigma to%            (1/2)sigma^2, and changed log output accordingly.% 24 Apr 07: Added quadratic root-finding code as an option.% 24 Apr 07: Exit conditions need to guard against small ||r||%            (ie, a BP solution).  Added test1,test2,test3 below.% 15 May 07: Trigger to update tau is now based on relative difference%            in objective between consecutive iterations.% 15 Jul 07: Added code to allow a limited number of line-search%            errors. % 23 Feb 08: Fixed bug in one-norm projection using weights. Thanks%            to Xiangrui Meng for reporting this bug.% 26 May 08: The simple call spgl1(A,b) now solves (BPDN) with sigma=0.    %   spgl1.m%   $Id: spgl1.m 1079 2008-08-20 21:34:15Z ewout78 $%%   ----------------------------------------------------------------------%   This file is part of SPGL1 (Spectral Projected-Gradient for L1).%%   Copyright (C) 2007 Ewout van den Berg and Michael P. Friedlander,%   Department of Computer Science, University of British Columbia, Canada.%   All rights reserved. E-mail: <{ewout78,mpf}@cs.ubc.ca>.%%   SPGL1 is free software; you can redistribute it and/or modify it%   under the terms of the GNU Lesser General Public License as%   published by the Free Software Foundation; either version 2.1 of the%   License, or (at your option) any later version.%%   SPGL1 is distributed in the hope that it will be useful, but WITHOUT%   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY%   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General%   Public License for more details.%%   You should have received a copy of the GNU Lesser General Public%   License along with SPGL1; if not, write to the Free Software%   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301%   USA%   ----------------------------------------------------------------------REVISION = '$Revision: 1017 $';DATE     = '$Date: 2008-06-16 22:43:07 -0700 (Mon, 16 Jun 2008) $';REVISION = REVISION(11:end-1);DATE     = DATE(35:50);tic;              % Start your watches!m = length(b);%----------------------------------------------------------------------% Check arguments. %----------------------------------------------------------------------if ~exist('options','var'), options = []; endif ~exist('x','var'), x = []; endif ~exist('sigma','var'), sigma = []; endif ~exist('tau','var'), tau = []; endif nargin < 2 || isempty(b) || isempty(A)   error('At least two arguments are required');elseif isempty(tau) && isempty(sigma)   tau = 0;   sigma = 0;   singleTau = false;elseif isempty(sigma) % && ~isempty(tau)  <-- implied   singleTau = true;else   if isempty(tau)      tau = 0;   end   singleTau = false;end%----------------------------------------------------------------------% Grab input options and set defaults where needed. %----------------------------------------------------------------------defaultopts = spgSetParms(...'fid'        ,      1 , ... % File ID for output'verbosity'  ,      2 , ... % Verbosity level'iterations' ,   10*m , ... % Max number of iterations'nPrevVals'  ,      3 , ... % Number previous func values for linesearch'bpTol'      ,  1e-06 , ... % Tolerance for basis pursuit solution 'optTol'     ,  1e-04 , ... % Optimality tolerance'decTol'     ,  1e-04 , ... % Req'd rel. change in primal obj. for Newton'stepMin'    ,  1e-16 , ... % Minimum spectral step'stepMax'    ,  1e+05 , ... % Maximum spectral step'rootMethod' ,      2 , ... % Root finding method: 2=quad,1=linear (not used).'activeSetIt',    Inf , ... % Exit with EXIT_ACTIVE_SET if nnz same for # its.'subspaceMin',      0 , ... % Use subspace minimization'iscomplex'  ,    NaN , ... % Flag set to indicate complex problem'maxMatvec'  ,    Inf , ... % Maximum matrix-vector multiplies allowed'weights'    ,      1 , ... % Weights W in ||Wx||_1'project'    , @NormL1_project , ...'primal_norm', @NormL1_primal  , ...'dual_norm'  , @NormL1_dual      ...   );options = spgSetParms(defaultopts, options);fid           = options.fid;logLevel      = options.verbosity;maxIts        = options.iterations;nPrevVals     = options.nPrevVals;bpTol         = options.bpTol;optTol        = options.optTol;decTol        = options.decTol;stepMin       = options.stepMin;stepMax       = options.stepMax;activeSetIt   = options.activeSetIt;subspaceMin   = options.subspaceMin;maxMatvec     = max(3,options.maxMatvec);weights       = options.weights;maxLineErrors = 10;     % Maximum number of line-search failures.pivTol        = 1e-12;  % Threshold for significant Newton step.%----------------------------------------------------------------------% Initialize local variables.%----------------------------------------------------------------------iter          = 0;  itnTotLSQR = 0; % Total SPGL1 and LSQR iterations.nProdA        = 0;  nProdAt    = 0;lastFv        = -inf(nPrevVals,1);  % Last m function values.nLineTot      = 0;                  % Total no. of linesearch steps.printTau      = false;nNewton       = 0;bNorm         = norm(b,2);stat          = false;timeProject   = 0;timeMatProd   = 0;nnzIter       = 0;                  % No. of its with fixed pattern.nnzIdx        = [];                 % Active-set indicator.subspace      = false;              % Flag if did subspace min in current itn.stepG         = 1;                  % Step length for projected gradient.testUpdateTau = 0;                  % Previous step did not update tau% Determine initial x, vector length n, and see if problem is complexexplicit = ~(isa(A,'function_handle'));if isempty(x)   if isnumeric(A)      n = size(A,2);      realx = isreal(A) && isreal(b);   else      x = Aprod(b,2);      n = length(x);      realx = isreal(x) && isreal(b);   end   x = zeros(n,1);else   n     = length(x);   realx = isreal(x) && isreal(b);endif isnumeric(A), realx = realx && isreal(A); end;% Override options when options.iscomplex flag is setif (~isnan(options.iscomplex)), realx = (options.iscomplex == 0); end% Check if all weights (if any) are strictly positive. In previous% versions we also checked if the number of weights was equal to% n. In the case of multiple measurement vectors, this no longer% needs to apply, so the check was removed.if ~isempty(weights)  if any(~isfinite(weights))     error('Entries in options.weights must be finite');  end  if any(weights <= 0)     error('Entries in options.weights must be strictly positive');  endelse  weights = 1;end% Quick exit if sigma >= ||b||.  Set tau = 0 to short-circuit the loop.if bNorm <= sigma   printf('W: sigma >= ||b||.  Exact solution is x = 0.\n');   tau = 0;  singleTau = true;end   % Don't do subspace minimization if x is complex.if ~realx && subspaceMin   printf('W: Subspace minimization disabled when variables are complex.\n');   subspaceMin = false;end% Pre-allocate iteration info vectorsxNorm1 = zeros(min(maxIts,10000),1);rNorm2 = zeros(min(maxIts,10000),1);lambda = zeros(min(maxIts,10000),1);% Exit conditions (constants).EXIT_ROOT_FOUND    = 1;EXIT_BPSOL1_FOUND  = 2;EXIT_BPSOL2_FOUND  = 3;EXIT_OPTIMAL       = 4;EXIT_ITERATIONS    = 5;EXIT_LINE_ERROR    = 6;EXIT_SUBOPTIMAL_BP = 7;EXIT_MATVEC_LIMIT  = 8;EXIT_ACTIVE_SET    = 9; % [sic]%----------------------------------------------------------------------% Log header.%----------------------------------------------------------------------printf('\n');printf(' %s\n',repmat('=',1,80));printf(' SPGL1  v.%s (%s)\n', REVISION, DATE);printf(' %s\n',repmat('=',1,80));printf(' %-22s: %8i %4s'   ,'No. rows'          ,m       ,'');printf(' %-22s: %8i\n'     ,'No. columns'       ,n          );printf(' %-22s: %8.2e %4s' ,'Initial tau'       ,tau     ,'');printf(' %-22s: %8.2e\n'   ,'Two-norm of b'     ,bNorm      );printf(' %-22s: %8.2e %4s' ,'Optimality tol'    ,optTol  ,'');if singleTau   printf(' %-22s: %8.2e\n'  ,'Target one-norm of x'  ,tau       );else   printf(' %-22s: %8.2e\n','Target objective'  ,sigma      );endprintf(' %-22s: %8.2e %4s' ,'Basis pursuit tol' ,bpTol   ,'');printf(' %-22s: %8i\n'     ,'Maximum iterations',maxIts     );printf('\n');if singleTau   logB = ' %5i  %13.7e  %13.7e  %9.2e  %6.1f  %6i  %6i';   logH = ' %5s  %13s  %13s  %9s  %6s  %6s  %6s\n';   printf(logH,'Iter','Objective','Relative Gap','gNorm','stepG','nnzX','nnzG');else   logB = ' %5i  %13.7e  %13.7e  %9.2e  %9.3e  %6.1f  %6i  %6i';   logH = ' %5s  %13s  %13s  %9s  %9s  %6s  %6s  %6s  %13s\n';   printf(logH,'Iter','Objective','Relative Gap','Rel Error',...          'gNorm','stepG','nnzX','nnzG','tau');end        % Project the starting point and evaluate function and gradient.x         = project(x,tau);r         = b - Aprod(x,1);  % r = b - Axg         =   - Aprod(r,2);  % g = -A'rf         = r'*r / 2; % Required for nonmonotone strategy.lastFv(1) = f;fBest     = f;xBest     = x;fOld      = f;% Compute projected gradient direction and initial steplength.dx     = project(x - g, tau) - x;dxNorm = norm(dx,inf);if dxNorm < (1 / stepMax)   gStep = stepMax;else   gStep = min( stepMax, max(stepMin, 1/dxNorm) );end%----------------------------------------------------------------------% MAIN LOOP.%----------------------------------------------------------------------while 1        %------------------------------------------------------------------    % Test exit conditions.    %------------------------------------------------------------------    % Compute quantities needed for log and exit conditions.    gNorm   = options.dual_norm(g,weights);    rNorm   = norm(r, 2);    gap     = r'*(r-b) + tau*gNorm;    rGap    = abs(gap) / max(1,f);    aError1 = rNorm - sigma;    aError2 = f - sigma^2 / 2;    rError1 = abs(aError1) / max(1,rNorm);    rError2 = abs(aError2) / max(1,f);    % Count number of consecutive iterations with identical support.    nnzOld = nnzIdx;    [nnzX,nnzG,nnzIdx,nnzDiff] = activeVars(x,g,nnzIdx,options);    if nnzDiff       nnzIter = 0;    else       nnzIter = nnzIter + 1;       if nnzIter >= activeSetIt, stat=EXIT_ACTIVE_SET; end    end        % Single tau: Check if we're optimal.    % The 2nd condition is there to guard against large tau.    if singleTau       if rGap <= optTol || rNorm < optTol*bNorm          stat  = EXIT_OPTIMAL;       end     % Multiple tau: Check if found root and/or if tau needs updating.    else              if rGap <= max(optTol, rError2) || rError1 <= optTol          % The problem is nearly optimal for the current tau.          % Check optimality of the current root.          test1 = rNorm       <=   bpTol * bNorm;          test2 = gNorm       <=   bpTol * rNorm;          test3 = rError1     <=  optTol;          test4 = rNorm       <=  sigma;                    if test4, stat=EXIT_SUBOPTIMAL_BP;end % Found suboptimal BP sol.          if test3, stat=EXIT_ROOT_FOUND;   end % Found approx root.          if test2, stat=EXIT_BPSOL2_FOUND; end % Gradient zero -> BP sol.          if test1, stat=EXIT_BPSOL1_FOUND; end % Resid minim'zd -> BP sol.       end       testRelChange1 = (abs(f - fOld) <= decTol * f);       testRelChange2 = (abs(f - fOld) <= 1e-1 * f * (abs(rNorm - sigma)));       testUpdateTau  = ((testRelChange1 && rNorm >  2 * sigma) || ...                         (testRelChange2 && rNorm <= 2 * sigma)) && ...                         ~stat && ~testUpdateTau;       if testUpdateTau          % Update tau.          tauOld   = tau;          tau      = max(0,tau + (rNorm * aError1) / gNorm);          nNewton  = nNewton + 1;          printTau = abs(tauOld - tau) >= 1e-6 * tau; % For log only.          if tau < tauOld             % The one-norm ball has decreased.  Need to make sure that the             % next iterate if feasible, which we do by projecting it.             x = project(x,tau);          end       end    end    % Too many its and not converged.    if ~stat  &&  iter >= maxIts        stat = EXIT_ITERATIONS;    end    %------------------------------------------------------------------    % Print log, update history and act on exit conditions.    %------------------------------------------------------------------    if logLevel >= 2 || singleTau || printTau || iter == 0 || stat       tauFlag = '              '; subFlag = '';       if printTau, tauFlag = sprintf(' %13.7e',tau);   end       if subspace, subFlag = sprintf(' S %2i',itnLSQR); end       if singleTau          printf(logB,iter,rNorm,rGap,gNorm,log10(stepG),nnzX,nnzG);          if subspace             printf('  %s',subFlag);          end       else          printf(logB,iter,rNorm,rGap,rError1,gNorm,log10(stepG),nnzX,nnzG);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -