poisson.hpp 20 KB

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