view toolboxes/alps/ALPS/one_ALPS.m @ 160:e3035d45d014 danieleb

Added support classes
author Daniele Barchiesi <daniele.barchiesi@eecs.qmul.ac.uk>
date Wed, 31 Aug 2011 10:53:10 +0100
parents 0de08f68256b
children
line wrap: on
line source
function [x_hat, numiter, x_path] = one_ALPS(y, Phi, K, params)
% =========================================================================
%                  1-ALPS(#) algorithm - Beta Version
% =========================================================================
% Algebraic Pursuit (ALPS) algorithm with 1-memory acceleration. 
% 
% Detailed discussion on the algorithm can be found in 
% [1] "On Accelerated Hard Thresholding Methods for Sparse Approximation", written
% by Volkan Cevher, Technical Report, 2011.
% =========================================================================
% INPUT ARGUMENTS:
% y                         M x 1 undersampled measurement vector.
% Phi                       M x N regression matrix.
% K                         Sparsity of underlying vector x* or desired
%                           sparsity of solution.
% params                    Structure of parameters. These are:
%
%    tol,...                Early stopping tolerance. Default value: tol =
%                           1-e5.
%    ALPSiters,...          Maximum number of algorithm iterations. Default
%                           value: 300. 
%    solveNewtonb,...       If solveNewtonb == 1: Corresponds to solving a 
%                           Newton system restricted to a sparse support. 
%                           It is implemented via conjugate gradients.  
%                           If solveNewtonb == 0: Step size selection as described
%                           in eqs. (12) and (13) in [1]. 
%                           Default value: solveNewtonb = 0.
%    gradientDescentx,...   If gradientDescentx == 1: single gradient
%                           update of x_{i+1} restricted ot its support with 
%                           line search. Default value: gradientDescentx =
%                           1.
%    solveNewtonx,...       If solveNewtonx == 1: Akin to Hard Thresholding Pursuit
%                           (c.f. Simon Foucart, "Hard Thresholding Pursuit," 
%                           preprint, 2010). Default vale: solveNewtonx = 0.
%    tau,...                Variable that controls the momentum in
%                           non-memoryless case. Ignored in memoryless
%                           case. Default value: tau = 1/2.
%                           Special cases:
%                               - tau = 0: momentum step size selection is
%                               driven by the following formulas:
%                                   a_1 = 1;
%                                   a_{i+1} = (1+\sqrt(1+4a_i^2)/2;
%                                   tau = (a_i - 1)/(a_{i+1});
%                               described in [2] "A fast iterative
%                               shrinkage-thresholding algorithm for linear
%                               inverse problems", Beck A., and Teboulle M.
%                               - tau = -1: momentum step size is automatically
%                               optimized in every step.
%                               - tau as a function handle: user defined
%                               behavior of tau momentum term.
%    mu,...                 Variable that controls the step size selection. 
%                           When mu = 0, step size is computed adaptively 
%                           per iteration. Default value: mu = 0. 
%    cg_maxiter,...         Maximum iterations for Conjugate-Gradients method.
%    cg_tol                 Tolerance variable for Conjugate-Gradients method.  
% =========================================================================
% OUTPUT ARGUMENTS:
% x_hat                     N x 1 recovered K-sparse vector.
% numiter                   Number of iterations executed.
% x_path                    Keeps a series of computed N x 1 K-sparse vectors 
%                           until the end of the iterative process.
% =========================================================================
% 01/04/2011, by Anastasios Kyrillidis. anastasios.kyrillidis@epfl.ch, EPFL.
% =========================================================================
% cgsolve.m is written by Justin Romberg, Caltech, Oct. 2005.
%                         Email: jrom@acm.caltech.edu
% =========================================================================
% This work was supported in part by the European Commission under Grant 
% MIRG-268398 and DARPA KeCoM program #11-DARPA-1055. VC also would like 
% to acknowledge Rice University for his Faculty Fellowship.
% =========================================================================

[M,N] = size(Phi);

%% Initialize transpose of measurement matrix

Phi_t = Phi';

%% Initialize to zero vector
x_cur = zeros(N,1);
y_cur = zeros(N,1);
Phi_x_cur = zeros(M,1);
Y_i = [];

x_path = zeros(N, params.ALPSiters);

%% CG params
if (params.solveNewtonx == 1 || params.solveNewtonb == 1)
    cg_verbose = 0;
    cg_A = Phi_t*Phi;
    cg_b = Phi_t*y;
end;

%% Determine momentum step size selection strategy
fista = 0;
optimizeTau = 0;
a_prev = 1;
function_tau = 0;

if (isa(params.tau,'float'))
    function_tau = 0;
    if (params.tau == 0)
        fista = 1;
        optimizeTau = 0;
    elseif (params.tau == -1)
        optimizeTau = 1;
        fista = 0;
    end;
elseif (isa(params.tau, 'function_handle'))
    function_tau = 1;
end;

%% Determine step size selection strategy
function_mu = 0;
adaptive_mu = 0;

if (isa(params.mu,'float'))
    function_mu = 0;
    if (params.mu == 0)
        adaptive_mu = 1;
    else
        adaptive_mu = 0;
    end;
elseif (isa(params.mu,'function_handle'))
    function_mu = 1;
end;

%% Help variables
complementary_Yi = ones(N,1);

i = 1;
%% 1-ALPS(#)
while (i <= params.ALPSiters)
    x_path(:,i) = x_cur;
    x_prev = x_cur;        
    
    % Compute the residual
    if (i == 1)
        res = y;
        % Compute the derivative
        der = Phi_t*res;
    else
        % Compute the derivative
        if (optimizeTau)
            res = y - Phi_x_cur - params.tau*Phi_diff;
        else
            res = y - Phi(:,Y_i)*y_cur(Y_i);
        end;
        der = Phi_t*res;
    end;
    
    Phi_x_prev = Phi_x_cur;               
    
    % Determine S_i set via eq. (11) (change of variable from x_i to y_i)
    complementary_Yi(Y_i) = 0;
    [tmpArg, ind_der] = sort(abs(der).*complementary_Yi, 'descend');  
    complementary_Yi(Y_i) = 1;
    S_i = [Y_i; ind_der(1:K)];
        
    ider = der(S_i);
    if (params.solveNewtonb == 1)     
        % Compute least squares solution of the system A*y = (A*A)x using CG                        
        if (params.useCG == 1)
            [b, tmpArg, tmpArg] = cgsolve(cg_A(S_i, S_i), cg_b(S_i), params.cg_tol, params.cg_maxiter, cg_verbose);
        else 
            b = cg_A(S_i,S_i)\cg_b(S_i);
        end;
    else
        % Step size selection via eq. (12) and eq. (13) (change of variable from x_i to y_i)
        if (adaptive_mu)
            Pder = Phi(:,S_i)*ider;
            mu_bar = ider'*ider/(Pder'*Pder);            
            b = y_cur(S_i) + (mu_bar)*ider;        
        elseif (function_mu)
            b = y_cur(S_i) + params.mu(i)*ider;
        else b = y_cur(S_i) + params.mu*ider;
        end;
    end;

    % Hard-threshold b and compute X_{i+1}
    [tmpArg, ind_b] = sort(abs(b), 'descend');
    x_cur = zeros(N,1);
    x_cur(S_i(ind_b(1:K))) = b(ind_b(1:K));
    X_i = S_i(ind_b(1:K));

    if (params.gradientDescentx == 1)
        % Calculate gradient of estimated vector x_cur
        Phi_x_cur = Phi(:,X_i)*x_cur(X_i);
        res = y - Phi_x_cur;
        der = Phi_t*res;
        ider = der(X_i);
        
        if (adaptive_mu)
            Pder = Phi(:,X_i)*ider;
            mu_bar = ider'*ider/(Pder'*Pder);
            x_cur(X_i) = x_cur(X_i) + mu_bar*ider;
        elseif (function_mu)
            x_cur(X_i) = x_cur(X_i) + params.mu(i)*ider;
        else x_cur(X_i) = x_cur(X_i) + params.mu*ider;
        end;
    elseif (params.solveNewtonx == 1)                
        % Similar to HTP
        if (params.useCG == 1)
            [v, tmpArg, tmpArg] = cgsolve(cg_A(X_i, X_i), cg_b(X_i), params.cg_tol, params.cg_maxiter, cg_verbose);
        else
            v = cg_A(X_i, X_i)\cg_b(X_i);
        end;
        x_cur(X_i) = v;
    end;
    
    if (~function_tau)    % If tau is not a function handle...
        if (fista)        % Fista configuration
            a_cur = (1 + sqrt(1 + 4*a_prev^2))/2;
            params.tau = (a_prev - 1)/a_cur;
            a_prev = a_cur;
        elseif (optimizeTau)   % Compute optimized tau

            % tau = argmin ||u - Phi*y_{i+1}|| 
            %     = <res, Phi*(x_cur - x_prev)>/||Phi*(x_cur - x_prev)||^2        

            Phi_x_cur = Phi(:,X_i)*x_cur(X_i);
            res = y - Phi_x_cur;
            if (i == 1)
                Phi_diff = Phi_x_cur;
            else
                Phi_diff = Phi_x_cur - Phi_x_prev;
            end;
            params.tau = res'*Phi_diff/(Phi_diff'*Phi_diff);
        end;

        y_cur = x_cur + params.tau*(x_cur - x_prev);
        Y_i = find(ne(y_cur, 0));
    else
        y_cur = x_cur + params.tau(i)*(x_cur - x_prev);
        Y_i = find(ne(y_cur, 0));
    end;
        
    % Test stopping criterion
    if (i > 1) && (norm(x_cur - x_prev) < params.tol*norm(x_cur))
        break;
    end;
    i = i + 1;
end;

x_hat = x_cur;
numiter= i;

if (i > params.ALPSiters)
    x_path = x_path(:,1:numiter-1);
else
    x_path = x_path(:,1:numiter);
end;