function [Up,Sp,Vp] = addblock_svd_update( U, S, V, A, force_orth ) % function [Up,Sp,Vp] = addblock_svd_update( U, S, V, A, force_orth ) % % Given the SVD of % % X = U*S*V' % % update it to be the SVD of % % [X A] = Up*Sp*Vp' % % that is, add new columns (ie, data points). % % I have found that it is faster to add several (say, 200) data points % at a time, rather than updating it incrementally with individual % data points (for 500 dimensional vectors, the speedup was roughly % 25x). However, in the rank-one case there is structure that I have % not exploited, so that may still be faster than a block method. % % The subspace rotations involved may not preserve orthogonality due % to numerical round-off errors. To compensate, you can set the % "force_orth" flag, which will force orthogonality via a QR plus % another SVD. In a long loop, you may want to force orthogonality % every so often. % % See Matthew Brand, "Fast low-rank modifications of the thin % singular value decomposition". % % D. Wingate 8/17/2007 % current_rank = size( U, 2 ); % P is an orthogonal basis of the column-space % of (I-UU')a, which is the component of "a" that is % orthogonal to U. m = U' * A; p = A - U*m; P = orth( p ); % p may not have full rank. If not, P will be too small. Pad % with zeros. P = [ P zeros(size(P,1), size(p,2)-size(P,2)) ]; Ra = P' * p; % % Diagonalize K, maintaining rank % z = zeros( size(m) ); K = [ S m ; z' Ra ]; [tUp,tSp,tVp] = svds( K, current_rank ); % % Now update our matrices! % Sp = tSp; Up = [ U P ] * tUp; % this may not preserve orthogonality over % many repetitions. See below. % Exploit structure to compute this fast: Vp = [ V Q ] * tVp; if ( ~isempty(V) ) Vp = V * tVp( 1:current_rank, : ); else Vp = []; end; Vp = [ Vp ; tVp( current_rank+1:size(tVp,1), : ) ]; % The above rotations may not preserve orthogonality, so we explicitly % deal with that via a QR plus another SVD. In a long loop, you may % want to force orthogonality every so often. if ( force_orth ) [UQ,UR] = qr( Up, 0 ); [VQ,VR] = qr( Vp, 0 ); [tUp,tSp,tVp] = svds( UR * Sp * VR', current_rank ); Up = UQ * tUp; Vp = VQ * tVp; Sp = tSp; end; return;