Chris@16
|
1 /* boost random/poisson_distribution.hpp header file
|
Chris@16
|
2 *
|
Chris@16
|
3 * Copyright Jens Maurer 2002
|
Chris@16
|
4 * Copyright Steven Watanabe 2010
|
Chris@16
|
5 * Distributed under the Boost Software License, Version 1.0. (See
|
Chris@16
|
6 * accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
7 * http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
8 *
|
Chris@16
|
9 * See http://www.boost.org for most recent version including documentation.
|
Chris@16
|
10 *
|
Chris@101
|
11 * $Id$
|
Chris@16
|
12 *
|
Chris@16
|
13 */
|
Chris@16
|
14
|
Chris@16
|
15 #ifndef BOOST_RANDOM_POISSON_DISTRIBUTION_HPP
|
Chris@16
|
16 #define BOOST_RANDOM_POISSON_DISTRIBUTION_HPP
|
Chris@16
|
17
|
Chris@16
|
18 #include <boost/config/no_tr1/cmath.hpp>
|
Chris@16
|
19 #include <cstdlib>
|
Chris@16
|
20 #include <iosfwd>
|
Chris@16
|
21 #include <boost/assert.hpp>
|
Chris@16
|
22 #include <boost/limits.hpp>
|
Chris@16
|
23 #include <boost/random/uniform_01.hpp>
|
Chris@16
|
24 #include <boost/random/detail/config.hpp>
|
Chris@16
|
25
|
Chris@16
|
26 #include <boost/random/detail/disable_warnings.hpp>
|
Chris@16
|
27
|
Chris@16
|
28 namespace boost {
|
Chris@16
|
29 namespace random {
|
Chris@16
|
30
|
Chris@16
|
31 namespace detail {
|
Chris@16
|
32
|
Chris@16
|
33 template<class RealType>
|
Chris@16
|
34 struct poisson_table {
|
Chris@16
|
35 static RealType value[10];
|
Chris@16
|
36 };
|
Chris@16
|
37
|
Chris@16
|
38 template<class RealType>
|
Chris@16
|
39 RealType poisson_table<RealType>::value[10] = {
|
Chris@16
|
40 0.0,
|
Chris@16
|
41 0.0,
|
Chris@16
|
42 0.69314718055994529,
|
Chris@16
|
43 1.7917594692280550,
|
Chris@16
|
44 3.1780538303479458,
|
Chris@16
|
45 4.7874917427820458,
|
Chris@16
|
46 6.5792512120101012,
|
Chris@16
|
47 8.5251613610654147,
|
Chris@16
|
48 10.604602902745251,
|
Chris@16
|
49 12.801827480081469
|
Chris@16
|
50 };
|
Chris@16
|
51
|
Chris@16
|
52 }
|
Chris@16
|
53
|
Chris@16
|
54 /**
|
Chris@16
|
55 * An instantiation of the class template @c poisson_distribution is a
|
Chris@16
|
56 * model of \random_distribution. The poisson distribution has
|
Chris@16
|
57 * \f$p(i) = \frac{e^{-\lambda}\lambda^i}{i!}\f$
|
Chris@16
|
58 *
|
Chris@16
|
59 * This implementation is based on the PTRD algorithm described
|
Chris@16
|
60 *
|
Chris@16
|
61 * @blockquote
|
Chris@16
|
62 * "The transformed rejection method for generating Poisson random variables",
|
Chris@16
|
63 * Wolfgang Hormann, Insurance: Mathematics and Economics
|
Chris@16
|
64 * Volume 12, Issue 1, February 1993, Pages 39-45
|
Chris@16
|
65 * @endblockquote
|
Chris@16
|
66 */
|
Chris@16
|
67 template<class IntType = int, class RealType = double>
|
Chris@16
|
68 class poisson_distribution {
|
Chris@16
|
69 public:
|
Chris@16
|
70 typedef IntType result_type;
|
Chris@16
|
71 typedef RealType input_type;
|
Chris@16
|
72
|
Chris@16
|
73 class param_type {
|
Chris@16
|
74 public:
|
Chris@16
|
75 typedef poisson_distribution distribution_type;
|
Chris@16
|
76 /**
|
Chris@16
|
77 * Construct a param_type object with the parameter "mean"
|
Chris@16
|
78 *
|
Chris@16
|
79 * Requires: mean > 0
|
Chris@16
|
80 */
|
Chris@16
|
81 explicit param_type(RealType mean_arg = RealType(1))
|
Chris@16
|
82 : _mean(mean_arg)
|
Chris@16
|
83 {
|
Chris@16
|
84 BOOST_ASSERT(_mean > 0);
|
Chris@16
|
85 }
|
Chris@16
|
86 /* Returns the "mean" parameter of the distribution. */
|
Chris@16
|
87 RealType mean() const { return _mean; }
|
Chris@16
|
88 #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS
|
Chris@16
|
89 /** Writes the parameters of the distribution to a @c std::ostream. */
|
Chris@16
|
90 template<class CharT, class Traits>
|
Chris@16
|
91 friend std::basic_ostream<CharT, Traits>&
|
Chris@16
|
92 operator<<(std::basic_ostream<CharT, Traits>& os,
|
Chris@16
|
93 const param_type& parm)
|
Chris@16
|
94 {
|
Chris@16
|
95 os << parm._mean;
|
Chris@16
|
96 return os;
|
Chris@16
|
97 }
|
Chris@16
|
98
|
Chris@16
|
99 /** Reads the parameters of the distribution from a @c std::istream. */
|
Chris@16
|
100 template<class CharT, class Traits>
|
Chris@16
|
101 friend std::basic_istream<CharT, Traits>&
|
Chris@16
|
102 operator>>(std::basic_istream<CharT, Traits>& is, param_type& parm)
|
Chris@16
|
103 {
|
Chris@16
|
104 is >> parm._mean;
|
Chris@16
|
105 return is;
|
Chris@16
|
106 }
|
Chris@16
|
107 #endif
|
Chris@16
|
108 /** Returns true if the parameters have the same values. */
|
Chris@16
|
109 friend bool operator==(const param_type& lhs, const param_type& rhs)
|
Chris@16
|
110 {
|
Chris@16
|
111 return lhs._mean == rhs._mean;
|
Chris@16
|
112 }
|
Chris@16
|
113 /** Returns true if the parameters have different values. */
|
Chris@16
|
114 friend bool operator!=(const param_type& lhs, const param_type& rhs)
|
Chris@16
|
115 {
|
Chris@16
|
116 return !(lhs == rhs);
|
Chris@16
|
117 }
|
Chris@16
|
118 private:
|
Chris@16
|
119 RealType _mean;
|
Chris@16
|
120 };
|
Chris@16
|
121
|
Chris@16
|
122 /**
|
Chris@16
|
123 * Constructs a @c poisson_distribution with the parameter @c mean.
|
Chris@16
|
124 *
|
Chris@16
|
125 * Requires: mean > 0
|
Chris@16
|
126 */
|
Chris@16
|
127 explicit poisson_distribution(RealType mean_arg = RealType(1))
|
Chris@16
|
128 : _mean(mean_arg)
|
Chris@16
|
129 {
|
Chris@16
|
130 BOOST_ASSERT(_mean > 0);
|
Chris@16
|
131 init();
|
Chris@16
|
132 }
|
Chris@16
|
133
|
Chris@16
|
134 /**
|
Chris@16
|
135 * Construct an @c poisson_distribution object from the
|
Chris@16
|
136 * parameters.
|
Chris@16
|
137 */
|
Chris@16
|
138 explicit poisson_distribution(const param_type& parm)
|
Chris@16
|
139 : _mean(parm.mean())
|
Chris@16
|
140 {
|
Chris@16
|
141 init();
|
Chris@16
|
142 }
|
Chris@16
|
143
|
Chris@16
|
144 /**
|
Chris@16
|
145 * Returns a random variate distributed according to the
|
Chris@16
|
146 * poisson distribution.
|
Chris@16
|
147 */
|
Chris@16
|
148 template<class URNG>
|
Chris@16
|
149 IntType operator()(URNG& urng) const
|
Chris@16
|
150 {
|
Chris@16
|
151 if(use_inversion()) {
|
Chris@16
|
152 return invert(urng);
|
Chris@16
|
153 } else {
|
Chris@16
|
154 return generate(urng);
|
Chris@16
|
155 }
|
Chris@16
|
156 }
|
Chris@16
|
157
|
Chris@16
|
158 /**
|
Chris@16
|
159 * Returns a random variate distributed according to the
|
Chris@16
|
160 * poisson distribution with parameters specified by param.
|
Chris@16
|
161 */
|
Chris@16
|
162 template<class URNG>
|
Chris@16
|
163 IntType operator()(URNG& urng, const param_type& parm) const
|
Chris@16
|
164 {
|
Chris@16
|
165 return poisson_distribution(parm)(urng);
|
Chris@16
|
166 }
|
Chris@16
|
167
|
Chris@16
|
168 /** Returns the "mean" parameter of the distribution. */
|
Chris@16
|
169 RealType mean() const { return _mean; }
|
Chris@16
|
170
|
Chris@16
|
171 /** Returns the smallest value that the distribution can produce. */
|
Chris@16
|
172 IntType min BOOST_PREVENT_MACRO_SUBSTITUTION() const { return 0; }
|
Chris@16
|
173 /** Returns the largest value that the distribution can produce. */
|
Chris@16
|
174 IntType max BOOST_PREVENT_MACRO_SUBSTITUTION() const
|
Chris@16
|
175 { return (std::numeric_limits<IntType>::max)(); }
|
Chris@16
|
176
|
Chris@16
|
177 /** Returns the parameters of the distribution. */
|
Chris@16
|
178 param_type param() const { return param_type(_mean); }
|
Chris@16
|
179 /** Sets parameters of the distribution. */
|
Chris@16
|
180 void param(const param_type& parm)
|
Chris@16
|
181 {
|
Chris@16
|
182 _mean = parm.mean();
|
Chris@16
|
183 init();
|
Chris@16
|
184 }
|
Chris@16
|
185
|
Chris@16
|
186 /**
|
Chris@16
|
187 * Effects: Subsequent uses of the distribution do not depend
|
Chris@16
|
188 * on values produced by any engine prior to invoking reset.
|
Chris@16
|
189 */
|
Chris@16
|
190 void reset() { }
|
Chris@16
|
191
|
Chris@16
|
192 #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS
|
Chris@16
|
193 /** Writes the parameters of the distribution to a @c std::ostream. */
|
Chris@16
|
194 template<class CharT, class Traits>
|
Chris@16
|
195 friend std::basic_ostream<CharT,Traits>&
|
Chris@16
|
196 operator<<(std::basic_ostream<CharT,Traits>& os,
|
Chris@16
|
197 const poisson_distribution& pd)
|
Chris@16
|
198 {
|
Chris@16
|
199 os << pd.param();
|
Chris@16
|
200 return os;
|
Chris@16
|
201 }
|
Chris@16
|
202
|
Chris@16
|
203 /** Reads the parameters of the distribution from a @c std::istream. */
|
Chris@16
|
204 template<class CharT, class Traits>
|
Chris@16
|
205 friend std::basic_istream<CharT,Traits>&
|
Chris@16
|
206 operator>>(std::basic_istream<CharT,Traits>& is, poisson_distribution& pd)
|
Chris@16
|
207 {
|
Chris@16
|
208 pd.read(is);
|
Chris@16
|
209 return is;
|
Chris@16
|
210 }
|
Chris@16
|
211 #endif
|
Chris@16
|
212
|
Chris@16
|
213 /** Returns true if the two distributions will produce the same
|
Chris@16
|
214 sequence of values, given equal generators. */
|
Chris@16
|
215 friend bool operator==(const poisson_distribution& lhs,
|
Chris@16
|
216 const poisson_distribution& rhs)
|
Chris@16
|
217 {
|
Chris@16
|
218 return lhs._mean == rhs._mean;
|
Chris@16
|
219 }
|
Chris@16
|
220 /** Returns true if the two distributions could produce different
|
Chris@16
|
221 sequences of values, given equal generators. */
|
Chris@16
|
222 friend bool operator!=(const poisson_distribution& lhs,
|
Chris@16
|
223 const poisson_distribution& rhs)
|
Chris@16
|
224 {
|
Chris@16
|
225 return !(lhs == rhs);
|
Chris@16
|
226 }
|
Chris@16
|
227
|
Chris@16
|
228 private:
|
Chris@16
|
229
|
Chris@16
|
230 /// @cond show_private
|
Chris@16
|
231
|
Chris@16
|
232 template<class CharT, class Traits>
|
Chris@16
|
233 void read(std::basic_istream<CharT, Traits>& is) {
|
Chris@16
|
234 param_type parm;
|
Chris@16
|
235 if(is >> parm) {
|
Chris@16
|
236 param(parm);
|
Chris@16
|
237 }
|
Chris@16
|
238 }
|
Chris@16
|
239
|
Chris@16
|
240 bool use_inversion() const
|
Chris@16
|
241 {
|
Chris@16
|
242 return _mean < 10;
|
Chris@16
|
243 }
|
Chris@16
|
244
|
Chris@16
|
245 static RealType log_factorial(IntType k)
|
Chris@16
|
246 {
|
Chris@16
|
247 BOOST_ASSERT(k >= 0);
|
Chris@16
|
248 BOOST_ASSERT(k < 10);
|
Chris@16
|
249 return detail::poisson_table<RealType>::value[k];
|
Chris@16
|
250 }
|
Chris@16
|
251
|
Chris@16
|
252 void init()
|
Chris@16
|
253 {
|
Chris@16
|
254 using std::sqrt;
|
Chris@16
|
255 using std::exp;
|
Chris@16
|
256
|
Chris@16
|
257 if(use_inversion()) {
|
Chris@16
|
258 _exp_mean = exp(-_mean);
|
Chris@16
|
259 } else {
|
Chris@16
|
260 _ptrd.smu = sqrt(_mean);
|
Chris@16
|
261 _ptrd.b = 0.931 + 2.53 * _ptrd.smu;
|
Chris@16
|
262 _ptrd.a = -0.059 + 0.02483 * _ptrd.b;
|
Chris@16
|
263 _ptrd.inv_alpha = 1.1239 + 1.1328 / (_ptrd.b - 3.4);
|
Chris@16
|
264 _ptrd.v_r = 0.9277 - 3.6224 / (_ptrd.b - 2);
|
Chris@16
|
265 }
|
Chris@16
|
266 }
|
Chris@16
|
267
|
Chris@16
|
268 template<class URNG>
|
Chris@16
|
269 IntType generate(URNG& urng) const
|
Chris@16
|
270 {
|
Chris@16
|
271 using std::floor;
|
Chris@16
|
272 using std::abs;
|
Chris@16
|
273 using std::log;
|
Chris@16
|
274
|
Chris@16
|
275 while(true) {
|
Chris@16
|
276 RealType u;
|
Chris@16
|
277 RealType v = uniform_01<RealType>()(urng);
|
Chris@16
|
278 if(v <= 0.86 * _ptrd.v_r) {
|
Chris@16
|
279 u = v / _ptrd.v_r - 0.43;
|
Chris@16
|
280 return static_cast<IntType>(floor(
|
Chris@16
|
281 (2*_ptrd.a/(0.5-abs(u)) + _ptrd.b)*u + _mean + 0.445));
|
Chris@16
|
282 }
|
Chris@16
|
283
|
Chris@16
|
284 if(v >= _ptrd.v_r) {
|
Chris@16
|
285 u = uniform_01<RealType>()(urng) - 0.5;
|
Chris@16
|
286 } else {
|
Chris@16
|
287 u = v/_ptrd.v_r - 0.93;
|
Chris@16
|
288 u = ((u < 0)? -0.5 : 0.5) - u;
|
Chris@16
|
289 v = uniform_01<RealType>()(urng) * _ptrd.v_r;
|
Chris@16
|
290 }
|
Chris@16
|
291
|
Chris@16
|
292 RealType us = 0.5 - abs(u);
|
Chris@16
|
293 if(us < 0.013 && v > us) {
|
Chris@16
|
294 continue;
|
Chris@16
|
295 }
|
Chris@16
|
296
|
Chris@16
|
297 RealType k = floor((2*_ptrd.a/us + _ptrd.b)*u+_mean+0.445);
|
Chris@16
|
298 v = v*_ptrd.inv_alpha/(_ptrd.a/(us*us) + _ptrd.b);
|
Chris@16
|
299
|
Chris@16
|
300 RealType log_sqrt_2pi = 0.91893853320467267;
|
Chris@16
|
301
|
Chris@16
|
302 if(k >= 10) {
|
Chris@16
|
303 if(log(v*_ptrd.smu) <= (k + 0.5)*log(_mean/k)
|
Chris@16
|
304 - _mean
|
Chris@16
|
305 - log_sqrt_2pi
|
Chris@16
|
306 + k
|
Chris@16
|
307 - (1/12. - (1/360. - 1/(1260.*k*k))/(k*k))/k) {
|
Chris@16
|
308 return static_cast<IntType>(k);
|
Chris@16
|
309 }
|
Chris@16
|
310 } else if(k >= 0) {
|
Chris@16
|
311 if(log(v) <= k*log(_mean)
|
Chris@16
|
312 - _mean
|
Chris@16
|
313 - log_factorial(static_cast<IntType>(k))) {
|
Chris@16
|
314 return static_cast<IntType>(k);
|
Chris@16
|
315 }
|
Chris@16
|
316 }
|
Chris@16
|
317 }
|
Chris@16
|
318 }
|
Chris@16
|
319
|
Chris@16
|
320 template<class URNG>
|
Chris@16
|
321 IntType invert(URNG& urng) const
|
Chris@16
|
322 {
|
Chris@16
|
323 RealType p = _exp_mean;
|
Chris@16
|
324 IntType x = 0;
|
Chris@16
|
325 RealType u = uniform_01<RealType>()(urng);
|
Chris@16
|
326 while(u > p) {
|
Chris@16
|
327 u = u - p;
|
Chris@16
|
328 ++x;
|
Chris@16
|
329 p = _mean * p / x;
|
Chris@16
|
330 }
|
Chris@16
|
331 return x;
|
Chris@16
|
332 }
|
Chris@16
|
333
|
Chris@16
|
334 RealType _mean;
|
Chris@16
|
335
|
Chris@16
|
336 union {
|
Chris@16
|
337 // for ptrd
|
Chris@16
|
338 struct {
|
Chris@16
|
339 RealType v_r;
|
Chris@16
|
340 RealType a;
|
Chris@16
|
341 RealType b;
|
Chris@16
|
342 RealType smu;
|
Chris@16
|
343 RealType inv_alpha;
|
Chris@16
|
344 } _ptrd;
|
Chris@16
|
345 // for inversion
|
Chris@16
|
346 RealType _exp_mean;
|
Chris@16
|
347 };
|
Chris@16
|
348
|
Chris@16
|
349 /// @endcond
|
Chris@16
|
350 };
|
Chris@16
|
351
|
Chris@16
|
352 } // namespace random
|
Chris@16
|
353
|
Chris@16
|
354 using random::poisson_distribution;
|
Chris@16
|
355
|
Chris@16
|
356 } // namespace boost
|
Chris@16
|
357
|
Chris@16
|
358 #include <boost/random/detail/enable_warnings.hpp>
|
Chris@16
|
359
|
Chris@16
|
360 #endif // BOOST_RANDOM_POISSON_DISTRIBUTION_HPP
|