Theoretica
A C++ numerical and automatic mathematical library
Loading...
Searching...
No Matches
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
12namespace theoretica {
13
14
18 using pdf_sampling_function = real(*)(const std::vector<real>&, PRNG&);
19
20
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
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
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
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
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
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
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
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
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
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
538
539
544
545
550
551
556
557
560 return pdf_sampler(rand_laplace, {mu, b}, generator);
561 }
562
563 };
564
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
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:198
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:333
dual2 ln(dual2 x)
Compute the natural logarithm of a second order dual number.
Definition dual2_functions.h:151
dual2 abs(dual2 x)
Compute the absolute value of a second order dual number.
Definition dual2_functions.h:198
constexpr uint64_t STATISTICS_RAND_PREC
Default precision for random number generation using rand_uniform()
Definition constants.h:330
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
std::remove_reference_t< decltype(std::declval< Structure >()[0])> vector_element_t
Extract the type of a vector (or any indexable container) from its operator[].
Definition core_traits.h:134
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:315
real powf(real x, real a)
Approximate x elevated to a real exponent.
Definition real_analysis.h:795
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:86
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:207
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:100
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:72
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:216
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:228
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