Charades
random.h
1 #ifndef _RANDOM_H_
2 #define _RANDOM_H_
3 
4 #include <assert.h>
5 #include <math.h>
6 #include <random>
7 
8 #include "clcg4.h"
9 #include "typedefs.h"
10 #include "xoroshiro.h"
11 
12 #define tw_opi 6.28318530718
13 
14 // TODO: This is mainly here to define RNG for LPs, remove someday
15 #ifdef USE_XOROSHIRO
16 typedef xoroshiro128plus RNG;
17 inline void tw_rand_init(uint32_t v, uint32_t w) {}
18 #else
19 typedef clcg4 RNG;
20 inline void tw_rand_init(uint32_t v, uint32_t w) { clcg4::init(v, w); }
21 #endif
22 
23 template <typename G>
24 inline double tw_rand_unif(G& g) {
25  return std::generate_canonical<double, std::numeric_limits<double>::digits>(g);
26 }
27 
28 template <>
29 inline double tw_rand_unif(clcg4& g) {
30  return g();
31 }
32 
33 // TODO: @bug Be careful not to pass LONG_MAX into the high variable for the
34 // function below. high + 1 will cause it to overflow.
35 template <typename G>
36 int64_t tw_rand_integer(G& g, int64_t low, int64_t high) {
37  if (high < low) {
38  return 0;
39  } else {
40  return (low + (int64_t)(tw_rand_unif(g) * (high + 1 - low)));
41  }
42 }
43 
44 // TODO: @bug Be careful not to pass ULONG_MAX into the high variable for the
45 // function below. high + 1 will cause it to overflow.
46 template <typename G>
47 uint64_t tw_rand_ulong(G& g, uint64_t low, uint64_t high) {
48  if (high < low) {
49  return 0;
50  } else {
51  return (low + (uint64_t)(tw_rand_unif(g) * (high + 1 - low)));
52  }
53 }
54 
55 template <typename G>
56 int64_t tw_rand_binomial(G& g, int64_t N, double P) {
57  int64_t sucesses = 0;
58 
59  for (int trials = 0; trials < N; trials++) {
60  if (tw_rand_unif(g) <= P) {
61  sucesses++;
62  }
63  }
64 
65  return sucesses;
66 }
67 
68 template <typename G>
69 int64_t tw_rand_geometric(G& g, double P) {
70  assert(P > 0);
71  int count = 1;
72  while (tw_rand_unif(g) > P) {
73  count++;
74  }
75 
76  return count;
77 }
78 
79 template <typename G>
80 double tw_rand_exponential(G& g, double Lambda) {
81  return -Lambda * log(tw_rand_unif(g));
82 }
83 
84 template <typename G>
85 double tw_rand_pareto(G& g, double scale, double shape) {
86  return scale * 1.0/pow(tw_rand_unif(g), 1/shape);
87 }
88 
89 template <typename G>
90 double tw_rand_gamma(G& g, double shape, double scale) {
91  double a, b, q, phi, d;
92 
93  if (shape > 1) {
94  a = 1 / sqrt(2 * shape - 1);
95  b = shape - log(4);
96  q = shape + 1 / a;
97  phi = 4.5;
98  d = 1 + log(phi);
99 
100  while (1) {
101  double U_One = tw_rand_unif(g);
102  double U_Two = tw_rand_unif(g);
103  double V = a * log(U_One / (1 - U_One));
104  double Y = shape * exp(V);
105  double Z = U_One * U_One * U_Two;
106  double W = b + q * V - Y;
107 
108  double temp1 = W + d - phi * Z;
109  double temp2 = log(Z);
110 
111  if (temp1 >= 0 || W >= temp2) {
112  return scale * Y;
113  }
114  }
115  } else if (shape == 1) {
116  return (tw_rand_exponential(g, scale));
117  } else {
118  b = (exp(1) + shape) / exp(1);
119 
120  while (1) {
121  double U_One = tw_rand_unif(g);
122  double P = b * U_One;
123 
124  if (P <= 1) {
125  double Y = pow(P, (1 / shape));
126  double U_Two = tw_rand_unif(g);
127 
128  if (U_Two <= exp(-Y)) {
129  return scale * Y;
130  }
131  } else {
132  double Y = -log((b - P) / shape);
133  double U_Two = tw_rand_unif(g);
134 
135  if (U_Two <= pow(Y, (shape - 1))) {
136  return scale * Y;
137  }
138  }
139  }
140  }
141 }
142 
143 // Uses the Box-Muller transform to get a random number from a normal
144 // distribution from two independent random numbers from a uniform distribution
145 template <typename G>
146 double tw_rand_normal01(G& g) {
147  return (sqrt(-2.0 * log(tw_rand_unif(g))) * sin(tw_opi * tw_rand_unif(g)));
148 }
149 
150 template <typename G>
151 double tw_rand_normal_sd(G& g, double Mu, double Sd) {
152  return Mu + (tw_rand_normal01(g) * Sd);
153 }
154 
155 template <typename G>
156 double tw_rand_lognormal(G& g, double mean, double sd) {
157  return exp( mean + sd * tw_rand_normal01(g));
158 }
159 
160 template <typename G>
161 int64_t tw_rand_poisson(G& g, double Lambda) {
162  double a = exp(-Lambda);
163  double b = 1;
164  int64_t count = 0;
165 
166  b = b * tw_rand_unif(g);
167  while (b >= a) {
168  b = b * tw_rand_unif(g);
169  count++;
170  }
171 
172  return count;
173 }
174 
175 template <typename G>
176 double tw_rand_weibull(G& g, double mean, double shape) {
177  double scale = mean / tgamma( ((double)1.0 + (double)1.0/shape));
178  return scale * pow(-log( tw_rand_unif(g)), (double)1.0/shape);
179 }
180 
181 #endif
Definition: xoroshiro.h:10
Implementation of a CLCG4 random number generator, based on the reversible implementation from ROSS (...
Definition: clcg4.h:14
Declares most types used within the simulator and by models.