-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmulti.cc
121 lines (94 loc) · 2.71 KB
/
multi.cc
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <gsl/gsl_randist.h>
#include <gsl/gsl_rng.h>
#include <random>
#include <vector>
#include "multi.h"
static std::vector<long double> unif_gen(int n) {
std::vector<long double> dist(n);
std::vector<long double> expo(n + 1);
std::random_device rd;
std::mt19937_64 gen(rd());
std::uniform_real_distribution<> unif_dis(0.0, 1.0);
long double total = 0;
for (int i = 0; i < n + 1; i ++) {
expo[i] = - log(unif_dis(gen));
total += expo[i];
}
long double cum = 0;
for (int i = 0; i < n; i ++) {
cum += expo[i];
dist[i] = cum / total;
}
return dist;
}
/*
* The O(n + k) algorithm for multinomial sampling.
*/
std::vector<uint64_t> full_uniform(int n, const std::vector<long double>& dist) {
std::vector<long double> unifs = unif_gen(n);
std::vector<uint64_t> output(dist.size());
long double cum = dist.front();
int di = 0;
for (auto iter = unifs.begin(); iter != unifs.end(); iter++) {
while (*iter >= cum)
cum += dist[++di];
output[di] ++;
}
return output;
}
/*
* The O(n + k log n) algorithm for multinomial sampling.
*/
std::vector<uint64_t> full_uniform_bin_search(int n, const std::vector<long double>& dist) {
std::vector<long double> unifs = unif_gen(n);
std::vector<uint64_t> output(dist.size());
long double cum = 0;
auto last = unifs.begin();
for (int i = 0; i < dist.size(); i ++) {
cum += dist[i];
auto loc = std::lower_bound(last, unifs.end(), cum);
output[i] = std::distance(last, loc) - 1;
last = loc;
}
return output;
}
/*
* The O(n log k) algorithm for multinomial sampling.
*/
std::vector<uint64_t> reverse_bin_search(int n, const std::vector<long double>& dist) {
std::vector<long double> dist_cum(dist.size());
std::vector<uint64_t> output(dist.size());
long double cum = 0;
for (int i = 0; i < dist.size(); i ++) {
dist_cum[i] = cum;
cum += dist[i];
}
std::random_device rd;
std::mt19937_64 gen(rd());
std::uniform_real_distribution<> unif(0, 1);
for (int i = 0; i < n; i ++) {
int x = std::distance(dist_cum.begin(), std::lower_bound(dist_cum.begin(), dist_cum.end(), unif(gen))) - 1;
output[x] ++;
}
return output;
}
/*
* The O(k) BTPE algorithm for multinomial sampling.
*/
std::vector<uint64_t> btpe(int n, const std::vector<long double>& dist) {
gsl_rng* r = gsl_rng_alloc(gsl_rng_taus);
std::random_device rd;
gsl_rng_set(r, rd());
std::vector<uint64_t> output(dist.size());
double cum = 0;
uint64_t sampled = 0;
for (int i = 0; i < dist.size(); i ++) {
double p = dist[i] / (1 - cum);
uint64_t tot = n - sampled;
output[i] = gsl_ran_binomial(r, p, tot);
cum += dist[i];
sampled += output[i];
}
gsl_rng_free(r);
return output;
}