-
Notifications
You must be signed in to change notification settings - Fork 8
/
stream_mod_sulq.m
70 lines (61 loc) · 1.79 KB
/
stream_mod_sulq.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
function [U, S] = stream_mod_sulq(Y, r, e_p, delta, b, thresh)
%STREAM_MOD_SULQ Perform Streaming MOD-SuLQ.
%
% Based on work of Grammenos et al.: https://arxiv.org/abs/1907.08059
%
% Author: Andreas Grammenos (ag926@cl.cam.ac.uk)
%
% Last touched date: 19/04/2020
%
% License: GPLv3
%
% grab the size
[dim, ~] = size(Y);
% check if we are given a block, if not use a block equal to r.
if nargin < 5
b = r;
elseif b < r
error("block size cannot be less than target rank.")
end
% set the threshold for processing in one go (for speed).
if nargin < 6
thresh = 50;
end
% initialise
U = NaN;
S = NaN;
% run for the blocks
blocks = floor(dim/b);
% check if it fits in one block.
if blocks < 2 || dim < thresh
% generate the mod-sulq mask for Y
B = Y*Y';
mask = stream_mod_sulq_mask(B, e_p, delta);
% B = mod_sulq(Y, .1, .1);
% now get the pc's
[U, S, ~] = svds(B + mask, r);
% [U, S, ~] = svds(B, r);
return
end
% otherwise run for all the blocks minus one; since, if there is spillage
% then the last block has to be slightly larger.
for k = 1:blocks-1
% fetch the current B bounds from Y
min_t = ((k-1)*b)+1;
max_t = k*b;
% slice B block from Y*Y' subject to the indices defined by min_t/max_t.
B = (1/b) * Y * Y(min_t:max_t, :)';
% generate the mod-sulq mask for that block
mask = stream_mod_sulq_mask(B, e_p, delta);
% update the block
[U, S, ~] = ssvdr_block_update(B + mask, r, U, S);
end
% compute last min_t
min_t = (k*b) + 1;
% might be one block and something, due to spillage.
B = Y*Y(min_t:end, :)';
% generate the mod-sulq mask for that block
mask = stream_mod_sulq_mask(B, e_p, delta);
% final leftovers
[U, S, ~] = ssvdr_block_update(B + mask, r, U, S);
end