Theoretica
Scientific Computing
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
35
36 // Generate a uniform random real number in [0, 1]
37 real x = (g() % prec) / static_cast<real>(prec);
38
39 // Transform to target interval
40 return a + (b - a) * x;
41 }
42
43
48 inline real rand_uniform(const std::vector<real>& theta, PRNG& g) {
49
50 if(theta.size() != 2) {
51 TH_MATH_ERROR("rand_uniform", theta.size(), MathError::InvalidArgument);
52 return nan();
53 }
54
55 return rand_uniform(theta[0], theta[1], g);
56 }
57
58
64
65 return (g() % 2 == 0) ? 1 : -1;
66 }
67
68
73 inline real rand_cointoss(const std::vector<real>& theta, PRNG& g) {
74 return rand_cointoss(g);
75 }
76
77
83 inline real rand_diceroll(unsigned int faces, PRNG& g) {
84
85 if(faces == 0) {
87 return nan();
88 }
89
90 return (g() % faces) + 1;
91 }
92
93
98 inline real rand_diceroll(const std::vector<real>& theta, PRNG& g) {
99
100 if(theta.size() != 1) {
101 TH_MATH_ERROR("rand_diceroll", theta.size(), MathError::InvalidArgument);
102 return nan();
103 }
104
105 if(theta[0] < 0) {
106 TH_MATH_ERROR("rand_diceroll", theta[0], MathError::InvalidArgument);
107 return nan();
108 }
109
110 return rand_diceroll(theta[0], g);
111 }
112
113
135 const vec<real>& theta,
136 real x1, real x2,
137 real y1, real y2, PRNG& g,
138 unsigned int max_iter = STATISTICS_TRYANDCATCH_ITER) {
139
140 real x;
141 real y;
142
143 unsigned int iter = 0;
144
145 do {
146 x = rand_uniform(x1, x2, g);
147 y = rand_uniform(y1, y2, g);
148 iter++;
149 } while(y > f(x, theta) && iter <= max_iter);
150
151 if(iter > max_iter) {
153 return nan();
154 }
155
156 return x;
157 }
158
159
171 stat_function f, const vec<real>& theta,
173 PRNG& g, unsigned int max_tries = 100) {
174
175 for (unsigned int i = 0; i < max_tries; ++i) {
176
177 // Generate a random number following
178 // the p(x) probability distribution
179 // by the inverse cumulative distribution function
180 const real u_1 = rand_uniform(0, 1, g);
181 const real x_p = Pinv(u_1);
182
183 const real u_2 = rand_uniform(0, 1, g);
184
185 // Accept the sample if f(x_p)/g(x_p) > u_2
186 if(u_2 * p(x_p) < f(x_p, theta))
187 return x_p;
188 }
189
190 TH_MATH_ERROR("rand_reject_sample", max_tries, MathError::NoConvergence);
191 return nan();
192 }
193
194
201
202 static real spare;
203 static bool has_spare = false;
204
205 if(has_spare) {
206 has_spare = false;
207 return mean + spare * sigma;
208 }
209
210 real x, y, s;
211
212 // Generate a random point inside the unit circle
213 do {
214
215 x = rand_uniform(-1, 1, g);
216 y = rand_uniform(-1, 1, g);
217 s = square(x) + square(y);
218
219 } while(s >= 1 || s <= MACH_EPSILON);
220
221 // Project the point
222 s = sqrt(-2 * ln(s) / s);
223
224 // Keep the second generated value for future calls
225 spare = y * s;
226 has_spare = true;
227
228 return mean + sigma * x * s;
229 }
230
231
238
239 static real spare;
240 static bool has_spare = false;
241
242 if(has_spare) {
243 has_spare = false;
244 return mean + spare * sigma;
245 }
246
247 // Generate a random point inside the unit circle
248
249 const real x = rand_uniform(0, 1, g);
250 const real y = rand_uniform(0, 1, g);
251
252 const real x_transf = sqrt(-2 * ln(x));
253
254 const real u = x_transf * cos(TAU * y);
255 const real v = x_transf * sin(TAU * y);
256
257 spare = v;
258 has_spare = true;
259
260 return mean + sigma * u;
261 }
262
263
276
277 // Fixed N = 12
278 constexpr unsigned int N = 12;
279
280 real s = 0;
281 for (unsigned int i = 0; i < N; ++i)
282 s += rand_uniform(-1, 1, g);
283
284 // f(u) = 1/2 (in [-1, 1])
285 // E[u] = 0
286 // sqrt(V[u]) = 1 / sqrt(3N) = 1 / 6
287
288 return mean + (s / static_cast<real>(N)) * sigma * 6;
289 }
290
291
309 real mean, real sigma,
310 PRNG& g, unsigned int N) {
311
312 real s = 0;
313 for (unsigned int i = 0; i < N; ++i)
314 s += rand_uniform(-1, 1, g);
315
316 // f(u) = 1/2 (in [-1, 1])
317 // E[u] = 0
318 // sqrt(V[u]) = 1 / sqrt(3N)
319
320 return mean + (s / static_cast<real>(N)) * sigma * sqrt(3 * N);
321 }
322
323
327 return rand_gaussian_polar(mean, sigma, g);
328 }
329
330
335 inline real rand_gaussian(const std::vector<real>& theta, PRNG& g) {
336
337 if(theta.size() != 2) {
338 TH_MATH_ERROR("rand_gaussian", theta.size(), MathError::InvalidArgument);
339 return nan();
340 }
341
342 return rand_gaussian(theta[0], theta[1], g);
343 }
344
345
349
350 if(abs(lambda) < MACH_EPSILON) {
351 TH_MATH_ERROR("rand_exponential", lambda, MathError::DivByZero);
352 return nan();
353 }
354
355 return -ln(1 - rand_uniform(0, 1, g)) / lambda;
356 }
357
358
363 inline real rand_exponential(const std::vector<real>& theta, PRNG& g) {
364
365 if(theta.size() != 1) {
366 TH_MATH_ERROR("rand_exponential", theta.size(), MathError::InvalidArgument);
367 return nan();
368 }
369
370 return rand_exponential(theta[0], g);
371 }
372
373
377
378 return sigma * sqrt(-2 * ln(1 - rand_uniform(0, 1, g)));
379 }
380
381
386 inline real rand_rayleigh(const std::vector<real>& theta, PRNG& g) {
387
388 if(theta.size() != 1) {
389 TH_MATH_ERROR("rand_rayleigh", theta.size(), MathError::InvalidArgument);
390 return nan();
391 }
392
393 return rand_rayleigh(theta[0], g);
394 }
395
396
400
401 return alpha * tan(PI * (rand_uniform(0, 1, g) - 0.5)) + mu;
402 }
403
404
409 inline real rand_cauchy(const std::vector<real>& theta, PRNG& g) {
410
411 if(theta.size() != 2) {
412 TH_MATH_ERROR("rand_cauchy", theta.size(), MathError::InvalidArgument);
413 return nan();
414 }
415
416 return rand_cauchy(theta[0], theta[1], g);
417 }
418
419
423
424 const real u = rand_uniform(0, 0.5, g);
425 return mu - b * rand_cointoss(g) * ln(1 - 2 * abs(u));
426 }
427
428
431 inline real rand_laplace(const std::vector<real>& theta, PRNG& g) {
432
433 if(theta.size() != 2) {
434 TH_MATH_ERROR("rand_laplace", theta.size(), MathError::InvalidArgument);
435 return nan();
436 }
437
438 return rand_laplace(theta[0], theta[1], g);
439 }
440
441
445
446 return x_m / powf(1 - rand_uniform(0, 1, g), 1.0 / alpha);
447 }
448
449
454 inline real rand_pareto(const std::vector<real>& theta, PRNG& g) {
455
456 if(theta.size() != 2) {
457 TH_MATH_ERROR("rand_pareto", theta.size(), MathError::InvalidArgument);
458 return nan();
459 }
460
461 return rand_pareto(theta[0], theta[1], g);
462 }
463
464
469 struct pdf_sampler {
470
473
475 std::vector<real> theta;
476
479
480
484 const std::vector<real>& theta,
486
487
489 inline real next() {
490 return pdf(theta, generator);
491 }
492
494 inline real operator()() {
495 return next();
496 }
497
499 template<typename Vector>
500 inline void fill(Vector& x, size_t N) {
501
502 // Make sure that the buffer has enough space
503 if (x.size() < N) {
504
505 x.resize(N);
506
507 if (x.size() < N) {
508 TH_MATH_ERROR("pdf_sampler::fill", N, MathError::InvalidArgument);
510 return;
511 }
512 }
513
514 for (size_t i = 0; i < N; ++i)
515 x[i] = next();
516 }
517
518
520 template<typename Vector>
521 inline void fill(Vector& x) {
522
523 for (auto& x_i : x)
524 x_i = next();
525 }
526
527
530 x = next();
531 return *this;
532 }
533
534
537 return pdf_sampler(rand_uniform, {a, b}, generator);
538 }
539
540
543 return pdf_sampler(rand_gaussian, {mean, sigma}, generator);
544 }
545
546
551
552
557
558
563
564
569
570
573 return pdf_sampler(rand_laplace, {mu, b}, generator);
574 }
575
576 };
577
589 real x0, PRNG& rnd, unsigned int depth = STATISTICS_METROPOLIS_DEPTH) {
590
591 real current = x0, next;
592
593 for(unsigned int i = 0; i < depth; i++) {
594
595 // Computes the next step
596 next = current + g();
597
598 // Checks acceptance rate
599 if(rand_uniform(0, 1, rnd) * pdf(current) <= pdf(next))
600 current = next;
601 }
602
603 return current;
604 }
605
606
618 real x0, unsigned int depth = STATISTICS_METROPOLIS_DEPTH) {
619 return metropolis(pdf, g, x0, g.generator, depth);
620 }
621
622}
623
624#endif
A pseudorandom number generator.
Definition prng.h:19
A statically allocated N-dimensional vector with elements of the given type.
Definition vec.h:92
#define TH_MATH_ERROR(F_NAME, VALUE, EXCEPTION)
TH_MATH_ERROR is a macro which throws exceptions or modifies errno (depending on which compilation op...
Definition error.h:219
Vector & vec_error(Vector &v)
Overwrite the given vector with the error vector with NaN values.
Definition algebra.h:58
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:422
double real
A real number, defined as a floating point type.
Definition constants.h:207
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:342
dual2 ln(dual2 x)
Compute the natural logarithm of a second order dual number.
Definition dual2_functions.h:195
dual2 abs(dual2 x)
Compute the absolute value of a second order dual number.
Definition dual2_functions.h:242
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:444
real rand_exponential(real lambda, PRNG &g)
Generate a random number following an exponential distribution using the quantile (inverse) function ...
Definition sampling.h:348
Vector make_error()
Create a vector representing an error state, with all NaN values.
Definition algebra.h:103
real rand_rayleigh(real sigma, PRNG &g)
Generate a random number following a Rayleigh distribution using the quantile (inverse) function meth...
Definition sampling.h:376
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:587
constexpr unsigned int STATISTICS_TRYANDCATCH_ITER
Maximum number of failed iterations for the Try-and-Catch algorithm.
Definition constants.h:324
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:170
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:326
TH_CONSTEXPR real nan()
Return a quiet NaN number in floating point representation.
Definition error.h:74
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:275
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:237
real rand_diceroll(unsigned int faces, PRNG &g)
Dice roll random generator.
Definition sampling.h:83
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:63
@ InvalidArgument
Invalid argument.
@ NoConvergence
Algorithm did not converge.
@ DivByZero
Division by zero.
constexpr real MACH_EPSILON
Machine epsilon for the real type.
Definition constants.h:216
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:399
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:26
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:200
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:134
std::function< real(real)> real_function
Function pointer to a real function of real variable.
Definition function.h:20
complex< T > powf(complex< T > z, real p)
Compute a complex number raised to a real power.
Definition complex_analysis.h:65
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:225
constexpr real TAU
The Tau mathematical constant (Pi times 2)
Definition constants.h:237
real rand_uniform(real a, real b, PRNG &g, uint64_t prec=PSEUDORANDOM_PREC)
Generate a pseudorandom real number in [a, b] using a preexisting generator.
Definition sampling.h:34
constexpr uint64_t PSEUDORANDOM_PREC
Default precision for random number generation using rand_uniform()
Definition constants.h:339
Pseudorandom number generation.
A probability density function sampler which generates pseudorandom numbers following asymptotically ...
Definition sampling.h:469
void fill(Vector &x, size_t N)
Fill a vector with sampled points.
Definition sampling.h:500
void fill(Vector &x)
Fill a vector with sampled points.
Definition sampling.h:521
pdf_sampler & operator>>(real &x)
Stream the next generated number.
Definition sampling.h:529
std::vector< real > theta
The parameters of the target distribution.
Definition sampling.h:475
PRNG & generator
A pseudorandom number generator.
Definition sampling.h:478
static pdf_sampler rayleigh(real sigma, PRNG &generator)
Returns a Rayleigh distribution sampler.
Definition sampling.h:560
static pdf_sampler cauchy(real mu, real alpha, PRNG &generator)
Returns a Cauchy distribution sampler.
Definition sampling.h:554
real operator()()
Generate the next number.
Definition sampling.h:494
pdf_sampler(pdf_sampling_function pdf, const std::vector< real > &theta, PRNG &generator)
Initialize the sampler with the given parameters.
Definition sampling.h:482
pdf_sampling_function pdf
A p.d.f sampling function.
Definition sampling.h:472
static pdf_sampler exponential(real lambda, PRNG &generator)
Returns an exponential distribution sampler.
Definition sampling.h:548
static pdf_sampler gaussian(real mean, real sigma, PRNG &generator)
Returns a Gaussian distribution sampler.
Definition sampling.h:542
static pdf_sampler laplace(real mu, real b, PRNG &generator)
Returns a Laplace distribution sampler.
Definition sampling.h:572
static pdf_sampler pareto(real x_m, real alpha, PRNG &generator)
Returns a Pareto distribution sampler.
Definition sampling.h:566
real next()
Generate the next number.
Definition sampling.h:489
static pdf_sampler uniform(real a, real b, PRNG &generator)
Returns a uniform distribution sampler.
Definition sampling.h:536