vSMC  v3.0.0
Scalable Monte Carlo
gamma_distribution.hpp
Go to the documentation of this file.
1 //============================================================================
2 // vSMC/include/vsmc/rng/gamma_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_GAMMA_DISTRIBUTION_HPP
33 #define VSMC_RNG_GAMMA_DISTRIBUTION_HPP
34 
38 
39 namespace vsmc
40 {
41 
42 namespace internal
43 {
44 
45 template <typename RealType>
46 inline bool gamma_distribution_check_param(RealType alpha, RealType beta)
47 {
48  return alpha > 0 && beta > 0;
49 }
50 
56 }; // enum GammaDistributionAlgorithm
57 
58 template <typename RealType>
60 {
61  public:
62  GammaDistributionConstant(RealType alpha = 1, RealType beta = 1)
63  {
64  reset(alpha, beta);
65  }
66 
67  void reset(RealType alpha, RealType)
68  {
69  if (alpha < static_cast<RealType>(0.6))
71  else if (alpha < 1)
73  else if (alpha > 1)
75  else
77 
78  d = c = 0;
79  switch (algorithm) {
81  d = 1 - alpha;
82  c = 1 / alpha;
83  break;
85  d = std::pow(alpha, alpha / (1 - alpha)) * (1 - alpha);
86  c = 1 / alpha;
87  break;
89  d = alpha - static_cast<RealType>(1) / 3;
90  c = 1 / (3 * std::sqrt(d));
91  break;
92  case GammaDistributionAlgorithmE: break;
93  }
94  }
95 
96  RealType d;
97  RealType c;
99 }; // class GammaDistributionConstant
100 
101 } // namespace internal
102 
105 template <typename RealType>
107 {
108  VSMC_DEFINE_RNG_DISTRIBUTION_2(Gamma, gamma, alpha, 1, beta, 1)
109 
110  public:
111  result_type min() const { return 0; }
112 
113  result_type max() const { return std::numeric_limits<result_type>::max(); }
114 
115  void reset() { constant_.reset(alpha(), beta()); }
116 
117  private:
119 
120  bool is_equal(const distribution_type &other) const
121  {
122  if (!is_equal(constant_.d, other.constant_.d))
123  return false;
124  if (!is_equal(constant_.c, other.constant_.c))
125  return false;
126  if (!is_equal(constant_.algorithm, other.constant_.algorithm))
127  return false;
128  return true;
129  }
130 
131  template <typename CharT, typename Traits>
132  void ostream(std::basic_ostream<CharT, Traits> &) const
133  {
134  }
135 
136  template <typename CharT, typename Traits>
137  void istream(std::basic_istream<CharT, Traits> &)
138  {
139  reset();
140  }
141 
142  template <typename RNGType>
143  result_type generate(RNGType &rng, const param_type &param)
144  {
145  if (param == param_)
146  return generate(rng, param_, constant_);
147 
149  param.alpha(), param.beta());
150 
151  return generate(rng, param, constant);
152  }
153 
154  template <typename RNGType>
155  result_type generate(RNGType &rng, const param_type &param,
157  {
158  result_type r = 0;
159  switch (constant.algorithm) {
161  r = generate_t(rng, param, constant);
162  break;
164  r = generate_w(rng, param, constant);
165  break;
167  r = generate_n(rng, param, constant);
168  break;
170  r = generate_e(rng, param, constant);
171  break;
172  }
173 
174  return param.beta() * r;
175  }
176 
177  template <typename RNGType>
178  result_type generate_t(RNGType &rng, const param_type &param,
180  {
182  while (true) {
183  result_type u = 1 - u01(rng);
184  result_type e = -std::log(u01(rng));
185  if (u > constant.d) {
186  u = -std::log(constant.c * (1 - u));
187  e += u;
188  u = constant.d + param.alpha() * u;
189  }
190  result_type r = std::exp(constant.c * std::log(u));
191  if (std::abs(r) < e)
192  return r;
193  }
194  }
195 
196  template <typename RNGType>
197  result_type generate_w(RNGType &rng, const param_type &,
199  {
201  result_type u = 0;
202  result_type e = 0;
203  result_type r = 0;
204  do {
205  u = -std::log(u01(rng));
206  e = -std::log(u01(rng));
207  r = std::exp(constant.c * std::log(u));
208  } while (u + e < constant.d + r);
209 
210  return r;
211  }
212 
213  template <typename RNGType>
214  result_type generate_n(RNGType &rng, const param_type &,
216  {
218  NormalDistribution<RealType> rnorm(0, 1);
219  while (true) {
220  result_type u = u01(rng);
221  result_type e = 0;
222  result_type v = 0;
223  result_type w = 0;
224  do {
225  w = rnorm(rng);
226  v = 1 + constant.c * w;
227  } while (v <= 0);
228  v = v * v * v;
229 
230  e = 1 - static_cast<result_type>(0.0331) * (w * w) * (w * w);
231  if (u < e)
232  return constant.d * v;
233 
234  e = w * w / 2 + constant.d * (1 - v + std::log(v));
235  if (std::log(u) < e)
236  return constant.d * v;
237  }
238  }
239 
240  template <typename RNGType>
241  result_type generate_e(RNGType &rng, const param_type &,
243  {
245 
246  return -std::log(u01(rng));
247  }
248 }; // class GammaDistribution
249 
250 namespace internal
251 {
252 
253 template <std::size_t K, typename RealType, typename RNGType>
254 inline std::size_t gamma_distribution_impl_t(RNGType &rng, std::size_t n,
255  RealType *r, RealType alpha, RealType beta,
256  const GammaDistributionConstant<RealType> &constant)
257 {
258  const RealType d = constant.d;
259  const RealType c = constant.c;
261  RealType *const u = s.data();
262  RealType *const e = s.data() + n;
263  RealType *const x = s.data() + n * 2;
264 
265  u01_oo_distribution(rng, n * 2, s.data());
266  log(n, e, e);
267  mul(n, static_cast<RealType>(-1), e, e);
268  for (std::size_t i = 0; i != n; ++i) {
269  if (u[i] > d) {
270  u[i] = -std::log(c * (1 - u[i]));
271  e[i] += u[i];
272  u[i] = d + alpha * u[i];
273  }
274  }
275  log(n, u, x);
276  mul(n, c, x, x);
277  exp(n, x, x);
278  abs(n, x, u);
279  mul(n, beta, x, x);
280 
281  std::size_t m = 0;
282  for (std::size_t i = 0; i != n; ++i)
283  if (u[i] < e[i])
284  r[m++] = x[i];
285 
286  return m;
287 }
288 
289 template <std::size_t K, typename RealType, typename RNGType>
290 inline std::size_t gamma_distribution_impl_w(RNGType &rng, std::size_t n,
291  RealType *r, RealType, RealType beta,
292  const GammaDistributionConstant<RealType> &constant)
293 {
294  const RealType d = constant.d;
295  const RealType c = constant.c;
297  RealType *const u = s.data();
298  RealType *const e = s.data() + n;
299  RealType *const x = s.data() + n * 2;
300 
301  u01_oo_distribution(rng, n * 2, s.data());
302  log(n * 2, s.data(), s.data());
303  mul(n * 2, static_cast<RealType>(-1), s.data(), s.data());
304  log(n, s.data(), x);
305  mul(n, c, x, x);
306  exp(n, x, x);
307  add(n, u, e, u);
308  add(n, d, x, e);
309  mul(n, beta, x, x);
310 
311  std::size_t m = 0;
312  for (std::size_t i = 0; i != n; ++i)
313  if (u[i] > e[i])
314  r[m++] = x[i];
315 
316  return m;
317 }
318 
319 template <std::size_t K, typename RealType, typename RNGType>
320 inline std::size_t gamma_distribution_impl_n(RNGType &rng, std::size_t n,
321  RealType *r, RealType, RealType beta,
322  const GammaDistributionConstant<RealType> &constant)
323 {
324  const RealType d = constant.d;
325  const RealType c = constant.c;
327  RealType *const u = s.data();
328  RealType *const e = s.data() + n;
329  RealType *const v = s.data() + n * 2;
330  RealType *const w = s.data() + n * 3;
331  RealType *const x = s.data() + n * 4;
332 
333  u01_oo_distribution(rng, n, u);
335  rng, n, w, static_cast<RealType>(0), static_cast<RealType>(1));
336  fma(n, c, w, static_cast<RealType>(1), v);
337  NormalDistribution<RealType> rnorm(0, 1);
338  for (std::size_t i = 0; i != n; ++i) {
339  if (v[i] <= 0) {
340  do {
341  w[i] = rnorm(rng);
342  v[i] = 1 + c * w[i];
343  } while (v[i] <= 0);
344  }
345  }
346  sqr(n, v, e);
347  mul(n, v, e, v);
348  sqr(n, w, e);
349  sqr(n, e, e);
350  fma(n, -static_cast<RealType>(0.0331), e, static_cast<RealType>(1), e);
351  mul(n, d * beta, v, x);
352 
353  std::size_t m = 0;
354  for (std::size_t i = 0; i != n; ++i) {
355  if (u[i] < e[i]) {
356  r[m++] = x[i];
357  } else {
358  e[i] = w[i] * w[i] / 2 + d * (1 - v[i] + std::log(v[i]));
359  if (std::log(u[i]) < e[i])
360  r[m++] = x[i];
361  }
362  }
363 
364  return m;
365 }
366 
367 template <std::size_t, typename RealType, typename RNGType>
368 inline std::size_t gamma_distribution_impl_e(RNGType &rng, std::size_t n,
369  RealType *r, RealType, RealType beta,
371 {
372  u01_oo_distribution(rng, n, r);
373  log(n, r, r);
374  mul(n, -beta, r, r);
375 
376  return n;
377 }
378 
379 template <std::size_t K, typename RealType, typename RNGType>
380 inline std::size_t gamma_distribution_impl(RNGType &rng, std::size_t n,
381  RealType *r, RealType alpha, RealType beta,
382  const GammaDistributionConstant<RealType> &constant)
383 {
384  switch (constant.algorithm) {
386  return gamma_distribution_impl_t<K>(
387  rng, n, r, alpha, beta, constant);
389  return gamma_distribution_impl_w<K>(
390  rng, n, r, alpha, beta, constant);
392  return gamma_distribution_impl_n<K>(
393  rng, n, r, alpha, beta, constant);
395  return gamma_distribution_impl_e<K>(
396  rng, n, r, alpha, beta, constant);
397  }
398  return 0;
399 }
400 
401 } // namespace vsmc::internal
402 
405 template <typename RealType, typename RNGType>
406 inline void gamma_distribution(
407  RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta)
408 {
409  static_assert(std::is_floating_point<RealType>::value,
410  "**gamma_distribution** USED WITH RealType OTHER THAN FLOATING POINT "
411  "TYPES");
412 
413  const std::size_t k = internal::BufferSize<RealType>::value;
414  const internal::GammaDistributionConstant<RealType> constant(alpha);
415  while (n > k) {
416  std::size_t m = internal::gamma_distribution_impl<k>(
417  rng, k, r, alpha, beta, constant);
418  if (m == 0)
419  break;
420  n -= m;
421  r += m;
422  }
423  std::size_t m =
424  internal::gamma_distribution_impl<k>(rng, n, r, alpha, beta, constant);
425  n -= m;
426  r += m;
427  if (n > 0) {
428  GammaDistribution<RealType> dist(alpha, beta);
429  for (std::size_t i = 0; i != n; ++i)
430  r[i] = dist(rng);
431  }
432 }
433 
434 VSMC_DEFINE_RNG_DISTRIBUTION_RAND_2(Gamma, gamma, alpha, beta)
435 
436 } // namespace vsmc
437 
438 #endif // VSMC_RNG_GAMMA_DISTRIBUTION_HPP
Definition: monitor.hpp:48
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 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 gamma_distribution_impl_n(RNGType &rng, std::size_t n, RealType *r, RealType, RealType beta, const GammaDistributionConstant< RealType > &constant)
void u01_oo_distribution(RNGType &rng, std::size_t n, RealType *r)
Generate standard uniform random variates on (0, 1)
GammaDistributionConstant(RealType alpha=1, RealType beta=1)
result_type max() const
Standard uniform distribution on (0, 1)
void normal_distribution(RNGType &, std::size_t, RealType *, RealType, RealType)
Generating Normal random variates.
std::size_t gamma_distribution_impl_t(RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta, const GammaDistributionConstant< RealType > &constant)
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
bool gamma_distribution_check_param(RealType alpha, RealType beta)
GammaDistribution< RealType > distribution_type
void exp(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:115
std::size_t gamma_distribution_impl(RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta, const GammaDistributionConstant< RealType > &constant)
std::size_t gamma_distribution_impl_e(RNGType &rng, std::size_t n, RealType *r, RealType, RealType beta, const GammaDistributionConstant< RealType > &)
std::size_t gamma_distribution_impl_w(RNGType &rng, std::size_t n, RealType *r, RealType, RealType beta, const GammaDistributionConstant< RealType > &constant)
void fma(std::size_t n, const T *a, const T *b, const T *c, T *y)
For , compute .
Definition: vmath.hpp:361
std::basic_istream< CharT, Traits > & istream(std::basic_istream< CharT, Traits > &is, std::array< T, N > &ary)
Definition: basic.hpp:243
void add(std::size_t n, const float *a, const float *b, float *y)
Definition: vmath.hpp:74
#define VSMC_DEFINE_RNG_DISTRIBUTION_RAND_2(Name, name, p1, p2)
std::array with proper alignment
void gamma_distribution(RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta)
Generating gamma random variates.
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
void abs(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:78