]> git.donarmstrong.com Git - rsem.git/blobdiff - boost/random/poisson_distribution.hpp
Updated boost to v1.55.0
[rsem.git] / boost / random / poisson_distribution.hpp
index 9a2e4b9846bbab2c71d48ad42e8db25d7cea3233..c1eac37164a7d9d8a186bbe80bae49cc3b5e12cf 100644 (file)
@@ -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 $
  *
  */
 
 #define BOOST_RANDOM_POISSON_DISTRIBUTION_HPP
 
 #include <boost/config/no_tr1/cmath.hpp>
-#include <cassert>
-#include <iostream>
+#include <cstdlib>
+#include <iosfwd>
+#include <boost/assert.hpp>
 #include <boost/limits.hpp>
-#include <boost/static_assert.hpp>
+#include <boost/random/uniform_01.hpp>
 #include <boost/random/detail/config.hpp>
 
+#include <boost/random/detail/disable_warnings.hpp>
+
 namespace boost {
+namespace random {
+
+namespace detail {
+
+template<class RealType>
+struct poisson_table {
+    static RealType value[10];
+};
+
+template<class RealType>
+RealType poisson_table<RealType>::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 IntType = int, class RealType = double>
-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<IntType>::is_integer);
-    BOOST_STATIC_ASSERT(!std::numeric_limits<RealType>::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<class CharT, class Traits>
+        friend std::basic_ostream<CharT, Traits>&
+        operator<<(std::basic_ostream<CharT, Traits>& os,
+                   const param_type& parm)
+        {
+            os << parm._mean;
+            return os;
+        }
+
+        /** Reads the parameters of the distribution from a @c std::istream. */
+        template<class CharT, class Traits>
+        friend std::basic_istream<CharT, Traits>&
+        operator>>(std::basic_istream<CharT, Traits>& 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<class URNG>
+    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<class URNG>
+    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<class Engine>
-  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<IntType>::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<class CharT, class Traits>
-  friend std::basic_ostream<CharT,Traits>&
-  operator<<(std::basic_ostream<CharT,Traits>& os, const poisson_distribution& pd)
-  {
-    os << pd._mean;
-    return os;
-  }
-
-  template<class CharT, class Traits>
-  friend std::basic_istream<CharT,Traits>&
-  operator>>(std::basic_istream<CharT,Traits>& 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<class CharT, class Traits>
+    friend std::basic_ostream<CharT,Traits>&
+    operator<<(std::basic_ostream<CharT,Traits>& os,
+               const poisson_distribution& pd)
+    {
+        os << pd.param();
+        return os;
+    }
+    
+    /** Reads the parameters of the distribution from a @c std::istream. */
+    template<class CharT, class Traits>
+    friend std::basic_istream<CharT,Traits>&
+    operator>>(std::basic_istream<CharT,Traits>& 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<class CharT, class Traits>
+    void read(std::basic_istream<CharT, Traits>& 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<RealType>::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<class URNG>
+    IntType generate(URNG& urng) const
+    {
+        using std::floor;
+        using std::abs;
+        using std::log;
+
+        while(true) {
+            RealType u;
+            RealType v = uniform_01<RealType>()(urng);
+            if(v <= 0.86 * _ptrd.v_r) {
+                u = v / _ptrd.v_r - 0.43;
+                return static_cast<IntType>(floor(
+                    (2*_ptrd.a/(0.5-abs(u)) + _ptrd.b)*u + _mean + 0.445));
+            }
+
+            if(v >= _ptrd.v_r) {
+                u = uniform_01<RealType>()(urng) - 0.5;
+            } else {
+                u = v/_ptrd.v_r - 0.93;
+                u = ((u < 0)? -0.5 : 0.5) - u;
+                v = uniform_01<RealType>()(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<IntType>(k);
+                }
+            } else if(k >= 0) {
+                if(log(v) <= k*log(_mean)
+                           - _mean
+                           - log_factorial(static_cast<IntType>(k))) {
+                    return static_cast<IntType>(k);
+                }
+            }
+        }
+    }
+
+    template<class URNG>
+    IntType invert(URNG& urng) const
+    {
+        RealType p = _exp_mean;
+        IntType x = 0;
+        RealType u = uniform_01<RealType>()(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 <boost/random/detail/enable_warnings.hpp>
+
 #endif // BOOST_RANDOM_POISSON_DISTRIBUTION_HPP