vSMC
vSMC: 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.6L))
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  template <typename RNGType>
121  result_type generate(RNGType &rng, const param_type &param)
122  {
123  if (param == param_)
124  return generate(rng, param_, constant_);
125 
127  param.alpha(), param.beta());
128 
129  return generate(rng, param, constant);
130  }
131 
132  template <typename RNGType>
133  result_type generate(RNGType &rng, const param_type &param,
135  {
136  result_type r = 0;
137  switch (constant.algorithm) {
139  r = generate_t(rng, param, constant);
140  break;
142  r = generate_w(rng, param, constant);
143  break;
145  r = generate_n(rng, param, constant);
146  break;
148  r = generate_e(rng, param, constant);
149  break;
150  }
151 
152  return param.beta() * r;
153  }
154 
155  template <typename RNGType>
156  result_type generate_t(RNGType &rng, const param_type &param,
158  {
160  while (true) {
161  result_type u = u01(rng);
162  result_type e = -std::log(u01(rng));
163  if (u > constant.d) {
164  u = -std::log(constant.c * (1 - u));
165  e += u;
166  u = constant.d + param.alpha() * u;
167  }
168  result_type r = std::exp(constant.c * std::log(u));
169  if (std::abs(r) < e)
170  return r;
171  }
172  }
173 
174  template <typename RNGType>
175  result_type generate_w(RNGType &rng, const param_type &,
177  {
179  result_type u = 0;
180  result_type e = 0;
181  result_type r = 0;
182  do {
183  u = -std::log(u01(rng));
184  e = -std::log(u01(rng));
185  r = std::exp(constant.c * std::log(u));
186  } while (u + e < constant.d + r);
187 
188  return r;
189  }
190 
191  template <typename RNGType>
192  result_type generate_n(RNGType &rng, const param_type &,
194  {
196  NormalDistribution<RealType> rnorm(0, 1);
197  while (true) {
198  result_type u = u01(rng);
199  result_type e = 0;
200  result_type v = 0;
201  result_type w = 0;
202  do {
203  w = rnorm(rng);
204  v = 1 + constant.c * w;
205  } while (v <= 0);
206  v = v * v * v;
207 
208  e = 1 - static_cast<result_type>(0.0331) * (w * w) * (w * w);
209  if (u < e)
210  return constant.d * v;
211 
212  e = w * w / 2 + constant.d * (1 - v + std::log(v));
213  if (std::log(u) < e)
214  return constant.d * v;
215  }
216  }
217 
218  template <typename RNGType>
219  result_type generate_e(RNGType &rng, const param_type &,
221  {
223 
224  return -std::log(u01(rng));
225  }
226 }; // class GammaDistribution
227 
228 namespace internal
229 {
230 
231 template <std::size_t K, typename RealType, typename RNGType>
232 inline std::size_t gamma_distribution_impl_t(RNGType &rng, std::size_t n,
233  RealType *r, RealType alpha, RealType beta,
234  const GammaDistributionConstant<RealType> &constant)
235 {
236  const RealType d = constant.d;
237  const RealType c = constant.c;
238  RealType s[K * 3];
239  RealType *const u = s;
240  RealType *const e = s + n;
241  RealType *const x = s + n * 2;
242 
243  u01_distribution(rng, n * 2, s);
244  log(n, e, e);
245  mul(n, static_cast<RealType>(-1), e, e);
246  for (std::size_t i = 0; i != n; ++i) {
247  if (u[i] > d) {
248  u[i] = -std::log(c * (1 - u[i]));
249  e[i] += u[i];
250  u[i] = d + alpha * u[i];
251  }
252  }
253  log(n, u, x);
254  mul(n, c, x, x);
255  exp(n, x, x);
256  abs(n, x, u);
257  mul(n, beta, x, x);
258 
259  std::size_t m = 0;
260  for (std::size_t i = 0; i != n; ++i)
261  if (u[i] < e[i])
262  r[m++] = x[i];
263 
264  return m;
265 }
266 
267 template <std::size_t K, typename RealType, typename RNGType>
268 inline std::size_t gamma_distribution_impl_w(RNGType &rng, std::size_t n,
269  RealType *r, RealType, RealType beta,
270  const GammaDistributionConstant<RealType> &constant)
271 {
272  const RealType d = constant.d;
273  const RealType c = constant.c;
274  RealType s[K * 3];
275  RealType *const u = s;
276  RealType *const e = s + n;
277  RealType *const x = s + n * 2;
278 
279  u01_distribution(rng, n * 2, s);
280  log(n * 2, s, s);
281  mul(n * 2, static_cast<RealType>(-1), s, s);
282  log(n, s, x);
283  mul(n, c, x, x);
284  exp(n, x, x);
285  add(n, u, e, u);
286  add(n, d, x, e);
287  mul(n, beta, x, x);
288 
289  std::size_t m = 0;
290  for (std::size_t i = 0; i != n; ++i)
291  if (u[i] > e[i])
292  r[m++] = x[i];
293 
294  return m;
295 }
296 
297 template <std::size_t K, typename RealType, typename RNGType>
298 inline std::size_t gamma_distribution_impl_n(RNGType &rng, std::size_t n,
299  RealType *r, RealType, RealType beta,
300  const GammaDistributionConstant<RealType> &constant)
301 {
302  const RealType d = constant.d;
303  const RealType c = constant.c;
304  RealType s[K * 5];
305  RealType *const u = s;
306  RealType *const e = s + n;
307  RealType *const v = s + n * 2;
308  RealType *const w = s + n * 3;
309  RealType *const x = s + n * 4;
310 
311  u01_distribution(rng, n, u);
313  rng, n, w, static_cast<RealType>(0), static_cast<RealType>(1));
314  fma(n, c, w, static_cast<RealType>(1), v);
315  NormalDistribution<RealType> rnorm(0, 1);
316  for (std::size_t i = 0; i != n; ++i) {
317  if (v[i] <= 0) {
318  do {
319  w[i] = rnorm(rng);
320  v[i] = 1 + c * w[i];
321  } while (v[i] <= 0);
322  }
323  }
324  sqr(n, v, e);
325  mul(n, v, e, v);
326  sqr(n, w, e);
327  sqr(n, e, e);
328  fma(n, -static_cast<RealType>(0.0331), e, static_cast<RealType>(1), e);
329  mul(n, d * beta, v, x);
330 
331  std::size_t m = 0;
332  for (std::size_t i = 0; i != n; ++i) {
333  if (u[i] < e[i]) {
334  r[m++] = x[i];
335  } else {
336  e[i] = w[i] * w[i] / 2 + d * (1 - v[i] + std::log(v[i]));
337  if (std::log(u[i]) < e[i])
338  r[m++] = x[i];
339  }
340  }
341 
342  return m;
343 }
344 
345 template <std::size_t, typename RealType, typename RNGType>
346 inline std::size_t gamma_distribution_impl_e(RNGType &rng, std::size_t n,
347  RealType *r, RealType, RealType beta,
349 {
350  u01_distribution(rng, n, r);
351  log(n, r, r);
352  mul(n, -beta, r, r);
353 
354  return n;
355 }
356 
357 template <std::size_t K, typename RealType, typename RNGType>
358 inline std::size_t gamma_distribution_impl(RNGType &rng, std::size_t n,
359  RealType *r, RealType alpha, RealType beta,
360  const GammaDistributionConstant<RealType> &constant)
361 {
362  switch (constant.algorithm) {
364  return gamma_distribution_impl_t<K>(
365  rng, n, r, alpha, beta, constant);
367  return gamma_distribution_impl_w<K>(
368  rng, n, r, alpha, beta, constant);
370  return gamma_distribution_impl_n<K>(
371  rng, n, r, alpha, beta, constant);
373  return gamma_distribution_impl_e<K>(
374  rng, n, r, alpha, beta, constant);
375  }
376  return 0;
377 }
378 
379 } // namespace vsmc::internal
380 
383 template <typename RealType, typename RNGType>
384 inline void gamma_distribution(
385  RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta)
386 {
387  static_assert(std::is_floating_point<RealType>::value,
388  "**gamma_distribution** USED WITH RealType OTHER THAN FLOATING POINT "
389  "TYPES");
390 
391  const std::size_t k = 1024;
392  const internal::GammaDistributionConstant<RealType> constant(alpha);
393  while (n > k) {
394  std::size_t m = internal::gamma_distribution_impl<k>(
395  rng, k, r, alpha, beta, constant);
396  if (m == 0)
397  break;
398  n -= m;
399  r += m;
400  }
401  std::size_t m =
402  internal::gamma_distribution_impl<k>(rng, n, r, alpha, beta, constant);
403  n -= m;
404  r += m;
405  if (n > 0) {
406  GammaDistribution<RealType> dist(alpha, beta);
407  for (std::size_t i = 0; i != n; ++i)
408  r[i] = dist(rng);
409  }
410 }
411 
412 VSMC_DEFINE_RNG_DISTRIBUTION_RAND_2(Gamma, gamma, alpha, beta)
413 
414 } // namespace vsmc
415 
416 #endif // VSMC_RNG_GAMMA_DISTRIBUTION_HPP
Definition: monitor.hpp:49
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 sqrt(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:129
std::size_t gamma_distribution_impl_n(RNGType &rng, std::size_t n, RealType *r, RealType, RealType beta, const GammaDistributionConstant< RealType > &constant)
GammaDistributionConstant(RealType alpha=1, RealType beta=1)
void u01_distribution(RNGType &, std::size_t, RealType *)
Generate standard uniform random variates.
result_type max() const
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:135
bool gamma_distribution_check_param(RealType alpha, RealType beta)
Normal distribution.
Definition: common.hpp:582
void exp(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:146
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:257
void add(std::size_t n, const float *a, const float *b, float *y)
Definition: vmath.hpp:109
Standard uniform distribution.
Definition: common.hpp:597
#define VSMC_DEFINE_RNG_DISTRIBUTION_RAND_2(Name, name, p1, p2)
Definition: common.hpp:409
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:148
void sqr(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:111
void abs(std::size_t n, const float *a, float *y)
Definition: vmath.hpp:113