diff matlab/OMP/greed_omp_qr.m @ 2:735a0e24575c

Organized folders: added tests, apps, matlab, docs folders. Added __init__.py files
author nikcleju
date Fri, 21 Oct 2011 13:53:49 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/matlab/OMP/greed_omp_qr.m	Fri Oct 21 13:53:49 2011 +0000
@@ -0,0 +1,472 @@
+function [s, err_mse, iter_time]=greed_omp_qr(x,A,m,varargin)
+% greed_omp_qr: Orthogonal Matching Pursuit algorithm based on QR
+% factorisation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Usage
+% [s, err_mse, iter_time]=greed_omp_qr(x,P,m,'option_name','option_value')
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Input
+%   Mandatory:
+%               x   Observation vector to be decomposed
+%               P   Either:
+%                       1) An nxm matrix (n must be dimension of x)
+%                       2) A function handle (type "help function_format" 
+%                          for more information)
+%                          Also requires specification of P_trans option.
+%                       3) An object handle (type "help object_format" for 
+%                          more information)
+%               m   length of s 
+%
+%   Possible additional options:
+%   (specify as many as you want using 'option_name','option_value' pairs)
+%   See below for explanation of options:
+%__________________________________________________________________________
+%   option_name    |     available option_values                | default
+%--------------------------------------------------------------------------
+%   stopCrit       | M, corr, mse, mse_change                   | M
+%   stopTol        | number (see below)                         | n/4
+%   P_trans        | function_handle (see below)                | 
+%   maxIter        | positive integer (see below)               | n
+%   verbose        | true, false                                | false
+%   start_val      | vector of length m                         | zeros
+%
+%   Available stopping criteria :
+%               M           -   Extracts exactly M = stopTol elements.
+%               corr        -   Stops when maximum correlation between
+%                               residual and atoms is below stopTol value.
+%               mse         -   Stops when mean squared error of residual 
+%                               is below stopTol value.
+%               mse_change  -   Stops when the change in the mean squared 
+%                               error falls below stopTol value.
+%
+%   stopTol: Value for stopping criterion.
+%
+%   P_trans: If P is a function handle, then P_trans has to be specified and 
+%            must be a function handle. 
+%
+%   maxIter: Maximum number of allowed iterations.
+%
+%   verbose: Logical value to allow algorithm progress to be displayed.
+%
+%   start_val: Allows algorithms to start from partial solution.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Outputs
+%    s              Solution vector 
+%    err_mse        Vector containing mse of approximation error for each 
+%                   iteration
+%    iter_time      Vector containing computation times for each iteration
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Description
+%   greed_omp_qr performs a greedy signal decomposition. 
+%   In each iteration a new element is selected depending on the inner
+%   product between the current residual and columns in P.
+%   The non-zero elements of s are approximated by orthogonally projecting 
+%   x onto the selected elements in each iteration.
+%   The algorithm uses QR decomposition.
+%
+% See Also
+%   greed_omp_chol, greed_omp_cg, greed_omp_cgp, greed_omp_pinv, 
+%   greed_omp_linsolve, greed_gp, greed_nomp
+%
+% Copyright (c) 2007 Thomas Blumensath
+%
+% The University of Edinburgh
+% Email: thomas.blumensath@ed.ac.uk
+% Comments and bug reports welcome
+%
+% This file is part of sparsity Version 0.1
+% Created: April 2007
+%
+% Part of this toolbox was developed with the support of EPSRC Grant
+% D000246/1
+%
+% Please read COPYRIGHT.m for terms and conditions.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                    Default values and initialisation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+[n1 n2]=size(x);
+if n2 == 1
+    n=n1;
+elseif n1 == 1
+    x=x';
+    n=n2;
+else
+   display('x must be a vector.');
+   return
+end
+    
+sigsize     = x'*x/n;
+initial_given=0;
+err_mse     = [];
+iter_time   = [];
+STOPCRIT    = 'M';
+STOPTOL     = ceil(n/4);
+MAXITER     = n;
+verbose     = false;
+s_initial   = zeros(m,1);
+
+
+if verbose
+   display('Initialising...') 
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                           Output variables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+switch nargout 
+    case 3
+        comp_err=true;
+        comp_time=true;
+    case 2 
+        comp_err=true;
+        comp_time=false;
+    case 1
+        comp_err=false;
+        comp_time=false;
+    case 0
+        error('Please assign output variable.')
+    otherwise
+        error('Too many output arguments specified')
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                       Look through options
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Put option into nice format
+Options={};
+OS=nargin-3;
+c=1;
+for i=1:OS
+    if isa(varargin{i},'cell')
+        CellSize=length(varargin{i});
+        ThisCell=varargin{i};
+        for j=1:CellSize
+            Options{c}=ThisCell{j};
+            c=c+1;
+        end
+    else
+        Options{c}=varargin{i};
+        c=c+1;
+    end
+end
+OS=length(Options);
+if rem(OS,2)
+   error('Something is wrong with argument name and argument value pairs.') 
+end
+
+for i=1:2:OS
+   switch Options{i}
+        case {'stopCrit'}
+            if (strmatch(Options{i+1},{'M'; 'corr'; 'mse'; 'mse_change'},'exact'));
+                STOPCRIT    = Options{i+1};  
+            else error('stopCrit must be char string [M, corr, mse, mse_change]. Exiting.'); end 
+        case {'stopTol'}
+            if isa(Options{i+1},'numeric') ; STOPTOL     = Options{i+1};   
+            else error('stopTol must be number. Exiting.'); end
+        case {'P_trans'} 
+            if isa(Options{i+1},'function_handle'); Pt = Options{i+1};   
+            else error('P_trans must be function _handle. Exiting.'); end
+        case {'maxIter'}
+            if isa(Options{i+1},'numeric'); MAXITER     = Options{i+1};             
+            else error('maxIter must be a number. Exiting.'); end
+        case {'verbose'}
+            if isa(Options{i+1},'logical'); verbose     = Options{i+1};   
+            else error('verbose must be a logical. Exiting.'); end 
+        case {'start_val'}
+            if isa(Options{i+1},'numeric') & length(Options{i+1}) == m ;
+                s_initial     = Options{i+1};   
+                initial_given=1;
+            else error('start_val must be a vector of length m. Exiting.'); end
+        otherwise
+            error('Unrecognised option. Exiting.') 
+   end
+end
+
+
+
+if strcmp(STOPCRIT,'M') 
+    maxM=STOPTOL;
+else
+    maxM=MAXITER;
+end
+
+if nargout >=2
+    err_mse = zeros(maxM,1);
+end
+if nargout ==3
+    iter_time = zeros(maxM,1);
+end
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                        Make P and Pt functions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if          isa(A,'float')      P =@(z) A*z;  Pt =@(z) A'*z;
+elseif      isobject(A)         P =@(z) A*z;  Pt =@(z) A'*z;
+elseif      isa(A,'function_handle') 
+    try
+        if          isa(Pt,'function_handle'); P=A;
+        else        error('If P is a function handle, Pt also needs to be a function handle. Exiting.'); end
+    catch error('If P is a function handle, Pt needs to be specified. Exiting.'); end
+else        error('P is of unsupported type. Use matrix, function_handle or object. Exiting.'); end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                 Random Check to see if dictionary is normalised 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+        % Commented by Nic, 13 Sept 2011
+        % Don't want any slow text output
+%         mask=zeros(m,1);
+%         mask(ceil(rand*m))=1;
+%         nP=norm(P(mask));
+%         if abs(1-nP)>1e-3;
+%             display('Dictionary appears not to have unit norm columns.')
+%         end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%              Check if we have enough memory and initialise 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        
+
+        try Q=zeros(n,maxM);
+        catch error('Variable size is too large. Please try greed_omp_chol algorithm or reduce MAXITER.')
+        end 
+        try R=zeros(maxM);
+        catch error('Variable size is too large. Please try greed_omp_chol algorithm or reduce MAXITER.')
+        end
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                        Do we start from zero or not?
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if initial_given ==1;
+    IN          = find(s_initial);
+    if ~isempty(IN)
+        Residual    = x-P(s_initial);
+        lengthIN=length(IN);
+        z=[];
+        for k=1:length(IN)
+            % Extract new element
+             mask=zeros(m,1);
+             mask(IN(k))=1;
+             new_element=P(mask);
+
+            % Orthogonalise new element 
+             qP=Q(:,1:k-1)'*new_element;
+             q=new_element-Q(:,1:k-1)*(qP);
+
+             nq=norm(q);
+             q=q/nq;
+            % Update QR factorisation 
+             R(1:k-1,k)=qP;
+             R(k,k)=nq;
+             Q(:,k)=q;
+
+             z(k)=q'*x;
+        end
+        s           = s_initial;
+        Residual=x-Q(:,k)*z;
+        oldERR      = Residual'*Residual/n;
+    else
+    	IN          = [];
+        Residual    = x;
+        s           = s_initial;
+        sigsize     = x'*x/n;
+        oldERR      = sigsize;
+        k=0;
+        z=[];
+    end
+    
+else
+    IN          = [];
+    Residual    = x;
+    s           = s_initial;
+    sigsize     = x'*x/n;
+    oldERR      = sigsize;
+    k=0;
+    z=[];
+end
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                        Main algorithm
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if verbose
+   display('Main iterations...') 
+end
+tic
+t=0;
+DR=Pt(Residual);
+done = 0;
+iter=1;
+
+%Nic: find norms of dictionary atoms, for RandOMP
+% for i = 1:m
+%     norms(i) = norm(P([zeros(i-1,1) ; 1 ; zeros(m-i,1)]));
+% end
+
+while ~done
+    
+     % Select new element
+     DR(IN)=0;
+     % Nic: replace selection with random variable
+     % i.e. Randomized OMP!!
+     % DON'T FORGET ABOUT THIS!!
+     [v I]=max(abs(DR));
+     %I = randp(exp(abs(DR).^2 ./ (norms.^2)'), [1 1]);
+     IN=[IN I];
+
+    
+     k=k+1;
+     % Extract new element
+     mask=zeros(m,1);
+     mask(IN(k))=1;
+     new_element=P(mask);
+
+    % Orthogonalise new element 
+     qP=Q(:,1:k-1)'*new_element;
+     q=new_element-Q(:,1:k-1)*(qP);
+
+     nq=norm(q);
+     q=q/nq;
+    % Update QR factorisation 
+     R(1:k-1,k)=qP;
+     R(k,k)=nq;
+     Q(:,k)=q;
+
+     z(k)=q'*x;
+   
+    % New residual 
+     Residual=Residual-q*(z(k));
+     DR=Pt(Residual);
+     
+     ERR=Residual'*Residual/n;
+     if comp_err
+         err_mse(iter)=ERR;
+     end
+     
+     if comp_time
+         iter_time(iter)=toc;
+     end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                        Are we done yet?
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+     
+     if strcmp(STOPCRIT,'M')
+         if iter >= STOPTOL
+             done =1;
+         elseif verbose && toc-t>10
+            display(sprintf('Iteration %i. --- %i iterations to go',iter ,STOPTOL-iter)) 
+            t=toc;
+         end
+    elseif strcmp(STOPCRIT,'mse')
+         if comp_err
+            if err_mse(iter)<STOPTOL;
+                done = 1; 
+            elseif verbose && toc-t>10
+                display(sprintf('Iteration %i. --- %i mse',iter ,err_mse(iter))) 
+                t=toc;
+            end
+         else
+             if ERR<STOPTOL;
+                done = 1; 
+             elseif verbose && toc-t>10
+                display(sprintf('Iteration %i. --- %i mse',iter ,ERR)) 
+                t=toc;
+             end
+         end
+     elseif strcmp(STOPCRIT,'mse_change') && iter >=2
+         if comp_err && iter >=2
+              if ((err_mse(iter-1)-err_mse(iter))/sigsize <STOPTOL);
+                done = 1; 
+             elseif verbose && toc-t>10
+                display(sprintf('Iteration %i. --- %i mse change',iter ,(err_mse(iter-1)-err_mse(iter))/sigsize )) 
+                t=toc;
+             end
+         else
+             if ((oldERR - ERR)/sigsize < STOPTOL);
+                done = 1; 
+             elseif verbose && toc-t>10
+                display(sprintf('Iteration %i. --- %i mse change',iter ,(oldERR - ERR)/sigsize)) 
+                t=toc;
+             end
+         end
+     elseif strcmp(STOPCRIT,'corr') 
+          if max(abs(DR)) < STOPTOL;
+             done = 1; 
+          elseif verbose && toc-t>10
+                display(sprintf('Iteration %i. --- %i corr',iter ,max(abs(DR)))) 
+                t=toc;
+          end
+     end
+     
+    % Also stop if residual gets too small or maxIter reached
+     if comp_err
+         if err_mse(iter)<1e-16
+             display('Stopping. Exact signal representation found!')
+             done=1;
+         end
+     else
+
+
+         if iter>1
+             if ERR<1e-16
+                 display('Stopping. Exact signal representation found!')
+                 done=1;
+             end
+         end
+     end
+
+     if iter >= MAXITER
+         display('Stopping. Maximum number of iterations reached!')
+         done = 1; 
+     end
+     
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                    If not done, take another round
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+   
+     if ~done
+        iter=iter+1;
+        oldERR=ERR;
+     end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%            Now we can solve for s by back-substitution
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ s(IN)=R(1:k,1:k)\z(1:k)';
+ 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                  Only return as many elements as iterations
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if nargout >=2
+    err_mse = err_mse(1:iter);
+end
+if nargout ==3
+    iter_time = iter_time(1:iter);
+end
+if verbose
+   display('Done') 
+end
+
+% Change history
+%
+% 8 of Februray: Algo does no longer stop if dictionary is not normaliesd.