📄 perform_homotopy.m
字号:
function [X,lambda_list,sparsity_list] = perform_homotopy(D,y,options)% perform_homotopy - compute the L1 regularization path%% X = perform_homotopy(D,y,options);%% Copyright (c) 2008 Gabriel Peyren = size(D,2);niter = getoptions(options, 'niter', min(round(size(D)))/2);lambdaStop = 0;solFreq = 1;verbose = 0;[X, numIters, activationHist] = SolveLasso(D, y, n, 'lasso', niter, lambdaStop, solFreq, verbose);lambda_list = [];sparsity_list = sum(X~=0);return;tol = 1e-15;tol = 1e-3;X = zeros(p,niter);xbp = zeros(p,1);sparsity_list = [];lambda_list = [];for i=1:niter % correlation C = D'*(y-D*xbp); lambda = max(abs(C)); % support for update S = find( abs(abs(C/lambda)-1)<tol); I = ones(p,1); I(S)=0; Sc = find(I); % update direction d = zeros(p,1); d(S) = (D(:,S)'*D(:,S)) \ sign( C(S) ); % useful vector v = D(:,S)*d(S); % Compute minimum |gamma| so that situation 1) is in force. w = ( lambda-C(Sc) ) ./ ( 1 - D(:,Sc)'*v ); gamma1 = min(w(w>0)); % Compute minimum |gamma| so that situation 2) is in force. w = ( lambda+C(Sc) ) ./ ( 1 + D(:,Sc)'*v ); gamma2 = min(w(w>0)); % Compute minimum |gamma| so that situation 3) is in force. w = -xbp(S)./d(S); gamma3 = min(w(w>0)); % any condition is in force gamma = min([gamma1 gamma2 gamma3]); % new solution xbp = xbp + gamma*d; X(:,i) = xbp; % record sparsity and lambda sparsity_list(i) = sum( abs(xbp)>1e-9 ); lambda_list(i) = lambda;endfunction [sols, numIters, activationHist] = SolveLasso(A, y, N, algType, maxIters, lambdaStop, solFreq, verbose, OptTol)% SolveLasso: Implements the LARS/Lasso algorithms% Usage% [sols, numIters, activationHist] = SolveLasso(A, y, N, algType,% maxIters, lambdaStop, solFreq, verbose, OptTol)% Input% A Either an explicit nxN matrix, with rank(A) = min(N,n) % by assumption, or a string containing the name of a % function implementing an implicit matrix (see below for % details on the format of the function).% y vector of length n.% N length of solution vector. % algType 'lars' for the Lars algorithm, % 'lasso' for lars with the lasso modification (default)% maxIters maximum number of LARS iterations to perform. If not% specified, runs to stopping condition (default)% lambdaStop If specified (and > 0), the algorithm terminates when the% Lagrange multiplier <= lambdaStop. % solFreq if =0 returns only the final solution, if >0, returns an % array of solutions, one every solFreq iterations (default 0). % verbose 1 to print out detailed progress at each iteration, 0 for% no output (default)% OptTol Error tolerance, default 1e-5% Outputs% sols solution of the Lasso/LARS problem% numIters Total number of steps taken% activationHist Array of indices showing elements entering and % leaving the solution set% Description% SolveLasso implements the LARS algorithm, as described by Efron et al. in % "Least Angle Regression". Currently, the original algorithm is% implemented, as well as the lasso modification, which solves % min || y - Ax ||_2^2 s.t || x ||_1 <= t% for all t > 0, using a path following method with parameter t.% The implementation implicitly factors the active set matrix A(:,I)% using Choleskly updates. % The matrix A can be either an explicit matrix, or an implicit operator% implemented as an m-file. If using the implicit form, the user should% provide the name of a function of the following format:% y = OperatorName(mode, m, n, x, I, dim)% This function gets as input a vector x and an index set I, and returns% y = A(:,I)*x if mode = 1, or y = A(:,I)'*x if mode = 2. % A is the m by dim implicit matrix implemented by the function. I is a% subset of the columns of A, i.e. a subset of 1:dim of length n. x is a% vector of length n is mode = 1, or a vector of length m is mode = 2.% References% B. Efron, T. Hastie, I. Johnstone and R. Tibshirani, % "Least Angle Regression", Annals of Statistics, 32, 407-499, 2004% See Also% SolveOMP, SolveBP, SolveStOMP%if nargin < 9, OptTol = 1e-5;endif nargin < 8, verbose = 0;endif nargin < 7, solFreq = 0;endif nargin < 6, lambdaStop = 0;endif nargin < 5, maxIters = 10*N;endif nargin < 4, algType = 'lasso';endswitch lower(algType) case 'lars' isLasso = 0; case 'lasso' isLasso = 1;endexplicitA = ~(ischar(A) || isa(A, 'function_handle'));n = length(y);% Global variables for linsolve functionglobal opts opts_tr machPrecopts.UT = true; opts_tr.UT = true; opts_tr.TRANSA = true;machPrec = 1e-5;x = zeros(N,1);iter = 0;% First vector to enter the active set is the one with maximum correlationif (explicitA) corr = A'*y; else corr = feval(A,2,n,N,y,1:N,N); % = A'*y endlambda = max(abs(corr));newIndices = find(abs(abs(corr)-lambda) < machPrec)'; % Initialize Cholesky factor of A_IR_I = [];activeSet = [];for j = 1:length(newIndices) iter = iter+1; [R_I, flag] = updateChol(R_I, n, N, A, explicitA, activeSet, newIndices(j)); activeSet = [activeSet newIndices(j)]; if verbose fprintf('Iteration %d: Adding variable %d\n', iter, activeSet(j)); endendactivationHist = activeSet;collinearIndices = [];sols = [];done = 0;while ~done % Compute Lars direction - Equiangular vector dx = zeros(N,1); % Solve the equation (A_I'*A_I)dx_I = corr_I z = linsolve(R_I,corr(activeSet),opts_tr); dx(activeSet) = linsolve(R_I,z,opts); if (explicitA) dmu = A'*(A(:,activeSet)*dx(activeSet)); else dmu = feval(A,1,n,length(activeSet),dx(activeSet),activeSet,N); dmu = feval(A,2,n,N,dmu,1:N,N); end % For Lasso, Find first active vector to violate sign constraint if isLasso zc = -x(activeSet)./dx(activeSet); gammaI = min([zc(zc > 0); inf]); removeIndices = activeSet(find(zc == gammaI)); else gammaI = Inf; removeIndices = []; end % Find first inactive vector to enter the active set if (length(activeSet) >= min(n, N)) gammaIc = 1; else inactiveSet = 1:N; inactiveSet(activeSet) = 0; inactiveSet(collinearIndices) = 0; inactiveSet = find(inactiveSet > 0); lambda = abs(corr(activeSet(1))); dmu_Ic = dmu(inactiveSet); c_Ic = corr(inactiveSet); epsilon = 1e-12; gammaArr = [(lambda-c_Ic)./(lambda - dmu_Ic + epsilon) (lambda+c_Ic)./(lambda + dmu_Ic + epsilon)]'; gammaArr(gammaArr < machPrec) = inf; gammaArr = min(gammaArr)'; [gammaIc, Imin] = min(gammaArr); end % If gammaIc = 1, we are at the LS solution if (1-gammaIc) < OptTol newIndices = []; else newIndices = inactiveSet(find(abs(gammaArr - gammaIc) < machPrec)); %newIndices = inactiveSet(Imin); end gammaMin = min(gammaIc,gammaI); % Compute the next Lars step x = x + gammaMin*dx; corr = corr - gammaMin*dmu; % Check stopping condition if ((1-gammaMin) < OptTol) | ((lambdaStop > 0) & (lambda <= lambdaStop)) done = 1; end % Add new indices to active set if (gammaIc <= gammaI) && (length(newIndices) > 0) for j = 1:length(newIndices) iter = iter+1; if verbose fprintf('Iteration %d: Adding variable %d\n', iter, newIndices(j)); end % Update the Cholesky factorization of A_I [R_I, flag] = updateChol(R_I, n, N, A, explicitA, activeSet, newIndices(j)); % Check for collinearity if (flag) collinearIndices = [collinearIndices newIndices(j)]; if verbose fprintf('Iteration %d: Variable %d is collinear\n', iter, newIndices(j)); end else activeSet = [activeSet newIndices(j)]; activationHist = [activationHist newIndices(j)]; end end end % Remove violating indices from active set if (gammaI <= gammaIc) for j = 1:length(removeIndices) iter = iter+1; col = find(activeSet == removeIndices(j)); if verbose fprintf('Iteration %d: Dropping variable %d\n', iter, removeIndices(j)); end % Downdate the Cholesky factorization of A_I R_I = downdateChol(R_I,col); activeSet = [activeSet(1:col-1), activeSet(col+1:length(activeSet))]; % Reset collinear set collinearIndices = []; end x(removeIndices) = 0; % To avoid numerical errors activationHist = [activationHist -removeIndices]; end if iter >= maxIters done = 1; end if done | ((solFreq > 0) & (~mod(iter,solFreq))) sols = [sols x]; endendnumIters = iter;clear opts opts_tr machPrec%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%function [R, flag] = updateChol(R, n, N, A, explicitA, activeSet, newIndex)% updateChol: Updates the Cholesky factor R of the matrix % A(:,activeSet)'*A(:,activeSet) by adding A(:,newIndex)% If the candidate column is in the span of the existing % active set, R is not updated, and flag is set to 1.global opts_tr machPrecflag = 0;if (explicitA) newVec = A(:,newIndex);else e = zeros(N,1); e(newIndex) = 1; newVec = feval(A,1,n,N,e,1:N,N); endif length(activeSet) == 0, R = sqrt(sum(newVec.^2));else if (explicitA) p = linsolve(R,A(:,activeSet)'*A(:,newIndex),opts_tr); else AnewVec = feval(A,2,n,length(activeSet),newVec,activeSet,N); p = linsolve(R,AnewVec,opts_tr); end q = sum(newVec.^2) - sum(p.^2); if (q <= machPrec) % Collinear vector flag = 1; else R = [R p; zeros(1, size(R,2)) sqrt(q)]; endend%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%function R = downdateChol(R, j)% downdateChol: `Downdates' the cholesky factor R by removing the % column indexed by j.% Remove the j-th columnR(:,j) = [];[m,n] = size(R);% R now has nonzeros below the diagonal in columns j through n.% We use plane rotations to zero the 'violating nonzeros'.for k = j:n p = k:k+1; [G,R(p,k)] = planerot(R(p,k)); if k < n R(p,k+1:n) = G*R(p,k+1:n); endend% Remove last row of zeros from RR = R(1:n,:);%% Copyright (c) 2006. Yaakov Tsaig and Joshua Sweetkind-Singer% %% Part of SparseLab Version:100% Created Tuesday March 28, 2006% This is Copyrighted Material% For Copying permissions see COPYING.m% Comments? e-mail sparselab@stanford.edu%
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -