changeset 66:ee10ffb60428

Implemented projection on an ellipsoid and modified SL0 accordingly.
author Nic Cleju <nikcleju@gmail.com>
date Mon, 23 Apr 2012 10:55:49 +0300
parents 3d53309236c4
children a8d96e67717e
files pyCSalgos/SL0/EllipseProj.py pyCSalgos/SL0/SL0_approx.py
diffstat 2 files changed, 1070 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pyCSalgos/SL0/EllipseProj.py	Mon Apr 23 10:55:49 2012 +0300
@@ -0,0 +1,607 @@
+# -*- coding: utf-8 -*-
+"""
+
+Author: Nicolae Cleju
+"""
+__author__ = "Nicolae Cleju"
+__license__ = "GPL"
+__email__ = "nikcleju@gmail.com"
+
+
+import numpy
+import scipy
+import math
+import cvxpy
+
+class EllipseProjDaiError(Exception):
+#  def __init__(self, e):
+#    self._e = e
+  pass
+
+def ellipse_proj_cvxpy(A,b,p,epsilon):
+  b = b.reshape((b.size,1))
+  p = p.reshape((p.size,1))
+  A = cvxpy.matrix(A)
+  b = cvxpy.matrix(b)
+  p = cvxpy.matrix(p)
+
+  x = cvxpy.variable(p.shape[0],1)                 # Create optimization variable
+  prog = cvxpy.program(cvxpy.minimize(cvxpy.norm2(p - x)),              # Create problem instance
+            [cvxpy.leq(cvxpy.norm2(b-A*x),epsilon)])
+  #prog.solve(quiet=True)                              # Get optimal value
+  prog.solve()                              # Get optimal value
+  return numpy.array(x.value).flatten()
+
+def ellipse_proj_dai(A,x,s,eps):
+  
+  A_pinv = numpy.linalg.pinv(A)
+  
+  AA = numpy.dot(A.T, A)
+  bb = -numpy.dot(x.T,A)
+  alpha = eps*eps - numpy.inner(x,x)
+  
+  direction = numpy.dot(A_pinv,(numpy.dot(A,s)-x))
+  s0 = s - (1.0 - eps/numpy.linalg.norm(numpy.dot(A,direction))) * direction
+  
+  a = s
+  xk = s0
+  m1 = 1
+  m2 = 1
+  c1 = 0.1
+  c2 = 0.8
+  done = False
+  k = 0
+  while not done and k < 50:
+    
+    uk = numpy.dot(AA,xk) + bb
+    vk = a - xk
+    
+    zk = uk - (numpy.inner(uk,vk)/numpy.inner(vk,vk))*vk
+    vtav = numpy.inner(vk,numpy.dot(AA,vk))
+    vtv = numpy.inner(vk,vk)
+    ztaz = numpy.inner(zk,numpy.dot(AA,zk))
+    ztz = numpy.inner(zk,zk)
+    vtaz = numpy.inner(vk,numpy.dot(AA,zk))
+    gammak1 = 1.0/(0.5 * ( vtav/vtv + ztaz/ztz + math.sqrt((vtaz/vtv - ztaz/ztz)**2 + 4*vtaz**2/vtv/ztz)))
+    
+    pk = vk / numpy.linalg.norm(vk)
+    qk = zk / numpy.linalg.norm(zk)
+    Hk = numpy.zeros((pk.size,2))
+    Hk[:,0] = pk
+    Hk[:,1] = qk
+    Ak = numpy.dot(Hk.T, numpy.dot(AA,Hk))
+    bk = numpy.dot(Hk.T,uk)
+    
+    #al = numpy.dot(Hk, numpy.dot(Hk.T, a))
+    al = numpy.array([numpy.linalg.norm(vk), 0])
+    D,Q = numpy.linalg.eig(Ak)
+    Q = Q.T
+    ah = numpy.dot(Q,al) + (1.0/D) * numpy.dot(Q,bk)
+    
+    l1 = D[0]
+    l2 = D[1]
+    Qbk = numpy.dot(Q,bk)
+    beta = numpy.dot(Qbk.T, (1.0/D) * Qbk)
+    hstar1s = numpy.roots(numpy.array([ (l1-l2)**2*l1, 
+                                  2*(l1-l2)*l2*ah[0]*l1,
+                                  -(l1-l2)**2*beta + l2**2*ah[0]**2*l1 + l1**2*l2*ah[1]**2,
+                                  -2*beta*(l1-l2)*l2*ah[0],
+                                  -beta*l2**2*ah[0]**2]))
+    hstar2s = numpy.zeros_like(hstar1s)
+    i_s = []
+    illcond = False  # flag if ill conditioned problem (numerical errros)
+    for i in range(hstar1s.size):
+      
+      # Protect against bad conditioning (ratio of two very small values)
+      if numpy.abs(l1*ah[1]) > 1e-6 and numpy.abs((l1-l2) + l2*ah[0]/hstar1s[i]) > 1e-6:
+        
+        # Ignore small imaginary parts
+        if numpy.abs(numpy.imag(hstar1s[i])) < 1e-10:
+          hstar1s[i] = numpy.real(hstar1s[i])
+        
+        hstar2s[i] = l1*ah[1] / ((l1-l2)*hstar1s[i] + l2*ah[0]) * hstar1s[i]
+        
+        # Ignore small imaginary parts
+        if numpy.abs(numpy.imag(hstar2s[i])) < 1e-10:
+          hstar2s[i] = numpy.real(hstar2s[i])
+          
+        if (ah[0] - hstar1s[i]) / (l1*hstar1s[i]) > 0 and (ah[1] - hstar2s[i]) / (l2*hstar2s[i]) > 0:
+          i_s.append(i)
+        
+      else:
+        # Cannot rely on hstar2s[i] calculation since it is the ratio of two small numbers
+        # Do a vertical projection instead
+          hstar1 = ah[0]
+          hstar2 = numpy.sign(ah[1]) * math.sqrt((beta - l1*ah[0]**2)/l2)
+          illcond = True  # Flag, so we don't take i_s[] into account anymore
+    
+    if illcond:
+      print "Ill conditioned problem, do vertical projection instead"
+      # hstar1 and hstar2 are already set above, nothing to do here
+    else:
+      if len(i_s) > 1:
+        hstar1 = hstar1s[i_s[0]].real
+        hstar2 = hstar2s[i_s[0]].real
+      elif len(i_s) == 0:
+        # Again do vertical projection
+        hstar1 = ah[0]
+        hstar2 = numpy.sign(ah[1]) * math.sqrt((beta - l1*ah[0]**2)/l2)
+      else:
+        # Everything is ok
+        hstar1 = hstar1s[i_s].real
+        hstar2 = hstar2s[i_s].real
+      
+    ahstar = numpy.array([hstar1, hstar2]).flatten()
+    alstar = numpy.dot(Q.T, ahstar - (1.0/D) * numpy.dot(Q,bk))
+    alstar1 = alstar[0]
+    alstar2 = alstar[1]
+    etak = 1 - alstar1/numpy.linalg.norm(vk) + numpy.inner(uk,vk)/vtv*alstar2/numpy.linalg.norm(zk)
+    gammak2 = -alstar2/numpy.linalg.norm(zk)/etak
+    if k % (m1+m2) < m1:
+      gammak = gammak2
+    else:
+      gammak = c1*gammak1 + c2*gammak2
+      
+    # Safeguard:
+    if gammak < 0:
+      gammak = gammak1
+
+    ck = xk - gammak * uk
+    wk = ck - a
+    
+    ga = numpy.dot(AA,a) + bb
+    qa = numpy.inner(a,numpy.dot(AA,a)) + 2*numpy.inner(bb,a)
+    # Check if delta < 0 but very small (possibly numerical errors)
+    if (numpy.inner(ga,wk)/numpy.inner(wk, numpy.dot(AA,wk)))**2 - (qa-alpha)/numpy.inner(wk, numpy.dot(AA,wk)) < 0 and abs((numpy.inner(ga,wk)/numpy.inner(wk, numpy.dot(AA,wk)))**2 - (qa-alpha)/numpy.inner(wk, numpy.dot(AA,wk))) < 1e-10:
+      etak = -numpy.inner(ga,wk)/numpy.inner(wk, numpy.dot(AA,wk))
+    else:
+      assert ((numpy.inner(ga,wk)/numpy.inner(wk, numpy.dot(AA,wk)))**2 - (qa-alpha)/numpy.inner(wk, numpy.dot(AA,wk)) >= 0)
+      etak = -numpy.inner(ga,wk)/numpy.inner(wk, numpy.dot(AA,wk)) - math.sqrt((numpy.inner(ga,wk)/numpy.inner(wk, numpy.dot(AA,wk)))**2 - (qa-alpha)/numpy.inner(wk, numpy.dot(AA,wk)))
+    xk = a + etak * wk
+    
+    if (1 - numpy.inner(uk,vk) / numpy.linalg.norm(uk) / numpy.linalg.norm(vk)) <= 0.01:
+      done = True
+    k = k+1
+  
+  return xk
+
+  
+def ellipse_proj_proj(A,x,s,eps,L2):
+  A_pinv = numpy.linalg.pinv(A)
+  u,singvals,v  = numpy.linalg.svd(A, full_matrices=0)
+  singvals = numpy.flipud(singvals)
+  s_orig = s
+  
+  for j in range(L2):
+    direction = numpy.dot(A_pinv,(numpy.dot(A,s)-x))
+
+    if (numpy.linalg.norm(numpy.dot(A,direction)) >= eps):
+      
+      P = numpy.dot(numpy.dot(u,v), s)
+      sproj = s - (1.0 - eps/numpy.linalg.norm(numpy.dot(A,direction))) * direction
+      P0 = numpy.dot(numpy.dot(u,v), sproj)
+      
+      tangent = (P0 * (singvals**2)).reshape((1,P.size))
+      uu,ss,vv = numpy.linalg.svd(tangent)
+      svd = vv[1:,:]
+      P1 = numpy.linalg.solve(numpy.vstack((tangent,svd)), numpy.vstack((numpy.array([[eps]]), numpy.dot(svd, P).reshape((svd.shape[0],1)))))
+      
+      # Take only a smaller step
+      #P1 = P0.reshape((P0.size,1)) + 0.1*(P1-P0.reshape((P0.size,1)))
+      
+      #s = numpy.dot(A_pinv,P1).flatten() + numpy.dot(A_pinv,numpy.dot(A,s)).flatten()
+      s = numpy.dot(numpy.linalg.pinv(numpy.dot(u,v)),P1).flatten() + (s-numpy.dot(A_pinv,numpy.dot(A,s)).flatten())
+      
+      #assert(numpy.linalg.norm(x - numpy.dot(A,s)) < eps + 1e-6)          
+  
+  direction = numpy.dot(A_pinv,(numpy.dot(A,s)-x))
+  if (numpy.linalg.norm(numpy.dot(A,direction)) >= eps):
+    s = s - (1.0 - eps/numpy.linalg.norm(numpy.dot(A,direction))) * direction  
+    
+  return s
+
+def ellipse_proj_logbarrier(A,b,p,epsilon,verbose=False):
+  return l1qc_logbarrier(numpy.zeros_like(p), p, A, A.T, b, epsilon, lbtol=1e-3, mu=10, cgtol=1e-8, cgmaxiter=200, verbose=verbose)
+
+def l1qc_newton(x0, p, A, At, b, epsilon, tau, newtontol, newtonmaxiter, cgtol, cgmaxiter, verbose=False):
+    # Newton algorithm for log-barrier subproblems for l1 minimization
+    # with quadratic constraints.
+    #
+    # Usage: 
+    # [xp,up,niter] = l1qc_newton(x0, u0, A, At, b, epsilon, tau, 
+    #                             newtontol, newtonmaxiter, cgtol, cgmaxiter)
+    #
+    # x0,u0 - starting points
+    #
+    # A - Either a handle to a function that takes a N vector and returns a K 
+    #     vector , or a KxN matrix.  If A is a function handle, the algorithm
+    #     operates in "largescale" mode, solving the Newton systems via the
+    #     Conjugate Gradients algorithm.
+    #
+    # At - Handle to a function that takes a K vector and returns an N vector.
+    #      If A is a KxN matrix, At is ignored.
+    #
+    # b - Kx1 vector of observations.
+    #
+    # epsilon - scalar, constraint relaxation parameter
+    #
+    # tau - Log barrier parameter.
+    #
+    # newtontol - Terminate when the Newton decrement is <= newtontol.
+    #         Default = 1e-3.
+    #
+    # newtonmaxiter - Maximum number of iterations.
+    #         Default = 50.
+    #
+    # cgtol - Tolerance for Conjugate Gradients; ignored if A is a matrix.
+    #     Default = 1e-8.
+    #
+    # cgmaxiter - Maximum number of iterations for Conjugate Gradients; ignored
+    #     if A is a matrix.
+    #     Default = 200.
+    #
+    # Written by: Justin Romberg, Caltech
+    # Email: jrom@acm.caltech.edu
+    # Created: October 2005
+    #
+    
+    # check if the matrix A is implicit or explicit
+    #largescale = isa(A,'function_handle');
+    if hasattr(A, '__call__'):
+        largescale = True
+    else:
+        largescale = False    
+    
+    # line search parameters
+    alpha = 0.01
+    beta = 0.5
+    
+    #if (~largescale), AtA = A'*A; end
+    if not largescale:
+        AtA = numpy.dot(A.T,A)
+    
+    # initial point
+    x = x0.copy()
+    #u = u0.copy()
+    #if (largescale), r = A(x) - b; else  r = A*x - b; end
+    if largescale:
+        r = A(x) - b
+    else:
+        r = numpy.dot(A,x) - b
+        
+    #fu1 = x - u
+    #fu2 = -x - u
+    fe = 1.0/2*(numpy.vdot(r,r) - epsilon**2)
+    #f = u.sum() - (1.0/tau)*(numpy.log(-fu1).sum() + numpy.log(-fu2).sum() + math.log(-fe))
+    f = numpy.linalg.norm(p-x)**2 - (1.0/tau) * math.log(-fe)
+    
+    niter = 0
+    done = 0
+    while not done:
+      
+      #if (largescale), atr = At(r); else  atr = A'*r; end
+      if largescale:
+          atr = At(r)
+      else:
+          atr = numpy.dot(A.T,r)
+      
+      ##ntgz = 1./fu1 - 1./fu2 + 1/fe*atr;
+      #ntgz = 1.0/fu1 - 1.0/fu2 + 1.0/fe*atr
+      ntgz = 1.0/fe*atr
+      ##ntgu = -tau - 1./fu1 - 1./fu2;
+      #ntgu = -tau - 1.0/fu1 - 1.0/fu2
+      ##gradf = -(1/tau)*[ntgz; ntgu];
+      #gradf = -(1.0/tau)*numpy.concatenate((ntgz, ntgu),0)
+      gradf = 2*x + 2*p -(1.0/tau)*ntgz
+      
+      ##sig11 = 1./fu1.^2 + 1./fu2.^2;
+      #sig11 = 1.0/(fu1**2) + 1.0/(fu2**2)
+      ##sig12 = -1./fu1.^2 + 1./fu2.^2;
+      #sig12 = -1.0/(fu1**2) + 1.0/(fu2**2)
+      ##sigx = sig11 - sig12.^2./sig11;
+      #sigx = sig11 - (sig12**2)/sig11
+        
+      ##w1p = ntgz - sig12./sig11.*ntgu;
+      #w1p = ntgz - sig12/sig11*ntgu
+      #w1p = -tau * (2*x + 2*p) + ntgz
+      w1p = -gradf
+      if largescale:
+        #h11pfun = @(z) sigx.*z - (1/fe)*At(A(z)) + 1/fe^2*(atr'*z)*atr;
+        h11pfun = lambda z: sigx*z - (1.0/fe)*At(A(z)) + 1.0/(fe**2)*numpy.dot(numpy.dot(atr.T,z),atr)
+        dx,cgres,cgiter = cgsolve(h11pfun, w1p, cgtol, cgmaxiter, 0)
+        if (cgres > 1.0/2):
+          if verbose:
+            print 'Cannot solve system.  Returning previous iterate.  (See Section 4 of notes for more information.)'
+          xp = x.copy()
+          up = u.copy()
+          return xp,up,niter
+        #end
+        Adx = A(dx)
+      else:
+        ##H11p = diag(sigx) - (1/fe)*AtA + (1/fe)^2*atr*atr';
+        # Attention: atr is column vector, so atr*atr' means outer(atr,atr)
+        #H11p = numpy.diag(sigx) - (1.0/fe)*AtA + (1.0/fe)**2*numpy.outer(atr,atr)
+        H11p = 2 * numpy.eye(x.size) - (1.0/fe)*AtA + (1.0/fe)**2*numpy.outer(atr,atr)
+        #opts.POSDEF = true; opts.SYM = true;
+        #[dx,hcond] = linsolve(H11p, w1p, opts);
+        #if (hcond < 1e-14)
+        #  disp('Matrix ill-conditioned.  Returning previous iterate.  (See Section 4 of notes for more information.)');
+        #  xp = x;  up = u;
+        #  return
+        #end
+        try:
+            dx = scipy.linalg.solve(H11p, w1p, sym_pos=True)
+            #dx = numpy.linalg.solve(H11p, w1p)
+            hcond = 1.0/numpy.linalg.cond(H11p)
+        except scipy.linalg.LinAlgError:
+            if verbose:
+              print 'Matrix ill-conditioned.  Returning previous iterate.  (See Section 4 of notes for more information.)'
+            xp = x.copy()
+            #up = u.copy()
+            #return xp,up,niter
+            return xp,niter
+        if hcond < 1e-14:
+            if verbose:
+              print 'Matrix ill-conditioned.  Returning previous iterate.  (See Section 4 of notes for more information.)'
+            xp = x.copy()
+            #up = u.copy()
+            #return xp,up,niter
+            return xp,niter
+        
+        #Adx = A*dx;
+        Adx = numpy.dot(A,dx)
+      #end
+      ##du = (1./sig11).*ntgu - (sig12./sig11).*dx;  
+      #du = (1.0/sig11)*ntgu - (sig12/sig11)*dx;
+     
+      # minimum step size that stays in the interior
+      ##ifu1 = find((dx-du) > 0); ifu2 = find((-dx-du) > 0);
+      #ifu1 = numpy.nonzero((dx-du)>0)
+      #ifu2 = numpy.nonzero((-dx-du)>0)
+      #aqe = Adx'*Adx;   bqe = 2*r'*Adx;   cqe = r'*r - epsilon^2;
+      aqe = numpy.dot(Adx.T,Adx)
+      bqe = 2*numpy.dot(r.T,Adx)
+      cqe = numpy.vdot(r,r) - epsilon**2
+      #smax = min(1,min([...
+      #  -fu1(ifu1)./(dx(ifu1)-du(ifu1)); -fu2(ifu2)./(-dx(ifu2)-du(ifu2)); ...
+      #  (-bqe+sqrt(bqe^2-4*aqe*cqe))/(2*aqe)
+      #  ]));
+      #smax = min(1,numpy.concatenate( (-fu1[ifu1]/(dx[ifu1]-du[ifu1]) , -fu2[ifu2]/(-dx[ifu2]-du[ifu2]) , numpy.array([ (-bqe + math.sqrt(bqe**2-4*aqe*cqe))/(2*aqe) ]) ) , 0).min())
+      smax = min(1,numpy.array([ (-bqe + math.sqrt(bqe**2-4*aqe*cqe))/(2*aqe) ] ).min())
+      
+      s = 0.99 * smax
+      
+      # backtracking line search
+      suffdec = 0
+      backiter = 0
+      while not suffdec:
+        #xp = x + s*dx;  up = u + s*du;  rp = r + s*Adx;
+        xp = x + s*dx
+        #up = u + s*du
+        rp = r + s*Adx
+        #fu1p = xp - up;  fu2p = -xp - up;  fep = 1/2*(rp'*rp - epsilon^2);
+        #fu1p = xp - up
+        #fu2p = -xp - up
+        fep = 0.5*(numpy.vdot(rp,rp) - epsilon**2)
+        ##fp = sum(up) - (1/tau)*(sum(log(-fu1p)) + sum(log(-fu2p)) + log(-fep));
+        #fp = up.sum() - (1.0/tau)*(numpy.log(-fu1p).sum() + numpy.log(-fu2p).sum() + math.log(-fep))
+        fp = numpy.linalg.norm(p-xp)**2 - (1.0/tau) * math.log(-fep)
+        #flin = f + alpha*s*(gradf'*[dx; du]);
+        flin = f + alpha*s*numpy.dot(gradf.T , dx)
+        #suffdec = (fp <= flin);
+        if fp <= flin:
+            suffdec = True
+        else:
+            suffdec = False
+        
+        s = beta*s
+        backiter = backiter + 1
+        if (backiter > 132):
+          if verbose:
+            print 'Stuck on backtracking line search, returning previous iterate.  (See Section 4 of notes for more information.)'
+          xp = x.copy()
+          #up = u.copy()
+          #return xp,up,niter
+          return xp,niter
+        #end
+      #end
+      
+      # set up for next iteration
+      ##x = xp; u = up;  r = rp;
+      x = xp.copy()
+      #u = up.copy()
+      r = rp.copy()
+      ##fu1 = fu1p;  fu2 = fu2p;  fe = fep;  f = fp;
+      #fu1 = fu1p.copy()
+      #fu2 = fu2p.copy()
+      fe = fep
+      f = fp
+      
+      ##lambda2 = -(gradf'*[dx; du]);
+      #lambda2 = -numpy.dot(gradf.T , numpy.concatenate((dx,du),0))
+      lambda2 = -numpy.dot(gradf.T , dx)
+      ##stepsize = s*norm([dx; du]);
+      #stepsize = s * numpy.linalg.norm(numpy.concatenate((dx,du),0))
+      stepsize = s * numpy.linalg.norm(dx)
+      niter = niter + 1
+      #done = (lambda2/2 < newtontol) | (niter >= newtonmaxiter);
+      if lambda2/2.0 < newtontol or niter >= newtonmaxiter:
+          done = 1
+      else:
+          done = 0
+      
+      #disp(sprintf('Newton iter = #d, Functional = #8.3f, Newton decrement = #8.3f, Stepsize = #8.3e', ...
+      if verbose:
+        print 'Newton iter = ',niter,', Functional = ',f,', Newton decrement = ',lambda2/2.0,', Stepsize = ',stepsize
+
+      if verbose:
+        if largescale:
+          print '                CG Res = ',cgres,', CG Iter = ',cgiter
+        else:
+          print '                  H11p condition number = ',hcond
+      #end
+          
+    #end
+    #return xp,up,niter
+    return xp,niter
+
+#function xp = l1qc_logbarrier(x0, A, At, b, epsilon, lbtol, mu, cgtol, cgmaxiter)
+def l1qc_logbarrier(x0, p, A, At, b, epsilon, lbtol=1e-3, mu=10, cgtol=1e-8, cgmaxiter=200, verbose=False):
+    # Solve quadratically constrained l1 minimization:
+    # min ||x||_1   s.t.  ||Ax - b||_2 <= \epsilon
+    #
+    # Reformulate as the second-order cone program
+    # min_{x,u}  sum(u)   s.t.    x - u <= 0,
+    #                            -x - u <= 0,
+    #      1/2(||Ax-b||^2 - \epsilon^2) <= 0
+    # and use a log barrier algorithm.
+    #
+    # Usage:  xp = l1qc_logbarrier(x0, A, At, b, epsilon, lbtol, mu, cgtol, cgmaxiter)
+    #
+    # x0 - Nx1 vector, initial point.
+    #
+    # A - Either a handle to a function that takes a N vector and returns a K 
+    #     vector , or a KxN matrix.  If A is a function handle, the algorithm
+    #     operates in "largescale" mode, solving the Newton systems via the
+    #     Conjugate Gradients algorithm.
+    #
+    # At - Handle to a function that takes a K vector and returns an N vector.
+    #      If A is a KxN matrix, At is ignored.
+    #
+    # b - Kx1 vector of observations.
+    #
+    # epsilon - scalar, constraint relaxation parameter
+    #
+    # lbtol - The log barrier algorithm terminates when the duality gap <= lbtol.
+    #         Also, the number of log barrier iterations is completely
+    #         determined by lbtol.
+    #         Default = 1e-3.
+    #
+    # mu - Factor by which to increase the barrier constant at each iteration.
+    #      Default = 10.
+    #
+    # cgtol - Tolerance for Conjugate Gradients; ignored if A is a matrix.
+    #     Default = 1e-8.
+    #
+    # cgmaxiter - Maximum number of iterations for Conjugate Gradients; ignored
+    #     if A is a matrix.
+    #     Default = 200.
+    #
+    # Written by: Justin Romberg, Caltech
+    # Email: jrom@acm.caltech.edu
+    # Created: October 2005
+    #
+
+    
+    # Check if epsilon > 0. If epsilon is 0, the algorithm fails. You should run the algo with equality constraint instead  
+    if epsilon == 0:
+      raise l1qcInputValueError('Epsilon should be > 0!')       
+    
+    #largescale = isa(A,'function_handle');
+    if hasattr(A, '__call__'):
+        largescale = True
+    else:
+        largescale = False
+    
+    #    if (nargin < 6), lbtol = 1e-3; end
+    #    if (nargin < 7), mu = 10; end
+    #    if (nargin < 8), cgtol = 1e-8; end
+    #    if (nargin < 9), cgmaxiter = 200; end
+    # Nic: added them as optional parameteres
+    
+    newtontol = lbtol
+    newtonmaxiter = 150
+    
+    #N = length(x0);
+    N = x0.size
+    
+    # starting point --- make sure that it is feasible
+    if largescale:
+      if numpy.linalg.norm(A(x0) - b) > epsilon:
+        if verbose:
+          print 'Starting point infeasible; using x0 = At*inv(AAt)*y.'
+        #AAt = @(z) A(At(z));
+        AAt = lambda z: A(At(z))
+        # TODO: implement cgsolve
+        w,cgres,cgiter = cgsolve(AAt, b, cgtol, cgmaxiter, 0)
+        if (cgres > 1.0/2):
+          if verbose:
+            print 'A*At is ill-conditioned: cannot find starting point'
+          xp = x0.copy()
+          return xp
+        #end
+        x0 = At(w)
+      #end
+    else:
+      if numpy.linalg.norm( numpy.dot(A,x0) - b ) > epsilon:
+        if verbose:
+          print 'Starting point infeasible; using x0 = At*inv(AAt)*y.'
+        #opts.POSDEF = true; opts.SYM = true;
+        #[w, hcond] = linsolve(A*A', b, opts);
+        #if (hcond < 1e-14)
+        #  disp('A*At is ill-conditioned: cannot find starting point');
+        #  xp = x0;
+        #  return;
+        #end
+        try:
+            w = scipy.linalg.solve(numpy.dot(A,A.T), b, sym_pos=True)
+            #w = numpy.linalg.solve(numpy.dot(A,A.T), b)
+            hcond = 1.0/numpy.linalg.cond(numpy.dot(A,A.T))
+        except scipy.linalg.LinAlgError:
+            if verbose:
+              print 'A*At is ill-conditioned: cannot find starting point'
+            xp = x0.copy()
+            return xp
+        if hcond < 1e-14:
+            if verbose:
+              print 'A*At is ill-conditioned: cannot find starting point'
+            xp = x0.copy()
+            return xp           
+        #x0 = A'*w;
+        x0 = numpy.dot(A.T, w)
+      #end  
+    #end
+    x = x0.copy()
+    #u = (0.95)*numpy.abs(x0) + (0.10)*numpy.abs(x0).max()
+    
+    #disp(sprintf('Original l1 norm = #.3f, original functional = #.3f', sum(abs(x0)), sum(u)));
+    if verbose:
+      #print 'Original l1 norm = ',numpy.abs(x0).sum(),'original functional = ',u.sum()
+      print 'Original distance ||p-x|| = ',numpy.linalg.norm(p-x)
+    # choose initial value of tau so that the duality gap after the first
+    # step will be about the origial norm
+    #tau = max(((2*N+1.0)/numpy.abs(x0).sum()), 1)
+    # Nic:
+    tau = max(((2*N+1.0)/numpy.linalg.norm(p-x0)**2), 1)
+                                                                                                                              
+    lbiter = math.ceil((math.log(2*N+1)-math.log(lbtol)-math.log(tau))/math.log(mu))
+    #disp(sprintf('Number of log barrier iterations = #d\n', lbiter));
+    if verbose:
+      print 'Number of log barrier iterations = ',lbiter
+    
+    totaliter = 0
+    
+    # Added by Nic, to fix some crashing
+    if lbiter == 0:
+        xp = numpy.zeros(x0.size)
+    #end
+    
+    #for ii = 1:lbiter
+    for ii in numpy.arange(lbiter):
+    
+      #xp,up,ntiter = l1qc_newton(x, u, A, At, b, epsilon, tau, newtontol, newtonmaxiter, cgtol, cgmaxiter)
+      xp,ntiter = l1qc_newton(x, p, A, At, b, epsilon, tau, newtontol, newtonmaxiter, cgtol, cgmaxiter, verbose=verbose)
+      totaliter = totaliter + ntiter
+      
+      #disp(sprintf('\nLog barrier iter = #d, l1 = #.3f, functional = #8.3f, tau = #8.3e, total newton iter = #d\n', ...
+      #  ii, sum(abs(xp)), sum(up), tau, totaliter));
+      if verbose:
+        #print 'Log barrier iter = ',ii,', l1 = ',numpy.abs(xp).sum(),', functional = ',up.sum(),', tau = ',tau,', total newton iter = ',totaliter
+        print 'Log barrier iter = ',ii,', l1 = ',numpy.abs(xp).sum(),', functional = ',numpy.linalg.norm(p-xp),', tau = ',tau,', total newton iter = ',totaliter
+      x = xp.copy()
+      #u = up.copy()
+     
+      tau = mu*tau
+      
+    #end
+    return xp  
\ No newline at end of file
--- a/pyCSalgos/SL0/SL0_approx.py	Fri Mar 16 13:35:47 2012 +0200
+++ b/pyCSalgos/SL0/SL0_approx.py	Mon Apr 23 10:55:49 2012 +0300
@@ -12,13 +12,18 @@
 @author: Nic
 """
 
-import numpy as np
+import numpy
+import math
+#import cvxpy
+import EllipseProj
+
+
 
 #function s=SL0(A, x, sigma_min, sigma_decrease_factor, mu_0, L, A_pinv, true_s)
 def SL0_approx(A, x, eps, sigma_min, sigma_decrease_factor=0.5, mu_0=2, L=3, A_pinv=None, true_s=None):
   
   if A_pinv is None:
-    A_pinv = np.linalg.pinv(A)
+    A_pinv = numpy.linalg.pinv(A)
   
   if true_s is not None:
       ShowProgress = True
@@ -27,25 +32,227 @@
   
   # Initialization
   #s = A\x;
-  s = np.dot(A_pinv,x)
-  sigma = 2.0 * np.abs(s).max()
+  s = numpy.dot(A_pinv,x)
+  sigma = 2.0 * numpy.abs(s).max()
   
   # Main Loop
   while sigma>sigma_min:
-      for i in np.arange(L):
+      for i in numpy.arange(L):
           delta = OurDelta(s,sigma)
           s = s - mu_0*delta
           # At this point, s no longer exactly satisfies x = A*s
           # The original SL0 algorithm projects s onto {s | x = As} with
-          # s = s - np.dot(A_pinv,(np.dot(A,s)-x))   # Projection
+          # s = s - numpy.dot(A_pinv,(numpy.dot(A,s)-x))   # Projection
           # We want to project s onto {s | |x-As| < eps}
           # We move onto the direction -A_pinv*(A*s-x), but only with a
           # smaller step:
-          direction = np.dot(A_pinv,(np.dot(A,s)-x))
-          if (np.linalg.norm(np.dot(A,direction)) >= eps):
-            s = s - (1.0 - eps/np.linalg.norm(np.dot(A,direction))) * direction
+          direction = numpy.dot(A_pinv,(numpy.dot(A,s)-x))
+          if (numpy.linalg.norm(numpy.dot(A,direction)) >= eps):
+            s = s - (1.0 - eps/numpy.linalg.norm(numpy.dot(A,direction))) * direction
 
-          #assert(np.linalg.norm(x - np.dot(A,s)) < eps + 1e-6)          
+          #assert(numpy.linalg.norm(x - numpy.dot(A,s)) < eps + 1e-6)          
+      
+      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
+
+
+def SL0_approx_cvxpy(A, x, eps, sigma_min, sigma_decrease_factor=0.5, mu_0=2, L=3, A_pinv=None, true_s=None):
+  
+  if A_pinv is None:
+    A_pinv = numpy.linalg.pinv(A)
+  
+  if true_s is not None:
+      ShowProgress = True
+  else:
+      ShowProgress = False
+  
+  # Initialization
+  #s = A\x;
+  s = numpy.dot(A_pinv,x)
+  sigma = 2.0 * numpy.abs(s).max()
+  
+  # Main Loop
+  while sigma>sigma_min:
+      for i in numpy.arange(L):
+          delta = OurDelta(s,sigma)
+          s = s - mu_0*delta
+          # At this point, s no longer exactly satisfies x = A*s
+          # The original SL0 algorithm projects s onto {s | x = As} with
+          # s = s - numpy.dot(A_pinv,(numpy.dot(A,s)-x))   # Projection
+          # We want to project s onto {s | |x-As| < eps}
+          # We move onto the direction -A_pinv*(A*s-x), but only with a
+          # smaller step:
+          direction = numpy.dot(A_pinv,(numpy.dot(A,s)-x))
+          if (numpy.linalg.norm(numpy.dot(A,direction)) >= eps):
+            #s = s - (1.0 - eps/numpy.linalg.norm(numpy.dot(A,direction))) * direction
+            s = EllipseProj.ellipse_proj_cvxpy(A,x,s,eps)
+
+          #assert(numpy.linalg.norm(x - numpy.dot(A,s)) < eps + 1e-6)          
+      
+      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
+
+
+def SL0_approx_dai(A, x, eps, sigma_min, sigma_decrease_factor=0.5, mu_0=2, L=3, A_pinv=None, true_s=None):
+  
+  if A_pinv is None:
+    A_pinv = numpy.linalg.pinv(A)
+  
+  if true_s is not None:
+      ShowProgress = True
+  else:
+      ShowProgress = False
+  
+  # Initialization
+  #s = A\x;
+  s = numpy.dot(A_pinv,x)
+  sigma = 2.0 * numpy.abs(s).max()
+  
+  # Main Loop
+  while sigma>sigma_min:
+      for i in numpy.arange(L):
+          delta = OurDelta(s,sigma)
+          s = s - mu_0*delta
+          # At this point, s no longer exactly satisfies x = A*s
+          # The original SL0 algorithm projects s onto {s | x = As} with
+          # s = s - numpy.dot(A_pinv,(numpy.dot(A,s)-x))   # Projection
+          # We want to project s onto {s | |x-As| < eps}
+          # We move onto the direction -A_pinv*(A*s-x), but only with a
+          # smaller step:
+          direction = numpy.dot(A_pinv,(numpy.dot(A,s)-x))
+          if (numpy.linalg.norm(numpy.dot(A,direction)) >= eps):
+            #s = s - (1.0 - eps/numpy.linalg.norm(numpy.dot(A,direction))) * direction
+            try:
+              s = EllipseProj.ellipse_proj_dai(A,x,s,eps)
+            except Exception, e:
+              #raise EllipseProj.EllipseProjDaiError(e)
+              raise EllipseProj.EllipseProjDaiError()
+              
+
+          #assert(numpy.linalg.norm(x - numpy.dot(A,s)) < eps + 1e-6)          
+      
+      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
+
+def SL0_approx_proj(A, x, eps, sigma_min, sigma_decrease_factor=0.5, mu_0=2, L=3, L2=3, A_pinv=None, true_s=None):
+  
+  if A_pinv is None:
+    A_pinv = numpy.linalg.pinv(A)
+  
+  if true_s is not None:
+      ShowProgress = True
+  else:
+      ShowProgress = False
+  
+  # Initialization
+  #s = A\x;
+  s = numpy.dot(A_pinv,x)
+  sigma = 2.0 * numpy.abs(s).max()
+  
+  u,singvals,v  = numpy.linalg.svd(A, full_matrices=0)
+  
+  # Main Loop
+  while sigma>sigma_min:
+      for i in numpy.arange(L):
+          delta = OurDelta(s,sigma)
+          s = s - mu_0*delta
+          # At this point, s no longer exactly satisfies x = A*s
+          # The original SL0 algorithm projects s onto {s | x = As} with
+          # s = s - numpy.dot(A_pinv,(numpy.dot(A,s)-x))   # Projection
+          # We want to project s onto {s | |x-As| < eps}
+          # We move onto the direction -A_pinv*(A*s-x), but only with a
+          # smaller step:
+          s_orig = s
+
+          # Reference
+          direction = numpy.dot(A_pinv,(numpy.dot(A,s)-x))
+          if (numpy.linalg.norm(numpy.dot(A,direction)) >= eps):
+            #s = s - (1.0 - eps/numpy.linalg.norm(numpy.dot(A,direction))) * direction
+            s_cvxpy = EllipseProj.ellipse_proj_cvxpy(A,x,s,eps)       
+            
+          # Starting point
+          direction = numpy.dot(A_pinv,(numpy.dot(A,s)-x))
+          if (numpy.linalg.norm(numpy.dot(A,direction)) >= eps):
+            s_first = s - (1.0 - eps/numpy.linalg.norm(numpy.dot(A,direction))) * direction
+
+          #steps = 1
+          ##steps = math.floor(math.log2(numpy.lingl.norm(s)/eps))
+          #step = math.pow(numpy.linalg.norm(s)/eps, 1.0/steps)
+          #eps = eps * step**(steps-1)
+          #for k in range(steps):
+            
+          direction = numpy.dot(A_pinv,(numpy.dot(A,s)-x))
+          if (numpy.linalg.norm(numpy.dot(A,direction)) >= eps):
+            s = EllipseProj.ellipse_proj_proj(A,x,s,eps,L2)
+            
+            #eps = eps/step
+      
+      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
+  
+def SL0_approx_unconstrained(A, x, eps, lmbda, sigma_min, sigma_decrease_factor=0.5, mu_0=2, L=3, A_pinv=None, true_s=None):
+  
+  if A_pinv is None:
+    A_pinv = numpy.linalg.pinv(A)
+  
+  if true_s is not None:
+      ShowProgress = True
+  else:
+      ShowProgress = False
+  
+  # Initialization
+  #s = A\x;
+  s = numpy.dot(A_pinv,x)
+  sigma = 2.0 * numpy.abs(s).max()
+  
+  lmbda =   1./(0.007 + 3.5*(eps/x.size)**2)*1e-5
+  #lmbda = 0.5
+  mu = mu_0  
+  
+  # Main Loop
+  while sigma>sigma_min:
+      for i in numpy.arange(L):
+          #delta = OurDeltaUnconstrained(s,sigma,lmbda,A,x)
+          delta = s * numpy.exp( (-numpy.abs(s)**2) / sigma**2) + (sigma**2)*lmbda*2*numpy.dot(A.T, numpy.dot(A,s)-x)
+          snew = s - mu*delta
+          
+          Js    =    s.size - numpy.sum(numpy.exp( (-numpy.abs(s)**2)    / sigma**2)) + lmbda*numpy.linalg.norm(numpy.dot(A,s)   -x)**2
+          Jsnew = snew.size - numpy.sum(numpy.exp( (-numpy.abs(snew)**2) / sigma**2)) + lmbda*numpy.linalg.norm(numpy.dot(A,snew)-x)**2
+          
+          #if Jsnew < Js:
+          #  rho = 1.2
+          #else:
+          #  rho = 0.5
+          rho = 1
+
+          #s = s - mu*delta
+          s = snew.copy()
+          
+          mu = mu * rho
       
       if ShowProgress:
           #fprintf('     sigma=#f, SNR=#f\n',sigma,estimate_SNR(s,true_s))
@@ -64,9 +271,9 @@
 def SL0_approx_analysis(Aeps, Aexact, x, eps, sigma_min, sigma_decrease_factor=0.5, mu_0=2, L=3, Aeps_pinv=None, Aexact_pinv=None, true_s=None):
   
   if Aeps_pinv is None:
-    Aeps_pinv = np.linalg.pinv(Aeps)
+    Aeps_pinv = numpy.linalg.pinv(Aeps)
   if Aexact_pinv is None:
-    Aexact_pinv = np.linalg.pinv(Aexact)
+    Aexact_pinv = numpy.linalg.pinv(Aexact)
     
   if true_s is not None:
       ShowProgress = True
@@ -75,17 +282,17 @@
   
   # Initialization
   #s = A\x;
-  s = np.dot(Aeps_pinv,x)
-  sigma = 2.0 * np.abs(s).max()
+  s = numpy.dot(Aeps_pinv,x)
+  sigma = 2.0 * numpy.abs(s).max()
   
   # Main Loop
   while sigma>sigma_min:
-      for i in np.arange(L):
+      for i in numpy.arange(L):
           delta = OurDelta(s,sigma)
           s = s - mu_0*delta
           # At this point, s no longer exactly satisfies x = A*s
           # The original SL0 algorithm projects s onto {s | x = As} with
-          # s = s - np.dot(A_pinv,(np.dot(A,s)-x))   # Projection
+          # s = s - numpy.dot(A_pinv,(numpy.dot(A,s)-x))   # Projection
           #
           # We want to project s onto {s | |x-AEPS*s|<eps AND |Aexact*s|=0}
           # First:   make s orthogonal to Aexact (|Aexact*s|=0)
@@ -94,13 +301,70 @@
           #
           # 1. Make s orthogonal to Aexact:
           #     s = s - Aexact_pinv * Aexact * s
-          s = s - np.dot(Aexact_pinv,(np.dot(Aexact,s)))
+          s = s - numpy.dot(Aexact_pinv,(numpy.dot(Aexact,s)))
           # 2. Move onto the direction -A_pinv*(A*s-x), but only with a smaller step:
-          direction = np.dot(Aeps_pinv,(np.dot(Aeps,s)-x))
-          if (np.linalg.norm(np.dot(Aeps,direction)) >= eps):
-            s = s - (1.0 - eps/np.linalg.norm(np.dot(Aeps,direction))) * direction
+          direction = numpy.dot(Aeps_pinv,(numpy.dot(Aeps,s)-x))
+          # Nic 10.04.2012: Why numpy.dot(Aeps,direction) and not just 'direction'?
+          # Nic 10.04.2012: because 'direction' is of size(s), but I'm interested in it's projection on Aeps
+          if (numpy.linalg.norm(numpy.dot(Aeps,direction)) >= eps):
+            s = s - (1.0 - eps/numpy.linalg.norm(numpy.dot(Aeps,direction))) * direction
 
-          #assert(np.linalg.norm(x - np.dot(A,s)) < eps + 1e-6)          
+          #assert(numpy.linalg.norm(x - numpy.dot(A,s)) < eps + 1e-6)          
+      
+      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
+  
+
+def SL0_approx_analysis_cvxpy(Aeps, Aexact, x, eps, sigma_min, sigma_decrease_factor=0.5, mu_0=2, L=3, Aeps_pinv=None, Aexact_pinv=None, true_s=None):
+  
+  if Aeps_pinv is None:
+    Aeps_pinv = numpy.linalg.pinv(Aeps)
+  if Aexact_pinv is None:
+    Aexact_pinv = numpy.linalg.pinv(Aexact)
+    
+  if true_s is not None:
+      ShowProgress = True
+  else:
+      ShowProgress = False
+  
+  # Initialization
+  #s = A\x;
+  s = numpy.dot(Aeps_pinv,x)
+  sigma = 2.0 * numpy.abs(s).max()
+  
+  # Main Loop
+  while sigma>sigma_min:
+      for i in numpy.arange(L):
+          delta = OurDelta(s,sigma)
+          s = s - mu_0*delta
+          # At this point, s no longer exactly satisfies x = A*s
+          # The original SL0 algorithm projects s onto {s | x = As} with
+          # s = s - numpy.dot(A_pinv,(numpy.dot(A,s)-x))   # Projection
+          #
+          # We want to project s onto {s | |x-AEPS*s|<eps AND |Aexact*s|=0}
+          # First:   make s orthogonal to Aexact (|Aexact*s|=0)
+          # Second:  move onto the direction -A_pinv*(A*s-x), but only with a smaller step:
+          # This separation assumes that the rows of Aexact are orthogonal to the rows of Aeps
+          #
+          # 1. Make s orthogonal to Aexact:
+          #     s = s - Aexact_pinv * Aexact * s
+          s = s - numpy.dot(Aexact_pinv,(numpy.dot(Aexact,s)))
+          # 2. Move onto the direction -A_pinv*(A*s-x), but only with a smaller step:
+          direction = numpy.dot(Aeps_pinv,(numpy.dot(Aeps,s)-x))
+          # Nic 10.04.2012: Why numpy.dot(Aeps,direction) and not just 'direction'?
+          # Nic 10.04.2012: because 'direction' is of size(s), but I'm interested in it's projection on Aeps
+          if (numpy.linalg.norm(numpy.dot(Aeps,direction)) >= eps):
+            #  s = s - (1.0 - eps/numpy.linalg.norm(numpy.dot(Aeps,direction))) * direction
+            s = EllipseProj.ellipse_proj_cvxpy(Aeps,x,s,eps)
+            #s = EllipseProj.ellipse_proj_logbarrier(Aeps,x,s,eps)
+
+          #assert(numpy.linalg.norm(x - numpy.dot(A,s)) < eps + 1e-6)          
       
       if ShowProgress:
           #fprintf('     sigma=#f, SNR=#f\n',sigma,estimate_SNR(s,true_s))
@@ -111,17 +375,193 @@
   
   return s
 
+
+def SL0_approx_analysis_dai(Aeps, Aexact, x, eps, sigma_min, sigma_decrease_factor=0.5, mu_0=2, L=3, Aeps_pinv=None, Aexact_pinv=None, true_s=None):
+  
+  if Aeps_pinv is None:
+    Aeps_pinv = numpy.linalg.pinv(Aeps)
+  if Aexact_pinv is None:
+    Aexact_pinv = numpy.linalg.pinv(Aexact)
+    
+  if true_s is not None:
+      ShowProgress = True
+  else:
+      ShowProgress = False
+  
+  # Initialization
+  #s = A\x;
+  s = numpy.dot(Aeps_pinv,x)
+  sigma = 2.0 * numpy.abs(s).max()
+  
+  # Main Loop
+  while sigma>sigma_min:
+      for i in numpy.arange(L):
+          delta = OurDelta(s,sigma)
+          s = s - mu_0*delta
+          # At this point, s no longer exactly satisfies x = A*s
+          # The original SL0 algorithm projects s onto {s | x = As} with
+          # s = s - numpy.dot(A_pinv,(numpy.dot(A,s)-x))   # Projection
+          #
+          # We want to project s onto {s | |x-AEPS*s|<eps AND |Aexact*s|=0}
+          # First:   make s orthogonal to Aexact (|Aexact*s|=0)
+          # Second:  move onto the direction -A_pinv*(A*s-x), but only with a smaller step:
+          # This separation assumes that the rows of Aexact are orthogonal to the rows of Aeps
+          #
+          # 1. Make s orthogonal to Aexact:
+          #     s = s - Aexact_pinv * Aexact * s
+          s = s - numpy.dot(Aexact_pinv,(numpy.dot(Aexact,s)))
+          # 2. Move onto the direction -A_pinv*(A*s-x), but only with a smaller step:
+          direction = numpy.dot(Aeps_pinv,(numpy.dot(Aeps,s)-x))
+          # Nic 10.04.2012: Why numpy.dot(Aeps,direction) and not just 'direction'?
+          # Nic 10.04.2012: because 'direction' is of size(s), but I'm interested in it's projection on Aeps
+          if (numpy.linalg.norm(numpy.dot(Aeps,direction)) >= eps):
+            #  s = s - (1.0 - eps/numpy.linalg.norm(numpy.dot(Aeps,direction))) * direction
+            try:
+              s = EllipseProj.ellipse_proj_dai(Aeps,x,s,eps)
+            except Exception, e:
+              #raise EllipseProj.EllipseProjDaiError(e)
+              raise EllipseProj.EllipseProjDaiError()
+
+          #assert(numpy.linalg.norm(x - numpy.dot(A,s)) < eps + 1e-6)          
+      
+      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
+
+def SL0_robust_analysis(Aeps, Aexact, x, eps, sigma_min, sigma_decrease_factor=0.5, mu_0=2, L=3, Aeps_pinv=None, Aexact_pinv=None, true_s=None):
+  
+  if Aeps_pinv is None:
+    Aeps_pinv = numpy.linalg.pinv(Aeps)
+  if Aexact_pinv is None:
+    Aexact_pinv = numpy.linalg.pinv(Aexact)
+    
+  if true_s is not None:
+      ShowProgress = True
+  else:
+      ShowProgress = False
+  
+  # Initialization
+  #s = A\x;
+  s = numpy.dot(Aeps_pinv,x)
+  sigma = 2.0 * numpy.abs(s).max()
+  
+  # Main Loop
+  while sigma>sigma_min:
+      for i in numpy.arange(L):
+          delta = OurDelta(s,sigma)
+          s = s - mu_0*delta
+          # At this point, s no longer exactly satisfies x = A*s
+          # The original SL0 algorithm projects s onto {s | x = As} with
+          # s = s - numpy.dot(A_pinv,(numpy.dot(A,s)-x))   # Projection
+          #
+          # 1. Make s orthogonal to Aexact:
+          #     s = s - Aexact_pinv * Aexact * s
+          s = s - numpy.dot(Aexact_pinv,(numpy.dot(Aexact,s)))
+          # 2. 
+          if (numpy.linalg.norm(numpy.dot(Aeps,s) - x) >= eps):
+            s = s - numpy.dot(Aeps.T , numpy.dot(numpy.linalg.inv(numpy.dot(Aeps,Aeps.T)), numpy.dot(Aeps,s)-x))
+      
+      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
+ 
+#def SL0_approx_analysis_unconstrained(Aeps, Aexact, x, eps, sigma_min, sigma_decrease_factor=0.5, mu_0=2, L=3, Aeps_pinv=None, Aexact_pinv=None, true_s=None):
+#  
+#  if Aeps_pinv is None:
+#    Aeps_pinv = numpy.linalg.pinv(Aeps)
+#  if Aexact_pinv is None:
+#    Aexact_pinv = numpy.linalg.pinv(Aexact)
+#    
+#  if true_s is not None:
+#      ShowProgress = True
+#  else:
+#      ShowProgress = False
+#  
+#  # Initialization
+#  #s = A\x;
+#  s = numpy.dot(Aeps_pinv,x)
+#  sigma = 2.0 * numpy.abs(s).max()
+#  
+#  lmbda_orig = 1./(0.007 + 3.5*(eps/x.size)**2)
+#  #lmbda = 100/sigma**2
+#  mu = mu_0
+#  
+#  # Main Loop
+#  while sigma>sigma_min:
+#    
+#      lmbda = lmbda_orig * sigma**2
+#      
+#      for i in numpy.arange(L):
+#          delta = OurDeltaUnconstrained(s,sigma,lmbda,Aeps,x)
+#          snew = s - mu*delta
+#          
+#          Js    =    s.size - numpy.sum(numpy.exp( (-numpy.abs(s)**2)    / sigma**2)) + lmbda*numpy.linalg.norm(numpy.dot(Aeps,s)   -x)**2
+#          Jsnew = snew.size - numpy.sum(numpy.exp( (-numpy.abs(snew)**2) / sigma**2)) + lmbda*numpy.linalg.norm(numpy.dot(Aeps,snew)-x)**2
+#          
+#          if Jsnew < Js:
+#            rho = 1.2
+#          else:
+#            rho = 0.5
+#
+#          #s = s - mu*delta
+#          s = snew.copy()
+#          
+#          mu = mu * rho
+#          
+#          
+#          # At this point, s no longer exactly satisfies x = A*s
+#          # The original SL0 algorithm projects s onto {s | x = As} with
+#          # s = s - numpy.dot(A_pinv,(numpy.dot(A,s)-x))   # Projection
+#          #
+#          # We want to project s onto {s | |x-AEPS*s|<eps AND |Aexact*s|=0}
+#          # First:   make s orthogonal to Aexact (|Aexact*s|=0)
+#          # Second:  move onto the direction -A_pinv*(A*s-x), but only with a smaller step:
+#          # This separation assumes that the rows of Aexact are orthogonal to the rows of Aeps
+#          #
+#          # 1. Make s orthogonal to Aexact:
+#          #     s = s - Aexact_pinv * Aexact * s
+#          s = s - numpy.dot(Aexact_pinv,(numpy.dot(Aexact,s)))
+#          # 2. 
+#
+#          #assert(numpy.linalg.norm(x - numpy.dot(A,s)) < eps + 1e-6)          
+#      
+#      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
+#      lmbda = 100/sigma**2
+#  
+#  return s 
  
 ####################################################################
 #function delta=OurDelta(s,sigma)
 def OurDelta(s,sigma):
   
-  return s * np.exp( (-np.abs(s)**2) / sigma**2)
+  return s * numpy.exp( (-numpy.abs(s)**2) / sigma**2)
+
+
+def OurDeltaUnconstrained(s,sigma,lmbda,A,x):
+  
+  return s * numpy.exp( (-numpy.abs(s)**2) / sigma**2) + lmbda*2*numpy.dot(A.T, numpy.dot(A,s)-x)
+
   
 ####################################################################
 #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())
+  return 10*numpy.log10((true_s**2).sum()/(err**2).sum())
 
+