Theoretica
A C++ numerical and automatic mathematical library
sampling.h
Go to the documentation of this file.
1 
3 
4 #ifndef THEORETICA_SAMPLING_H
5 #define THEORETICA_SAMPLING_H
6 
7 
8 #include "../core/function.h"
9 #include "./prng.h"
10 
11 
12 namespace theoretica {
13 
14 
18  using pdf_sampling_function = real(*)(const std::vector<real>&, PRNG&);
19 
20 
33  inline real rand_uniform(real a, real b, PRNG& g, uint64_t prec = STATISTICS_RAND_PREC) {
34 
35  // Generate a uniform random real number in [0, 1]
36  real x = (g() % prec) / static_cast<real>(prec);
37 
38  // Transform to target interval
39  return a + (b - a) * x;
40  }
41 
42 
47  inline real rand_uniform(const std::vector<real>& theta, PRNG& g) {
48 
49  if(theta.size() != 2) {
50  TH_MATH_ERROR("rand_uniform", theta.size(), INVALID_ARGUMENT);
51  return nan();
52  }
53 
54  return rand_uniform(theta[0], theta[1], g);
55  }
56 
57 
62  inline real rand_cointoss(PRNG& g) {
63 
64  return (g() % 2 == 0) ? 1 : -1;
65  }
66 
67 
72  inline real rand_cointoss(const std::vector<real>& theta, PRNG& g) {
73  return rand_cointoss(g);
74  }
75 
76 
82  inline real rand_diceroll(unsigned int faces, PRNG& g) {
83 
84  if(faces == 0) {
85  TH_MATH_ERROR("rand_diceroll", faces, INVALID_ARGUMENT);
86  return nan();
87  }
88 
89  return (g() % faces) + 1;
90  }
91 
92 
97  inline real rand_diceroll(const std::vector<real>& theta, PRNG& g) {
98 
99  if(theta.size() != 1) {
100  TH_MATH_ERROR("rand_diceroll", theta.size(), INVALID_ARGUMENT);
101  return nan();
102  }
103 
104  if(theta[0] < 0) {
105  TH_MATH_ERROR("rand_diceroll", theta[0], INVALID_ARGUMENT);
106  return nan();
107  }
108 
109  return rand_diceroll(theta[0], g);
110  }
111 
112 
134  const vec<real>& theta,
135  real x1, real x2,
136  real y1, real y2, PRNG& g,
137  unsigned int max_iter = STATISTICS_TRYANDCATCH_ITER) {
138 
139  real x;
140  real y;
141 
142  unsigned int iter = 0;
143 
144  do {
145  x = rand_uniform(x1, x2, g);
146  y = rand_uniform(y1, y2, g);
147  iter++;
148  } while(y > f(x, theta) && iter <= max_iter);
149 
150  if(iter > max_iter) {
151  TH_MATH_ERROR("rand_dist_tac", iter, NO_ALGO_CONVERGENCE);
152  return nan();
153  }
154 
155  return x;
156  }
157 
158 
170  stat_function f, const vec<real>& theta,
172  PRNG& g, unsigned int max_tries = 100) {
173 
174  for (unsigned int i = 0; i < max_tries; ++i) {
175 
176  // Generate a random number following
177  // the p(x) probability distribution
178  // by the inverse cumulative distribution function
179  const real u_1 = rand_uniform(0, 1, g);
180  const real x_p = Pinv(u_1);
181 
182  const real u_2 = rand_uniform(0, 1, g);
183 
184  // Accept the sample if f(x_p)/g(x_p) > u_2
185  if(u_2 * p(x_p) < f(x_p, theta))
186  return x_p;
187  }
188 
189  TH_MATH_ERROR("rand_reject_sample", max_tries, NO_ALGO_CONVERGENCE);
190  return nan();
191  }
192 
193 
199  inline real rand_gaussian_polar(real mean, real sigma, PRNG& g) {
200 
201  static real spare;
202  static bool has_spare = false;
203 
204  if(has_spare) {
205  has_spare = false;
206  return mean + spare * sigma;
207  }
208 
209  real x, y, s;
210 
211  // Generate a random point inside the unit circle
212  do {
213 
214  x = rand_uniform(-1, 1, g);
215  y = rand_uniform(-1, 1, g);
216  s = square(x) + square(y);
217 
218  } while(s >= 1 || s <= MACH_EPSILON);
219 
220  // Project the point
221  s = sqrt(-2 * ln(s) / s);
222 
223  // Keep the second generated value for future calls
224  spare = y * s;
225  has_spare = true;
226 
227  return mean + sigma * x * s;
228  }
229 
230 
237 
238  static real spare;
239  static bool has_spare = false;
240 
241  if(has_spare) {
242  has_spare = false;
243  return mean + spare * sigma;
244  }
245 
246  // Generate a random point inside the unit circle
247 
248  const real x = rand_uniform(0, 1, g);
249  const real y = rand_uniform(0, 1, g);
250 
251  const real x_transf = sqrt(-2 * ln(x));
252 
253  const real u = x_transf * cos(TAU * y);
254  const real v = x_transf * sin(TAU * y);
255 
256  spare = v;
257  has_spare = true;
258 
259  return mean + sigma * u;
260  }
261 
262 
274  inline real rand_gaussian_clt(real mean, real sigma, PRNG& g) {
275 
276  // Fixed N = 12
277  constexpr unsigned int N = 12;
278 
279  real s = 0;
280  for (unsigned int i = 0; i < N; ++i)
281  s += rand_uniform(-1, 1, g);
282 
283  // f(u) = 1/2 (in [-1, 1])
284  // E[u] = 0
285  // sqrt(V[u]) = 1 / sqrt(3N) = 1 / 6
286 
287  return mean + (s / static_cast<real>(N)) * sigma * 6;
288  }
289 
290 
308  real mean, real sigma,
309  PRNG& g, unsigned int N) {
310 
311  real s = 0;
312  for (unsigned int i = 0; i < N; ++i)
313  s += rand_uniform(-1, 1, g);
314 
315  // f(u) = 1/2 (in [-1, 1])
316  // E[u] = 0
317  // sqrt(V[u]) = 1 / sqrt(3N)
318 
319  return mean + (s / static_cast<real>(N)) * sigma * sqrt(3 * N);
320  }
321 
322 
325  inline real rand_gaussian(real mean, real sigma, PRNG& g) {
326  return rand_gaussian_polar(mean, sigma, g);
327  }
328 
329 
334  inline real rand_gaussian(const std::vector<real>& theta, PRNG& g) {
335 
336  if(theta.size() != 2) {
337  TH_MATH_ERROR("rand_gaussian", theta.size(), INVALID_ARGUMENT);
338  return nan();
339  }
340 
341  return rand_gaussian(theta[0], theta[1], g);
342  }
343 
344 
347  inline real rand_exponential(real lambda, PRNG& g) {
348 
349  if(abs(lambda) < MACH_EPSILON) {
350  TH_MATH_ERROR("rand_exponential", lambda, DIV_BY_ZERO);
351  return nan();
352  }
353 
354  return -ln(1 - rand_uniform(0, 1, g)) / lambda;
355  }
356 
357 
362  inline real rand_exponential(const std::vector<real>& theta, PRNG& g) {
363 
364  if(theta.size() != 1) {
365  TH_MATH_ERROR("rand_exponential", theta.size(), INVALID_ARGUMENT);
366  return nan();
367  }
368 
369  return rand_exponential(theta[0], g);
370  }
371 
372 
375  inline real rand_rayleigh(real sigma, PRNG& g) {
376 
377  return sigma * sqrt(-2 * ln(1 - rand_uniform(0, 1, g)));
378  }
379 
380 
385  inline real rand_rayleigh(const std::vector<real>& theta, PRNG& g) {
386 
387  if(theta.size() != 1) {
388  TH_MATH_ERROR("rand_rayleigh", theta.size(), INVALID_ARGUMENT);
389  return nan();
390  }
391 
392  return rand_rayleigh(theta[0], g);
393  }
394 
395 
398  inline real rand_cauchy(real mu, real alpha, PRNG& g) {
399 
400  return alpha * tan(PI * (rand_uniform(0, 1, g) - 0.5)) + mu;
401  }
402 
403 
408  inline real rand_cauchy(const std::vector<real>& theta, PRNG& g) {
409 
410  if(theta.size() != 2) {
411  TH_MATH_ERROR("rand_cauchy", theta.size(), INVALID_ARGUMENT);
412  return nan();
413  }
414 
415  return rand_cauchy(theta[0], theta[1], g);
416  }
417 
418 
421  inline real rand_laplace(real mu, real b, PRNG& g) {
422 
423  const real u = rand_uniform(0, 0.5, g);
424  return mu - b * rand_cointoss(g) * ln(1 - 2 * abs(u));
425  }
426 
427 
430  inline real rand_laplace(const std::vector<real>& theta, PRNG& g) {
431 
432  if(theta.size() != 2) {
433  TH_MATH_ERROR("rand_laplace", theta.size(), INVALID_ARGUMENT);
434  return nan();
435  }
436 
437  return rand_laplace(theta[0], theta[1], g);
438  }
439 
440 
443  inline real rand_pareto(real x_m, real alpha, PRNG& g) {
444 
445  return x_m / powf(1 - rand_uniform(0, 1, g), 1.0 / alpha);
446  }
447 
448 
453  inline real rand_pareto(const std::vector<real>& theta, PRNG& g) {
454 
455  if(theta.size() != 2) {
456  TH_MATH_ERROR("rand_pareto", theta.size(), INVALID_ARGUMENT);
457  return nan();
458  }
459 
460  return rand_pareto(theta[0], theta[1], g);
461  }
462 
463 
468  struct pdf_sampler {
469 
472 
474  std::vector<real> theta;
475 
478 
479 
483  const std::vector<real>& theta,
485 
486 
488  inline real next() {
489  return pdf(theta, generator);
490  }
491 
493  inline real operator()() {
494  return next();
495  }
496 
498  template<typename Vector>
499  inline void fill(Vector& x, size_t N) {
500 
501  for (size_t i = 0; i < N; ++i)
502  x[i] = next();
503  }
504 
505 
507  template<typename Vector>
508  inline void fill(Vector& x) {
509 
510  for (size_t i = 0; i < x.size(); ++i)
511  x[i] = next();
512  }
513 
514 
517  x = next();
518  return *this;
519  }
520 
521 
524  return pdf_sampler(rand_uniform, {a, b}, generator);
525  }
526 
527 
530  return pdf_sampler(rand_gaussian, {mean, sigma}, generator);
531  }
532 
533 
536  return pdf_sampler(rand_exponential, {lambda}, generator);
537  }
538 
539 
541  static pdf_sampler cauchy(real mu, real alpha, PRNG& generator) {
542  return pdf_sampler(rand_cauchy, {mu, alpha}, generator);
543  }
544 
545 
548  return pdf_sampler(rand_rayleigh, {sigma}, generator);
549  }
550 
551 
553  static pdf_sampler pareto(real x_m, real alpha, PRNG& generator) {
554  return pdf_sampler(rand_pareto, {x_m, alpha}, generator);
555  }
556 
557 
560  return pdf_sampler(rand_laplace, {mu, b}, generator);
561  }
562 
563  };
564 
574  inline real metropolis(
575  real_function pdf, pdf_sampler& g,
576  real x0, PRNG& rnd, unsigned int depth = STATISTICS_METROPOLIS_DEPTH) {
577 
578  real current = x0, next;
579 
580  for(unsigned int i = 0; i < depth; i++) {
581 
582  // Computes the next step
583  next = current + g();
584 
585  // Checks acceptance rate
586  if(rand_uniform(0, 1, rnd) * pdf(current) <= pdf(next))
587  current = next;
588  }
589 
590  return current;
591  }
592 
593 
605  real x0, unsigned int depth = STATISTICS_METROPOLIS_DEPTH) {
606  return metropolis(pdf, g, x0, g.generator, depth);
607  }
608 
609 }
610 
611 #endif
A pseudorandom number generator.
Definition: prng.h:18
#define TH_MATH_ERROR(F_NAME, VALUE, EXCEPTION)
TH_MATH_ERROR is a macro which throws exceptions or modifies errno (depending on which compiling opti...
Definition: error.h:219
real mean(const histogram &h)
Compute the mean of the values of a histogram.
Definition: histogram.h:296
Main namespace of the library which contains all functions and objects.
Definition: algebra.h:27
real rand_laplace(real mu, real b, PRNG &g)
Generate a random number following a Laplace distribution using the quantile (inverse) function metho...
Definition: sampling.h:421
double real
A real number, defined as a floating point type.
Definition: constants.h:188
real(*)(const std::vector< real > &, PRNG &) pdf_sampling_function
A p.d.f sampling function taking as input the parameters of the distribution and a pseudorandom numbe...
Definition: sampling.h:18
dual2 sqrt(dual2 x)
Compute the square root of a second order dual number.
Definition: dual2_functions.h:54
constexpr unsigned int STATISTICS_METROPOLIS_DEPTH
Default depth of the Metropolis algorithm.
Definition: constants.h:317
dual2 ln(dual2 x)
Compute the natural logarithm of a second order dual number.
Definition: dual2_functions.h:139
dual2 abs(dual2 x)
Compute the absolute value of a second order dual number.
Definition: dual2_functions.h:183
constexpr uint64_t STATISTICS_RAND_PREC
Default precision for random number generation using rand_uniform()
Definition: constants.h:314
real rand_pareto(real x_m, real alpha, PRNG &g)
Generate a random number following a Pareto distribution using the quantile (inverse) function method...
Definition: sampling.h:443
real rand_exponential(real lambda, PRNG &g)
Generate a random number following an exponential distribution using the quantile (inverse) function ...
Definition: sampling.h:347
real rand_rayleigh(real sigma, PRNG &g)
Generate a random number following a Rayleigh distribution using the quantile (inverse) function meth...
Definition: sampling.h:375
real rand_uniform(real a, real b, PRNG &g, uint64_t prec=STATISTICS_RAND_PREC)
Generate a pseudorandom real number in [a, b] using a preexisting generator.
Definition: sampling.h:33
real metropolis(real_function pdf, pdf_sampler &g, real x0, PRNG &rnd, unsigned int depth=STATISTICS_METROPOLIS_DEPTH)
Metropolis algorithm for distribution sampling using a symmetric proposal distribution.
Definition: sampling.h:574
constexpr unsigned int STATISTICS_TRYANDCATCH_ITER
Maximum number of failed iterations for the Try-and-Catch algorithm.
Definition: constants.h:299
real powf(real x, real a)
Approximate x elevated to a real exponent.
Definition: real_analysis.h:796
real rand_rejectsamp(stat_function f, const vec< real > &theta, real_function p, real_function Pinv, PRNG &g, unsigned int max_tries=100)
Generate a random number following any given distribution using rejection sampling.
Definition: sampling.h:169
real rand_gaussian(real mean, real sigma, PRNG &g)
Generate a random number following a Gaussian distribution using the best available algorithm.
Definition: sampling.h:325
real rand_gaussian_clt(real mean, real sigma, PRNG &g)
Generate a random number in a range following a Gaussian distribution by exploiting the Central Limit...
Definition: sampling.h:274
real rand_gaussian_boxmuller(real mean, real sigma, PRNG &g)
Generate a random number following a Gaussian distribution using the Box-Muller method.
Definition: sampling.h:236
real rand_diceroll(unsigned int faces, PRNG &g)
Dice roll random generator.
Definition: sampling.h:82
dual2 cos(dual2 x)
Compute the cosine of a second order dual number.
Definition: dual2_functions.h:82
real rand_cointoss(PRNG &g)
Coin toss random generator.
Definition: sampling.h:62
constexpr real MACH_EPSILON
Machine epsilon for the real type.
Definition: constants.h:197
real rand_cauchy(real mu, real alpha, PRNG &g)
Generate a random number following a Cauchy distribution using the quantile (inverse) function method...
Definition: sampling.h:398
std::function< real(real, const vec< real > &)> stat_function
Function pointer to a probability distribution function where the first argument is the variable and ...
Definition: function.h:30
dual2 tan(dual2 x)
Compute the tangent of a second order dual number.
Definition: dual2_functions.h:94
real rand_gaussian_polar(real mean, real sigma, PRNG &g)
Generate a random number following a Gaussian distribution using Marsaglia's polar method.
Definition: sampling.h:199
real rand_trycatch(stat_function f, const vec< real > &theta, real x1, real x2, real y1, real y2, PRNG &g, unsigned int max_iter=STATISTICS_TRYANDCATCH_ITER)
Generate a pseudorandom value following any probability distribution function using the Try-and-Catch...
Definition: sampling.h:133
std::function< real(real)> real_function
Function pointer to a real function of real variable.
Definition: function.h:20
dual2 sin(dual2 x)
Compute the sine of a second order dual number.
Definition: dual2_functions.h:70
dual2 square(dual2 x)
Return the square of a second order dual number.
Definition: dual2_functions.h:23
constexpr real PI
The Pi mathematical constant.
Definition: constants.h:206
real nan()
Return a quiet NaN number in floating point representation.
Definition: error.h:54
constexpr real TAU
The Tau mathematical constant (Pi times 2)
Definition: constants.h:218
Pseudorandom number generator class.
A probability density function sampler which generates pseudorandom numbers following asymptotically ...
Definition: sampling.h:468
void fill(Vector &x, size_t N)
Fill a vector with sampled points.
Definition: sampling.h:499
void fill(Vector &x)
Fill a vector with sampled points.
Definition: sampling.h:508
pdf_sampler & operator>>(real &x)
Stream the next generated number.
Definition: sampling.h:516
std::vector< real > theta
The parameters of the target distribution.
Definition: sampling.h:474
PRNG & generator
A pseudorandom number generator.
Definition: sampling.h:477
static pdf_sampler rayleigh(real sigma, PRNG &generator)
Returns a Rayleigh distribution sampler.
Definition: sampling.h:547
static pdf_sampler cauchy(real mu, real alpha, PRNG &generator)
Returns a Cauchy distribution sampler.
Definition: sampling.h:541
real operator()()
Generate the next number.
Definition: sampling.h:493
pdf_sampler(pdf_sampling_function pdf, const std::vector< real > &theta, PRNG &generator)
Initialize the sampler with the given parameters.
Definition: sampling.h:481
pdf_sampling_function pdf
A p.d.f sampling function.
Definition: sampling.h:471
static pdf_sampler exponential(real lambda, PRNG &generator)
Returns an exponential distribution sampler.
Definition: sampling.h:535
static pdf_sampler gaussian(real mean, real sigma, PRNG &generator)
Returns a Gaussian distribution sampler.
Definition: sampling.h:529
static pdf_sampler laplace(real mu, real b, PRNG &generator)
Returns a Laplace distribution sampler.
Definition: sampling.h:559
static pdf_sampler pareto(real x_m, real alpha, PRNG &generator)
Returns a Pareto distribution sampler.
Definition: sampling.h:553
real next()
Generate the next number.
Definition: sampling.h:488
static pdf_sampler uniform(real a, real b, PRNG &generator)
Returns a uniform distribution sampler.
Definition: sampling.h:523