Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:39:44

0001 // boost\math\distributions\poisson.hpp
0002 
0003 // Copyright John Maddock 2006.
0004 // Copyright Paul A. Bristow 2007.
0005 
0006 // Use, modification and distribution are subject to the
0007 // Boost Software License, Version 1.0.
0008 // (See accompanying file LICENSE_1_0.txt
0009 // or copy at http://www.boost.org/LICENSE_1_0.txt)
0010 
0011 // Poisson distribution is a discrete probability distribution.
0012 // It expresses the probability of a number (k) of
0013 // events, occurrences, failures or arrivals occurring in a fixed time,
0014 // assuming these events occur with a known average or mean rate (lambda)
0015 // and are independent of the time since the last event.
0016 // The distribution was discovered by Simeon-Denis Poisson (1781-1840).
0017 
0018 // Parameter lambda is the mean number of events in the given time interval.
0019 // The random variate k is the number of events, occurrences or arrivals.
0020 // k argument may be integral, signed, or unsigned, or floating point.
0021 // If necessary, it has already been promoted from an integral type.
0022 
0023 // Note that the Poisson distribution
0024 // (like others including the binomial, negative binomial & Bernoulli)
0025 // is strictly defined as a discrete function:
0026 // only integral values of k are envisaged.
0027 // However because the method of calculation uses a continuous gamma function,
0028 // it is convenient to treat it as if a continuous function,
0029 // and permit non-integral values of k.
0030 // To enforce the strict mathematical model, users should use floor or ceil functions
0031 // on k outside this function to ensure that k is integral.
0032 
0033 // See http://en.wikipedia.org/wiki/Poisson_distribution
0034 // http://documents.wolfram.com/v5/Add-onsLinks/StandardPackages/Statistics/DiscreteDistributions.html
0035 
0036 #ifndef BOOST_MATH_SPECIAL_POISSON_HPP
0037 #define BOOST_MATH_SPECIAL_POISSON_HPP
0038 
0039 #include <boost/math/distributions/fwd.hpp>
0040 #include <boost/math/special_functions/gamma.hpp> // for incomplete gamma. gamma_q
0041 #include <boost/math/special_functions/trunc.hpp> // for incomplete gamma. gamma_q
0042 #include <boost/math/distributions/complement.hpp> // complements
0043 #include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
0044 #include <boost/math/special_functions/fpclassify.hpp> // isnan.
0045 #include <boost/math/special_functions/factorials.hpp> // factorials.
0046 #include <boost/math/tools/roots.hpp> // for root finding.
0047 #include <boost/math/distributions/detail/inv_discrete_quantile.hpp>
0048 
0049 #include <utility>
0050 #include <limits>
0051 
0052 namespace boost
0053 {
0054   namespace math
0055   {
0056     namespace poisson_detail
0057     {
0058       // Common error checking routines for Poisson distribution functions.
0059       // These are convoluted, & apparently redundant, to try to ensure that
0060       // checks are always performed, even if exceptions are not enabled.
0061 
0062       template <class RealType, class Policy>
0063       inline bool check_mean(const char* function, const RealType& mean, RealType* result, const Policy& pol)
0064       {
0065         if(!(boost::math::isfinite)(mean) || (mean < 0))
0066         {
0067           *result = policies::raise_domain_error<RealType>(
0068             function,
0069             "Mean argument is %1%, but must be >= 0 !", mean, pol);
0070           return false;
0071         }
0072         return true;
0073       } // bool check_mean
0074 
0075       template <class RealType, class Policy>
0076       inline bool check_mean_NZ(const char* function, const RealType& mean, RealType* result, const Policy& pol)
0077       { // mean == 0 is considered an error.
0078         if( !(boost::math::isfinite)(mean) || (mean <= 0))
0079         {
0080           *result = policies::raise_domain_error<RealType>(
0081             function,
0082             "Mean argument is %1%, but must be > 0 !", mean, pol);
0083           return false;
0084         }
0085         return true;
0086       } // bool check_mean_NZ
0087 
0088       template <class RealType, class Policy>
0089       inline bool check_dist(const char* function, const RealType& mean, RealType* result, const Policy& pol)
0090       { // Only one check, so this is redundant really but should be optimized away.
0091         return check_mean_NZ(function, mean, result, pol);
0092       } // bool check_dist
0093 
0094       template <class RealType, class Policy>
0095       inline bool check_k(const char* function, const RealType& k, RealType* result, const Policy& pol)
0096       {
0097         if((k < 0) || !(boost::math::isfinite)(k))
0098         {
0099           *result = policies::raise_domain_error<RealType>(
0100             function,
0101             "Number of events k argument is %1%, but must be >= 0 !", k, pol);
0102           return false;
0103         }
0104         return true;
0105       } // bool check_k
0106 
0107       template <class RealType, class Policy>
0108       inline bool check_dist_and_k(const char* function, RealType mean, RealType k, RealType* result, const Policy& pol)
0109       {
0110         if((check_dist(function, mean, result, pol) == false) ||
0111           (check_k(function, k, result, pol) == false))
0112         {
0113           return false;
0114         }
0115         return true;
0116       } // bool check_dist_and_k
0117 
0118       template <class RealType, class Policy>
0119       inline bool check_prob(const char* function, const RealType& p, RealType* result, const Policy& pol)
0120       { // Check 0 <= p <= 1
0121         if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1))
0122         {
0123           *result = policies::raise_domain_error<RealType>(
0124             function,
0125             "Probability argument is %1%, but must be >= 0 and <= 1 !", p, pol);
0126           return false;
0127         }
0128         return true;
0129       } // bool check_prob
0130 
0131       template <class RealType, class Policy>
0132       inline bool check_dist_and_prob(const char* function, RealType mean,  RealType p, RealType* result, const Policy& pol)
0133       {
0134         if((check_dist(function, mean, result, pol) == false) ||
0135           (check_prob(function, p, result, pol) == false))
0136         {
0137           return false;
0138         }
0139         return true;
0140       } // bool check_dist_and_prob
0141 
0142     } // namespace poisson_detail
0143 
0144     template <class RealType = double, class Policy = policies::policy<> >
0145     class poisson_distribution
0146     {
0147     public:
0148       using value_type = RealType;
0149       using policy_type = Policy;
0150 
0151       explicit poisson_distribution(RealType l_mean = 1) : m_l(l_mean) // mean (lambda).
0152       { // Expected mean number of events that occur during the given interval.
0153         RealType r;
0154         poisson_detail::check_dist(
0155            "boost::math::poisson_distribution<%1%>::poisson_distribution",
0156           m_l,
0157           &r, Policy());
0158       } // poisson_distribution constructor.
0159 
0160       RealType mean() const
0161       { // Private data getter function.
0162         return m_l;
0163       }
0164     private:
0165       // Data member, initialized by constructor.
0166       RealType m_l; // mean number of occurrences.
0167     }; // template <class RealType, class Policy> class poisson_distribution
0168 
0169     using poisson = poisson_distribution<double>; // Reserved name of type double.
0170 
0171     #ifdef __cpp_deduction_guides
0172     template <class RealType>
0173     poisson_distribution(RealType)->poisson_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0174     #endif
0175 
0176     // Non-member functions to give properties of the distribution.
0177 
0178     template <class RealType, class Policy>
0179     inline std::pair<RealType, RealType> range(const poisson_distribution<RealType, Policy>& /* dist */)
0180     { // Range of permissible values for random variable k.
0181        using boost::math::tools::max_value;
0182        return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>()); // Max integer?
0183     }
0184 
0185     template <class RealType, class Policy>
0186     inline std::pair<RealType, RealType> support(const poisson_distribution<RealType, Policy>& /* dist */)
0187     { // Range of supported values for random variable k.
0188        // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
0189        using boost::math::tools::max_value;
0190        return std::pair<RealType, RealType>(static_cast<RealType>(0),  max_value<RealType>());
0191     }
0192 
0193     template <class RealType, class Policy>
0194     inline RealType mean(const poisson_distribution<RealType, Policy>& dist)
0195     { // Mean of poisson distribution = lambda.
0196       return dist.mean();
0197     } // mean
0198 
0199     template <class RealType, class Policy>
0200     inline RealType mode(const poisson_distribution<RealType, Policy>& dist)
0201     { // mode.
0202       BOOST_MATH_STD_USING // ADL of std functions.
0203       return floor(dist.mean());
0204     }
0205 
0206     // Median now implemented via quantile(half) in derived accessors.
0207 
0208     template <class RealType, class Policy>
0209     inline RealType variance(const poisson_distribution<RealType, Policy>& dist)
0210     { // variance.
0211       return dist.mean();
0212     }
0213 
0214     // standard_deviation provided by derived accessors.
0215 
0216     template <class RealType, class Policy>
0217     inline RealType skewness(const poisson_distribution<RealType, Policy>& dist)
0218     { // skewness = sqrt(l).
0219       BOOST_MATH_STD_USING // ADL of std functions.
0220       return 1 / sqrt(dist.mean());
0221     }
0222 
0223     template <class RealType, class Policy>
0224     inline RealType kurtosis_excess(const poisson_distribution<RealType, Policy>& dist)
0225     { // skewness = sqrt(l).
0226       return 1 / dist.mean(); // kurtosis_excess 1/mean from Wiki & MathWorld eq 31.
0227       // http://mathworld.wolfram.com/Kurtosis.html explains that the kurtosis excess
0228       // is more convenient because the kurtosis excess of a normal distribution is zero
0229       // whereas the true kurtosis is 3.
0230     } // RealType kurtosis_excess
0231 
0232     template <class RealType, class Policy>
0233     inline RealType kurtosis(const poisson_distribution<RealType, Policy>& dist)
0234     { // kurtosis is 4th moment about the mean = u4 / sd ^ 4
0235       // http://en.wikipedia.org/wiki/Kurtosis
0236       // kurtosis can range from -2 (flat top) to +infinity (sharp peak & heavy tails).
0237       // http://www.itl.nist.gov/div898/handbook/eda/section3/eda35b.htm
0238       return 3 + 1 / dist.mean(); // NIST.
0239       // http://mathworld.wolfram.com/Kurtosis.html explains that the kurtosis excess
0240       // is more convenient because the kurtosis excess of a normal distribution is zero
0241       // whereas the true kurtosis is 3.
0242     } // RealType kurtosis
0243 
0244     template <class RealType, class Policy>
0245     RealType pdf(const poisson_distribution<RealType, Policy>& dist, const RealType& k)
0246     { // Probability Density/Mass Function.
0247       // Probability that there are EXACTLY k occurrences (or arrivals).
0248       BOOST_FPU_EXCEPTION_GUARD
0249 
0250       BOOST_MATH_STD_USING // for ADL of std functions.
0251 
0252       RealType mean = dist.mean();
0253       // Error check:
0254       RealType result = 0;
0255       if(false == poisson_detail::check_dist_and_k(
0256         "boost::math::pdf(const poisson_distribution<%1%>&, %1%)",
0257         mean,
0258         k,
0259         &result, Policy()))
0260       {
0261         return result;
0262       }
0263 
0264       // Special case of mean zero, regardless of the number of events k.
0265       if (mean == 0)
0266       { // Probability for any k is zero.
0267         return 0;
0268       }
0269       if (k == 0)
0270       { // mean ^ k = 1, and k! = 1, so can simplify.
0271         return exp(-mean);
0272       }
0273       return boost::math::gamma_p_derivative(k+1, mean, Policy());
0274     } // pdf
0275 
0276     template <class RealType, class Policy>
0277     RealType logpdf(const poisson_distribution<RealType, Policy>& dist, const RealType& k)
0278     {
0279       BOOST_FPU_EXCEPTION_GUARD
0280 
0281       BOOST_MATH_STD_USING // for ADL of std functions.
0282       using boost::math::lgamma;
0283 
0284       RealType mean = dist.mean();
0285       // Error check:
0286       RealType result = -std::numeric_limits<RealType>::infinity();
0287       if(false == poisson_detail::check_dist_and_k(
0288         "boost::math::pdf(const poisson_distribution<%1%>&, %1%)",
0289         mean,
0290         k,
0291         &result, Policy()))
0292       {
0293         return result;
0294       }
0295 
0296       // Special case of mean zero, regardless of the number of events k.
0297       if (mean == 0)
0298       { // Probability for any k is zero.
0299         return std::numeric_limits<RealType>::quiet_NaN();
0300       }
0301       
0302       // Special case where k and lambda are both positive
0303       if(k > 0 && mean > 0)
0304       {
0305         return -lgamma(k+1) + k*log(mean) - mean;
0306       }
0307 
0308       result = log(pdf(dist, k));
0309       return result;
0310     }
0311 
0312     template <class RealType, class Policy>
0313     RealType cdf(const poisson_distribution<RealType, Policy>& dist, const RealType& k)
0314     { // Cumulative Distribution Function Poisson.
0315       // The random variate k is the number of occurrences(or arrivals)
0316       // k argument may be integral, signed, or unsigned, or floating point.
0317       // If necessary, it has already been promoted from an integral type.
0318       // Returns the sum of the terms 0 through k of the Poisson Probability Density or Mass (pdf).
0319 
0320       // But note that the Poisson distribution
0321       // (like others including the binomial, negative binomial & Bernoulli)
0322       // is strictly defined as a discrete function: only integral values of k are envisaged.
0323       // However because of the method of calculation using a continuous gamma function,
0324       // it is convenient to treat it as if it is a continuous function
0325       // and permit non-integral values of k.
0326       // To enforce the strict mathematical model, users should use floor or ceil functions
0327       // outside this function to ensure that k is integral.
0328 
0329       // The terms are not summed directly (at least for larger k)
0330       // instead the incomplete gamma integral is employed,
0331 
0332       BOOST_MATH_STD_USING // for ADL of std function exp.
0333 
0334       RealType mean = dist.mean();
0335       // Error checks:
0336       RealType result = 0;
0337       if(false == poisson_detail::check_dist_and_k(
0338         "boost::math::cdf(const poisson_distribution<%1%>&, %1%)",
0339         mean,
0340         k,
0341         &result, Policy()))
0342       {
0343         return result;
0344       }
0345       // Special cases:
0346       if (mean == 0)
0347       { // Probability for any k is zero.
0348         return 0;
0349       }
0350       if (k == 0)
0351       {
0352         // mean (and k) have already been checked,
0353         // so this avoids unnecessary repeated checks.
0354        return exp(-mean);
0355       }
0356       // For small integral k could use a finite sum -
0357       // it's cheaper than the gamma function.
0358       // BUT this is now done efficiently by gamma_q function.
0359       // Calculate poisson cdf using the gamma_q function.
0360       return gamma_q(k+1, mean, Policy());
0361     } // binomial cdf
0362 
0363     template <class RealType, class Policy>
0364     RealType cdf(const complemented2_type<poisson_distribution<RealType, Policy>, RealType>& c)
0365     { // Complemented Cumulative Distribution Function Poisson
0366       // The random variate k is the number of events, occurrences or arrivals.
0367       // k argument may be integral, signed, or unsigned, or floating point.
0368       // If necessary, it has already been promoted from an integral type.
0369       // But note that the Poisson distribution
0370       // (like others including the binomial, negative binomial & Bernoulli)
0371       // is strictly defined as a discrete function: only integral values of k are envisaged.
0372       // However because of the method of calculation using a continuous gamma function,
0373       // it is convenient to treat it as is it is a continuous function
0374       // and permit non-integral values of k.
0375       // To enforce the strict mathematical model, users should use floor or ceil functions
0376       // outside this function to ensure that k is integral.
0377 
0378       // Returns the sum of the terms k+1 through inf of the Poisson Probability Density/Mass (pdf).
0379       // The terms are not summed directly (at least for larger k)
0380       // instead the incomplete gamma integral is employed,
0381 
0382       RealType const& k = c.param;
0383       poisson_distribution<RealType, Policy> const& dist = c.dist;
0384 
0385       RealType mean = dist.mean();
0386 
0387       // Error checks:
0388       RealType result = 0;
0389       if(false == poisson_detail::check_dist_and_k(
0390         "boost::math::cdf(const poisson_distribution<%1%>&, %1%)",
0391         mean,
0392         k,
0393         &result, Policy()))
0394       {
0395         return result;
0396       }
0397       // Special case of mean, regardless of the number of events k.
0398       if (mean == 0)
0399       { // Probability for any k is unity, complement of zero.
0400         return 1;
0401       }
0402       if (k == 0)
0403       { // Avoid repeated checks on k and mean in gamma_p.
0404          return -boost::math::expm1(-mean, Policy());
0405       }
0406       // Unlike un-complemented cdf (sum from 0 to k),
0407       // can't use finite sum from k+1 to infinity for small integral k,
0408       // anyway it is now done efficiently by gamma_p.
0409       return gamma_p(k + 1, mean, Policy()); // Calculate Poisson cdf using the gamma_p function.
0410       // CCDF = gamma_p(k+1, lambda)
0411     } // poisson ccdf
0412 
0413     template <class RealType, class Policy>
0414     inline RealType quantile(const poisson_distribution<RealType, Policy>& dist, const RealType& p)
0415     { // Quantile (or Percent Point) Poisson function.
0416       // Return the number of expected events k for a given probability p.
0417       static const char* function = "boost::math::quantile(const poisson_distribution<%1%>&, %1%)";
0418       RealType result = 0; // of Argument checks:
0419       if(false == poisson_detail::check_prob(
0420         function,
0421         p,
0422         &result, Policy()))
0423       {
0424         return result;
0425       }
0426       // Special case:
0427       if (dist.mean() == 0)
0428       { // if mean = 0 then p = 0, so k can be anything?
0429          if (false == poisson_detail::check_mean_NZ(
0430          function,
0431          dist.mean(),
0432          &result, Policy()))
0433         {
0434           return result;
0435         }
0436       }
0437       if(p == 0)
0438       {
0439          return 0; // Exact result regardless of discrete-quantile Policy
0440       }
0441       if(p == 1)
0442       {
0443          return policies::raise_overflow_error<RealType>(function, 0, Policy());
0444       }
0445       using discrete_type = typename Policy::discrete_quantile_type;
0446       std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0447       RealType guess;
0448       RealType factor = 8;
0449       RealType z = dist.mean();
0450       if(z < 1)
0451          guess = z;
0452       else
0453          guess = boost::math::detail::inverse_poisson_cornish_fisher(z, p, RealType(1-p), Policy());
0454       if(z > 5)
0455       {
0456          if(z > 1000)
0457             factor = 1.01f;
0458          else if(z > 50)
0459             factor = 1.1f;
0460          else if(guess > 10)
0461             factor = 1.25f;
0462          else
0463             factor = 2;
0464          if(guess < 1.1)
0465             factor = 8;
0466       }
0467 
0468       return detail::inverse_discrete_quantile(
0469          dist,
0470          p,
0471          false,
0472          guess,
0473          factor,
0474          RealType(1),
0475          discrete_type(),
0476          max_iter);
0477    } // quantile
0478 
0479     template <class RealType, class Policy>
0480     inline RealType quantile(const complemented2_type<poisson_distribution<RealType, Policy>, RealType>& c)
0481     { // Quantile (or Percent Point) of Poisson function.
0482       // Return the number of expected events k for a given
0483       // complement of the probability q.
0484       //
0485       // Error checks:
0486       static const char* function = "boost::math::quantile(complement(const poisson_distribution<%1%>&, %1%))";
0487       RealType q = c.param;
0488       const poisson_distribution<RealType, Policy>& dist = c.dist;
0489       RealType result = 0;  // of argument checks.
0490       if(false == poisson_detail::check_prob(
0491         function,
0492         q,
0493         &result, Policy()))
0494       {
0495         return result;
0496       }
0497       // Special case:
0498       if (dist.mean() == 0)
0499       { // if mean = 0 then p = 0, so k can be anything?
0500          if (false == poisson_detail::check_mean_NZ(
0501          function,
0502          dist.mean(),
0503          &result, Policy()))
0504         {
0505           return result;
0506         }
0507       }
0508       if(q == 0)
0509       {
0510          return policies::raise_overflow_error<RealType>(function, 0, Policy());
0511       }
0512       if(q == 1)
0513       {
0514          return 0;  // Exact result regardless of discrete-quantile Policy
0515       }
0516       using discrete_type = typename Policy::discrete_quantile_type;
0517       std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0518       RealType guess;
0519       RealType factor = 8;
0520       RealType z = dist.mean();
0521       if(z < 1)
0522          guess = z;
0523       else
0524          guess = boost::math::detail::inverse_poisson_cornish_fisher(z, RealType(1-q), q, Policy());
0525       if(z > 5)
0526       {
0527          if(z > 1000)
0528             factor = 1.01f;
0529          else if(z > 50)
0530             factor = 1.1f;
0531          else if(guess > 10)
0532             factor = 1.25f;
0533          else
0534             factor = 2;
0535          if(guess < 1.1)
0536             factor = 8;
0537       }
0538 
0539       return detail::inverse_discrete_quantile(
0540          dist,
0541          q,
0542          true,
0543          guess,
0544          factor,
0545          RealType(1),
0546          discrete_type(),
0547          max_iter);
0548    } // quantile complement.
0549 
0550   } // namespace math
0551 } // namespace boost
0552 
0553 // This include must be at the end, *after* the accessors
0554 // for this distribution have been defined, in order to
0555 // keep compilers that support two-phase lookup happy.
0556 #include <boost/math/distributions/detail/derived_accessors.hpp>
0557 
0558 #endif // BOOST_MATH_SPECIAL_POISSON_HPP
0559 
0560 
0561