Version: SMASH-1.5
random.h
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2018
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #ifndef SRC_INCLUDE_RANDOM_H_
11 #define SRC_INCLUDE_RANDOM_H_
12 
13 #include <cassert>
14 #include <limits>
15 #include <random>
16 #include <utility>
17 #include <vector>
18 
19 namespace smash {
20 
24 namespace random {
25 
27 using Engine = std::mt19937_64;
28 
30 extern /*thread_local (see #3075)*/ Engine engine;
31 
48 template <typename T>
49 class uniform_dist {
50  public:
57  uniform_dist(T min, T max) : distribution(min, max) {}
59  T operator()() { return distribution(engine); }
60 
61  private:
63  std::uniform_real_distribution<T> distribution;
64 };
65 
67 template <typename T>
68 void set_seed(T &&seed) {
69  static_assert(std::is_same<Engine::result_type, uint64_t>::value,
70  "experiment.cc needs the seed to be 64 bits");
71  engine.seed(std::forward<T>(seed));
72 }
73 
75 inline Engine::result_type advance() { return engine(); }
76 
84 template <typename T>
85 T uniform(T min, T max) {
86  return std::uniform_real_distribution<T>(min, max)(engine);
87 }
88 
96 template <typename T>
97 T uniform_int(T min, T max) {
98  return std::uniform_int_distribution<T>(min, max)(engine);
99 }
100 
109 template <typename T = double>
111  return std::generate_canonical<T, std::numeric_limits<double>::digits>(
112  engine);
113 }
114 
118 template <typename T = double>
120  // use 'nextafter' to generate a value that is guaranteed to be larger than 0
121  return std::nextafter(
122  std::generate_canonical<T, std::numeric_limits<double>::digits>(engine),
123  T(1));
124 }
125 
131 template <typename T>
133  return uniform_dist<T>(min, max);
134 }
135 
145 template <typename T = double>
146 T exponential(T lambda) {
147  // We are not using std::exponential_distribution because of a bug in the
148  // implementations by clang and gcc.
149  return -std::log(canonical_nonzero()) / lambda;
150 }
151 
162 template <typename T = double>
163 T expo(T A, T x1, T x2) {
164  const T a1 = A * x1, a2 = A * x2;
165  const T a_min = std::log(std::numeric_limits<T>::min());
166 #ifndef NDEBUG
167  assert(A > T(0.) && x1 >= x2 && a1 > a_min);
168 #endif
169  const T r1 = std::exp(a1);
170  const T r2 = a2 > a_min ? std::exp(a2) : T(0.); // prevent underflow
171  T x;
172  do {
173  /* sample repeatedly until x is in the requested range
174  * (it can get outside due to numerical errors, see issue #2959) */
175  x = std::log(uniform(r1, r2)) / A;
176  } while (!(x <= x1 && x > x2));
177  return x;
178 }
179 
186 template <typename T>
187 int sgn(T val) {
188  return (T(0) < val) - (val < T(0));
189 }
190 
199 template <typename T = double>
200 T power(T n, T xMin, T xMax) {
201  const T n1 = n + 1;
202  if (std::abs(n1) < 1E-3) {
203  return xMin * std::pow(xMax / xMin, canonical());
204  } else if (xMin > 0. && xMax > 0.) {
205  return std::pow(uniform(std::pow(xMin, n1), std::pow(xMax, n1)), 1. / n1);
206  } else {
207  return sgn(xMin) * std::pow(uniform(std::pow(std::abs(xMin), n1),
208  std::pow(std::abs(xMax), n1)),
209  1. / n1);
210  }
211 }
212 
222 template <typename T>
223 int poisson(const T &lam) {
224  return std::poisson_distribution<int>(lam)(engine);
225 }
226 
234 template <typename T>
235 int binomial(const int N, const T &p) {
236  return std::binomial_distribution<int>(N, p)(engine);
237 }
238 
246 template <typename T>
247 double normal(const T &mean, const T &sigma) {
248  return std::normal_distribution<double>(mean, sigma)(engine);
249 }
250 
254 template <typename T>
256  public:
262 
266  explicit discrete_dist(const std::vector<T> &plist)
267  : distribution(plist.begin(), plist.end()) {}
268 
272  explicit discrete_dist(std::initializer_list<T> l) : distribution(l) {}
273 
277  void reset_weights(const std::vector<T> &plist) {
278  distribution = std::discrete_distribution<>(plist.begin(), plist.end());
279  }
283  int operator()() { return distribution(engine); }
284 
285  private:
287  std::discrete_distribution<> distribution;
288 };
289 
303 template <typename T = double>
304 T cauchy(T pole, T width, T min, T max) {
305  /* Use double-precision variables, in order to work around a glibc bug in
306  * tanf:
307  * https://sourceware.org/bugzilla/show_bug.cgi?id=18221 */
308  const double u_min = std::atan((min - pole) / width);
309  const double u_max = std::atan((max - pole) / width);
310  const double u = uniform(u_min, u_max);
311  return pole + width * std::tan(u);
312 }
313 
325 template <typename T = double>
326 T beta(T a, T b) {
327  // Otherwise the integral over probability density diverges
328  assert(a > T(0.0) && b > T(0.0));
329  const T x1 = std::gamma_distribution<T>(a)(engine);
330  const T x2 = std::gamma_distribution<T>(b)(engine);
331  return x1 / (x1 + x2);
332 }
333 
347 template <typename T = double>
348 T beta_a0(T xmin, T b) {
349  assert(xmin > T(0.0) && xmin < T(1.0));
350  T y;
351  do {
352  y = uniform(0.0, -std::log(xmin));
353  } while (std::pow((1.0 - std::exp(-y)), b) < canonical());
354  return std::exp(-y);
355 }
356 
375  public:
384  BesselSampler(const double poisson_mean1, const double poisson_mean2,
385  const int fixed_difference);
386 
392  std::pair<int, int> sample();
393 
394  private:
404  static double r_(int n, double a);
405 
408 
410  double m_;
411 
413  const double a_;
414 
416  const int N_;
417 
419  const bool N_is_positive_;
420 
426  static constexpr double m_switch_method_ = 6.0;
427 
429  static constexpr double negligible_probability_ = 1.e-12;
430 
432  double mu_;
433 
435  double sigma_;
436 };
437 
438 } // namespace random
439 } // namespace smash
440 
441 #endif // SRC_INCLUDE_RANDOM_H_
T expo(T A, T x1, T x2)
Draws a random number x from an exponential distribution exp(A*x), where A is assumed to be positive...
Definition: random.h:163
T beta_a0(T xmin, T b)
Draws a random number from a beta-distribution with a = 0.
Definition: random.h:348
discrete_dist(const std::vector< T > &plist)
Construct from probability vector.
Definition: random.h:266
random::discrete_dist< double > dist_
Vector to store tabulated values of probabilities for small m case (m <6).
Definition: random.h:407
std::uniform_real_distribution< T > distribution
The distribution object that is being used.
Definition: random.h:63
static constexpr double negligible_probability_
Probabilities smaller than negligibly_probability are neglected.
Definition: random.h:429
double mu_
Mean of the Bessel distribution.
Definition: random.h:432
void set_seed(T &&seed)
Sets the seed of the random number engine.
Definition: random.h:68
std::pair< int, int > sample()
Sample two numbers from given Poissonians with a fixed difference.
Definition: random.cc:57
T exponential(T lambda)
Draws an exponentially distributed random number.
Definition: random.h:146
T canonical()
Definition: random.h:110
BesselSampler(const double poisson_mean1, const double poisson_mean2, const int fixed_difference)
Construct a BesselSampler.
Definition: random.cc:17
T uniform_int(T min, T max)
Definition: random.h:97
Engine::result_type advance()
Advance the engine&#39;s state and return the generated value.
Definition: random.h:75
static constexpr double m_switch_method_
Switching mode to normal approximation.
Definition: random.h:426
std::discrete_distribution distribution
The distribution object that is being used.
Definition: random.h:287
const int N_
First parameter of Bessel distribution (= in Yuan2000).
Definition: random.h:416
const bool N_is_positive_
Boolean variable to verify that N > 0.
Definition: random.h:419
T canonical_nonzero()
Definition: random.h:119
discrete_dist(std::initializer_list< T > l)
Construct from probability list.
Definition: random.h:272
The intention of this class is to efficiently sample from the Bessel distribution ...
Definition: random.h:374
T uniform(T min, T max)
Definition: random.h:85
Discrete distribution with weight given by probability vector.
Definition: random.h:255
double sigma_
Standard deviation of the Bessel distribution.
Definition: random.h:435
T cauchy(T pole, T width, T min, T max)
Draws a random number from a Cauchy distribution (sometimes also called Lorentz or non-relativistic B...
Definition: random.h:304
uniform_dist< T > make_uniform_distribution(T min, T max)
Definition: random.h:132
Engine engine
The engine that is used commonly by all distributions.
Definition: random.cc:15
T power(T n, T xMin, T xMax)
Draws a random number according to a power-law distribution ~ x^n.
Definition: random.h:200
int binomial(const int N, const T &p)
Returns a binomially distributed random number.
Definition: random.h:235
constexpr int p
Proton.
void reset_weights(const std::vector< T > &plist)
Reset the discrete distribution from a new probability list.
Definition: random.h:277
int poisson(const T &lam)
Returns a Poisson distributed random number.
Definition: random.h:223
std::mt19937_64 Engine
The random number engine used is the Mersenne Twister.
Definition: random.h:27
Provides uniform random numbers on a fixed interval.
Definition: random.h:49
double normal(const T &mean, const T &sigma)
Returns a random number drawn from a normal distribution.
Definition: random.h:247
static double r_(int n, double a)
Compute the ratio of two Bessel functions r(n,a) = bessel_I(n+1,a)/bessel_I(n,a) using the continued ...
Definition: random.cc:65
double m_
Mode of the Bessel function, see Yuan2000 for details.
Definition: random.h:410
constexpr int n
Neutron.
T beta(T a, T b)
Draws a random number from a beta-distribution, where probability density of is .
Definition: random.h:326
const double a_
Second parameter of Bessel distribution, see Yuan2000 for details.
Definition: random.h:413
uniform_dist(T min, T max)
Creates the object and fixes the interval.
Definition: random.h:57
discrete_dist()
Default discrete distribution.
Definition: random.h:261
Definition: action.h:24
int sgn(T val)
Signum function.
Definition: random.h:187
int operator()()
Draw a random number from the discrete distribution.
Definition: random.h:283