MCKL
Monte Carlo Kernel Library
gamma_distribution.hpp
Go to the documentation of this file.
1 //============================================================================
2 // MCKL/include/mckl/random/gamma_distribution.hpp
3 //----------------------------------------------------------------------------
4 // MCKL: Monte Carlo Kernel Library
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2018, 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 MCKL_RANDOM_GAMMA_DISTRIBUTION_HPP
33 #define MCKL_RANDOM_GAMMA_DISTRIBUTION_HPP
34 
38 
39 namespace mckl {
40 
41 namespace internal {
42 
43 template <typename RealType>
44 inline bool gamma_distribution_check_param(RealType alpha, RealType beta)
45 {
46  return alpha > 0 && beta > 0;
47 }
48 
54 }; // enum GammaDistributionAlgorithm
55 
56 MCKL_PUSH_CLANG_WARNING("-Wpadded")
57 template <typename RealType>
59 {
60  public:
61  GammaDistributionConstant(RealType alpha = 1, RealType = 1)
62  {
63  if (alpha < static_cast<RealType>(0.6)) {
64  algorithm_ = GammaDistributionAlgorithmT;
65  } else if (alpha < 1) {
66  algorithm_ = GammaDistributionAlgorithmW;
67  } else if (alpha > 1) {
68  algorithm_ = GammaDistributionAlgorithmN;
69  } else {
70  algorithm_ = GammaDistributionAlgorithmE;
71  }
72 
73  d_ = c_ = 0;
74  switch (algorithm_) {
76  d_ = 1 - alpha;
77  c_ = 1 / alpha;
78  break;
80  d_ = std::pow(alpha, alpha / (1 - alpha)) * (1 - alpha);
81  c_ = 1 / alpha;
82  break;
84  d_ = alpha - const_one<RealType>() / 3;
85  c_ = 1 / (3 * std::sqrt(d_));
86  break;
88  break;
89  }
90  }
91 
92  RealType d() const { return d_; }
93  RealType c() const { return c_; }
94  GammaDistributionAlgorithm algorithm() const { return algorithm_; }
95 
98  {
99  MCKL_PUSH_CLANG_WARNING("-Wfloat-equal")
100  MCKL_PUSH_INTEL_WARNING(1572) // floating-point comparison
101  if (c1.d_ != c2.d_) {
102  return false;
103  }
104  if (c1.c_ != c2.c_) {
105  return false;
106  }
107  if (c1.algorithm_ != c2.algorithm_) {
108  return false;
109  }
110  return true;
113  }
114 
115  private:
116  RealType d_;
117  RealType c_;
118  GammaDistributionAlgorithm algorithm_;
119 }; // class GammaDistributionConstant
121 
122 template <std::size_t K, typename RealType, typename RNGType>
123 inline std::size_t gamma_distribution_impl_t(RNGType &rng, std::size_t n,
124  RealType *r, RealType alpha, RealType beta,
125  const GammaDistributionConstant<RealType> &constant)
126 {
127  alignas(MCKL_ALIGNMENT) std::array<RealType, K * 3> s;
128  const RealType d = constant.d();
129  const RealType c = constant.c();
130  RealType *const u = s.data();
131  RealType *const e = s.data() + n;
132  RealType *const x = s.data() + n * 2;
133 
134  u01_oo_distribution(rng, n * 2, s.data());
135  log(n, e, e);
136  mul(n, static_cast<RealType>(-1), e, e);
137  for (std::size_t i = 0; i != n; ++i) {
138  if (u[i] > d) {
139  u[i] = -std::log(c * (1 - u[i]));
140  e[i] += u[i];
141  u[i] = d + alpha * u[i];
142  }
143  }
144  log(n, u, x);
145  mul(n, c, x, x);
146  exp(n, x, x);
147  abs(n, x, u);
148  mul(n, beta, x, x);
149 
150  std::size_t m = 0;
151  for (std::size_t i = 0; i != n; ++i) {
152  if (u[i] < e[i]) {
153  r[m++] = x[i];
154  }
155  }
156 
157  return m;
158 }
159 
160 template <std::size_t K, typename RealType, typename RNGType>
161 inline std::size_t gamma_distribution_impl_w(RNGType &rng, std::size_t n,
162  RealType *r, RealType, RealType beta,
163  const GammaDistributionConstant<RealType> &constant)
164 {
165  alignas(MCKL_ALIGNMENT) std::array<RealType, K * 3> s;
166  const RealType d = constant.d();
167  const RealType c = constant.c();
168  RealType *const u = s.data();
169  RealType *const e = s.data() + n;
170  RealType *const x = s.data() + n * 2;
171 
172  u01_oo_distribution(rng, n * 2, s.data());
173  log(n * 2, s.data(), s.data());
174  mul(n * 2, static_cast<RealType>(-1), s.data(), s.data());
175  log(n, s.data(), x);
176  mul(n, c, x, x);
177  exp(n, x, x);
178  add(n, u, e, u);
179  add(n, d, x, e);
180  mul(n, beta, x, x);
181 
182  std::size_t m = 0;
183  for (std::size_t i = 0; i != n; ++i) {
184  if (u[i] > e[i]) {
185  r[m++] = x[i];
186  }
187  }
188 
189  return m;
190 }
191 
192 template <std::size_t K, typename RealType, typename RNGType>
193 inline std::size_t gamma_distribution_impl_n(RNGType &rng, std::size_t n,
194  RealType *r, RealType, RealType beta,
195  const GammaDistributionConstant<RealType> &constant)
196 {
197  alignas(MCKL_ALIGNMENT) std::array<RealType, K * 5> s;
198  const RealType d = constant.d();
199  const RealType c = constant.c();
200  RealType *const u = s.data();
201  RealType *const e = s.data() + n;
202  RealType *const v = s.data() + n * 2;
203  RealType *const w = s.data() + n * 3;
204  RealType *const x = s.data() + n * 4;
205 
206  u01_oo_distribution(rng, n, u);
208  rng, n, w, const_zero<RealType>(), const_one<RealType>());
209  muladd(n, c, w, const_one<RealType>(), v);
210  NormalDistribution<RealType> rnorm(0, 1);
211  for (std::size_t i = 0; i != n; ++i) {
212  if (v[i] <= 0) {
213  do {
214  w[i] = rnorm(rng);
215  v[i] = 1 + c * w[i];
216  } while (v[i] <= 0);
217  }
218  }
219  sqr(n, v, e);
220  mul(n, v, e, v);
221  sqr(n, w, e);
222  sqr(n, e, e);
223  muladd(n, -static_cast<RealType>(0.0331), e, const_one<RealType>(), e);
224  mul(n, d * beta, v, x);
225 
226  std::size_t m = 0;
227  for (std::size_t i = 0; i != n; ++i) {
228  if (u[i] < e[i]) {
229  r[m++] = x[i];
230  } else {
231  e[i] = w[i] * w[i] / 2 + d * (1 - v[i] + std::log(v[i]));
232  if (std::log(u[i]) < e[i]) {
233  r[m++] = x[i];
234  }
235  }
236  }
237 
238  return m;
239 }
240 
241 template <std::size_t, typename RealType, typename RNGType>
242 inline std::size_t gamma_distribution_impl_e(RNGType &rng, std::size_t n,
243  RealType *r, RealType, RealType beta,
245 {
246  u01_oo_distribution(rng, n, r);
247  log(n, r, r);
248  mul(n, -beta, r, r);
249 
250  return n;
251 }
252 
253 template <std::size_t K, typename RealType, typename RNGType>
254 inline std::size_t gamma_distribution_impl(RNGType &rng, std::size_t n,
255  RealType *r, RealType alpha, RealType beta,
256  const GammaDistributionConstant<RealType> &constant)
257 {
258  switch (constant.algorithm()) {
260  return gamma_distribution_impl_t<K>(
261  rng, n, r, alpha, beta, constant);
263  return gamma_distribution_impl_w<K>(
264  rng, n, r, alpha, beta, constant);
266  return gamma_distribution_impl_n<K>(
267  rng, n, r, alpha, beta, constant);
269  return gamma_distribution_impl_e<K>(
270  rng, n, r, alpha, beta, constant);
271  }
272  return 0;
273 }
274 
275 } // namespace internal
276 
277 template <typename RealType, typename RNGType>
278 inline void gamma_distribution(
279  RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta)
280 {
281  const std::size_t k = BufferSize<RealType>::value;
282  const internal::GammaDistributionConstant<RealType> constant(alpha, beta);
283  while (n > k) {
284  std::size_t m = internal::gamma_distribution_impl<k>(
285  rng, k, r, alpha, beta, constant);
286  if (m == 0) {
287  break;
288  }
289  n -= m;
290  r += m;
291  }
292  std::size_t m =
293  internal::gamma_distribution_impl<k>(rng, n, r, alpha, beta, constant);
294  n -= m;
295  r += m;
296  if (n > 0) {
297  GammaDistribution<RealType> dist(alpha, beta);
298  for (std::size_t i = 0; i != n; ++i) {
299  r[i] = dist(rng);
300  }
301  }
302 }
303 
304 template <typename RealType, typename RNGType>
305 inline void gamma_distribution(RNGType &rng, std::size_t n, RealType *r,
306  const typename GammaDistribution<RealType>::param_type &param)
307 {
308  gamma_distribution(rng, n, r, param.alpha(), param.beta());
309 }
310 
313 template <typename RealType>
315 {
318  Gamma, gamma, RealType, result_type, alpha, 1, result_type, beta, 1)
319 
320  public:
321  result_type min() const { return 0; }
322 
323  result_type max() const { return std::numeric_limits<result_type>::max(); }
324 
325  void reset()
326  {
327  constant_ =
329  }
330 
331  private:
333 
334  bool is_equal(const distribution_type &other) const
335  {
336  return constant_ == other.constant_;
337  }
338 
339  template <typename CharT, typename Traits>
340  void ostream(std::basic_ostream<CharT, Traits> &) const
341  {
342  }
343 
344  template <typename CharT, typename Traits>
345  void istream(std::basic_istream<CharT, Traits> &)
346  {
347  reset();
348  }
349 
350  template <typename RNGType>
351  result_type generate(RNGType &rng, const param_type &param)
352  {
353  if (param == param_) {
354  return generate(rng, param_, constant_);
355  }
356 
358  param.alpha(), param.beta());
359 
360  return generate(rng, param, constant);
361  }
362 
363  template <typename RNGType>
364  result_type generate(RNGType &rng, const param_type &param,
366  {
367  result_type r = 0;
368  switch (constant.algorithm()) {
370  r = generate_t(rng, param, constant);
371  break;
373  r = generate_w(rng, param, constant);
374  break;
376  r = generate_n(rng, param, constant);
377  break;
379  r = generate_e(rng, param, constant);
380  break;
381  }
382 
383  return param.beta() * r;
384  }
385 
386  template <typename RNGType>
387  result_type generate_t(RNGType &rng, const param_type &param,
389  {
391  while (true) {
392  result_type u = 1 - u01(rng);
393  result_type e = -std::log(u01(rng));
394  if (u > constant.d()) {
395  u = -std::log(constant.c() * (1 - u));
396  e += u;
397  u = constant.d() + param.alpha() * u;
398  }
399  result_type r = std::exp(constant.c() * std::log(u));
400  if (std::abs(r) < e) {
401  return r;
402  }
403  }
404  }
405 
406  template <typename RNGType>
407  result_type generate_w(RNGType &rng, const param_type &,
409  {
411  result_type u = 0;
412  result_type e = 0;
413  result_type r = 0;
414  do {
415  u = -std::log(u01(rng));
416  e = -std::log(u01(rng));
417  r = std::exp(constant.c() * std::log(u));
418  } while (u + e < constant.d() + r);
419 
420  return r;
421  }
422 
423  template <typename RNGType>
424  result_type generate_n(RNGType &rng, const param_type &,
426  {
428  NormalDistribution<RealType> rnorm(0, 1);
429  while (true) {
430  result_type u = u01(rng);
431  result_type e = 0;
432  result_type v = 0;
433  result_type w = 0;
434  do {
435  w = rnorm(rng);
436  v = 1 + constant.c() * w;
437  } while (v <= 0);
438  v = v * v * v;
439 
440  e = 1 - static_cast<result_type>(0.0331) * (w * w) * (w * w);
441  if (u < e) {
442  return constant.d() * v;
443  }
444 
445  e = w * w / 2 + constant.d() * (1 - v + std::log(v));
446  if (std::log(u) < e) {
447  return constant.d() * v;
448  }
449  }
450  }
451 
452  template <typename RNGType>
453  result_type generate_e(RNGType &rng, const param_type &,
455  {
457 
458  return -std::log(u01(rng));
459  }
460 }; // class GammaDistribution
461 
463 
464 } // namespace mckl
465 
466 #endif // MCKL_RANDOM_GAMMA_DISTRIBUTION_HPP
#define MCKL_DEFINE_RANDOM_DISTRIBUTION_2( Name, name, T, T1, p1, v1, T2, p2, v2)
void pow(std::size_t n, const float *a, const float *b, float *y)
Definition: vmf.hpp:184
void mul(std::size_t n, const float *a, const float *b, float *y)
Definition: vmf.hpp:124
void normal_distribution(MKLEngine< BRNG, Bits > &rng, std::size_t n, float *r, float mean, float stddev)
Definition: mkl.hpp:1386
GammaDistributionAlgorithm algorithm() const
#define MCKL_PUSH_CLANG_WARNING(warning)
Definition: compiler.h:63
GammaDistribution< RealType > distribution_type
void log(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:226
void u01_oo_distribution(RNGType &rng, std::size_t n, RealType *r)
void gamma_distribution(RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta)
T muladd(T a, T b, T c)
Definition: vmf.hpp:673
std::size_t gamma_distribution_impl_t(RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta, const GammaDistributionConstant< RealType > &constant)
#define MCKL_DEFINE_RANDOM_DISTRIBUTION_RAND(Name, T)
RealType u01(UIntType u)
Convert uniform unsigned integers to floating points within [0, 1].
Definition: u01.hpp:88
void abs(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:128
std::basic_ostream< CharT, Traits > & ostream(std::basic_ostream< CharT, Traits > &os, const std::array< T, N > &ary)
Definition: iostream.hpp:46
std::size_t gamma_distribution_impl_n(RNGType &rng, std::size_t n, RealType *r, RealType, RealType beta, const GammaDistributionConstant< RealType > &constant)
Standard uniform distribution on (0, 1)
void sqr(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:123
#define MCKL_PUSH_INTEL_WARNING(wid)
Definition: compiler.h:88
GammaDistributionConstant(RealType alpha=1, RealType=1)
void sqrt(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:177
Definition: mcmc.hpp:40
void exp(std::size_t n, const float *a, float *y)
Definition: vmf.hpp:221
bool gamma_distribution_check_param(RealType alpha, RealType beta)
#define MCKL_POP_CLANG_WARNING
Definition: compiler.h:66
#define MCKL_ALIGNMENT
The default alignment for scalar type.
Definition: config.h:187
bool is_equal(const float &v1, const float &v2)
Definition: is_equal.hpp:41
#define MCKL_DEFINE_RANDOM_DISTRIBUTION_ASSERT_REAL_TYPE(Name)
std::size_t gamma_distribution_impl_w(RNGType &rng, std::size_t n, RealType *r, RealType, RealType beta, const GammaDistributionConstant< RealType > &constant)
std::basic_istream< CharT, Traits > & istream(std::basic_istream< CharT, Traits > &is, std::array< T, N > &ary)
Definition: iostream.hpp:66
std::size_t gamma_distribution_impl_e(RNGType &rng, std::size_t n, RealType *r, RealType, RealType beta, const GammaDistributionConstant< RealType > &)
friend bool operator==(const GammaDistributionConstant< RealType > &c1, const GammaDistributionConstant< RealType > &c2)
std::size_t gamma_distribution_impl(RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta, const GammaDistributionConstant< RealType > &constant)
#define MCKL_POP_INTEL_WARNING
Definition: compiler.h:89
void add(std::size_t n, const float *a, const float *b, float *y)
Definition: vmf.hpp:119