forked from andersonwinkler/PALM
-
Notifications
You must be signed in to change notification settings - Fork 0
/
palm_randg.m
80 lines (68 loc) · 2.01 KB
/
palm_randg.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
70
71
72
73
74
75
76
77
78
79
80
function g = palm_randg(a,siz)
% Generate random Gamma variables.
%
% g = palm_randg(a,siz)
%
% a : Parameter A (= k) of the Gamma distribution. The shape
% (or rate) parameter is fixed at 1.
% siz : A vector indicating the size of the array to be created.
% g : Gamma-distributed variables.
%
% Reference:
% * Marsaglia G, Tsang WW. A simple method for generating gamma
% variables. ACM Trans Math Softw. 2000;26(3):363-372.
%
% _____________________________________
% Anderson M. Winkler
% FMRIB / University of Oxford
% May/2015
% http://brainder.org
if exist('randg','builtin') || exist('randg','file'),
% randg is a build-in in Octave, and a MEX in Matlab in the
% Stats Toolbox. If it's available, let's use it. It's
% about 4x faster in Octave, and 6x times faster in Matlab.
g = randg(a,siz);
else
% Constants for below
if a < 1,
d = 1+a-1/3;
else
d = a-1/3;
end
c = 1/sqrt(9*d);
% Fill g as the random vars satisfy the criteria below
g = nan(siz);
ig = isnan(g(:));
while any(ig),
gw = nan(sum(ig),1);
% Make the Gaussian variable
x = nan(size(gw));
v = -ones(size(gw));
iv = true(size(gw));
while any(iv),
x(iv) = randn(sum(iv),1);
v(iv) = (1+c.*x(iv)).^3;
iv(iv) = v(iv) <= 0;
end
% Make the uniform variable
U = rand(size(gw));
% Apply both criteria
iU = U < 1-0.0331*x.^4;
if any(iU),
gw(iU) = d.*v(iU);
end
iU = ~iU;
if any(iU),
iU(iU) = log(U(iU)) < 0.5*x(iU).^2+d*(1-v(iU)+log(v(iU)));
gw(iU) = d.*v(iU);
end
% Go for the next round if needed
g(ig) = gw;
ig = isnan(g(:));
end
% See Marsaglia & Tsang (2000), page 371 (the note below the Table):
% Gamma(a) = Gamma(a+1)*U^(1/a)
if a < 1,
g = g.*rand(size(g)).^(1/a);
end
end