annotate matlab/NESTA/NESTA.m @ 56:de6299dcb49e

Changed directory structure - part 5
author nikcleju
date Wed, 14 Dec 2011 14:51:35 +0000
parents 7524d7749456
children
rev   line source
nikcleju@45 1 function [xk,niter,residuals,outputData,opts] =NESTA(A,At,b,muf,delta,opts)
nikcleju@45 2 % [xk,niter,residuals,outputData] =NESTA(A,At,b,muf,delta,opts)
nikcleju@45 3 %
nikcleju@45 4 % Solves a L1 minimization problem under a quadratic constraint using the
nikcleju@45 5 % Nesterov algorithm, with continuation:
nikcleju@45 6 %
nikcleju@45 7 % min_x || U x ||_1 s.t. ||y - Ax||_2 <= delta
nikcleju@45 8 %
nikcleju@45 9 % Continuation is performed by sequentially applying Nesterov's algorithm
nikcleju@45 10 % with a decreasing sequence of values of mu0 >= mu >= muf
nikcleju@45 11 %
nikcleju@45 12 % The primal prox-function is also adapted by accounting for a first guess
nikcleju@45 13 % xplug that also tends towards x_muf
nikcleju@45 14 %
nikcleju@45 15 % The observation matrix A is a projector
nikcleju@45 16 %
nikcleju@45 17 % Inputs: A and At - measurement matrix and adjoint (either a matrix, in which
nikcleju@45 18 % case At is unused, or function handles). m x n dimensions.
nikcleju@45 19 % b - Observed data, a m x 1 array
nikcleju@45 20 % muf - The desired value of mu at the last continuation step.
nikcleju@45 21 % A smaller mu leads to higher accuracy.
nikcleju@45 22 % delta - l2 error bound. This enforces how close the variable
nikcleju@45 23 % must fit the observations b, i.e. || y - Ax ||_2 <= delta
nikcleju@45 24 % If delta = 0, enforces y = Ax
nikcleju@45 25 % Common heuristic: delta = sqrt(m + 2*sqrt(2*m))*sigma;
nikcleju@45 26 % where sigma=std(noise).
nikcleju@45 27 % opts -
nikcleju@45 28 % This is a structure that contains additional options,
nikcleju@45 29 % some of which are optional.
nikcleju@45 30 % The fieldnames are case insensitive. Below
nikcleju@45 31 % are the possible fieldnames:
nikcleju@45 32 %
nikcleju@45 33 % opts.xplug - the first guess for the primal prox-function, and
nikcleju@45 34 % also the initial point for xk. By default, xplug = At(b)
nikcleju@45 35 % opts.U and opts.Ut - Analysis/Synthesis operators
nikcleju@45 36 % (either matrices of function handles).
nikcleju@45 37 % opts.normU - if opts.U is provided, this should be norm(U)
nikcleju@45 38 % otherwise it will have to be calculated (potentially
nikcleju@45 39 % expensive)
nikcleju@45 40 % opts.MaxIntIter - number of continuation steps.
nikcleju@45 41 % default is 5
nikcleju@45 42 % opts.maxiter - max number of iterations in an inner loop.
nikcleju@45 43 % default is 10,000
nikcleju@45 44 % opts.TolVar - tolerance for the stopping criteria
nikcleju@45 45 % opts.stopTest - which stopping criteria to apply
nikcleju@45 46 % opts.stopTest == 1 : stop when the relative
nikcleju@45 47 % change in the objective function is less than
nikcleju@45 48 % TolVar
nikcleju@45 49 % opts.stopTest == 2 : stop with the l_infinity norm
nikcleju@45 50 % of difference in the xk variable is less
nikcleju@45 51 % than TolVar
nikcleju@45 52 % opts.TypeMin - if this is 'L1' (default), then
nikcleju@45 53 % minimizes a smoothed version of the l_1 norm.
nikcleju@45 54 % If this is 'tv', then minimizes a smoothed
nikcleju@45 55 % version of the total-variation norm.
nikcleju@45 56 % The string is case insensitive.
nikcleju@45 57 % opts.Verbose - if this is 0 or false, then very
nikcleju@45 58 % little output is displayed. If this is 1 or true,
nikcleju@45 59 % then output every iteration is displayed.
nikcleju@45 60 % If this is a number p greater than 1, then
nikcleju@45 61 % output is displayed every pth iteration.
nikcleju@45 62 % opts.fid - if this is 1 (default), the display is
nikcleju@45 63 % the usual Matlab screen. If this is the file-id
nikcleju@45 64 % of a file opened with fopen, then the display
nikcleju@45 65 % will be redirected to this file.
nikcleju@45 66 % opts.errFcn - if this is a function handle,
nikcleju@45 67 % then the program will evaluate opts.errFcn(xk)
nikcleju@45 68 % at every iteration and display the result.
nikcleju@45 69 % ex. opts.errFcn = @(x) norm( x - x_true )
nikcleju@45 70 % opts.outFcn - if this is a function handle,
nikcleju@45 71 % then then program will evaluate opts.outFcn(xk)
nikcleju@45 72 % at every iteration and save the results in outputData.
nikcleju@45 73 % If the result is a vector (as opposed to a scalar),
nikcleju@45 74 % it should be a row vector and not a column vector.
nikcleju@45 75 % ex. opts.outFcn = @(x) [norm( x - xtrue, 'inf' ),...
nikcleju@45 76 % norm( x - xtrue) / norm(xtrue)]
nikcleju@45 77 % opts.AAtinv - this is an experimental new option. AAtinv
nikcleju@45 78 % is the inverse of AA^*. This allows the use of a
nikcleju@45 79 % matrix A which is not a projection, but only
nikcleju@45 80 % for the noiseless (i.e. delta = 0) case.
nikcleju@45 81 % opts.USV - another experimental option. This supercedes
nikcleju@45 82 % the AAtinv option, so it is recommended that you
nikcleju@45 83 % do not define AAtinv. This allows the use of a matrix
nikcleju@45 84 % A which is not a projection, and works for the
nikcleju@45 85 % noisy ( i.e. delta > 0 ) case.
nikcleju@45 86 % opts.USV should contain three fields:
nikcleju@45 87 % opts.USV.U is the U from [U,S,V] = svd(A)
nikcleju@45 88 % likewise, opts.USV.S and opts.USV.V are S and V
nikcleju@45 89 % from svd(A). S may be a matrix or a vector.
nikcleju@45 90 %
nikcleju@45 91 % Outputs:
nikcleju@45 92 % xk - estimate of the solution x
nikcleju@45 93 % niter - number of iterations
nikcleju@45 94 % residuals - first column is the residual at every step,
nikcleju@45 95 % second column is the value of f_mu at every step
nikcleju@45 96 % outputData - a matrix, where each row r is the output
nikcleju@45 97 % from opts.outFcn, if supplied.
nikcleju@45 98 % opts - the structure containing the options that were used
nikcleju@45 99 %
nikcleju@45 100 % Written by: Jerome Bobin, Caltech
nikcleju@45 101 % Email: bobin@acm.caltech.edu
nikcleju@45 102 % Created: February 2009
nikcleju@45 103 % Modified (version 1.0): May 2009, Jerome Bobin and Stephen Becker, Caltech
nikcleju@45 104 % Modified (version 1.1): Nov 2009, Stephen Becker, Caltech
nikcleju@45 105 %
nikcleju@45 106 % NESTA Version 1.1
nikcleju@45 107 % See also Core_Nesterov
nikcleju@45 108
nikcleju@45 109
nikcleju@45 110 if nargin < 6, opts = []; end
nikcleju@45 111 if isempty(opts) && isnumeric(opts), opts = struct; end
nikcleju@45 112
nikcleju@45 113 %---- Set defaults
nikcleju@45 114 fid = setOpts('fid',1);
nikcleju@45 115 Verbose = setOpts('Verbose',true);
nikcleju@45 116 function printf(varargin), fprintf(fid,varargin{:}); end
nikcleju@45 117 MaxIntIter = setOpts('MaxIntIter',5,1);
nikcleju@45 118 TypeMin = setOpts('TypeMin','L1');
nikcleju@45 119 TolVar = setOpts('tolvar',1e-5);
nikcleju@45 120 [U,U_userSet] = setOpts('U', @(x) x );
nikcleju@45 121 if ~isa(U,'function_handle')
nikcleju@45 122 Ut = setOpts('Ut',[]);
nikcleju@45 123 else
nikcleju@45 124 Ut = setOpts('Ut', @(x) x );
nikcleju@45 125 end
nikcleju@45 126 xplug = setOpts('xplug',[]);
nikcleju@45 127 normU = setOpts('normU',[]); % so we can tell if it's been set
nikcleju@45 128
nikcleju@45 129 residuals = []; outputData = [];
nikcleju@45 130 AAtinv = setOpts('AAtinv',[]);
nikcleju@45 131 USV = setOpts('USV',[]);
nikcleju@45 132 if ~isempty(USV)
nikcleju@45 133 if isstruct(USV)
nikcleju@45 134 Q = USV.U; % we can't use "U" as the variable name
nikcleju@45 135 % since "U" already refers to the analysis operator
nikcleju@45 136 S = USV.S;
nikcleju@45 137 if isvector(S), s = S; %S = diag(s);
nikcleju@45 138 else s = diag(S); end
nikcleju@45 139 %V = USV.V;
nikcleju@45 140 else
nikcleju@45 141 error('opts.USV must be a structure');
nikcleju@45 142 end
nikcleju@45 143 end
nikcleju@45 144
nikcleju@45 145 % -- We can handle non-projections IF a (fast) routine for computing
nikcleju@45 146 % the psuedo-inverse is available.
nikcleju@45 147 % We can handle a nonzero delta, but we need the full SVD
nikcleju@45 148 if isempty(AAtinv) && isempty(USV)
nikcleju@45 149 % Check if A is a partial isometry, i.e. if AA' = I
nikcleju@45 150 z = randn(size(b));
nikcleju@45 151 if isa(A,'function_handle'), AAtz = A(At(z));
nikcleju@45 152 else AAtz = A*(A'*z); end
nikcleju@45 153 if norm( AAtz - z )/norm(z) > 1e-8
nikcleju@45 154 error('Measurement matrix A must be a partial isometry: AA''=I');
nikcleju@45 155 end
nikcleju@45 156 end
nikcleju@45 157
nikcleju@45 158 % -- Find a initial guess if not already provided.
nikcleju@45 159 % Use least-squares solution: x_ref = A'*inv(A*A')*b
nikcleju@45 160 % If A is a projection, the least squares solution is trivial
nikcleju@45 161 if isempty(xplug) || norm(xplug) < 1e-12
nikcleju@45 162 if ~isempty(USV) && isempty(AAtinv)
nikcleju@45 163 AAtinv = Q*diag( s.^(-2) )*Q';
nikcleju@45 164 end
nikcleju@45 165 if ~isempty(AAtinv)
nikcleju@45 166 if delta > 0 && isempty(USV)
nikcleju@45 167 error('delta must be zero for non-projections');
nikcleju@45 168 end
nikcleju@45 169 if isa(AAtinv,'function_handle')
nikcleju@45 170 x_ref = AAtinv(b);
nikcleju@45 171 else
nikcleju@45 172 x_ref = AAtinv * b;
nikcleju@45 173 end
nikcleju@45 174 else
nikcleju@45 175 x_ref = b;
nikcleju@45 176 end
nikcleju@45 177
nikcleju@45 178 if isa(A,'function_handle')
nikcleju@45 179 x_ref=At(x_ref);
nikcleju@45 180 else
nikcleju@45 181 x_ref = A'*x_ref;
nikcleju@45 182 end
nikcleju@45 183
nikcleju@45 184 if isempty(xplug)
nikcleju@45 185 xplug = x_ref;
nikcleju@45 186 end
nikcleju@45 187 % x_ref itself is used to calculate mu_0
nikcleju@45 188 % in the case that xplug has very small norm
nikcleju@45 189 else
nikcleju@45 190 x_ref = xplug;
nikcleju@45 191 end
nikcleju@45 192
nikcleju@45 193 % use x_ref, not xplug, to find mu_0
nikcleju@45 194 if isa(U,'function_handle')
nikcleju@45 195 Ux_ref = U(x_ref);
nikcleju@45 196 else
nikcleju@45 197 Ux_ref = U*x_ref;
nikcleju@45 198 end
nikcleju@45 199 switch lower(TypeMin)
nikcleju@45 200 case 'l1'
nikcleju@45 201 mu0 = 0.9*max(abs(Ux_ref));
nikcleju@45 202 case 'tv'
nikcleju@45 203 mu0 = ValMUTv(Ux_ref);
nikcleju@45 204 end
nikcleju@45 205
nikcleju@45 206 % -- If U was set by the user and normU not supplied, then calcuate norm(U)
nikcleju@45 207 if U_userSet && isempty(normU)
nikcleju@45 208 % simple case: U*U' = I or U'*U = I, in which case norm(U) = 1
nikcleju@45 209 z = randn(size(xplug));
nikcleju@45 210 if isa(U,'function_handle'), UtUz = Ut(U(z)); else UtUz = U'*(U*z); end
nikcleju@45 211 if norm( UtUz - z )/norm(z) < 1e-8
nikcleju@45 212 normU = 1;
nikcleju@45 213 else
nikcleju@45 214 z = randn(size(Ux_ref));
nikcleju@45 215 if isa(U,'function_handle')
nikcleju@45 216 UUtz = U(Ut(z));
nikcleju@45 217 else
nikcleju@45 218 UUtz = U*(U'*z);
nikcleju@45 219 end
nikcleju@45 220 if norm( UUtz - z )/norm(z) < 1e-8
nikcleju@45 221 normU = 1;
nikcleju@45 222 end
nikcleju@45 223 end
nikcleju@45 224
nikcleju@45 225 if isempty(normU)
nikcleju@45 226 % have to actually calculate the norm
nikcleju@45 227 if isa(U,'function_handle')
nikcleju@45 228 [normU,cnt] = my_normest(U,Ut,length(xplug),1e-3,30);
nikcleju@45 229 if cnt == 30, printf('Warning: norm(U) may be inaccurate\n'); end
nikcleju@45 230 else
nikcleju@45 231 [mU,nU] = size(U);
nikcleju@45 232 if mU < nU, UU = U*U'; else UU = U'*U; end
nikcleju@45 233 % last resort is to call MATLAB's "norm", which is slow
nikcleju@45 234 if norm( UU - diag(diag(UU)),'fro') < 100*eps
nikcleju@45 235 % this means the matrix is diagonal, so norm is easy:
nikcleju@45 236 normU = sqrt( max(abs(diag(UU))) );
nikcleju@45 237 elseif issparse(UU)
nikcleju@45 238 normU = sqrt( normest(UU) );
nikcleju@45 239 else
nikcleju@45 240 if min(size(U)) > 2000
nikcleju@45 241 % norm(randn(2000)) takes about 5 seconds on my PC
nikcleju@45 242 printf('Warning: calculation of norm(U) may be slow\n');
nikcleju@45 243 end
nikcleju@45 244 normU = sqrt( norm(UU) );
nikcleju@45 245 end
nikcleju@45 246 end
nikcleju@45 247 end
nikcleju@45 248 opts.normU = normU;
nikcleju@45 249 end
nikcleju@45 250
nikcleju@45 251
nikcleju@45 252 niter = 0;
nikcleju@45 253 Gamma = (muf/mu0)^(1/MaxIntIter);
nikcleju@45 254 mu = mu0;
nikcleju@45 255 Gammat= (TolVar/0.1)^(1/MaxIntIter);
nikcleju@45 256 TolVar = 0.1;
nikcleju@45 257
nikcleju@45 258 for nl=1:MaxIntIter
nikcleju@45 259
nikcleju@45 260 mu = mu*Gamma;
nikcleju@45 261 TolVar=TolVar*Gammat; opts.TolVar = TolVar;
nikcleju@45 262 opts.xplug = xplug;
nikcleju@45 263 if Verbose, printf('\tBeginning %s Minimization; mu = %g\n',opts.TypeMin,mu); end
nikcleju@45 264 [xk,niter_int,res,out,optsOut] = Core_Nesterov(...
nikcleju@45 265 A,At,b,mu,delta,opts);
nikcleju@45 266
nikcleju@45 267 xplug = xk;
nikcleju@45 268 niter = niter_int + niter;
nikcleju@45 269
nikcleju@45 270 residuals = [residuals; res];
nikcleju@45 271 outputData = [outputData; out];
nikcleju@45 272
nikcleju@45 273 end
nikcleju@45 274 opts = optsOut;
nikcleju@45 275
nikcleju@45 276
nikcleju@45 277 %---- internal routine for setting defaults
nikcleju@45 278 function [var,userSet] = setOpts(field,default,mn,mx)
nikcleju@45 279 var = default;
nikcleju@45 280 % has the option already been set?
nikcleju@45 281 if ~isfield(opts,field)
nikcleju@45 282 % see if there is a capitalization problem:
nikcleju@45 283 names = fieldnames(opts);
nikcleju@45 284 for i = 1:length(names)
nikcleju@45 285 if strcmpi(names{i},field)
nikcleju@45 286 opts.(field) = opts.(names{i});
nikcleju@45 287 opts = rmfield(opts,names{i});
nikcleju@45 288 break;
nikcleju@45 289 end
nikcleju@45 290 end
nikcleju@45 291 end
nikcleju@45 292 if isfield(opts,field) && ~isempty(opts.(field))
nikcleju@45 293 var = opts.(field); % override the default
nikcleju@45 294 userSet = true;
nikcleju@45 295 else
nikcleju@45 296 userSet = false;
nikcleju@45 297 end
nikcleju@45 298 % perform error checking, if desired
nikcleju@45 299 if nargin >= 3 && ~isempty(mn)
nikcleju@45 300 if var < mn
nikcleju@45 301 printf('Variable %s is %f, should be at least %f\n',...
nikcleju@45 302 field,var,mn); error('variable out-of-bounds');
nikcleju@45 303 end
nikcleju@45 304 end
nikcleju@45 305 if nargin >= 4 && ~isempty(mx)
nikcleju@45 306 if var > mx
nikcleju@45 307 printf('Variable %s is %f, should be at least %f\n',...
nikcleju@45 308 field,var,mn); error('variable out-of-bounds');
nikcleju@45 309 end
nikcleju@45 310 end
nikcleju@45 311 opts.(field) = var;
nikcleju@45 312 end
nikcleju@45 313
nikcleju@45 314
nikcleju@45 315
nikcleju@45 316
nikcleju@45 317 %---- internal routine for setting mu0 in the tv minimization case
nikcleju@45 318 function th=ValMUTv(x)
nikcleju@45 319
nikcleju@45 320 N = length(x);n = floor(sqrt(N));
nikcleju@45 321 Dv = spdiags([reshape([-ones(n-1,n); zeros(1,n)],N,1) ...
nikcleju@45 322 reshape([zeros(1,n); ones(n-1,n)],N,1)], [0 1], N, N);
nikcleju@45 323 Dh = spdiags([reshape([-ones(n,n-1) zeros(n,1)],N,1) ...
nikcleju@45 324 reshape([zeros(n,1) ones(n,n-1)],N,1)], [0 n], N, N);
nikcleju@45 325 D = sparse([Dh;Dv]);
nikcleju@45 326
nikcleju@45 327
nikcleju@45 328 Dhx = Dh*x;
nikcleju@45 329 Dvx = Dv*x;
nikcleju@45 330
nikcleju@45 331 sk = sqrt(abs(Dhx).^2 + abs(Dvx).^2);
nikcleju@45 332 th = max(sk);
nikcleju@45 333
nikcleju@45 334 end
nikcleju@45 335
nikcleju@45 336 end %-- end of NESTA function
nikcleju@45 337
nikcleju@45 338 %%%%%%%%%%%% POWER METHOD TO ESTIMATE NORM %%%%%%%%%%%%%%%
nikcleju@45 339 % Copied from MATLAB's "normest" function, but allows function handles, not just sparse matrices
nikcleju@45 340 function [e,cnt] = my_normest(S,St,n,tol, maxiter)
nikcleju@45 341 %MY_NORMEST Estimate the matrix 2-norm via power method.
nikcleju@45 342 if nargin < 4, tol = 1.e-6; end
nikcleju@45 343 if nargin < 5, maxiter = 20; end
nikcleju@45 344 if isempty(St)
nikcleju@45 345 St = S; % we assume the matrix is symmetric;
nikcleju@45 346 end
nikcleju@45 347 x = ones(n,1);
nikcleju@45 348 cnt = 0;
nikcleju@45 349 e = norm(x);
nikcleju@45 350 if e == 0, return, end
nikcleju@45 351 x = x/e;
nikcleju@45 352 e0 = 0;
nikcleju@45 353 while abs(e-e0) > tol*e && cnt < maxiter
nikcleju@45 354 e0 = e;
nikcleju@45 355 Sx = S(x);
nikcleju@45 356 if nnz(Sx) == 0
nikcleju@45 357 Sx = rand(size(Sx));
nikcleju@45 358 end
nikcleju@45 359 e = norm(Sx);
nikcleju@45 360 x = St(Sx);
nikcleju@45 361 x = x/norm(x);
nikcleju@45 362 cnt = cnt+1;
nikcleju@45 363 end
nikcleju@45 364 end