1 |
#include <RanGen.h> |
2 |
|
3 |
using namespace std; |
4 |
|
5 |
ClassImp(RanGen); |
6 |
|
7 |
RanGen::RanGen(Int_t seed) : TRandom3(seed){ |
8 |
} |
9 |
|
10 |
RanGen::~RanGen(){}; |
11 |
|
12 |
Double_t RanGen::Gamma(Int_t n, Double_t theta){ |
13 |
|
14 |
Double_t value = 0; |
15 |
|
16 |
for(Int_t i=0; i<n; i++) value -= TMath::Log( this->Uniform() ); |
17 |
|
18 |
return value; |
19 |
|
20 |
} |
21 |
|
22 |
|
23 |
vector<Double_t> RanGen::Dirichlet(Int_t n, vector<Int_t> x){ |
24 |
|
25 |
Double_t sum = 0; |
26 |
vector<Double_t> gammas(n); |
27 |
vector<Double_t> value(n); |
28 |
|
29 |
for(Int_t i=0; i<n; i++){ |
30 |
gammas[i] = Gamma(x[i], 1); |
31 |
sum += gammas[i]; |
32 |
} |
33 |
|
34 |
for(Int_t i=0; i<n; i++){ |
35 |
if(sum) |
36 |
value[i] = gammas[i]/sum; |
37 |
else |
38 |
value[i] = 0; |
39 |
} |
40 |
|
41 |
return value; |
42 |
|
43 |
} |
44 |
|
45 |
|
46 |
Int_t RanGen::Binomial(Int_t n, Double_t p){ |
47 |
unsigned int i, a, b, k = 0; |
48 |
while (n > 10) /* This parameter is tunable */ |
49 |
{ |
50 |
double X; |
51 |
a = 1 + (n / 2); |
52 |
b = 1 + n - a; |
53 |
|
54 |
X = this->Beta((Int_t) a, (Int_t) b); |
55 |
|
56 |
if (X >= p) |
57 |
{ |
58 |
n = a - 1; |
59 |
p /= X; |
60 |
} |
61 |
else |
62 |
{ |
63 |
k += a; |
64 |
n = b - 1; |
65 |
p = (p - X) / (1 - X); |
66 |
} |
67 |
} |
68 |
|
69 |
for (i = 0; i < n; i++) |
70 |
{ |
71 |
double u = this->Uniform(); |
72 |
if (u < p) |
73 |
k++; |
74 |
} |
75 |
|
76 |
return k; |
77 |
|
78 |
} |
79 |
|
80 |
Double_t RanGen::Beta(const Int_t a, const Int_t b){ |
81 |
double x1 = this->Gamma(a, 1.0); |
82 |
double x2 = this->Gamma(b, 1.0); |
83 |
|
84 |
return x1 / (x1 + x2); |
85 |
} |
86 |
|
87 |
vector<Int_t> RanGen::Multinomial(Int_t N, vector<Double_t> p){ |
88 |
|
89 |
/* From the GSL Library: |
90 |
The multinomial distribution has the form |
91 |
|
92 |
N! n_1 n_2 n_K |
93 |
prob(n_1, n_2, ... n_K) = -------------------- p_1 p_2 ... p_K |
94 |
(n_1! n_2! ... n_K!) |
95 |
|
96 |
where n_1, n_2, ... n_K are nonnegative integers, sum_{k=1,K} n_k = N, |
97 |
and p = (p_1, p_2, ..., p_K) is a probability distribution. |
98 |
|
99 |
Random variates are generated using the conditional binomial method. |
100 |
This scales well with N and does not require a setup step. |
101 |
|
102 |
Ref: |
103 |
C.S. David, The computer generation of multinomial random variates, |
104 |
Comp. Stat. Data Anal. 16 (1993) 205-217 |
105 |
*/ |
106 |
|
107 |
size_t K = p.size(); |
108 |
vector<Int_t> n(K); |
109 |
|
110 |
size_t k; |
111 |
double norm = 0.0; |
112 |
double sum_p = 0.0; |
113 |
|
114 |
unsigned int sum_n = 0; |
115 |
|
116 |
/* p[k] may contain non-negative weights that do not sum to 1.0. |
117 |
* Even a probability distribution will not exactly sum to 1.0 |
118 |
* due to rounding errors. |
119 |
*/ |
120 |
|
121 |
for (k = 0; k < K; k++) |
122 |
{ |
123 |
norm += p[k]; |
124 |
} |
125 |
|
126 |
for (k = 0; k < K; k++) |
127 |
{ |
128 |
if (p[k] > 0.0) |
129 |
{ |
130 |
n[k] = this->Binomial(N - sum_n, p[k] / (norm - sum_p)); |
131 |
} |
132 |
else |
133 |
{ |
134 |
n[k] = 0; |
135 |
} |
136 |
|
137 |
sum_p += p[k]; |
138 |
sum_n += n[k]; |
139 |
} |
140 |
return n; |
141 |
|
142 |
} |