poisson.hpp 20 KB

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