function [L,S,fvals,resids] = pcp_admm(M,lambda,rho) % % [L,S] = pcp_admm(M) % [L,S] = pcp_admm(M,lambda) % [L,S] = pcp_admm(M,lambda,rho) % % Computes a solution to the Principal Component Pursuit (PCP) problem % minimize: ||L||_* + lambda*||S||_1 % subject to: L + S == M % via the Alternating Direction Method of Multipliers (ADMM) method % % Original Paper: % --------------- % Emmanuel J. Candes, Xiaodong Li, Yi Ma, and John Wright. % Robust principal component analysis. Technical report, % Stanford University, 2009. % % Input: % M = m-by-n data matrix % lambda = regularization parameter for original problem % default lambda = 1/sqrt(max(m,n)) % rho = starting penalty parameter for ADMM % default rho = 1 % this script automatically varies the penalty parameter % and stops on a relative criterion % % Output: % L = m-by-n, low-rank % S = m-by-n, sparse [m,n] = size(M); % default parameter values if nargin <= 2 rho = 1; end if nargin <= 1 lambda = 1/sqrt(max(m,n)); end % algorithm parameters and initial point MAX_ITER = 5000; TOL = 1e-2; L = ones(m,n); S = M - L; W = ones(m,n)/rho; fvals = []; resids = []; rhonext = rho; fprintf('Running ADMM...\n'); fprintf('Iteration | Objective | normf(L+S-M) | Dual resid | Time (s)\n'); for k=1:MAX_ITER titerstart = tic; % 1. prox of the nuclear norm [U,Sig,V] = svd(M-S-W,0); Lnext = U * diag(soft_thresh(diag(Sig), 1/rho)) * V'; % 2. prox of the l1 norm Snext = soft_thresh(M-Lnext-W, lambda/rho); % 3. residual running sum Wnext = W + (Lnext + Snext - M); % 4. evaluate primal and dual residuals % r^{k+1} = L^{k+1} + S^{k+1} - M % s^{k+1} = rho*(S^{k+1}-S^{k}) primal_resid = norm(Lnext + Snext - M,'fro'); dual_resid = rho*norm(Snext - S,'fro'); % 5. automatically vary the penalty parameter if primal_resid > 10*dual_resid rhonext = 2*rho; Wnext = Wnext/2; fprintf('--------> Increasing penalty to rho=%e\n', rhonext); elseif dual_resid > 10*primal_resid rhonext = rho/2; Wnext = 2*Wnext; fprintf('--------> Decreasing penalty to rho=%e\n', rhonext); else rhonext = rho; end % 6. update iterates L = Lnext; S = Snext; W = Wnext; rho = rhonext; % stopping criterion if primal_resid <= TOL && dual_resid <= TOL fprintf('Converged to TOL=%e in %d iterations\n', TOL, k); break; end % save the objective and feasibility residuals if mod(k, 1) == 0 fval = norm_nuc(L) + lambda*norm(S(:),1); fvals = [fvals, fval]; resids = [resids, [primal_resid; dual_resid]]; end % show progress titerstop = toc(titerstart); if mod(k, 1) == 0 fprintf('%9d | %e | %e | %e | %12f\n', ... k, fval, primal_resid, dual_resid, titerstop); end end if k == MAX_ITER fprintf('Failed to converge in MAX_ITER=%d iterations\n', MAX_ITER); end end function result = soft_thresh(X, kappa) % computes the shrinkage S_kappa(X) assert(kappa > 0, 'soft thresholding on negative kappa'); result = max(X - kappa,0) - max(-X - kappa,0); end