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-2015, 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 < 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 {
109  Gamma, gamma, RealType, result_type, alpha, 1, result_type, beta, 1)
111 
112  public:
113  result_type min VSMC_MNE() const { return 0; }
114 
115  result_type max VSMC_MNE() const
116  {
117  return std::numeric_limits<result_type>::max VSMC_MNE();
118  }
119 
120  void reset() { constant_.reset(alpha(), beta()); }
121 
122  private:
124 
125  template <typename RNGType>
126  result_type generate(RNGType &rng, const param_type &param)
127  {
128  if (param == param_)
129  return generate(rng, param_, constant_);
130 
132  param.alpha(), param.beta());
133 
134  return generate(rng, param, constant);
135  }
136 
137  template <typename RNGType>
138  result_type generate(RNGType &rng, const param_type &param,
140  {
141  result_type r = 0;
142  switch (constant.algorithm) {
144  r = generate_t(rng, param, constant);
145  break;
147  r = generate_w(rng, param, constant);
148  break;
150  r = generate_n(rng, param, constant);
151  break;
153  r = generate_e(rng, param, constant);
154  break;
155  }
156 
157  return param.beta() * r;
158  }
159 
160  template <typename RNGType>
161  result_type generate_t(RNGType &rng, const param_type &param,
163  {
165  while (true) {
166  result_type u = runif(rng);
167  result_type e = -std::log(runif(rng));
168  if (u > constant.d) {
169  u = -std::log(constant.c * (1 - u));
170  e += u;
171  u = constant.d + param.alpha() * u;
172  }
173  result_type r = std::exp(constant.c * std::log(u));
174  if (std::abs(r) < e)
175  return r;
176  }
177  }
178 
179  template <typename RNGType>
180  result_type generate_w(RNGType &rng, const param_type &,
182  {
184  result_type u = 0;
185  result_type e = 0;
186  result_type r = 0;
187  do {
188  u = -std::log(runif(rng));
189  e = -std::log(runif(rng));
190  r = std::exp(constant.c * std::log(u));
191  } while (u + e < constant.d + r);
192 
193  return r;
194  }
195 
196  template <typename RNGType>
197  result_type generate_n(RNGType &rng, const param_type &,
199  {
201  NormalDistribution<RealType> rnorm(0, 1);
202  while (true) {
203  result_type u = runif(rng);
204  result_type e = 0;
205  result_type v = 0;
206  result_type w = 0;
207  do {
208  w = rnorm(rng);
209  v = 1 + constant.c * w;
210  } while (v <= 0);
211  v = v * v * v;
212 
213  e = 1 - static_cast<result_type>(0.0331) * (w * w) * (w * w);
214  if (u < e)
215  return constant.d * v;
216 
217  e = w * w / 2 + constant.d * (1 - v + std::log(v));
218  if (std::log(u) < e)
219  return constant.d * v;
220  }
221  }
222 
223  template <typename RNGType>
224  result_type generate_e(RNGType &rng, const param_type &,
226  {
228 
229  return -std::log(runif(rng));
230  }
231 }; // class GammaDistribution
232 
233 namespace internal
234 {
235 
236 template <std::size_t K, typename RealType, typename RNGType>
237 inline std::size_t gamma_distribution_impl_t(RNGType &rng, std::size_t n,
238  RealType *r, RealType alpha, RealType beta,
239  const GammaDistributionConstant<RealType> &constant)
240 {
241  const RealType d = constant.d;
242  const RealType c = constant.c;
243  RealType s[K * 3];
244  RealType *const u = s;
245  RealType *const e = s + n;
246  RealType *const x = s + n * 2;
247 
248  u01_co_distribution(rng, n * 2, s);
249  log(n, e, e);
250  mul(n, static_cast<RealType>(-1), e, e);
251  for (std::size_t i = 0; i != n; ++i) {
252  if (u[i] > d) {
253  u[i] = -std::log(c * (1 - u[i]));
254  e[i] += u[i];
255  u[i] = d + alpha * u[i];
256  }
257  }
258  log(n, u, x);
259  mul(n, c, x, x);
260  exp(n, x, x);
261  abs(n, x, u);
262  mul(n, beta, x, x);
263 
264  std::size_t m = 0;
265  for (std::size_t i = 0; i != n; ++i)
266  if (u[i] < e[i])
267  r[m++] = x[i];
268 
269  return m;
270 }
271 
272 template <std::size_t K, typename RealType, typename RNGType>
273 inline std::size_t gamma_distribution_impl_w(RNGType &rng, std::size_t n,
274  RealType *r, RealType, RealType beta,
275  const GammaDistributionConstant<RealType> &constant)
276 {
277  const RealType d = constant.d;
278  const RealType c = constant.c;
279  RealType s[K * 3];
280  RealType *const u = s;
281  RealType *const e = s + n;
282  RealType *const x = s + n * 2;
283 
284  u01_co_distribution(rng, n * 2, s);
285  log(n * 2, s, s);
286  mul(n * 2, static_cast<RealType>(-1), s, s);
287  log(n, s, x);
288  mul(n, c, x, x);
289  exp(n, x, x);
290  add(n, u, e, u);
291  add(n, d, x, e);
292  mul(n, beta, x, x);
293 
294  std::size_t m = 0;
295  for (std::size_t i = 0; i != n; ++i)
296  if (u[i] > e[i])
297  r[m++] = x[i];
298 
299  return m;
300 }
301 
302 template <std::size_t K, typename RealType, typename RNGType>
303 inline std::size_t gamma_distribution_impl_n(RNGType &rng, std::size_t n,
304  RealType *r, RealType, RealType beta,
305  const GammaDistributionConstant<RealType> &constant)
306 {
307  const RealType d = constant.d;
308  const RealType c = constant.c;
309  RealType s[K * 5];
310  RealType *const u = s;
311  RealType *const e = s + n;
312  RealType *const v = s + n * 2;
313  RealType *const w = s + n * 3;
314  RealType *const x = s + n * 4;
315 
316  u01_co_distribution(rng, n, u);
318  rng, n, w, static_cast<RealType>(0), static_cast<RealType>(1));
319  fma(n, c, w, static_cast<RealType>(1), v);
320  NormalDistribution<RealType> rnorm(0, 1);
321  for (std::size_t i = 0; i != n; ++i) {
322  if (v[i] <= 0) {
323  do {
324  w[i] = rnorm(rng);
325  v[i] = 1 + c * w[i];
326  } while (v[i] <= 0);
327  }
328  }
329  sqr(n, v, e);
330  mul(n, v, e, v);
331  sqr(n, w, e);
332  sqr(n, e, e);
333  fma(n, -static_cast<RealType>(0.0331), e, static_cast<RealType>(1), e);
334  mul(n, d * beta, v, x);
335 
336  std::size_t m = 0;
337  for (std::size_t i = 0; i != n; ++i) {
338  if (u[i] < e[i]) {
339  r[m++] = x[i];
340  } else {
341  e[i] = w[i] * w[i] / 2 + d * (1 - v[i] + std::log(v[i]));
342  if (std::log(u[i]) < e[i])
343  r[m++] = x[i];
344  }
345  }
346 
347  return m;
348 }
349 
350 template <std::size_t, typename RealType, typename RNGType>
351 inline std::size_t gamma_distribution_impl_e(RNGType &rng, std::size_t n,
352  RealType *r, RealType, RealType beta,
354 {
355  u01_co_distribution(rng, n, r);
356  log(n, r, r);
357  mul(n, -beta, r, r);
358 
359  return n;
360 }
361 
362 template <std::size_t K, typename RealType, typename RNGType>
363 inline std::size_t gamma_distribution_impl(RNGType &rng, std::size_t n,
364  RealType *r, RealType alpha, RealType beta,
365  const GammaDistributionConstant<RealType> &constant)
366 {
367  switch (constant.algorithm) {
369  return gamma_distribution_impl_t<K>(
370  rng, n, r, alpha, beta, constant);
372  return gamma_distribution_impl_w<K>(
373  rng, n, r, alpha, beta, constant);
375  return gamma_distribution_impl_n<K>(
376  rng, n, r, alpha, beta, constant);
378  return gamma_distribution_impl_e<K>(
379  rng, n, r, alpha, beta, constant);
380  }
381  return 0;
382 }
383 
384 } // namespace vsmc::internal
385 
388 template <typename RealType, typename RNGType>
389 inline void gamma_distribution(
390  RNGType &rng, std::size_t n, RealType *r, RealType alpha, RealType beta)
391 {
392  const std::size_t k = 1000;
393  const internal::GammaDistributionConstant<RealType> constant(alpha);
394  while (n > k) {
395  std::size_t m = internal::gamma_distribution_impl<k>(
396  rng, k, r, alpha, beta, constant);
397  if (m == 0)
398  break;
399  n -= m;
400  r += m;
401  }
402  std::size_t m =
403  internal::gamma_distribution_impl<k>(rng, n, r, alpha, beta, constant);
404  n -= m;
405  r += m;
406  if (n > 0) {
407  GammaDistribution<RealType> dist(alpha, beta);
408  for (std::size_t i = 0; i != n; ++i)
409  r[i] = dist(rng);
410  }
411 }
412 
413 template <typename RealType, typename RNGType>
414 inline void rng_rand(RNGType &rng, GammaDistribution<RealType> &dist,
415  std::size_t n, RealType *r)
416 {
417  dist(rng, n, r);
418 }
419 
420 } // namespace vsmc
421 
422 #endif // VSMC_RNG_GAMMA_DISTRIBUTION_HPP
Definition: monitor.hpp:49
Standard uniform distribution with open/closed variants.
Definition: common.hpp:512
void mul(std::size_t n, const float *a, const float *b, float *y)
Definition: vmath.hpp:112
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 rng_rand(RNGType &rng, BernoulliDistribution< IntType > &dist, std::size_t n, IntType *r)
#define VSMC_DEFINE_RNG_DISTRIBUTION_OPERATORS
Definition: common.hpp:286
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
#define VSMC_DEFINE_RNG_DISTRIBUTION_2(Name, name, T, T1, p1, v1, T2, p2, v2)
Definition: common.hpp:159
bool gamma_distribution_check_param(RealType alpha, RealType beta)
#define VSMC_MNE
Definition: defines.hpp:38
Normal distribution.
Definition: common.hpp:500
void u01_co_distribution(RNGType &rng, std::size_t n, RealType *r)
Generate standard uniform random variates on closed-open interval.
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
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