vSMC
vSMC: Scalable Monte Carlo
beta_distribution.hpp
Go to the documentation of this file.
1 //============================================================================
2 // vSMC/include/vsmc/rng/beta_distribution.hpp
3 //----------------------------------------------------------------------------
4 // vSMC: Scalable Monte Carlo
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2016, Yan Zhou
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //============================================================================
31 
32 #ifndef VSMC_RNG_BETA_DISTRIBUTION_HPP
33 #define VSMC_RNG_BETA_DISTRIBUTION_HPP
34 
38 
39 namespace vsmc
40 {
41 
42 namespace internal
43 {
44 
45 template <typename RealType>
46 inline bool beta_distribution_check_param(RealType alpha, RealType beta)
47 {
48  return alpha > 0 && beta > 0;
49 }
50 
61 }; // enum BetaDistributionAlgorithm
62 
63 template <typename RealType>
65 {
66  public:
67  BetaDistributionConstant(RealType alpha = 1, RealType beta = 1)
68  {
69  reset(alpha, beta);
70  }
71 
72  void reset(RealType alpha, RealType beta)
73  {
74  const RealType K = static_cast<RealType>(0.852);
75  const RealType C = static_cast<RealType>(-0.956);
76  const RealType D = beta + K * alpha * alpha + C;
77  if (is_equal<RealType>(alpha, static_cast<RealType>(0.5)) &&
78  is_equal<RealType>(beta, static_cast<RealType>(0.5)))
80  else if (is_equal<RealType>(alpha, 1) && is_equal<RealType>(beta, 1))
82  else if (is_equal<RealType>(alpha, 1))
84  else if (is_equal<RealType>(beta, 1))
86  else if (alpha > 1 && beta > 1)
88  else if (alpha < 1 && beta < 1 && D <= 0)
90  else if (alpha < 1 && beta < 1)
92  else if (alpha < 1 && beta > 1)
94  else if (alpha > 1 && beta < 1)
96  else
98 
99  a = b = t = p = 0;
100  switch (algorithm) {
101  case BetaDistributionAlgorithmAS: break;
102  case BetaDistributionAlgorithm11: break;
103  case BetaDistributionAlgorithm1X: b = 1 / beta; break;
104  case BetaDistributionAlgorithmX1: a = 1 / alpha; break;
106  a = alpha + beta;
107  b = std::min(alpha, beta);
108  if (b > 1)
109  b = std::sqrt((2 * alpha * beta - a) / (a - 2));
110  b = 1 / b;
111  t = alpha + 1 / b;
112  p = a * std::log(a);
113  break;
115  a = 1 / alpha;
116  b = 1 / beta;
117  break;
119  a = 1 / alpha;
120  b = 1 / beta;
121  t = std::sqrt(alpha * (1 - alpha));
122  t /= t + std::sqrt(beta * (1 - beta));
123  p = beta * t;
124  p /= p + alpha * (1 - t);
125  break;
127  a = 1 / alpha;
128  b = 1 / beta;
129  t = 1 - alpha;
130  t /= t + beta;
131  p = beta * t;
132  p /= p + alpha * std::pow(1 - t, beta);
133  break;
135  a = 1 / beta;
136  b = 1 / alpha;
137  t = 1 - beta;
138  t /= t + alpha;
139  p = alpha * t;
140  p /= p + beta * std::pow(1 - t, alpha);
141  break;
142  }
143  }
144 
145  RealType a;
146  RealType b;
147  RealType t;
148  RealType p;
150 }; // class BetaDistributionConstant
151 
152 } // namespace internal
153 
156 template <typename RealType>
158 {
159  VSMC_DEFINE_RNG_DISTRIBUTION_2(Beta, beta, alpha, 1, beta, 1)
160 
161  public:
162  result_type min() const { return 0; }
163 
164  result_type max() const { return 1; }
165 
166  void reset() { constant_.reset(alpha(), beta()); }
167 
168  private:
170 
171  template <typename RNGType>
172  result_type generate(RNGType &rng, const param_type &param)
173  {
174  if (param == param_)
175  return generate(rng, param_, constant_);
176 
178  param.alpha(), param.beta());
179 
180  return generate(rng, param, constant);
181  }
182 
183  template <typename RNGType>
184  result_type generate(RNGType &rng, const param_type &param,
186  {
187  result_type r = 0;
188  switch (constant.algorithm) {
190  r = generate_as(rng, param, constant);
191  break;
193  r = generate_11(rng, param, constant);
194  break;
196  r = generate_1x(rng, param, constant);
197  break;
199  r = generate_x1(rng, param, constant);
200  break;
202  r = generate_c(rng, param, constant);
203  break;
205  r = generate_j(rng, param, constant);
206  break;
208  r = generate_a1(rng, param, constant);
209  break;
211  r = generate_a2(rng, param, constant);
212  break;
214  r = generate_a3(rng, param, constant);
215  break;
216  }
217 
218  return r;
219  }
220 
221  template <typename RNGType>
222  result_type generate_as(RNGType &rng, const param_type &,
224  {
226  result_type u = u01(rng);
227  u = std::sin(
228  -const_pi_by2<result_type>() + const_pi<result_type>() * u);
229 
230  return static_cast<result_type>(0.5) +
231  static_cast<result_type>(0.5) * u;
232  }
233 
234  template <typename RNGType>
235  result_type generate_11(RNGType &rng, const param_type &,
237  {
239 
240  return u01(rng);
241  }
242 
243  template <typename RNGType>
244  result_type generate_1x(RNGType &rng, const param_type &,
246  {
248 
249  return 1 - std::exp(constant.b * std::log(u01(rng)));
250  }
251 
252  template <typename RNGType>
253  result_type generate_x1(RNGType &rng, const param_type &,
255  {
257 
258  return std::exp(constant.a * std::log(u01(rng)));
259  }
260 
261  template <typename RNGType>
262  result_type generate_c(RNGType &rng, const param_type &param,
264  {
266  const result_type ln_4 = 2 * const_ln_2<result_type>();
267  result_type x = 0;
268  result_type y = 0;
269  result_type left = 0;
270  result_type right = 0;
271  do {
272  result_type u1 = u01(rng);
273  result_type u2 = u01(rng);
274  result_type v = constant.b * std::log(u1 / (1 - u1));
275  x = param.alpha() * std::exp(v);
276  y = param.beta() + x;
277  left = (constant.p - constant.a * std::log(y)) +
278  (constant.t * v - ln_4);
279  right = std::log(u1 * u1 * u2);
280  } while (left < right);
281 
282  return x / y;
283  }
284 
285  template <typename RNGType>
286  result_type generate_j(RNGType &rng, const param_type &,
288  {
290  result_type x = 0;
291  result_type y = 0;
292  do {
293  x = std::pow(u01(rng), constant.a);
294  y = std::pow(u01(rng), constant.b);
295  } while (x + y > 1);
296 
297  return x / (x + y);
298  }
299 
300  template <typename RNGType>
301  result_type generate_a1(RNGType &rng, const param_type &param,
303  {
305  while (true) {
306  result_type u = u01(rng);
307  result_type e = -std::log(u01(rng));
308  result_type x = 0;
309  result_type v = 0;
310  if (u < constant.p) {
311  x = constant.t * std::pow(u / constant.p, constant.a);
312  v = (1 - param.beta()) * std::log((1 - x) / (1 - constant.t));
313  } else {
314  x = 1 -
315  (1 - constant.t) *
316  std::pow((1 - u) / (1 - constant.p), constant.b);
317  v = (1 - param.alpha()) * std::log(x / constant.t);
318  }
319  if (v < e)
320  return x;
321  }
322  }
323 
324  template <typename RNGType>
325  result_type generate_a2(RNGType &rng, const param_type &param,
327  {
329  while (true) {
330  result_type u = u01(rng);
331  result_type e = -std::log(u01(rng));
332  result_type x = 0;
333  result_type v = 0;
334  if (u < constant.p) {
335  x = constant.t * std::pow(u / constant.p, constant.a);
336  v = (1 - param.beta()) * std::log(1 - x);
337  } else {
338  x = 1 -
339  (1 - constant.t) *
340  std::pow((1 - u) / (1 - constant.p), constant.b);
341  v = (1 - param.alpha()) * std::log(x / constant.t);
342  }
343  if (v < e)
344  return x;
345  }
346  }
347 
348  template <typename RNGType>
349  result_type generate_a3(RNGType &rng, const param_type &param,
351  {
353  while (true) {
354  result_type u = u01(rng);
355  result_type e = -std::log(u01(rng));
356  result_type x = 0;
357  result_type v = 0;
358  if (u < constant.p) {
359  x = constant.t * std::pow(u / constant.p, constant.a);
360  v = (1 - param.alpha()) * std::log(1 - x);
361  } else {
362  x = 1 -
363  (1 - constant.t) *
364  std::pow((1 - u) / (1 - constant.p), constant.b);
365  v = (1 - param.beta()) * std::log(x / constant.t);
366  }
367  if (v < e)
368  return 1 - x;
369  }
370  }
371 }; // class BetaDistribution
372 
373 namespace internal
374 {
375 
376 template <std::size_t, typename RealType, typename RNGType>
377 inline std::size_t beta_distribution_impl_as(RNGType &rng, std::size_t n,
378  RealType *r, RealType, RealType,
380 {
381  u01_distribution(rng, n, r);
382  fma(n, const_pi<RealType>(), r, -const_pi_by2<RealType>(), r);
383  sin(n, r, r);
384  fma(n, static_cast<RealType>(0.5), r, static_cast<RealType>(0.5), r);
385 
386  return n;
387 }
388 
389 template <std::size_t, typename RealType, typename RNGType>
390 inline std::size_t beta_distribution_impl_11(RNGType &rng, std::size_t n,
391  RealType *r, RealType, RealType,
393 {
394  u01_distribution(rng, n, r);
395 
396  return n;
397 }
398 
399 template <std::size_t, typename RealType, typename RNGType>
400 inline std::size_t beta_distribution_impl_1x(RNGType &rng, std::size_t n,
401  RealType *r, RealType, RealType,
402  const BetaDistributionConstant<RealType> &constant)
403 {
404  u01_distribution(rng, n, r);
405  log(n, r, r);
406  mul(n, constant.b, r, r);
407  exp(n, r, r);
408  sub(n, static_cast<RealType>(1), r, r);
409 
410  return n;
411 }
412 
413 template <std::size_t, typename RealType, typename RNGType>
414 inline std::size_t beta_distribution_impl_x1(RNGType &rng, std::size_t n,
415  RealType *r, RealType, RealType,
416  const BetaDistributionConstant<RealType> &constant)
417 {
418  u01_distribution(rng, n, r);
419  log(n, r, r);
420  mul(n, constant.a, r, r);
421  exp(n, r, r);
422 
423  return n;
424 }
425 
426 template <std::size_t K, typename RealType, typename RNGType>
427 inline std::size_t beta_distribution_impl_c(RNGType &rng, std::size_t n,
428  RealType *r, RealType alpha, RealType beta,
429  const BetaDistributionConstant<RealType> &constant)
430 {
431  const RealType a = constant.a;
432  const RealType b = constant.b;
433  const RealType t = constant.t;
434  const RealType p = constant.p;
435  const RealType ln_4 = 2 * const_ln_2<RealType>();
436  RealType s[K * 5];
437  RealType *const u1 = s;
438  RealType *const u2 = s + n;
439  RealType *const v = s + n * 2;
440  RealType *const x = s + n * 3;
441  RealType *const y = s + n * 4;
442  u01_distribution(rng, n * 2, s);
443  sub(n, static_cast<RealType>(1), u1, v);
444  div(n, u1, v, v);
445  log(n, v, v);
446  mul(n, b, v, v);
447  exp(n, v, x);
448  mul(n, alpha, x, x);
449  add(n, beta, x, y);
450  div(n, x, y, x);
451  sqr(n, u1, u1);
452  mul(n, u1, u2, u2);
453  log(n, u2, u2);
454  log(n, y, u1);
455  fma(n, -a, u1, p, u1);
456  fma(n, t, v, -ln_4, v);
457  add(n, v, u1, u1);
458 
459  std::size_t m = 0;
460  for (std::size_t i = 0; i != n; ++i)
461  if (u1[i] > u2[i])
462  r[m++] = x[i];
463 
464  return m;
465 }
466 
467 template <std::size_t K, typename RealType, typename RNGType>
468 inline std::size_t beta_distribution_impl_j(RNGType &rng, std::size_t n,
469  RealType *r, RealType, RealType,
470  const BetaDistributionConstant<RealType> &constant)
471 {
472  const RealType a = constant.a;
473  const RealType b = constant.b;
474  RealType s[K * 3];
475  RealType *const x = s;
476  RealType *const y = s + n;
477  RealType *const u = s + n * 2;
478  u01_distribution(rng, n * 2, s);
479  pow(n, x, a, x);
480  pow(n, y, b, y);
481  add(n, x, y, u);
482  div(n, x, u, x);
483 
484  std::size_t m = 0;
485  for (std::size_t i = 0; i != n; ++i)
486  if (u[i] < 1)
487  r[m++] = x[i];
488 
489  return m;
490 }
491 
492 template <std::size_t, typename RealType, typename RNGType>
493 inline std::size_t beta_distribution_impl_a1(RNGType &, std::size_t,
494  RealType *, RealType, RealType, const BetaDistributionConstant<RealType> &)
495 {
496  return 0;
497 }
498 
499 template <std::size_t, typename RealType, typename RNGType>
500 inline std::size_t beta_distribution_impl_a2(RNGType &, std::size_t,
501  RealType *, RealType, RealType, const BetaDistributionConstant<RealType> &)
502 {
503  return 0;
504 }
505 
506 template <std::size_t, typename RealType, typename RNGType>
507 inline std::size_t beta_distribution_impl_a3(RNGType &, std::size_t,
508  RealType *, RealType, RealType, const BetaDistributionConstant<RealType> &)
509 {
510  return 0;
511 }
512 
513 template <std::size_t K, typename RealType, typename RNGType>
514 inline std::size_t beta_distribution_impl(RNGType &rng, std::size_t n,
515  RealType *r, RealType alpha, RealType beta,
516  const BetaDistributionConstant<RealType> &constant)
517 {
518  switch (constant.algorithm) {
520  return beta_distribution_impl_as<K>(
521  rng, n, r, alpha, beta, constant);
523  return beta_distribution_impl_11<K>(
524  rng, n, r, alpha, beta, constant);
526  return beta_distribution_impl_1x<K>(
527  rng, n, r, alpha, beta, constant);
529  return beta_distribution_impl_x1<K>(
530  rng, n, r, alpha, beta, constant);
532  return beta_distribution_impl_c<K>(
533  rng, n, r, alpha, beta, constant);
535  return beta_distribution_impl_j<K>(
536  rng, n, r, alpha, beta, constant);
538  return beta_distribution_impl_a1<K>(
539  rng, n, r, alpha, beta, constant);
541  return beta_distribution_impl_a2<K>(
542  rng, n, r, alpha, beta, constant);
544  return beta_distribution_impl_a3<K>(
545  rng, n, r, alpha, beta, constant);
546  }
547  return 0;
548 }
549 
550 } // namespace vsmc::internal
551 
554 template <typename RealType, typename RNGType>
555 inline void beta_distribution(
556  RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta)
557 {
558  static_assert(std::is_floating_point<RealType>::value,
559  "**beta_distribution** USED WITH RealType OTHER THAN FLOATING POINT "
560  "TYPES");
561 
562  const std::size_t k = 1024;
563  const internal::BetaDistributionConstant<RealType> constant(alpha, beta);
564  while (n > k) {
565  std::size_t m = internal::beta_distribution_impl<k>(
566  rng, k, r, alpha, beta, constant);
567  if (m == 0)
568  break;
569  n -= m;
570  r += m;
571  }
572  std::size_t m =
573  internal::beta_distribution_impl<k>(rng, n, r, alpha, beta, constant);
574  n -= m;
575  r += m;
576  if (n > 0) {
577  BetaDistribution<RealType> dist(alpha, beta);
578  for (std::size_t i = 0; i != n; ++i)
579  r[i] = dist(rng);
580  }
581 }
582 
583 VSMC_DEFINE_RNG_DISTRIBUTION_RAND_2(Beta, beta, alpha, beta)
584 
585 } // namespace vsmc
586 
587 #endif // VSMC_RNG_BETA_DISTRIBUTION_HPP
Definition: monitor.hpp:49
result_type max() const
void mul(std::size_t n, const float *a, const float *b, float *y)
Definition: vmath.hpp:112
#define VSMC_DEFINE_RNG_DISTRIBUTION_2(Name, name, p1, v1, p2, v2)
Definition: common.hpp:374
void reset(RealType alpha, RealType beta)
std::size_t beta_distribution_impl_c(RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta, const BetaDistributionConstant< RealType > &constant)
void sqrt(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:129
std::size_t beta_distribution_impl_11(RNGType &rng, std::size_t n, RealType *r, RealType, RealType, const BetaDistributionConstant< RealType > &)
std::size_t beta_distribution_impl_j(RNGType &rng, std::size_t n, RealType *r, RealType, RealType, const BetaDistributionConstant< RealType > &constant)
std::size_t beta_distribution_impl(RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta, const BetaDistributionConstant< RealType > &constant)
void u01_distribution(RNGType &, std::size_t, RealType *)
Generate standard uniform random variates.
std::size_t beta_distribution_impl_as(RNGType &rng, std::size_t n, RealType *r, RealType, RealType, const BetaDistributionConstant< RealType > &)
std::size_t beta_distribution_impl_a2(RNGType &, std::size_t, RealType *, RealType, RealType, const BetaDistributionConstant< RealType > &)
void pow(std::size_t n, const float *a, const float *b, float *y)
Definition: vmath.hpp:135
BetaDistributionConstant(RealType alpha=1, RealType beta=1)
void exp(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:146
std::size_t beta_distribution_impl_x1(RNGType &rng, std::size_t n, RealType *r, RealType, RealType, const BetaDistributionConstant< RealType > &constant)
std::size_t beta_distribution_impl_a1(RNGType &, std::size_t, RealType *, RealType, RealType, const BetaDistributionConstant< RealType > &)
void div(std::size_t n, const float *a, const float *b, float *y)
Definition: vmath.hpp:128
void sub(std::size_t n, const float *a, const float *b, float *y)
Definition: vmath.hpp:110
void fma(std::size_t n, const T *a, const T *b, const T *c, T *y)
For , compute .
Definition: vmath.hpp:257
void sin(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:153
void beta_distribution(RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta)
Generating beta random variates.
void add(std::size_t n, const float *a, const float *b, float *y)
Definition: vmath.hpp:109
bool beta_distribution_check_param(RealType alpha, RealType beta)
Standard uniform distribution.
Definition: common.hpp:597
#define VSMC_DEFINE_RNG_DISTRIBUTION_RAND_2(Name, name, p1, p2)
Definition: common.hpp:409
void log(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:148
void sqr(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:111
std::size_t beta_distribution_impl_1x(RNGType &rng, std::size_t n, RealType *r, RealType, RealType, const BetaDistributionConstant< RealType > &constant)
std::size_t beta_distribution_impl_a3(RNGType &, std::size_t, RealType *, RealType, RealType, const BetaDistributionConstant< RealType > &)