X-Git-Url: https://git.donarmstrong.com/?p=rsem.git;a=blobdiff_plain;f=boost%2Frandom%2Fpoisson_distribution.hpp;fp=boost%2Frandom%2Fpoisson_distribution.hpp;h=c1eac37164a7d9d8a186bbe80bae49cc3b5e12cf;hp=9a2e4b9846bbab2c71d48ad42e8db25d7cea3233;hb=2d71eb92104693ca9baa5a2e1c23eeca776d8fd3;hpb=da57529b92adbb7ae74a89861cb39fb35ac7c62d diff --git a/boost/random/poisson_distribution.hpp b/boost/random/poisson_distribution.hpp index 9a2e4b9..c1eac37 100644 --- a/boost/random/poisson_distribution.hpp +++ b/boost/random/poisson_distribution.hpp @@ -1,13 +1,14 @@ /* boost random/poisson_distribution.hpp header file * * Copyright Jens Maurer 2002 + * Copyright Steven Watanabe 2010 * Distributed under the Boost Software License, Version 1.0. (See * accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * See http://www.boost.org for most recent version including documentation. * - * $Id: poisson_distribution.hpp 60755 2010-03-22 00:45:06Z steven_watanabe $ + * $Id: poisson_distribution.hpp 71018 2011-04-05 21:27:52Z steven_watanabe $ * */ @@ -15,102 +16,345 @@ #define BOOST_RANDOM_POISSON_DISTRIBUTION_HPP #include -#include -#include +#include +#include +#include #include -#include +#include #include +#include + namespace boost { +namespace random { + +namespace detail { + +template +struct poisson_table { + static RealType value[10]; +}; + +template +RealType poisson_table::value[10] = { + 0.0, + 0.0, + 0.69314718055994529, + 1.7917594692280550, + 3.1780538303479458, + 4.7874917427820458, + 6.5792512120101012, + 8.5251613610654147, + 10.604602902745251, + 12.801827480081469 +}; -// Knuth +} /** * An instantiation of the class template @c poisson_distribution is a * model of \random_distribution. The poisson distribution has * \f$p(i) = \frac{e^{-\lambda}\lambda^i}{i!}\f$ + * + * This implementation is based on the PTRD algorithm described + * + * @blockquote + * "The transformed rejection method for generating Poisson random variables", + * Wolfgang Hormann, Insurance: Mathematics and Economics + * Volume 12, Issue 1, February 1993, Pages 39-45 + * @endblockquote */ template -class poisson_distribution -{ +class poisson_distribution { public: - typedef RealType input_type; - typedef IntType result_type; - - /** - * Constructs a @c poisson_distribution with the parameter @c mean. - * - * Requires: mean > 0 - */ - explicit poisson_distribution(const RealType& mean_arg = RealType(1)) - : _mean(mean_arg) - { -#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS - // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope - BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); - BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); + typedef IntType result_type; + typedef RealType input_type; + + class param_type { + public: + typedef poisson_distribution distribution_type; + /** + * Construct a param_type object with the parameter "mean" + * + * Requires: mean > 0 + */ + explicit param_type(RealType mean_arg = RealType(1)) + : _mean(mean_arg) + { + BOOST_ASSERT(_mean > 0); + } + /* Returns the "mean" parameter of the distribution. */ + RealType mean() const { return _mean; } +#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS + /** Writes the parameters of the distribution to a @c std::ostream. */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, + const param_type& parm) + { + os << parm._mean; + return os; + } + + /** Reads the parameters of the distribution from a @c std::istream. */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, param_type& parm) + { + is >> parm._mean; + return is; + } #endif + /** Returns true if the parameters have the same values. */ + friend bool operator==(const param_type& lhs, const param_type& rhs) + { + return lhs._mean == rhs._mean; + } + /** Returns true if the parameters have different values. */ + friend bool operator!=(const param_type& lhs, const param_type& rhs) + { + return !(lhs == rhs); + } + private: + RealType _mean; + }; + + /** + * Constructs a @c poisson_distribution with the parameter @c mean. + * + * Requires: mean > 0 + */ + explicit poisson_distribution(RealType mean_arg = RealType(1)) + : _mean(mean_arg) + { + BOOST_ASSERT(_mean > 0); + init(); + } + + /** + * Construct an @c poisson_distribution object from the + * parameters. + */ + explicit poisson_distribution(const param_type& parm) + : _mean(parm.mean()) + { + init(); + } + + /** + * Returns a random variate distributed according to the + * poisson distribution. + */ + template + IntType operator()(URNG& urng) const + { + if(use_inversion()) { + return invert(urng); + } else { + return generate(urng); + } + } + + /** + * Returns a random variate distributed according to the + * poisson distribution with parameters specified by param. + */ + template + IntType operator()(URNG& urng, const param_type& parm) const + { + return poisson_distribution(parm)(urng); + } - assert(_mean > RealType(0)); - init(); - } - - // compiler-generated copy ctor and assignment operator are fine - - /** - * Returns: the "mean" parameter of the distribution. - */ - RealType mean() const { return _mean; } - void reset() { } - - template - result_type operator()(Engine& eng) - { - // TODO: This is O(_mean), but it should be O(log(_mean)) for large _mean - RealType product = RealType(1); - for(result_type m = 0; ; ++m) { - product *= eng(); - if(product <= _exp_mean) - return m; + /** Returns the "mean" parameter of the distribution. */ + RealType mean() const { return _mean; } + + /** Returns the smallest value that the distribution can produce. */ + IntType min BOOST_PREVENT_MACRO_SUBSTITUTION() const { return 0; } + /** Returns the largest value that the distribution can produce. */ + IntType max BOOST_PREVENT_MACRO_SUBSTITUTION() const + { return (std::numeric_limits::max)(); } + + /** Returns the parameters of the distribution. */ + param_type param() const { return param_type(_mean); } + /** Sets parameters of the distribution. */ + void param(const param_type& parm) + { + _mean = parm.mean(); + init(); } - } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { } #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const poisson_distribution& pd) - { - os << pd._mean; - return os; - } - - template - friend std::basic_istream& - operator>>(std::basic_istream& is, poisson_distribution& pd) - { - is >> std::ws >> pd._mean; - pd.init(); - return is; - } + /** Writes the parameters of the distribution to a @c std::ostream. */ + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, + const poisson_distribution& pd) + { + os << pd.param(); + return os; + } + + /** Reads the parameters of the distribution from a @c std::istream. */ + template + friend std::basic_istream& + operator>>(std::basic_istream& is, poisson_distribution& pd) + { + pd.read(is); + return is; + } #endif + + /** Returns true if the two distributions will produce the same + sequence of values, given equal generators. */ + friend bool operator==(const poisson_distribution& lhs, + const poisson_distribution& rhs) + { + return lhs._mean == rhs._mean; + } + /** Returns true if the two distributions could produce different + sequences of values, given equal generators. */ + friend bool operator!=(const poisson_distribution& lhs, + const poisson_distribution& rhs) + { + return !(lhs == rhs); + } private: - /// \cond hide_private_members - void init() - { -#ifndef BOOST_NO_STDC_NAMESPACE - // allow for Koenig lookup - using std::exp; -#endif - _exp_mean = exp(-_mean); - } - /// \endcond - RealType _mean; - // some precomputed data from the parameters - RealType _exp_mean; + /// @cond show_private + + template + void read(std::basic_istream& is) { + param_type parm; + if(is >> parm) { + param(parm); + } + } + + bool use_inversion() const + { + return _mean < 10; + } + + static RealType log_factorial(IntType k) + { + BOOST_ASSERT(k >= 0); + BOOST_ASSERT(k < 10); + return detail::poisson_table::value[k]; + } + + void init() + { + using std::sqrt; + using std::exp; + + if(use_inversion()) { + _exp_mean = exp(-_mean); + } else { + _ptrd.smu = sqrt(_mean); + _ptrd.b = 0.931 + 2.53 * _ptrd.smu; + _ptrd.a = -0.059 + 0.02483 * _ptrd.b; + _ptrd.inv_alpha = 1.1239 + 1.1328 / (_ptrd.b - 3.4); + _ptrd.v_r = 0.9277 - 3.6224 / (_ptrd.b - 2); + } + } + + template + IntType generate(URNG& urng) const + { + using std::floor; + using std::abs; + using std::log; + + while(true) { + RealType u; + RealType v = uniform_01()(urng); + if(v <= 0.86 * _ptrd.v_r) { + u = v / _ptrd.v_r - 0.43; + return static_cast(floor( + (2*_ptrd.a/(0.5-abs(u)) + _ptrd.b)*u + _mean + 0.445)); + } + + if(v >= _ptrd.v_r) { + u = uniform_01()(urng) - 0.5; + } else { + u = v/_ptrd.v_r - 0.93; + u = ((u < 0)? -0.5 : 0.5) - u; + v = uniform_01()(urng) * _ptrd.v_r; + } + + RealType us = 0.5 - abs(u); + if(us < 0.013 && v > us) { + continue; + } + + RealType k = floor((2*_ptrd.a/us + _ptrd.b)*u+_mean+0.445); + v = v*_ptrd.inv_alpha/(_ptrd.a/(us*us) + _ptrd.b); + + RealType log_sqrt_2pi = 0.91893853320467267; + + if(k >= 10) { + if(log(v*_ptrd.smu) <= (k + 0.5)*log(_mean/k) + - _mean + - log_sqrt_2pi + + k + - (1/12. - (1/360. - 1/(1260.*k*k))/(k*k))/k) { + return static_cast(k); + } + } else if(k >= 0) { + if(log(v) <= k*log(_mean) + - _mean + - log_factorial(static_cast(k))) { + return static_cast(k); + } + } + } + } + + template + IntType invert(URNG& urng) const + { + RealType p = _exp_mean; + IntType x = 0; + RealType u = uniform_01()(urng); + while(u > p) { + u = u - p; + ++x; + p = _mean * p / x; + } + return x; + } + + RealType _mean; + + union { + // for ptrd + struct { + RealType v_r; + RealType a; + RealType b; + RealType smu; + RealType inv_alpha; + } _ptrd; + // for inversion + RealType _exp_mean; + }; + + /// @endcond }; +} // namespace random + +using random::poisson_distribution; + } // namespace boost +#include + #endif // BOOST_RANDOM_POISSON_DISTRIBUTION_HPP