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 |