annotate matlab/NESTA/fastProjection.m @ 46:88f0ebe1667a

Finished NESTA implementation. Not tested yet
author nikcleju
date Tue, 29 Nov 2011 22:06:20 +0000
parents
children
rev   line source
nikcleju@46 1 function [x,k,l] = fastProjection( U, S, V, y, b, epsilon, lambda0, DISP )
nikcleju@46 2 % [x,niter,lambda] = fastProjection(U, S, V, y, b, epsilon, [lambda0], [DISP] )
nikcleju@46 3 %
nikcleju@46 4 % minimizes || x - y ||
nikcleju@46 5 % such that || Ax - b || <= epsilon
nikcleju@46 6 %
nikcleju@46 7 % where USV' = A (i.e the SVD of A)
nikcleju@46 8 %
nikcleju@46 9 % The optional input "lambda0" is a guess for the Lagrange parameter
nikcleju@46 10 %
nikcleju@46 11 % Warning: for speed, does not calculate A(y) to see if x = y is feasible
nikcleju@46 12 %
nikcleju@46 13 % NESTA Version 1.1
nikcleju@46 14 % See also Core_Nesterov
nikcleju@46 15
nikcleju@46 16 % Written by Stephen Becker, September 2009, srbecker@caltech.edu
nikcleju@46 17
nikcleju@46 18 DEBUG = true;
nikcleju@46 19 if nargin < 8
nikcleju@46 20 DISP = false;
nikcleju@46 21 end
nikcleju@46 22 % -- Parameters for Newton's method --
nikcleju@46 23 MAXIT = 70;
nikcleju@46 24 TOL = 1e-8 * epsilon;
nikcleju@46 25 % TOL = max( TOL, 10*eps ); % we can't do better than machine precision
nikcleju@46 26
nikcleju@46 27 m = size(U,1);
nikcleju@46 28 n = size(V,1);
nikcleju@46 29 mn = min([m,n]);
nikcleju@46 30 if numel(S) > mn^2, S = diag(diag(S)); end % S should be a small square matrix
nikcleju@46 31 r = size(S);
nikcleju@46 32 if size(U,2) > r, U = U(:,1:r); end
nikcleju@46 33 if size(V,2) > r, V = V(:,1:r); end
nikcleju@46 34
nikcleju@46 35 s = diag(S);
nikcleju@46 36 s2 = s.^2;
nikcleju@46 37
nikcleju@46 38 % What we want to do:
nikcleju@46 39 % b = b - A*y;
nikcleju@46 40 % bb = U'*b;
nikcleju@46 41
nikcleju@46 42 % if A doesn't have full row rank, then b may not be in the range
nikcleju@46 43 if size(U,1) > size(U,2)
nikcleju@46 44 bRange = U*(U'*b);
nikcleju@46 45 bNull = b - bRange;
nikcleju@46 46 epsilon = sqrt( epsilon^2 - norm(bNull)^2 );
nikcleju@46 47 end
nikcleju@46 48 b = U'*b - S*(V'*y); % parenthesis is very important! This is expensive.
nikcleju@46 49
nikcleju@46 50 % b2 = b.^2;
nikcleju@46 51 b2 = abs(b).^2; % for complex data
nikcleju@46 52 bs2 = b2.*s2;
nikcleju@46 53 epsilon2 = epsilon^2;
nikcleju@46 54
nikcleju@46 55 % The following routine need to be fast
nikcleju@46 56 % For efficiency (at cost of transparency), we are writing the calculations
nikcleju@46 57 % in a way that minimize number of operations. The functions "f"
nikcleju@46 58 % and "fp" represent f and its derivative.
nikcleju@46 59
nikcleju@46 60 % f = @(lambda) sum( b2 .*(1-lambda*s2).^(-2) ) - epsilon^2;
nikcleju@46 61 % fp = @(lambda) 2*sum( bs2 .*(1-lambda*s2).^(-3) );
nikcleju@46 62 if nargin < 7, lambda0 = 0; end
nikcleju@46 63 l = lambda0; oldff = 0;
nikcleju@46 64 one = ones(m,1);
nikcleju@46 65 alpha = 1; % take full Newton steps
nikcleju@46 66 for k = 1:MAXIT
nikcleju@46 67 % make f(l) and fp(l) as efficient as possible:
nikcleju@46 68 ls = one./(one-l*s2);
nikcleju@46 69 ls2 = ls.^2;
nikcleju@46 70 ls3 = ls2.*ls;
nikcleju@46 71 ff = b2.'*ls2; % should be .', not ', even for complex data
nikcleju@46 72 ff = ff - epsilon2;
nikcleju@46 73 fpl = 2*( bs2.'*ls3 ); % should be .', not ', even for complex data
nikcleju@46 74 % ff = f(l); % this is a little slower
nikcleju@46 75 % fpl = fp(l); % this is a little slower
nikcleju@46 76 d = -ff/fpl;
nikcleju@46 77 if DISP, fprintf('%2d, lambda is %5.2f, f(lambda) is %.2e, f''(lambda) is %.2e\n',...
nikcleju@46 78 k,l,ff,fpl ); end
nikcleju@46 79 if abs(ff) < TOL, break; end % stopping criteria
nikcleju@46 80 l_old = l;
nikcleju@46 81 if k>2 && ( abs(ff) > 10*abs(oldff+100) ) %|| abs(d) > 1e13 )
nikcleju@46 82 l = 0; alpha = 1/2;
nikcleju@46 83 % oldff = f(0);
nikcleju@46 84 oldff = sum(b2); oldff = oldff - epsilon2;
nikcleju@46 85 if DISP, disp('restarting'); end
nikcleju@46 86 else
nikcleju@46 87 if alpha < 1, alpha = (alpha+1)/2; end
nikcleju@46 88 l = l + alpha*d;
nikcleju@46 89 oldff = ff;
nikcleju@46 90 if l > 0
nikcleju@46 91 l = 0; % shouldn't be positive
nikcleju@46 92 oldff = sum(b2); oldff = oldff - epsilon2;
nikcleju@46 93 end
nikcleju@46 94 end
nikcleju@46 95 if l_old == l && l == 0
nikcleju@46 96 if DISP, disp('Making no progress; x = y is probably feasible'); end
nikcleju@46 97 break;
nikcleju@46 98 end
nikcleju@46 99 end
nikcleju@46 100 % if k == MAXIT && DEBUG, disp('maxed out iterations'); end
nikcleju@46 101 if l < 0
nikcleju@46 102 xhat = -l*s.*b./( 1 - l*s2 );
nikcleju@46 103 x = V*xhat + y;
nikcleju@46 104 else
nikcleju@46 105 % y is already feasible, so no need to project
nikcleju@46 106 l = 0;
nikcleju@46 107 x = y;
nikcleju@46 108 end