Mercurial > hg > sv-dependency-builds
comparison any/include/boost/math/distributions/poisson.hpp @ 160:cff480c41f97
Add some cross-platform Boost headers
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Sat, 16 Feb 2019 16:31:25 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
159:f4b37539fcc7 | 160:cff480c41f97 |
---|---|
1 // boost\math\distributions\poisson.hpp | |
2 | |
3 // Copyright John Maddock 2006. | |
4 // Copyright Paul A. Bristow 2007. | |
5 | |
6 // Use, modification and distribution are subject to the | |
7 // Boost Software License, Version 1.0. | |
8 // (See accompanying file LICENSE_1_0.txt | |
9 // or copy at http://www.boost.org/LICENSE_1_0.txt) | |
10 | |
11 // Poisson distribution is a discrete probability distribution. | |
12 // It expresses the probability of a number (k) of | |
13 // events, occurrences, failures or arrivals occurring in a fixed time, | |
14 // assuming these events occur with a known average or mean rate (lambda) | |
15 // and are independent of the time since the last event. | |
16 // The distribution was discovered by Simeon-Denis Poisson (1781-1840). | |
17 | |
18 // Parameter lambda is the mean number of events in the given time interval. | |
19 // The random variate k is the number of events, occurrences or arrivals. | |
20 // k argument may be integral, signed, or unsigned, or floating point. | |
21 // If necessary, it has already been promoted from an integral type. | |
22 | |
23 // Note that the Poisson distribution | |
24 // (like others including the binomial, negative binomial & Bernoulli) | |
25 // is strictly defined as a discrete function: | |
26 // only integral values of k are envisaged. | |
27 // However because the method of calculation uses a continuous gamma function, | |
28 // it is convenient to treat it as if a continous function, | |
29 // and permit non-integral values of k. | |
30 // To enforce the strict mathematical model, users should use floor or ceil functions | |
31 // on k outside this function to ensure that k is integral. | |
32 | |
33 // See http://en.wikipedia.org/wiki/Poisson_distribution | |
34 // http://documents.wolfram.com/v5/Add-onsLinks/StandardPackages/Statistics/DiscreteDistributions.html | |
35 | |
36 #ifndef BOOST_MATH_SPECIAL_POISSON_HPP | |
37 #define BOOST_MATH_SPECIAL_POISSON_HPP | |
38 | |
39 #include <boost/math/distributions/fwd.hpp> | |
40 #include <boost/math/special_functions/gamma.hpp> // for incomplete gamma. gamma_q | |
41 #include <boost/math/special_functions/trunc.hpp> // for incomplete gamma. gamma_q | |
42 #include <boost/math/distributions/complement.hpp> // complements | |
43 #include <boost/math/distributions/detail/common_error_handling.hpp> // error checks | |
44 #include <boost/math/special_functions/fpclassify.hpp> // isnan. | |
45 #include <boost/math/special_functions/factorials.hpp> // factorials. | |
46 #include <boost/math/tools/roots.hpp> // for root finding. | |
47 #include <boost/math/distributions/detail/inv_discrete_quantile.hpp> | |
48 | |
49 #include <utility> | |
50 | |
51 namespace boost | |
52 { | |
53 namespace math | |
54 { | |
55 namespace poisson_detail | |
56 { | |
57 // Common error checking routines for Poisson distribution functions. | |
58 // These are convoluted, & apparently redundant, to try to ensure that | |
59 // checks are always performed, even if exceptions are not enabled. | |
60 | |
61 template <class RealType, class Policy> | |
62 inline bool check_mean(const char* function, const RealType& mean, RealType* result, const Policy& pol) | |
63 { | |
64 if(!(boost::math::isfinite)(mean) || (mean < 0)) | |
65 { | |
66 *result = policies::raise_domain_error<RealType>( | |
67 function, | |
68 "Mean argument is %1%, but must be >= 0 !", mean, pol); | |
69 return false; | |
70 } | |
71 return true; | |
72 } // bool check_mean | |
73 | |
74 template <class RealType, class Policy> | |
75 inline bool check_mean_NZ(const char* function, const RealType& mean, RealType* result, const Policy& pol) | |
76 { // mean == 0 is considered an error. | |
77 if( !(boost::math::isfinite)(mean) || (mean <= 0)) | |
78 { | |
79 *result = policies::raise_domain_error<RealType>( | |
80 function, | |
81 "Mean argument is %1%, but must be > 0 !", mean, pol); | |
82 return false; | |
83 } | |
84 return true; | |
85 } // bool check_mean_NZ | |
86 | |
87 template <class RealType, class Policy> | |
88 inline bool check_dist(const char* function, const RealType& mean, RealType* result, const Policy& pol) | |
89 { // Only one check, so this is redundant really but should be optimized away. | |
90 return check_mean_NZ(function, mean, result, pol); | |
91 } // bool check_dist | |
92 | |
93 template <class RealType, class Policy> | |
94 inline bool check_k(const char* function, const RealType& k, RealType* result, const Policy& pol) | |
95 { | |
96 if((k < 0) || !(boost::math::isfinite)(k)) | |
97 { | |
98 *result = policies::raise_domain_error<RealType>( | |
99 function, | |
100 "Number of events k argument is %1%, but must be >= 0 !", k, pol); | |
101 return false; | |
102 } | |
103 return true; | |
104 } // bool check_k | |
105 | |
106 template <class RealType, class Policy> | |
107 inline bool check_dist_and_k(const char* function, RealType mean, RealType k, RealType* result, const Policy& pol) | |
108 { | |
109 if((check_dist(function, mean, result, pol) == false) || | |
110 (check_k(function, k, result, pol) == false)) | |
111 { | |
112 return false; | |
113 } | |
114 return true; | |
115 } // bool check_dist_and_k | |
116 | |
117 template <class RealType, class Policy> | |
118 inline bool check_prob(const char* function, const RealType& p, RealType* result, const Policy& pol) | |
119 { // Check 0 <= p <= 1 | |
120 if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1)) | |
121 { | |
122 *result = policies::raise_domain_error<RealType>( | |
123 function, | |
124 "Probability argument is %1%, but must be >= 0 and <= 1 !", p, pol); | |
125 return false; | |
126 } | |
127 return true; | |
128 } // bool check_prob | |
129 | |
130 template <class RealType, class Policy> | |
131 inline bool check_dist_and_prob(const char* function, RealType mean, RealType p, RealType* result, const Policy& pol) | |
132 { | |
133 if((check_dist(function, mean, result, pol) == false) || | |
134 (check_prob(function, p, result, pol) == false)) | |
135 { | |
136 return false; | |
137 } | |
138 return true; | |
139 } // bool check_dist_and_prob | |
140 | |
141 } // namespace poisson_detail | |
142 | |
143 template <class RealType = double, class Policy = policies::policy<> > | |
144 class poisson_distribution | |
145 { | |
146 public: | |
147 typedef RealType value_type; | |
148 typedef Policy policy_type; | |
149 | |
150 poisson_distribution(RealType l_mean = 1) : m_l(l_mean) // mean (lambda). | |
151 { // Expected mean number of events that occur during the given interval. | |
152 RealType r; | |
153 poisson_detail::check_dist( | |
154 "boost::math::poisson_distribution<%1%>::poisson_distribution", | |
155 m_l, | |
156 &r, Policy()); | |
157 } // poisson_distribution constructor. | |
158 | |
159 RealType mean() const | |
160 { // Private data getter function. | |
161 return m_l; | |
162 } | |
163 private: | |
164 // Data member, initialized by constructor. | |
165 RealType m_l; // mean number of occurrences. | |
166 }; // template <class RealType, class Policy> class poisson_distribution | |
167 | |
168 typedef poisson_distribution<double> poisson; // Reserved name of type double. | |
169 | |
170 // Non-member functions to give properties of the distribution. | |
171 | |
172 template <class RealType, class Policy> | |
173 inline const std::pair<RealType, RealType> range(const poisson_distribution<RealType, Policy>& /* dist */) | |
174 { // Range of permissible values for random variable k. | |
175 using boost::math::tools::max_value; | |
176 return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>()); // Max integer? | |
177 } | |
178 | |
179 template <class RealType, class Policy> | |
180 inline const std::pair<RealType, RealType> support(const poisson_distribution<RealType, Policy>& /* dist */) | |
181 { // Range of supported values for random variable k. | |
182 // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. | |
183 using boost::math::tools::max_value; | |
184 return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>()); | |
185 } | |
186 | |
187 template <class RealType, class Policy> | |
188 inline RealType mean(const poisson_distribution<RealType, Policy>& dist) | |
189 { // Mean of poisson distribution = lambda. | |
190 return dist.mean(); | |
191 } // mean | |
192 | |
193 template <class RealType, class Policy> | |
194 inline RealType mode(const poisson_distribution<RealType, Policy>& dist) | |
195 { // mode. | |
196 BOOST_MATH_STD_USING // ADL of std functions. | |
197 return floor(dist.mean()); | |
198 } | |
199 | |
200 //template <class RealType, class Policy> | |
201 //inline RealType median(const poisson_distribution<RealType, Policy>& dist) | |
202 //{ // median = approximately lambda + 1/3 - 0.2/lambda | |
203 // RealType l = dist.mean(); | |
204 // return dist.mean() + static_cast<RealType>(0.3333333333333333333333333333333333333333333333) | |
205 // - static_cast<RealType>(0.2) / l; | |
206 //} // BUT this formula appears to be out-by-one compared to quantile(half) | |
207 // Query posted on Wikipedia. | |
208 // Now implemented via quantile(half) in derived accessors. | |
209 | |
210 template <class RealType, class Policy> | |
211 inline RealType variance(const poisson_distribution<RealType, Policy>& dist) | |
212 { // variance. | |
213 return dist.mean(); | |
214 } | |
215 | |
216 // RealType standard_deviation(const poisson_distribution<RealType, Policy>& dist) | |
217 // standard_deviation provided by derived accessors. | |
218 | |
219 template <class RealType, class Policy> | |
220 inline RealType skewness(const poisson_distribution<RealType, Policy>& dist) | |
221 { // skewness = sqrt(l). | |
222 BOOST_MATH_STD_USING // ADL of std functions. | |
223 return 1 / sqrt(dist.mean()); | |
224 } | |
225 | |
226 template <class RealType, class Policy> | |
227 inline RealType kurtosis_excess(const poisson_distribution<RealType, Policy>& dist) | |
228 { // skewness = sqrt(l). | |
229 return 1 / dist.mean(); // kurtosis_excess 1/mean from Wiki & MathWorld eq 31. | |
230 // http://mathworld.wolfram.com/Kurtosis.html explains that the kurtosis excess | |
231 // is more convenient because the kurtosis excess of a normal distribution is zero | |
232 // whereas the true kurtosis is 3. | |
233 } // RealType kurtosis_excess | |
234 | |
235 template <class RealType, class Policy> | |
236 inline RealType kurtosis(const poisson_distribution<RealType, Policy>& dist) | |
237 { // kurtosis is 4th moment about the mean = u4 / sd ^ 4 | |
238 // http://en.wikipedia.org/wiki/Curtosis | |
239 // kurtosis can range from -2 (flat top) to +infinity (sharp peak & heavy tails). | |
240 // http://www.itl.nist.gov/div898/handbook/eda/section3/eda35b.htm | |
241 return 3 + 1 / dist.mean(); // NIST. | |
242 // http://mathworld.wolfram.com/Kurtosis.html explains that the kurtosis excess | |
243 // is more convenient because the kurtosis excess of a normal distribution is zero | |
244 // whereas the true kurtosis is 3. | |
245 } // RealType kurtosis | |
246 | |
247 template <class RealType, class Policy> | |
248 RealType pdf(const poisson_distribution<RealType, Policy>& dist, const RealType& k) | |
249 { // Probability Density/Mass Function. | |
250 // Probability that there are EXACTLY k occurrences (or arrivals). | |
251 BOOST_FPU_EXCEPTION_GUARD | |
252 | |
253 BOOST_MATH_STD_USING // for ADL of std functions. | |
254 | |
255 RealType mean = dist.mean(); | |
256 // Error check: | |
257 RealType result = 0; | |
258 if(false == poisson_detail::check_dist_and_k( | |
259 "boost::math::pdf(const poisson_distribution<%1%>&, %1%)", | |
260 mean, | |
261 k, | |
262 &result, Policy())) | |
263 { | |
264 return result; | |
265 } | |
266 | |
267 // Special case of mean zero, regardless of the number of events k. | |
268 if (mean == 0) | |
269 { // Probability for any k is zero. | |
270 return 0; | |
271 } | |
272 if (k == 0) | |
273 { // mean ^ k = 1, and k! = 1, so can simplify. | |
274 return exp(-mean); | |
275 } | |
276 return boost::math::gamma_p_derivative(k+1, mean, Policy()); | |
277 } // pdf | |
278 | |
279 template <class RealType, class Policy> | |
280 RealType cdf(const poisson_distribution<RealType, Policy>& dist, const RealType& k) | |
281 { // Cumulative Distribution Function Poisson. | |
282 // The random variate k is the number of occurrences(or arrivals) | |
283 // k argument may be integral, signed, or unsigned, or floating point. | |
284 // If necessary, it has already been promoted from an integral type. | |
285 // Returns the sum of the terms 0 through k of the Poisson Probability Density or Mass (pdf). | |
286 | |
287 // But note that the Poisson distribution | |
288 // (like others including the binomial, negative binomial & Bernoulli) | |
289 // is strictly defined as a discrete function: only integral values of k are envisaged. | |
290 // However because of the method of calculation using a continuous gamma function, | |
291 // it is convenient to treat it as if it is a continous function | |
292 // and permit non-integral values of k. | |
293 // To enforce the strict mathematical model, users should use floor or ceil functions | |
294 // outside this function to ensure that k is integral. | |
295 | |
296 // The terms are not summed directly (at least for larger k) | |
297 // instead the incomplete gamma integral is employed, | |
298 | |
299 BOOST_MATH_STD_USING // for ADL of std function exp. | |
300 | |
301 RealType mean = dist.mean(); | |
302 // Error checks: | |
303 RealType result = 0; | |
304 if(false == poisson_detail::check_dist_and_k( | |
305 "boost::math::cdf(const poisson_distribution<%1%>&, %1%)", | |
306 mean, | |
307 k, | |
308 &result, Policy())) | |
309 { | |
310 return result; | |
311 } | |
312 // Special cases: | |
313 if (mean == 0) | |
314 { // Probability for any k is zero. | |
315 return 0; | |
316 } | |
317 if (k == 0) | |
318 { // return pdf(dist, static_cast<RealType>(0)); | |
319 // but mean (and k) have already been checked, | |
320 // so this avoids unnecessary repeated checks. | |
321 return exp(-mean); | |
322 } | |
323 // For small integral k could use a finite sum - | |
324 // it's cheaper than the gamma function. | |
325 // BUT this is now done efficiently by gamma_q function. | |
326 // Calculate poisson cdf using the gamma_q function. | |
327 return gamma_q(k+1, mean, Policy()); | |
328 } // binomial cdf | |
329 | |
330 template <class RealType, class Policy> | |
331 RealType cdf(const complemented2_type<poisson_distribution<RealType, Policy>, RealType>& c) | |
332 { // Complemented Cumulative Distribution Function Poisson | |
333 // The random variate k is the number of events, occurrences or arrivals. | |
334 // k argument may be integral, signed, or unsigned, or floating point. | |
335 // If necessary, it has already been promoted from an integral type. | |
336 // But note that the Poisson distribution | |
337 // (like others including the binomial, negative binomial & Bernoulli) | |
338 // is strictly defined as a discrete function: only integral values of k are envisaged. | |
339 // However because of the method of calculation using a continuous gamma function, | |
340 // it is convenient to treat it as is it is a continous function | |
341 // and permit non-integral values of k. | |
342 // To enforce the strict mathematical model, users should use floor or ceil functions | |
343 // outside this function to ensure that k is integral. | |
344 | |
345 // Returns the sum of the terms k+1 through inf of the Poisson Probability Density/Mass (pdf). | |
346 // The terms are not summed directly (at least for larger k) | |
347 // instead the incomplete gamma integral is employed, | |
348 | |
349 RealType const& k = c.param; | |
350 poisson_distribution<RealType, Policy> const& dist = c.dist; | |
351 | |
352 RealType mean = dist.mean(); | |
353 | |
354 // Error checks: | |
355 RealType result = 0; | |
356 if(false == poisson_detail::check_dist_and_k( | |
357 "boost::math::cdf(const poisson_distribution<%1%>&, %1%)", | |
358 mean, | |
359 k, | |
360 &result, Policy())) | |
361 { | |
362 return result; | |
363 } | |
364 // Special case of mean, regardless of the number of events k. | |
365 if (mean == 0) | |
366 { // Probability for any k is unity, complement of zero. | |
367 return 1; | |
368 } | |
369 if (k == 0) | |
370 { // Avoid repeated checks on k and mean in gamma_p. | |
371 return -boost::math::expm1(-mean, Policy()); | |
372 } | |
373 // Unlike un-complemented cdf (sum from 0 to k), | |
374 // can't use finite sum from k+1 to infinity for small integral k, | |
375 // anyway it is now done efficiently by gamma_p. | |
376 return gamma_p(k + 1, mean, Policy()); // Calculate Poisson cdf using the gamma_p function. | |
377 // CCDF = gamma_p(k+1, lambda) | |
378 } // poisson ccdf | |
379 | |
380 template <class RealType, class Policy> | |
381 inline RealType quantile(const poisson_distribution<RealType, Policy>& dist, const RealType& p) | |
382 { // Quantile (or Percent Point) Poisson function. | |
383 // Return the number of expected events k for a given probability p. | |
384 static const char* function = "boost::math::quantile(const poisson_distribution<%1%>&, %1%)"; | |
385 RealType result = 0; // of Argument checks: | |
386 if(false == poisson_detail::check_prob( | |
387 function, | |
388 p, | |
389 &result, Policy())) | |
390 { | |
391 return result; | |
392 } | |
393 // Special case: | |
394 if (dist.mean() == 0) | |
395 { // if mean = 0 then p = 0, so k can be anything? | |
396 if (false == poisson_detail::check_mean_NZ( | |
397 function, | |
398 dist.mean(), | |
399 &result, Policy())) | |
400 { | |
401 return result; | |
402 } | |
403 } | |
404 if(p == 0) | |
405 { | |
406 return 0; // Exact result regardless of discrete-quantile Policy | |
407 } | |
408 if(p == 1) | |
409 { | |
410 return policies::raise_overflow_error<RealType>(function, 0, Policy()); | |
411 } | |
412 typedef typename Policy::discrete_quantile_type discrete_type; | |
413 boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>(); | |
414 RealType guess, factor = 8; | |
415 RealType z = dist.mean(); | |
416 if(z < 1) | |
417 guess = z; | |
418 else | |
419 guess = boost::math::detail::inverse_poisson_cornish_fisher(z, p, RealType(1-p), Policy()); | |
420 if(z > 5) | |
421 { | |
422 if(z > 1000) | |
423 factor = 1.01f; | |
424 else if(z > 50) | |
425 factor = 1.1f; | |
426 else if(guess > 10) | |
427 factor = 1.25f; | |
428 else | |
429 factor = 2; | |
430 if(guess < 1.1) | |
431 factor = 8; | |
432 } | |
433 | |
434 return detail::inverse_discrete_quantile( | |
435 dist, | |
436 p, | |
437 false, | |
438 guess, | |
439 factor, | |
440 RealType(1), | |
441 discrete_type(), | |
442 max_iter); | |
443 } // quantile | |
444 | |
445 template <class RealType, class Policy> | |
446 inline RealType quantile(const complemented2_type<poisson_distribution<RealType, Policy>, RealType>& c) | |
447 { // Quantile (or Percent Point) of Poisson function. | |
448 // Return the number of expected events k for a given | |
449 // complement of the probability q. | |
450 // | |
451 // Error checks: | |
452 static const char* function = "boost::math::quantile(complement(const poisson_distribution<%1%>&, %1%))"; | |
453 RealType q = c.param; | |
454 const poisson_distribution<RealType, Policy>& dist = c.dist; | |
455 RealType result = 0; // of argument checks. | |
456 if(false == poisson_detail::check_prob( | |
457 function, | |
458 q, | |
459 &result, Policy())) | |
460 { | |
461 return result; | |
462 } | |
463 // Special case: | |
464 if (dist.mean() == 0) | |
465 { // if mean = 0 then p = 0, so k can be anything? | |
466 if (false == poisson_detail::check_mean_NZ( | |
467 function, | |
468 dist.mean(), | |
469 &result, Policy())) | |
470 { | |
471 return result; | |
472 } | |
473 } | |
474 if(q == 0) | |
475 { | |
476 return policies::raise_overflow_error<RealType>(function, 0, Policy()); | |
477 } | |
478 if(q == 1) | |
479 { | |
480 return 0; // Exact result regardless of discrete-quantile Policy | |
481 } | |
482 typedef typename Policy::discrete_quantile_type discrete_type; | |
483 boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>(); | |
484 RealType guess, factor = 8; | |
485 RealType z = dist.mean(); | |
486 if(z < 1) | |
487 guess = z; | |
488 else | |
489 guess = boost::math::detail::inverse_poisson_cornish_fisher(z, RealType(1-q), q, Policy()); | |
490 if(z > 5) | |
491 { | |
492 if(z > 1000) | |
493 factor = 1.01f; | |
494 else if(z > 50) | |
495 factor = 1.1f; | |
496 else if(guess > 10) | |
497 factor = 1.25f; | |
498 else | |
499 factor = 2; | |
500 if(guess < 1.1) | |
501 factor = 8; | |
502 } | |
503 | |
504 return detail::inverse_discrete_quantile( | |
505 dist, | |
506 q, | |
507 true, | |
508 guess, | |
509 factor, | |
510 RealType(1), | |
511 discrete_type(), | |
512 max_iter); | |
513 } // quantile complement. | |
514 | |
515 } // namespace math | |
516 } // namespace boost | |
517 | |
518 // This include must be at the end, *after* the accessors | |
519 // for this distribution have been defined, in order to | |
520 // keep compilers that support two-phase lookup happy. | |
521 #include <boost/math/distributions/detail/derived_accessors.hpp> | |
522 #include <boost/math/distributions/detail/inv_discrete_quantile.hpp> | |
523 | |
524 #endif // BOOST_MATH_SPECIAL_POISSON_HPP | |
525 | |
526 | |
527 |