File indexing completed on 2025-09-17 08:35:33
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 #ifndef BOOST_MATH_SPECIAL_POISSON_HPP
0038 #define BOOST_MATH_SPECIAL_POISSON_HPP
0039
0040 #include <boost/math/tools/config.hpp>
0041 #include <boost/math/tools/tuple.hpp>
0042 #include <boost/math/tools/cstdint.hpp>
0043 #include <boost/math/tools/numeric_limits.hpp>
0044 #include <boost/math/distributions/fwd.hpp>
0045 #include <boost/math/special_functions/gamma.hpp> // for incomplete gamma. gamma_q
0046 #include <boost/math/special_functions/trunc.hpp> // for incomplete gamma. gamma_q
0047 #include <boost/math/distributions/complement.hpp> // complements
0048 #include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
0049 #include <boost/math/special_functions/fpclassify.hpp> // isnan.
0050 #include <boost/math/special_functions/factorials.hpp> // factorials.
0051 #include <boost/math/tools/roots.hpp> // for root finding.
0052 #include <boost/math/distributions/detail/inv_discrete_quantile.hpp>
0053
0054 namespace boost
0055 {
0056 namespace math
0057 {
0058 namespace poisson_detail
0059 {
0060
0061
0062
0063
0064 template <class RealType, class Policy>
0065 BOOST_MATH_GPU_ENABLED inline bool check_mean(const char* function, const RealType& mean, RealType* result, const Policy& pol)
0066 {
0067 if(!(boost::math::isfinite)(mean) || (mean < 0))
0068 {
0069 *result = policies::raise_domain_error<RealType>(
0070 function,
0071 "Mean argument is %1%, but must be >= 0 !", mean, pol);
0072 return false;
0073 }
0074 return true;
0075 }
0076
0077 template <class RealType, class Policy>
0078 BOOST_MATH_GPU_ENABLED inline bool check_mean_NZ(const char* function, const RealType& mean, RealType* result, const Policy& pol)
0079 {
0080 if( !(boost::math::isfinite)(mean) || (mean <= 0))
0081 {
0082 *result = policies::raise_domain_error<RealType>(
0083 function,
0084 "Mean argument is %1%, but must be > 0 !", mean, pol);
0085 return false;
0086 }
0087 return true;
0088 }
0089
0090 template <class RealType, class Policy>
0091 BOOST_MATH_GPU_ENABLED inline bool check_dist(const char* function, const RealType& mean, RealType* result, const Policy& pol)
0092 {
0093 return check_mean_NZ(function, mean, result, pol);
0094 }
0095
0096 template <class RealType, class Policy>
0097 BOOST_MATH_GPU_ENABLED inline bool check_k(const char* function, const RealType& k, RealType* result, const Policy& pol)
0098 {
0099 if((k < 0) || !(boost::math::isfinite)(k))
0100 {
0101 *result = policies::raise_domain_error<RealType>(
0102 function,
0103 "Number of events k argument is %1%, but must be >= 0 !", k, pol);
0104 return false;
0105 }
0106 return true;
0107 }
0108
0109 template <class RealType, class Policy>
0110 BOOST_MATH_GPU_ENABLED inline bool check_dist_and_k(const char* function, RealType mean, RealType k, RealType* result, const Policy& pol)
0111 {
0112 if((check_dist(function, mean, result, pol) == false) ||
0113 (check_k(function, k, result, pol) == false))
0114 {
0115 return false;
0116 }
0117 return true;
0118 }
0119
0120 template <class RealType, class Policy>
0121 BOOST_MATH_GPU_ENABLED inline bool check_prob(const char* function, const RealType& p, RealType* result, const Policy& pol)
0122 {
0123 if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1))
0124 {
0125 *result = policies::raise_domain_error<RealType>(
0126 function,
0127 "Probability argument is %1%, but must be >= 0 and <= 1 !", p, pol);
0128 return false;
0129 }
0130 return true;
0131 }
0132
0133 template <class RealType, class Policy>
0134 BOOST_MATH_GPU_ENABLED inline bool check_dist_and_prob(const char* function, RealType mean, RealType p, RealType* result, const Policy& pol)
0135 {
0136 if((check_dist(function, mean, result, pol) == false) ||
0137 (check_prob(function, p, result, pol) == false))
0138 {
0139 return false;
0140 }
0141 return true;
0142 }
0143
0144 }
0145
0146 template <class RealType = double, class Policy = policies::policy<> >
0147 class poisson_distribution
0148 {
0149 public:
0150 using value_type = RealType;
0151 using policy_type = Policy;
0152
0153 BOOST_MATH_GPU_ENABLED explicit poisson_distribution(RealType l_mean = 1) : m_l(l_mean)
0154 {
0155 RealType r;
0156 poisson_detail::check_dist(
0157 "boost::math::poisson_distribution<%1%>::poisson_distribution",
0158 m_l,
0159 &r, Policy());
0160 }
0161
0162 BOOST_MATH_GPU_ENABLED RealType mean() const
0163 {
0164 return m_l;
0165 }
0166 private:
0167
0168 RealType m_l;
0169 };
0170
0171 using poisson = poisson_distribution<double>;
0172
0173 #ifdef __cpp_deduction_guides
0174 template <class RealType>
0175 poisson_distribution(RealType)->poisson_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0176 #endif
0177
0178
0179
0180 template <class RealType, class Policy>
0181 BOOST_MATH_GPU_ENABLED inline boost::math::pair<RealType, RealType> range(const poisson_distribution<RealType, Policy>& )
0182 {
0183 using boost::math::tools::max_value;
0184 return boost::math::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
0185 }
0186
0187 template <class RealType, class Policy>
0188 BOOST_MATH_GPU_ENABLED inline boost::math::pair<RealType, RealType> support(const poisson_distribution<RealType, Policy>& )
0189 {
0190
0191 using boost::math::tools::max_value;
0192 return boost::math::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
0193 }
0194
0195 template <class RealType, class Policy>
0196 BOOST_MATH_GPU_ENABLED inline RealType mean(const poisson_distribution<RealType, Policy>& dist)
0197 {
0198 return dist.mean();
0199 }
0200
0201 template <class RealType, class Policy>
0202 BOOST_MATH_GPU_ENABLED inline RealType mode(const poisson_distribution<RealType, Policy>& dist)
0203 {
0204 BOOST_MATH_STD_USING
0205 return floor(dist.mean());
0206 }
0207
0208
0209
0210 template <class RealType, class Policy>
0211 BOOST_MATH_GPU_ENABLED inline RealType variance(const poisson_distribution<RealType, Policy>& dist)
0212 {
0213 return dist.mean();
0214 }
0215
0216
0217
0218 template <class RealType, class Policy>
0219 BOOST_MATH_GPU_ENABLED inline RealType skewness(const poisson_distribution<RealType, Policy>& dist)
0220 {
0221 BOOST_MATH_STD_USING
0222 return 1 / sqrt(dist.mean());
0223 }
0224
0225 template <class RealType, class Policy>
0226 BOOST_MATH_GPU_ENABLED inline RealType kurtosis_excess(const poisson_distribution<RealType, Policy>& dist)
0227 {
0228 return 1 / dist.mean();
0229
0230
0231
0232 }
0233
0234 template <class RealType, class Policy>
0235 BOOST_MATH_GPU_ENABLED inline RealType kurtosis(const poisson_distribution<RealType, Policy>& dist)
0236 {
0237
0238
0239
0240 return 3 + 1 / dist.mean();
0241
0242
0243
0244 }
0245
0246 template <class RealType, class Policy>
0247 BOOST_MATH_GPU_ENABLED RealType pdf(const poisson_distribution<RealType, Policy>& dist, const RealType& k)
0248 {
0249
0250 BOOST_FPU_EXCEPTION_GUARD
0251
0252 BOOST_MATH_STD_USING
0253
0254 RealType mean = dist.mean();
0255
0256 RealType result = 0;
0257 if(false == poisson_detail::check_dist_and_k(
0258 "boost::math::pdf(const poisson_distribution<%1%>&, %1%)",
0259 mean,
0260 k,
0261 &result, Policy()))
0262 {
0263 return result;
0264 }
0265
0266
0267 if (mean == 0)
0268 {
0269 return 0;
0270 }
0271 if (k == 0)
0272 {
0273 return exp(-mean);
0274 }
0275 return boost::math::gamma_p_derivative(k+1, mean, Policy());
0276 }
0277
0278 template <class RealType, class Policy>
0279 BOOST_MATH_GPU_ENABLED RealType logpdf(const poisson_distribution<RealType, Policy>& dist, const RealType& k)
0280 {
0281 BOOST_FPU_EXCEPTION_GUARD
0282
0283 BOOST_MATH_STD_USING
0284 using boost::math::lgamma;
0285
0286 RealType mean = dist.mean();
0287
0288 RealType result = -boost::math::numeric_limits<RealType>::infinity();
0289 if(false == poisson_detail::check_dist_and_k(
0290 "boost::math::pdf(const poisson_distribution<%1%>&, %1%)",
0291 mean,
0292 k,
0293 &result, Policy()))
0294 {
0295 return result;
0296 }
0297
0298
0299 if (mean == 0)
0300 {
0301 return boost::math::numeric_limits<RealType>::quiet_NaN();
0302 }
0303
0304
0305 if(k > 0 && mean > 0)
0306 {
0307 return -lgamma(k+1) + k*log(mean) - mean;
0308 }
0309
0310 result = log(pdf(dist, k));
0311 return result;
0312 }
0313
0314 template <class RealType, class Policy>
0315 BOOST_MATH_GPU_ENABLED RealType cdf(const poisson_distribution<RealType, Policy>& dist, const RealType& k)
0316 {
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334 BOOST_MATH_STD_USING
0335
0336 RealType mean = dist.mean();
0337
0338 RealType result = 0;
0339 if(false == poisson_detail::check_dist_and_k(
0340 "boost::math::cdf(const poisson_distribution<%1%>&, %1%)",
0341 mean,
0342 k,
0343 &result, Policy()))
0344 {
0345 return result;
0346 }
0347
0348 if (mean == 0)
0349 {
0350 return 0;
0351 }
0352 if (k == 0)
0353 {
0354
0355
0356 return exp(-mean);
0357 }
0358
0359
0360
0361
0362 return gamma_q(k+1, mean, Policy());
0363 }
0364
0365 template <class RealType, class Policy>
0366 BOOST_MATH_GPU_ENABLED RealType cdf(const complemented2_type<poisson_distribution<RealType, Policy>, RealType>& c)
0367 {
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384 RealType const& k = c.param;
0385 poisson_distribution<RealType, Policy> const& dist = c.dist;
0386
0387 RealType mean = dist.mean();
0388
0389
0390 RealType result = 0;
0391 if(false == poisson_detail::check_dist_and_k(
0392 "boost::math::cdf(const poisson_distribution<%1%>&, %1%)",
0393 mean,
0394 k,
0395 &result, Policy()))
0396 {
0397 return result;
0398 }
0399
0400 if (mean == 0)
0401 {
0402 return 1;
0403 }
0404 if (k == 0)
0405 {
0406 return -boost::math::expm1(-mean, Policy());
0407 }
0408
0409
0410
0411 return gamma_p(k + 1, mean, Policy());
0412
0413 }
0414
0415 template <class RealType, class Policy>
0416 BOOST_MATH_GPU_ENABLED inline RealType quantile(const poisson_distribution<RealType, Policy>& dist, const RealType& p)
0417 {
0418
0419 constexpr auto function = "boost::math::quantile(const poisson_distribution<%1%>&, %1%)";
0420 RealType result = 0;
0421 if(false == poisson_detail::check_prob(
0422 function,
0423 p,
0424 &result, Policy()))
0425 {
0426 return result;
0427 }
0428
0429 if (dist.mean() == 0)
0430 {
0431 if (false == poisson_detail::check_mean_NZ(
0432 function,
0433 dist.mean(),
0434 &result, Policy()))
0435 {
0436 return result;
0437 }
0438 }
0439 if(p == 0)
0440 {
0441 return 0;
0442 }
0443 if(p == 1)
0444 {
0445 return policies::raise_overflow_error<RealType>(function, 0, Policy());
0446 }
0447 using discrete_type = typename Policy::discrete_quantile_type;
0448 boost::math::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0449 RealType guess;
0450 RealType factor = 8;
0451 RealType z = dist.mean();
0452 if(z < 1)
0453 guess = z;
0454 else
0455 guess = boost::math::detail::inverse_poisson_cornish_fisher(z, p, RealType(1-p), Policy());
0456 if(z > 5)
0457 {
0458 if(z > 1000)
0459 factor = 1.01f;
0460 else if(z > 50)
0461 factor = 1.1f;
0462 else if(guess > 10)
0463 factor = 1.25f;
0464 else
0465 factor = 2;
0466 if(guess < 1.1)
0467 factor = 8;
0468 }
0469
0470 return detail::inverse_discrete_quantile(
0471 dist,
0472 p,
0473 false,
0474 guess,
0475 factor,
0476 RealType(1),
0477 discrete_type(),
0478 max_iter);
0479 }
0480
0481 template <class RealType, class Policy>
0482 BOOST_MATH_GPU_ENABLED inline RealType quantile(const complemented2_type<poisson_distribution<RealType, Policy>, RealType>& c)
0483 {
0484
0485
0486
0487
0488 constexpr auto function = "boost::math::quantile(complement(const poisson_distribution<%1%>&, %1%))";
0489 RealType q = c.param;
0490 const poisson_distribution<RealType, Policy>& dist = c.dist;
0491 RealType result = 0;
0492 if(false == poisson_detail::check_prob(
0493 function,
0494 q,
0495 &result, Policy()))
0496 {
0497 return result;
0498 }
0499
0500 if (dist.mean() == 0)
0501 {
0502 if (false == poisson_detail::check_mean_NZ(
0503 function,
0504 dist.mean(),
0505 &result, Policy()))
0506 {
0507 return result;
0508 }
0509 }
0510 if(q == 0)
0511 {
0512 return policies::raise_overflow_error<RealType>(function, 0, Policy());
0513 }
0514 if(q == 1)
0515 {
0516 return 0;
0517 }
0518 using discrete_type = typename Policy::discrete_quantile_type;
0519 boost::math::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0520 RealType guess;
0521 RealType factor = 8;
0522 RealType z = dist.mean();
0523 if(z < 1)
0524 guess = z;
0525 else
0526 guess = boost::math::detail::inverse_poisson_cornish_fisher(z, RealType(1-q), q, Policy());
0527 if(z > 5)
0528 {
0529 if(z > 1000)
0530 factor = 1.01f;
0531 else if(z > 50)
0532 factor = 1.1f;
0533 else if(guess > 10)
0534 factor = 1.25f;
0535 else
0536 factor = 2;
0537 if(guess < 1.1)
0538 factor = 8;
0539 }
0540
0541 return detail::inverse_discrete_quantile(
0542 dist,
0543 q,
0544 true,
0545 guess,
0546 factor,
0547 RealType(1),
0548 discrete_type(),
0549 max_iter);
0550 }
0551
0552 }
0553 }
0554
0555
0556
0557
0558 #include <boost/math/distributions/detail/derived_accessors.hpp>
0559
0560 #endif
0561
0562
0563