view pyCSalgos/SL0/SL0.py @ 51:eb4c66488ddf

Split algos.py and stdparams.py, added nesta to std1, 2, 3, 4
author nikcleju
date Wed, 07 Dec 2011 12:44:19 +0000
parents f31d5484a573
children
line wrap: on
line source
# -*- coding: utf-8 -*-
"""
Created on Sat Nov 05 18:39:54 2011

@author: Nic
"""

import numpy as np

#function s=SL0(A, x, sigma_min, sigma_decrease_factor, mu_0, L, A_pinv, true_s)
def SL0(A, x, sigma_min, sigma_decrease_factor=0.5, mu_0=2, L=3, A_pinv=None, true_s=None):
  #
  # SL0(A, x, sigma_min, sigma_decrease_factor, mu_0, L, A_pinv, true_s)
  #
  #   Returns the sparsest vector s which satisfies underdetermined system of
  #   linear equations  A*s=x, using  Smoothed L0  (SL0) algorithm. Note that 
  #   the matrix  A should  be a 'wide' matrix  (more columns than rows). The 
  #   number of the rows of  matrix A  should  be  equal to the length of the 
  #   column vector x.
  #
  #     The first 3 arguments should necessarily be provided by the user. The 
  #   other parameters have defult values  calculated within the function, or
  #   may be provided by the user.
  #
  #   Sequence of Sigma (sigma_min and sigma_decrease_factor):
  #     This is a decreasing geometric sequence of positive numbers:
  #       - The  first  element   of  the  sequence  of  sigma is  calculated 
  #     automatically. The last  element  is  given  by  'sigma_min', and the 
  #     change factor for decreasing sigma is given by 'sigma_decrease_factor'. 
  #       - The default value of 'sigma_decrease_factor' is 0.5. Larger value 
  #     gives better results  for less sparse sources, but it uses more steps 
  #     on   sigma   to  reach  sigma_min,  and  hence  it  requires   higher 
  #     computational cost.
  #       - There is no default  value for  'sigma_min',  and  it  should  be 
  #     provided  by  the  user (depending  on his/her estimated source noise 
  #     level,  or  his/her  desired  accuracy).  By `noise' we mean here the
  #     noise in the sources, that is, the energy of the inactive elements of
  #     's'.   For example,  by  the  noiseless  case,  we  mean the inactive
  #     elements of 's' are exactly equal to zero. As a rule of tumb, for the
  #     noisy case,  sigma_min should be about 2 to 4  times  of the standard
  #     deviation of this noise.  For the noiseless case, smaller 'sigma_min'
  #     results in  better estimation of the sparsest solution, and hence its
  #     value is determined by the desired accuracy.
  # 
  #   mu_0: 
  #        The  value  of  mu_0  scales  the sequence of mu. For each vlue of 
  #     sigma, the value of  mu is chosen via mu=mu_0*sigma^2. Note that this 
  #     value effects Convergence.
  #        The default value is mu_0=2 (see the paper).
  #
  #   L: 
  #        number  of  iterations of the internal (steepest ascent) loop. The
  #     default value is L=3.
  #
  #   A_pinv: 
  #        is the  pseudo-inverse of matrix A defined by A_pinv=A'*inv(A*A'). 
  #     If it is not provided, it will be calculated within the function.  If
  #     you use this function for solving x(t)=A s(t) for different values of
  #     't', it would be a good idea to calculate A_pinv outside the function
  #     to prevent its re-calculation for each 't'.
  #
  #   true_s: 
  #        is the  true value of the  sparse  solution.  This argument is for
  #     simulation purposes. If it is provided by the user, then the function
  #     will  calculate the SNR of the estimation for each value of sigma and
  #     it provides a progress report.
  #
  # Authors: Massoud Babaie-Zadeh and Hossein Mohimani
  # Version: 1.4
  # Last modified: 4 April 2010.
  #
  #
  # Web-page:
  # ------------------
  #    http://ee.sharif.ir/~SLzero
  #
  # Code History:
  #--------------
  # Version 2.0: 4 April 2010
  #        Doing a few small modifications that enable the code to work also
  #        for complex numbers (not only for real numbers).
  #
  # Version 1.3: 13 Sep 2008
  #        Just a few modifications in the comments
  #
  # Version 1.2: Adding some more comments in the help section
  #
  # Version 1.1: 4 August 2008
  #    - Using MATLAB's pseudo inverse function to generalize for the case
  #      the matrix A is not full-rank.
  #
  # Version 1.0 (first official version): 4 July 2008.
  #
  # First non-official version and algorithm development: Summer 2006
  #---------------------
  # Original Matab code:
  #
  #if nargin < 4
  #    sigma_decrease_factor = 0.5;
  #    A_pinv = pinv(A);
  #    mu_0 = 2;
  #    L = 3;
  #    ShowProgress = logical(0);
  #elseif nargin == 4
  #    A_pinv = pinv(A);
  #    mu_0 = 2;
  #    L = 3;
  #    ShowProgress = logical(0);
  #elseif nargin == 5
  #    A_pinv = pinv(A);
  #    L = 3;
  #    ShowProgress = logical(0);
  #elseif nargin == 6
  #    A_pinv = pinv(A);
  #    ShowProgress = logical(0);
  #elseif nargin == 7
  #    ShowProgress = logical(0);
  #elseif nargin == 8
  #    ShowProgress = logical(1);
  #else
  #    error('Error in calling SL0 function');
  #end
  #
  #
  ## Initialization
  ##s = A\x;
  #s = A_pinv*x;
  #sigma = 2*max(abs(s));
  #
  ## Main Loop
  #while sigma>sigma_min
  #    for i=1:L
  #        delta = OurDelta(s,sigma);
  #        s = s - mu_0*delta;
  #        s = s - A_pinv*(A*s-x);   # Projection
  #    end
  #    
  #    if ShowProgress
  #        fprintf('     sigma=#f, SNR=#f\n',sigma,estimate_SNR(s,true_s))
  #    end
  #    
  #    sigma = sigma * sigma_decrease_factor;
  #end
  #    
  #
  #####################################################################
  #function delta=OurDelta(s,sigma)
  #
  #delta = s.*exp(-abs(s).^2/sigma^2);
  #
  #####################################################################
  #function SNR=estimate_SNR(estim_s,true_s)
  #
  #err = true_s - estim_s;
  #SNR = 10*log10(sum(abs(true_s).^2)/sum(abs(err).^2));

  # End of original Matab code
  #----------------------------
  
  if A_pinv is None:
    A_pinv = np.linalg.pinv(A)
  
  if true_s is not None:
      ShowProgress = True
  else:
      ShowProgress = False
  
  # Initialization
  #s = A\x;
  s = np.dot(A_pinv,x)
  sigma = 2.0*np.abs(s).max()
  
  # Main Loop
  while sigma>sigma_min:
      for i in np.arange(L):
          delta = OurDelta(s,sigma)
          s = s - mu_0*delta
          s = s - np.dot(A_pinv,(np.dot(A,s)-x))   # Projection
      
      if ShowProgress:
          #fprintf('     sigma=#f, SNR=#f\n',sigma,estimate_SNR(s,true_s))
          string = '     sigma=%f, SNR=%f\n' % sigma,estimate_SNR(s,true_s)
          print string
      
      sigma = sigma * sigma_decrease_factor
  
  return s
  
  
####################################################################
#function delta=OurDelta(s,sigma)
def OurDelta(s,sigma):
  
  return s * np.exp( (-np.abs(s)**2) / sigma**2)
  
####################################################################
#function SNR=estimate_SNR(estim_s,true_s)
def estimate_SNR(estim_s, true_s):
  
  err = true_s - estim_s
  return 10*np.log10((true_s**2).sum()/(err**2).sum())