vSMC  v3.0.0
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(alpha, static_cast<RealType>(0.5)) &&
78  is_equal(beta, static_cast<RealType>(0.5)))
80  else if (is_one(alpha) && is_one(beta))
82  else if (is_one(alpha))
84  else if (is_one(beta))
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  bool is_equal(const distribution_type &other) const
172  {
173  if (!is_equal(constant_.a, other.constant_.a))
174  return false;
175  if (!is_equal(constant_.b, other.constant_.b))
176  return false;
177  if (!is_equal(constant_.t, other.constant_.t))
178  return false;
179  if (!is_equal(constant_.p, other.constant_.p))
180  return false;
181  if (!is_equal(constant_.algorithm, other.constant_.algorithm))
182  return false;
183  return true;
184  }
185 
186  template <typename CharT, typename Traits>
187  void ostream(std::basic_ostream<CharT, Traits> &) const
188  {
189  }
190 
191  template <typename CharT, typename Traits>
192  void istream(std::basic_istream<CharT, Traits> &)
193  {
194  reset();
195  }
196 
197  template <typename RNGType>
198  result_type generate(RNGType &rng, const param_type &param)
199  {
200  if (param == param_)
201  return generate(rng, param_, constant_);
202 
204  param.alpha(), param.beta());
205 
206  return generate(rng, param, constant);
207  }
208 
209  template <typename RNGType>
210  result_type generate(RNGType &rng, const param_type &param,
212  {
213  result_type r = 0;
214  switch (constant.algorithm) {
216  r = generate_as(rng, param, constant);
217  break;
219  r = generate_11(rng, param, constant);
220  break;
222  r = generate_1x(rng, param, constant);
223  break;
225  r = generate_x1(rng, param, constant);
226  break;
228  r = generate_c(rng, param, constant);
229  break;
231  r = generate_j(rng, param, constant);
232  break;
234  r = generate_a1(rng, param, constant);
235  break;
237  r = generate_a2(rng, param, constant);
238  break;
240  r = generate_a3(rng, param, constant);
241  break;
242  }
243 
244  return r;
245  }
246 
247  template <typename RNGType>
248  result_type generate_as(RNGType &rng, const param_type &,
250  {
252  result_type u = u01(rng);
253  u = std::sin(
254  -const_pi_by2<result_type>() + const_pi<result_type>() * u);
255 
256  return static_cast<result_type>(0.5) +
257  static_cast<result_type>(0.5) * u;
258  }
259 
260  template <typename RNGType>
261  result_type generate_11(RNGType &rng, const param_type &,
263  {
265 
266  return u01(rng);
267  }
268 
269  template <typename RNGType>
270  result_type generate_1x(RNGType &rng, const param_type &,
272  {
274 
275  return 1 - std::exp(constant.b * std::log(u01(rng)));
276  }
277 
278  template <typename RNGType>
279  result_type generate_x1(RNGType &rng, const param_type &,
281  {
283 
284  return std::exp(constant.a * std::log(u01(rng)));
285  }
286 
287  template <typename RNGType>
288  result_type generate_c(RNGType &rng, const param_type &param,
290  {
292  const result_type ln_4 = 2 * const_ln_2<result_type>();
293  result_type x = 0;
294  result_type y = 0;
295  result_type left = 0;
296  result_type right = 0;
297  do {
298  result_type u1 = u01(rng);
299  result_type u2 = u01(rng);
300  result_type v = constant.b * std::log(u1 / (1 - u1));
301  x = param.alpha() * std::exp(v);
302  y = param.beta() + x;
303  left = (constant.p - constant.a * std::log(y)) +
304  (constant.t * v - ln_4);
305  right = std::log(u1 * u1 * u2);
306  } while (left < right);
307 
308  return x / y;
309  }
310 
311  template <typename RNGType>
312  result_type generate_j(RNGType &rng, const param_type &,
314  {
316  result_type x = 0;
317  result_type y = 0;
318  do {
319  x = std::pow(u01(rng), constant.a);
320  y = std::pow(u01(rng), constant.b);
321  } while (x + y > 1);
322 
323  return x / (x + y);
324  }
325 
326  template <typename RNGType>
327  result_type generate_a1(RNGType &rng, const param_type &param,
329  {
331  while (true) {
332  result_type u = u01(rng);
333  result_type e = -std::log(u01(rng));
334  result_type x = 0;
335  result_type v = 0;
336  if (u < constant.p) {
337  x = constant.t * std::pow(u / constant.p, constant.a);
338  v = (1 - param.beta()) * std::log((1 - x) / (1 - constant.t));
339  } else {
340  x = 1 -
341  (1 - constant.t) *
342  std::pow((1 - u) / (1 - constant.p), constant.b);
343  v = (1 - param.alpha()) * std::log(x / constant.t);
344  }
345  if (v < e)
346  return x;
347  }
348  }
349 
350  template <typename RNGType>
351  result_type generate_a2(RNGType &rng, const param_type &param,
353  {
355  while (true) {
356  result_type u = u01(rng);
357  result_type e = -std::log(u01(rng));
358  result_type x = 0;
359  result_type v = 0;
360  if (u < constant.p) {
361  x = constant.t * std::pow(u / constant.p, constant.a);
362  v = (1 - param.beta()) * std::log(1 - x);
363  } else {
364  x = 1 -
365  (1 - constant.t) *
366  std::pow((1 - u) / (1 - constant.p), constant.b);
367  v = (1 - param.alpha()) * std::log(x / constant.t);
368  }
369  if (v < e)
370  return x;
371  }
372  }
373 
374  template <typename RNGType>
375  result_type generate_a3(RNGType &rng, const param_type &param,
377  {
379  while (true) {
380  result_type u = u01(rng);
381  result_type e = -std::log(u01(rng));
382  result_type x = 0;
383  result_type v = 0;
384  if (u < constant.p) {
385  x = constant.t * std::pow(u / constant.p, constant.a);
386  v = (1 - param.alpha()) * std::log(1 - x);
387  } else {
388  x = 1 -
389  (1 - constant.t) *
390  std::pow((1 - u) / (1 - constant.p), constant.b);
391  v = (1 - param.beta()) * std::log(x / constant.t);
392  }
393  if (v < e)
394  return 1 - x;
395  }
396  }
397 }; // class BetaDistribution
398 
399 namespace internal
400 {
401 
402 template <std::size_t, typename RealType, typename RNGType>
403 inline std::size_t beta_distribution_impl_as(RNGType &rng, std::size_t n,
404  RealType *r, RealType, RealType,
406 {
407  u01_oo_distribution(rng, n, r);
408  fma(n, const_pi<RealType>(), r, -const_pi_by2<RealType>(), r);
409  sin(n, r, r);
410  fma(n, static_cast<RealType>(0.5), r, static_cast<RealType>(0.5), r);
411 
412  return n;
413 }
414 
415 template <std::size_t, typename RealType, typename RNGType>
416 inline std::size_t beta_distribution_impl_11(RNGType &rng, std::size_t n,
417  RealType *r, RealType, RealType,
419 {
420  u01_oo_distribution(rng, n, r);
421 
422  return n;
423 }
424 
425 template <std::size_t, typename RealType, typename RNGType>
426 inline std::size_t beta_distribution_impl_1x(RNGType &rng, std::size_t n,
427  RealType *r, RealType, RealType,
428  const BetaDistributionConstant<RealType> &constant)
429 {
430  u01_oo_distribution(rng, n, r);
431  log(n, r, r);
432  mul(n, constant.b, r, r);
433  exp(n, r, r);
434  sub(n, static_cast<RealType>(1), r, r);
435 
436  return n;
437 }
438 
439 template <std::size_t, typename RealType, typename RNGType>
440 inline std::size_t beta_distribution_impl_x1(RNGType &rng, std::size_t n,
441  RealType *r, RealType, RealType,
442  const BetaDistributionConstant<RealType> &constant)
443 {
444  u01_oo_distribution(rng, n, r);
445  log(n, r, r);
446  mul(n, constant.a, r, r);
447  exp(n, r, r);
448 
449  return n;
450 }
451 
452 template <std::size_t K, typename RealType, typename RNGType>
453 inline std::size_t beta_distribution_impl_c(RNGType &rng, std::size_t n,
454  RealType *r, RealType alpha, RealType beta,
455  const BetaDistributionConstant<RealType> &constant)
456 {
457  const RealType a = constant.a;
458  const RealType b = constant.b;
459  const RealType t = constant.t;
460  const RealType p = constant.p;
461  const RealType ln_4 = 2 * const_ln_2<RealType>();
463  RealType *const u1 = s.data();
464  RealType *const u2 = s.data() + n;
465  RealType *const v = s.data() + n * 2;
466  RealType *const x = s.data() + n * 3;
467  RealType *const y = s.data() + n * 4;
468  u01_oo_distribution(rng, n * 2, s.data());
469  sub(n, static_cast<RealType>(1), u1, v);
470  div(n, u1, v, v);
471  log(n, v, v);
472  mul(n, b, v, v);
473  exp(n, v, x);
474  mul(n, alpha, x, x);
475  add(n, beta, x, y);
476  div(n, x, y, x);
477  sqr(n, u1, u1);
478  mul(n, u1, u2, u2);
479  log(n, u2, u2);
480  log(n, y, u1);
481  fma(n, -a, u1, p, u1);
482  fma(n, t, v, -ln_4, v);
483  add(n, v, u1, u1);
484 
485  std::size_t m = 0;
486  for (std::size_t i = 0; i != n; ++i)
487  if (u1[i] > u2[i])
488  r[m++] = x[i];
489 
490  return m;
491 }
492 
493 template <std::size_t K, typename RealType, typename RNGType>
494 inline std::size_t beta_distribution_impl_j(RNGType &rng, std::size_t n,
495  RealType *r, RealType, RealType,
496  const BetaDistributionConstant<RealType> &constant)
497 {
498  const RealType a = constant.a;
499  const RealType b = constant.b;
501  RealType *const x = s.data();
502  RealType *const y = s.data() + n;
503  RealType *const u = s.data() + n * 2;
504  u01_oo_distribution(rng, n * 2, s.data());
505  pow(n, x, a, x);
506  pow(n, y, b, y);
507  add(n, x, y, u);
508  div(n, x, u, x);
509 
510  std::size_t m = 0;
511  for (std::size_t i = 0; i != n; ++i)
512  if (u[i] < 1)
513  r[m++] = x[i];
514 
515  return m;
516 }
517 
518 template <std::size_t, typename RealType, typename RNGType>
519 inline std::size_t beta_distribution_impl_a1(RNGType &, std::size_t,
520  RealType *, RealType, RealType, const BetaDistributionConstant<RealType> &)
521 {
522  return 0;
523 }
524 
525 template <std::size_t, typename RealType, typename RNGType>
526 inline std::size_t beta_distribution_impl_a2(RNGType &, std::size_t,
527  RealType *, RealType, RealType, const BetaDistributionConstant<RealType> &)
528 {
529  return 0;
530 }
531 
532 template <std::size_t, typename RealType, typename RNGType>
533 inline std::size_t beta_distribution_impl_a3(RNGType &, std::size_t,
534  RealType *, RealType, RealType, const BetaDistributionConstant<RealType> &)
535 {
536  return 0;
537 }
538 
539 template <std::size_t K, typename RealType, typename RNGType>
540 inline std::size_t beta_distribution_impl(RNGType &rng, std::size_t n,
541  RealType *r, RealType alpha, RealType beta,
542  const BetaDistributionConstant<RealType> &constant)
543 {
544  switch (constant.algorithm) {
546  return beta_distribution_impl_as<K>(
547  rng, n, r, alpha, beta, constant);
549  return beta_distribution_impl_11<K>(
550  rng, n, r, alpha, beta, constant);
552  return beta_distribution_impl_1x<K>(
553  rng, n, r, alpha, beta, constant);
555  return beta_distribution_impl_x1<K>(
556  rng, n, r, alpha, beta, constant);
558  return beta_distribution_impl_c<K>(
559  rng, n, r, alpha, beta, constant);
561  return beta_distribution_impl_j<K>(
562  rng, n, r, alpha, beta, constant);
564  return beta_distribution_impl_a1<K>(
565  rng, n, r, alpha, beta, constant);
567  return beta_distribution_impl_a2<K>(
568  rng, n, r, alpha, beta, constant);
570  return beta_distribution_impl_a3<K>(
571  rng, n, r, alpha, beta, constant);
572  }
573  return 0;
574 }
575 
576 } // namespace vsmc::internal
577 
580 template <typename RealType, typename RNGType>
581 inline void beta_distribution(
582  RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta)
583 {
584  static_assert(std::is_floating_point<RealType>::value,
585  "**beta_distribution** USED WITH RealType OTHER THAN FLOATING POINT "
586  "TYPES");
587 
588  const std::size_t k = internal::BufferSize<RealType>::value;
589  const internal::BetaDistributionConstant<RealType> constant(alpha, beta);
590  while (n > k) {
591  std::size_t m = internal::beta_distribution_impl<k>(
592  rng, k, r, alpha, beta, constant);
593  if (m == 0)
594  break;
595  n -= m;
596  r += m;
597  }
598  std::size_t m =
599  internal::beta_distribution_impl<k>(rng, n, r, alpha, beta, constant);
600  n -= m;
601  r += m;
602  if (n > 0) {
603  BetaDistribution<RealType> dist(alpha, beta);
604  for (std::size_t i = 0; i != n; ++i)
605  r[i] = dist(rng);
606  }
607 }
608 
609 VSMC_DEFINE_RNG_DISTRIBUTION_RAND_2(Beta, beta, alpha, beta)
610 
611 } // namespace vsmc
612 
613 #endif // VSMC_RNG_BETA_DISTRIBUTION_HPP
Definition: monitor.hpp:48
result_type max() const
void mul(std::size_t n, const float *a, const float *b, float *y)
Definition: vmath.hpp:77
#define VSMC_DEFINE_RNG_DISTRIBUTION_2(Name, name, p1, v1, p2, v2)
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:96
std::basic_ostream< CharT, Traits > & ostream(std::basic_ostream< CharT, Traits > &os, const std::array< T, N > &ary)
Definition: basic.hpp:215
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_oo_distribution(RNGType &rng, std::size_t n, RealType *r)
Generate standard uniform random variates on (0, 1)
std::size_t beta_distribution_impl_as(RNGType &rng, std::size_t n, RealType *r, RealType, RealType, const BetaDistributionConstant< RealType > &)
Standard uniform distribution on (0, 1)
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:102
RealType u01(UIntType u) noexcept
Convert uniform unsigned integers to floating points within [0, 1].
Definition: u01.hpp:213
bool is_equal(const T &a, const T &b, std::true_type)
Definition: basic.hpp:83
BetaDistributionConstant(RealType alpha=1, RealType beta=1)
void exp(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:115
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:95
void sub(std::size_t n, const float *a, const float *b, float *y)
Definition: vmath.hpp:75
bool is_one(const T &a)
Definition: basic.hpp:107
void fma(std::size_t n, const T *a, const T *b, const T *c, T *y)
For , compute .
Definition: vmath.hpp:361
void sin(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:122
std::basic_istream< CharT, Traits > & istream(std::basic_istream< CharT, Traits > &is, std::array< T, N > &ary)
Definition: basic.hpp:243
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:74
bool beta_distribution_check_param(RealType alpha, RealType beta)
#define VSMC_DEFINE_RNG_DISTRIBUTION_RAND_2(Name, name, p1, p2)
std::array with proper alignment
void log(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:117
void sqr(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:76
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 > &)