gamma_distribution.hpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /* boost random/gamma_distribution.hpp header file
  2. *
  3. * Copyright Jens Maurer 2002
  4. * Copyright Steven Watanabe 2010
  5. * Distributed under the Boost Software License, Version 1.0. (See
  6. * accompanying file LICENSE_1_0.txt or copy at
  7. * http://www.boost.org/LICENSE_1_0.txt)
  8. *
  9. * See http://www.boost.org for most recent version including documentation.
  10. *
  11. * $Id$
  12. *
  13. */
  14. #ifndef BOOST_RANDOM_GAMMA_DISTRIBUTION_HPP
  15. #define BOOST_RANDOM_GAMMA_DISTRIBUTION_HPP
  16. #include <boost/config/no_tr1/cmath.hpp>
  17. #include <istream>
  18. #include <iosfwd>
  19. #include <boost/assert.hpp>
  20. #include <boost/limits.hpp>
  21. #include <boost/static_assert.hpp>
  22. #include <boost/random/detail/config.hpp>
  23. #include <boost/random/exponential_distribution.hpp>
  24. namespace boost {
  25. namespace random {
  26. // The algorithm is taken from Knuth
  27. /**
  28. * The gamma distribution is a continuous distribution with two
  29. * parameters alpha and beta. It produces values > 0.
  30. *
  31. * It has
  32. * \f$\displaystyle p(x) = x^{\alpha-1}\frac{e^{-x/\beta}}{\beta^\alpha\Gamma(\alpha)}\f$.
  33. */
  34. template<class RealType = double>
  35. class gamma_distribution
  36. {
  37. public:
  38. typedef RealType input_type;
  39. typedef RealType result_type;
  40. class param_type
  41. {
  42. public:
  43. typedef gamma_distribution distribution_type;
  44. /**
  45. * Constructs a @c param_type object from the "alpha" and "beta"
  46. * parameters.
  47. *
  48. * Requires: alpha > 0 && beta > 0
  49. */
  50. param_type(const RealType& alpha_arg = RealType(1.0),
  51. const RealType& beta_arg = RealType(1.0))
  52. : _alpha(alpha_arg), _beta(beta_arg)
  53. {
  54. }
  55. /** Returns the "alpha" parameter of the distribution. */
  56. RealType alpha() const { return _alpha; }
  57. /** Returns the "beta" parameter of the distribution. */
  58. RealType beta() const { return _beta; }
  59. #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS
  60. /** Writes the parameters to a @c std::ostream. */
  61. template<class CharT, class Traits>
  62. friend std::basic_ostream<CharT, Traits>&
  63. operator<<(std::basic_ostream<CharT, Traits>& os,
  64. const param_type& parm)
  65. {
  66. os << parm._alpha << ' ' << parm._beta;
  67. return os;
  68. }
  69. /** Reads the parameters from a @c std::istream. */
  70. template<class CharT, class Traits>
  71. friend std::basic_istream<CharT, Traits>&
  72. operator>>(std::basic_istream<CharT, Traits>& is, param_type& parm)
  73. {
  74. is >> parm._alpha >> std::ws >> parm._beta;
  75. return is;
  76. }
  77. #endif
  78. /** Returns true if the two sets of parameters are the same. */
  79. friend bool operator==(const param_type& lhs, const param_type& rhs)
  80. {
  81. return lhs._alpha == rhs._alpha && lhs._beta == rhs._beta;
  82. }
  83. /** Returns true if the two sets fo parameters are different. */
  84. friend bool operator!=(const param_type& lhs, const param_type& rhs)
  85. {
  86. return !(lhs == rhs);
  87. }
  88. private:
  89. RealType _alpha;
  90. RealType _beta;
  91. };
  92. #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
  93. BOOST_STATIC_ASSERT(!std::numeric_limits<RealType>::is_integer);
  94. #endif
  95. /**
  96. * Creates a new gamma_distribution with parameters "alpha" and "beta".
  97. *
  98. * Requires: alpha > 0 && beta > 0
  99. */
  100. explicit gamma_distribution(const result_type& alpha_arg = result_type(1.0),
  101. const result_type& beta_arg = result_type(1.0))
  102. : _exp(result_type(1)), _alpha(alpha_arg), _beta(beta_arg)
  103. {
  104. BOOST_ASSERT(_alpha > result_type(0));
  105. BOOST_ASSERT(_beta > result_type(0));
  106. init();
  107. }
  108. /** Constructs a @c gamma_distribution from its parameters. */
  109. explicit gamma_distribution(const param_type& parm)
  110. : _exp(result_type(1)), _alpha(parm.alpha()), _beta(parm.beta())
  111. {
  112. init();
  113. }
  114. // compiler-generated copy ctor and assignment operator are fine
  115. /** Returns the "alpha" paramter of the distribution. */
  116. RealType alpha() const { return _alpha; }
  117. /** Returns the "beta" parameter of the distribution. */
  118. RealType beta() const { return _beta; }
  119. /** Returns the smallest value that the distribution can produce. */
  120. RealType min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; }
  121. /* Returns the largest value that the distribution can produce. */
  122. RealType max BOOST_PREVENT_MACRO_SUBSTITUTION () const
  123. { return (std::numeric_limits<RealType>::infinity)(); }
  124. /** Returns the parameters of the distribution. */
  125. param_type param() const { return param_type(_alpha, _beta); }
  126. /** Sets the parameters of the distribution. */
  127. void param(const param_type& parm)
  128. {
  129. _alpha = parm.alpha();
  130. _beta = parm.beta();
  131. init();
  132. }
  133. /**
  134. * Effects: Subsequent uses of the distribution do not depend
  135. * on values produced by any engine prior to invoking reset.
  136. */
  137. void reset() { _exp.reset(); }
  138. /**
  139. * Returns a random variate distributed according to
  140. * the gamma distribution.
  141. */
  142. template<class Engine>
  143. result_type operator()(Engine& eng)
  144. {
  145. #ifndef BOOST_NO_STDC_NAMESPACE
  146. // allow for Koenig lookup
  147. using std::tan; using std::sqrt; using std::exp; using std::log;
  148. using std::pow;
  149. #endif
  150. if(_alpha == result_type(1)) {
  151. return _exp(eng) * _beta;
  152. } else if(_alpha > result_type(1)) {
  153. // Can we have a boost::mathconst please?
  154. const result_type pi = result_type(3.14159265358979323846);
  155. for(;;) {
  156. result_type y = tan(pi * uniform_01<RealType>()(eng));
  157. result_type x = sqrt(result_type(2)*_alpha-result_type(1))*y
  158. + _alpha-result_type(1);
  159. if(x <= result_type(0))
  160. continue;
  161. if(uniform_01<RealType>()(eng) >
  162. (result_type(1)+y*y) * exp((_alpha-result_type(1))
  163. *log(x/(_alpha-result_type(1)))
  164. - sqrt(result_type(2)*_alpha
  165. -result_type(1))*y))
  166. continue;
  167. return x * _beta;
  168. }
  169. } else /* alpha < 1.0 */ {
  170. for(;;) {
  171. result_type u = uniform_01<RealType>()(eng);
  172. result_type y = _exp(eng);
  173. result_type x, q;
  174. if(u < _p) {
  175. x = exp(-y/_alpha);
  176. q = _p*exp(-x);
  177. } else {
  178. x = result_type(1)+y;
  179. q = _p + (result_type(1)-_p) * pow(x,_alpha-result_type(1));
  180. }
  181. if(u >= q)
  182. continue;
  183. return x * _beta;
  184. }
  185. }
  186. }
  187. template<class URNG>
  188. RealType operator()(URNG& urng, const param_type& parm) const
  189. {
  190. return gamma_distribution(parm)(urng);
  191. }
  192. #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS
  193. /** Writes a @c gamma_distribution to a @c std::ostream. */
  194. template<class CharT, class Traits>
  195. friend std::basic_ostream<CharT,Traits>&
  196. operator<<(std::basic_ostream<CharT,Traits>& os,
  197. const gamma_distribution& gd)
  198. {
  199. os << gd.param();
  200. return os;
  201. }
  202. /** Reads a @c gamma_distribution from a @c std::istream. */
  203. template<class CharT, class Traits>
  204. friend std::basic_istream<CharT,Traits>&
  205. operator>>(std::basic_istream<CharT,Traits>& is, gamma_distribution& gd)
  206. {
  207. gd.read(is);
  208. return is;
  209. }
  210. #endif
  211. /**
  212. * Returns true if the two distributions will produce identical
  213. * sequences of random variates given equal generators.
  214. */
  215. friend bool operator==(const gamma_distribution& lhs,
  216. const gamma_distribution& rhs)
  217. {
  218. return lhs._alpha == rhs._alpha
  219. && lhs._beta == rhs._beta
  220. && lhs._exp == rhs._exp;
  221. }
  222. /**
  223. * Returns true if the two distributions can produce different
  224. * sequences of random variates, given equal generators.
  225. */
  226. friend bool operator!=(const gamma_distribution& lhs,
  227. const gamma_distribution& rhs)
  228. {
  229. return !(lhs == rhs);
  230. }
  231. private:
  232. /// \cond hide_private_members
  233. template<class CharT, class Traits>
  234. void read(std::basic_istream<CharT, Traits>& is)
  235. {
  236. param_type parm;
  237. if(is >> parm) {
  238. param(parm);
  239. }
  240. }
  241. void init()
  242. {
  243. #ifndef BOOST_NO_STDC_NAMESPACE
  244. // allow for Koenig lookup
  245. using std::exp;
  246. #endif
  247. _p = exp(result_type(1)) / (_alpha + exp(result_type(1)));
  248. }
  249. /// \endcond
  250. exponential_distribution<RealType> _exp;
  251. result_type _alpha;
  252. result_type _beta;
  253. // some data precomputed from the parameters
  254. result_type _p;
  255. };
  256. } // namespace random
  257. using random::gamma_distribution;
  258. } // namespace boost
  259. #endif // BOOST_RANDOM_GAMMA_DISTRIBUTION_HPP