File indexing completed on 2025-01-18 09:39:42
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
0038
0039
0040
0041
0042
0043
0044 #ifndef BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP
0045 #define BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP
0046
0047 #include <boost/math/distributions/fwd.hpp>
0048 #include <boost/math/special_functions/beta.hpp> // for ibeta(a, b, x) == Ix(a, b).
0049 #include <boost/math/distributions/complement.hpp> // complement.
0050 #include <boost/math/distributions/detail/common_error_handling.hpp> // error checks domain_error & logic_error.
0051 #include <boost/math/special_functions/fpclassify.hpp> // isnan.
0052 #include <boost/math/tools/roots.hpp> // for root finding.
0053 #include <boost/math/distributions/detail/inv_discrete_quantile.hpp>
0054
0055 #include <limits> // using std::numeric_limits;
0056 #include <utility>
0057
0058 #if defined (BOOST_MSVC)
0059 # pragma warning(push)
0060
0061
0062
0063 #endif
0064
0065 namespace boost
0066 {
0067 namespace math
0068 {
0069 namespace negative_binomial_detail
0070 {
0071
0072 template <class RealType, class Policy>
0073 inline bool check_successes(const char* function, const RealType& r, RealType* result, const Policy& pol)
0074 {
0075 if( !(boost::math::isfinite)(r) || (r <= 0) )
0076 {
0077 *result = policies::raise_domain_error<RealType>(
0078 function,
0079 "Number of successes argument is %1%, but must be > 0 !", r, pol);
0080 return false;
0081 }
0082 return true;
0083 }
0084 template <class RealType, class Policy>
0085 inline bool check_success_fraction(const char* function, const RealType& p, RealType* result, const Policy& pol)
0086 {
0087 if( !(boost::math::isfinite)(p) || (p < 0) || (p > 1) )
0088 {
0089 *result = policies::raise_domain_error<RealType>(
0090 function,
0091 "Success fraction argument is %1%, but must be >= 0 and <= 1 !", p, pol);
0092 return false;
0093 }
0094 return true;
0095 }
0096 template <class RealType, class Policy>
0097 inline bool check_dist(const char* function, const RealType& r, const RealType& p, RealType* result, const Policy& pol)
0098 {
0099 return check_success_fraction(function, p, result, pol)
0100 && check_successes(function, r, result, pol);
0101 }
0102 template <class RealType, class Policy>
0103 inline bool check_dist_and_k(const char* function, const RealType& r, const RealType& p, RealType k, RealType* result, const Policy& pol)
0104 {
0105 if(check_dist(function, r, p, result, pol) == false)
0106 {
0107 return false;
0108 }
0109 if( !(boost::math::isfinite)(k) || (k < 0) )
0110 {
0111 *result = policies::raise_domain_error<RealType>(
0112 function,
0113 "Number of failures argument is %1%, but must be >= 0 !", k, pol);
0114 return false;
0115 }
0116 return true;
0117 }
0118
0119 template <class RealType, class Policy>
0120 inline bool check_dist_and_prob(const char* function, const RealType& r, RealType p, RealType prob, RealType* result, const Policy& pol)
0121 {
0122 if((check_dist(function, r, p, result, pol) && detail::check_probability(function, prob, result, pol)) == false)
0123 {
0124 return false;
0125 }
0126 return true;
0127 }
0128 }
0129
0130 template <class RealType = double, class Policy = policies::policy<> >
0131 class negative_binomial_distribution
0132 {
0133 public:
0134 typedef RealType value_type;
0135 typedef Policy policy_type;
0136
0137 negative_binomial_distribution(RealType r, RealType p) : m_r(r), m_p(p)
0138 {
0139 RealType result;
0140 negative_binomial_detail::check_dist(
0141 "negative_binomial_distribution<%1%>::negative_binomial_distribution",
0142 m_r,
0143 m_p,
0144 &result, Policy());
0145 }
0146
0147
0148 RealType success_fraction() const
0149 {
0150 return m_p;
0151 }
0152 RealType successes() const
0153 {
0154 return m_r;
0155 }
0156
0157 static RealType find_lower_bound_on_p(
0158 RealType trials,
0159 RealType successes,
0160 RealType alpha)
0161 {
0162 static const char* function = "boost::math::negative_binomial<%1%>::find_lower_bound_on_p";
0163 RealType result = 0;
0164 RealType failures = trials - successes;
0165 if(false == detail::check_probability(function, alpha, &result, Policy())
0166 && negative_binomial_detail::check_dist_and_k(
0167 function, successes, RealType(0), failures, &result, Policy()))
0168 {
0169 return result;
0170 }
0171
0172
0173
0174
0175
0176
0177
0178
0179 return ibeta_inv(successes, failures + 1, alpha, static_cast<RealType*>(nullptr), Policy());
0180 }
0181
0182 static RealType find_upper_bound_on_p(
0183 RealType trials,
0184 RealType successes,
0185 RealType alpha)
0186 {
0187 static const char* function = "boost::math::negative_binomial<%1%>::find_upper_bound_on_p";
0188 RealType result = 0;
0189 RealType failures = trials - successes;
0190 if(false == negative_binomial_detail::check_dist_and_k(
0191 function, successes, RealType(0), failures, &result, Policy())
0192 && detail::check_probability(function, alpha, &result, Policy()))
0193 {
0194 return result;
0195 }
0196 if(failures == 0)
0197 return 1;
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207 return ibetac_inv(successes, failures, alpha, static_cast<RealType*>(nullptr), Policy());
0208 }
0209
0210
0211
0212
0213 static RealType find_minimum_number_of_trials(
0214 RealType k,
0215 RealType p,
0216 RealType alpha)
0217 {
0218 static const char* function = "boost::math::negative_binomial<%1%>::find_minimum_number_of_trials";
0219
0220 RealType result = 0;
0221 if(false == negative_binomial_detail::check_dist_and_k(
0222 function, RealType(1), p, k, &result, Policy())
0223 && detail::check_probability(function, alpha, &result, Policy()))
0224 { return result; }
0225
0226 result = ibeta_inva(k + 1, p, alpha, Policy());
0227 return result + k;
0228 }
0229
0230 static RealType find_maximum_number_of_trials(
0231 RealType k,
0232 RealType p,
0233 RealType alpha)
0234 {
0235 static const char* function = "boost::math::negative_binomial<%1%>::find_maximum_number_of_trials";
0236
0237 RealType result = 0;
0238 if(false == negative_binomial_detail::check_dist_and_k(
0239 function, RealType(1), p, k, &result, Policy())
0240 && detail::check_probability(function, alpha, &result, Policy()))
0241 { return result; }
0242
0243 result = ibetac_inva(k + 1, p, alpha, Policy());
0244 return result + k;
0245 }
0246
0247 private:
0248 RealType m_r;
0249 RealType m_p;
0250 };
0251
0252 typedef negative_binomial_distribution<double> negative_binomial;
0253
0254 #ifdef __cpp_deduction_guides
0255 template <class RealType>
0256 negative_binomial_distribution(RealType,RealType)->negative_binomial_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0257 #endif
0258
0259 template <class RealType, class Policy>
0260 inline const std::pair<RealType, RealType> range(const negative_binomial_distribution<RealType, Policy>& )
0261 {
0262 using boost::math::tools::max_value;
0263 return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
0264 }
0265
0266 template <class RealType, class Policy>
0267 inline const std::pair<RealType, RealType> support(const negative_binomial_distribution<RealType, Policy>& )
0268 {
0269
0270 using boost::math::tools::max_value;
0271 return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
0272 }
0273
0274 template <class RealType, class Policy>
0275 inline RealType mean(const negative_binomial_distribution<RealType, Policy>& dist)
0276 {
0277 return dist.successes() * (1 - dist.success_fraction() ) / dist.success_fraction();
0278 }
0279
0280
0281
0282
0283
0284
0285
0286
0287 template <class RealType, class Policy>
0288 inline RealType mode(const negative_binomial_distribution<RealType, Policy>& dist)
0289 {
0290 BOOST_MATH_STD_USING
0291 return floor((dist.successes() -1) * (1 - dist.success_fraction()) / dist.success_fraction());
0292 }
0293
0294 template <class RealType, class Policy>
0295 inline RealType skewness(const negative_binomial_distribution<RealType, Policy>& dist)
0296 {
0297 BOOST_MATH_STD_USING
0298 RealType p = dist.success_fraction();
0299 RealType r = dist.successes();
0300
0301 return (2 - p) /
0302 sqrt(r * (1 - p));
0303 }
0304
0305 template <class RealType, class Policy>
0306 inline RealType kurtosis(const negative_binomial_distribution<RealType, Policy>& dist)
0307 {
0308
0309 RealType p = dist.success_fraction();
0310 RealType r = dist.successes();
0311 return 3 + (6 / r) + ((p * p) / (r * (1 - p)));
0312 }
0313
0314 template <class RealType, class Policy>
0315 inline RealType kurtosis_excess(const negative_binomial_distribution<RealType, Policy>& dist)
0316 {
0317
0318 RealType p = dist.success_fraction();
0319 RealType r = dist.successes();
0320 return (6 - p * (6-p)) / (r * (1-p));
0321 }
0322
0323 template <class RealType, class Policy>
0324 inline RealType variance(const negative_binomial_distribution<RealType, Policy>& dist)
0325 {
0326 return dist.successes() * (1 - dist.success_fraction())
0327 / (dist.success_fraction() * dist.success_fraction());
0328 }
0329
0330
0331
0332
0333
0334
0335
0336
0337 template <class RealType, class Policy>
0338 inline RealType pdf(const negative_binomial_distribution<RealType, Policy>& dist, const RealType& k)
0339 {
0340 BOOST_FPU_EXCEPTION_GUARD
0341
0342 static const char* function = "boost::math::pdf(const negative_binomial_distribution<%1%>&, %1%)";
0343
0344 RealType r = dist.successes();
0345 RealType p = dist.success_fraction();
0346 RealType result = 0;
0347 if(false == negative_binomial_detail::check_dist_and_k(
0348 function,
0349 r,
0350 dist.success_fraction(),
0351 k,
0352 &result, Policy()))
0353 {
0354 return result;
0355 }
0356
0357 result = (p/(r + k)) * ibeta_derivative(r, static_cast<RealType>(k+1), p, Policy());
0358
0359
0360 return result;
0361 }
0362
0363 template <class RealType, class Policy>
0364 inline RealType cdf(const negative_binomial_distribution<RealType, Policy>& dist, const RealType& k)
0365 {
0366 static const char* function = "boost::math::cdf(const negative_binomial_distribution<%1%>&, %1%)";
0367 using boost::math::ibeta;
0368
0369
0370 RealType p = dist.success_fraction();
0371 RealType r = dist.successes();
0372
0373 RealType result = 0;
0374 if(false == negative_binomial_detail::check_dist_and_k(
0375 function,
0376 r,
0377 dist.success_fraction(),
0378 k,
0379 &result, Policy()))
0380 {
0381 return result;
0382 }
0383
0384 RealType probability = ibeta(r, static_cast<RealType>(k+1), p, Policy());
0385
0386 return probability;
0387 }
0388
0389 template <class RealType, class Policy>
0390 inline RealType cdf(const complemented2_type<negative_binomial_distribution<RealType, Policy>, RealType>& c)
0391 {
0392
0393 static const char* function = "boost::math::cdf(const negative_binomial_distribution<%1%>&, %1%)";
0394 using boost::math::ibetac;
0395
0396
0397 RealType const& k = c.param;
0398 negative_binomial_distribution<RealType, Policy> const& dist = c.dist;
0399 RealType p = dist.success_fraction();
0400 RealType r = dist.successes();
0401
0402 RealType result = 0;
0403 if(false == negative_binomial_detail::check_dist_and_k(
0404 function,
0405 r,
0406 p,
0407 k,
0408 &result, Policy()))
0409 {
0410 return result;
0411 }
0412
0413
0414
0415
0416
0417 RealType probability = ibetac(r, static_cast<RealType>(k+1), p, Policy());
0418
0419
0420 return probability;
0421 }
0422
0423 template <class RealType, class Policy>
0424 inline RealType quantile(const negative_binomial_distribution<RealType, Policy>& dist, const RealType& P)
0425 {
0426
0427
0428
0429
0430
0431
0432 static const char* function = "boost::math::quantile(const negative_binomial_distribution<%1%>&, %1%)";
0433 BOOST_MATH_STD_USING
0434
0435 RealType p = dist.success_fraction();
0436 RealType r = dist.successes();
0437
0438 RealType result = 0;
0439 if(false == negative_binomial_detail::check_dist_and_prob
0440 (function, r, p, P, &result, Policy()))
0441 {
0442 return result;
0443 }
0444
0445
0446 if (P == 1)
0447 {
0448 result = policies::raise_overflow_error<RealType>(
0449 function,
0450 "Probability argument is 1, which implies infinite failures !", Policy());
0451 return result;
0452
0453
0454 }
0455 if (P == 0)
0456 {
0457 return 0;
0458 }
0459 if (P <= pow(dist.success_fraction(), dist.successes()))
0460 {
0461 return 0;
0462 }
0463 if(p == 0)
0464 {
0465 result = policies::raise_overflow_error<RealType>(
0466 function,
0467 "Success fraction is 0, which implies infinite failures !", Policy());
0468 return result;
0469
0470
0471 }
0472
0473
0474
0475
0476
0477 RealType guess = 0;
0478 RealType factor = 5;
0479 if(r * r * r * P * p > 0.005)
0480 guess = detail::inverse_negative_binomial_cornish_fisher(r, p, RealType(1-p), P, RealType(1-P), Policy());
0481
0482 if(guess < 10)
0483 {
0484
0485
0486
0487 guess = (std::min)(RealType(r * 2), RealType(10));
0488 }
0489 else
0490 factor = (1-P < sqrt(tools::epsilon<RealType>())) ? 2 : (guess < 20 ? 1.2f : 1.1f);
0491 BOOST_MATH_INSTRUMENT_CODE("guess = " << guess);
0492
0493
0494
0495 std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0496 typedef typename Policy::discrete_quantile_type discrete_type;
0497 return detail::inverse_discrete_quantile(
0498 dist,
0499 P,
0500 false,
0501 guess,
0502 factor,
0503 RealType(1),
0504 discrete_type(),
0505 max_iter);
0506 }
0507
0508 template <class RealType, class Policy>
0509 inline RealType quantile(const complemented2_type<negative_binomial_distribution<RealType, Policy>, RealType>& c)
0510 {
0511
0512
0513 static const char* function = "boost::math::quantile(const negative_binomial_distribution<%1%>&, %1%)";
0514 BOOST_MATH_STD_USING
0515
0516
0517 RealType Q = c.param;
0518 const negative_binomial_distribution<RealType, Policy>& dist = c.dist;
0519 RealType p = dist.success_fraction();
0520 RealType r = dist.successes();
0521 RealType result = 0;
0522 if(false == negative_binomial_detail::check_dist_and_prob(
0523 function,
0524 r,
0525 p,
0526 Q,
0527 &result, Policy()))
0528 {
0529 return result;
0530 }
0531
0532
0533
0534 if(Q == 1)
0535 {
0536
0537 return 0;
0538 }
0539 if(Q == 0)
0540 {
0541
0542 result = policies::raise_overflow_error<RealType>(
0543 function,
0544 "Probability argument complement is 0, which implies infinite failures !", Policy());
0545 return result;
0546
0547
0548 }
0549 if (-Q <= boost::math::powm1(dist.success_fraction(), dist.successes(), Policy()))
0550 {
0551 return 0;
0552 }
0553 if(p == 0)
0554 {
0555
0556 result = policies::raise_overflow_error<RealType>(
0557 function,
0558 "Success fraction is 0, which implies infinite failures !", Policy());
0559 return result;
0560
0561
0562 }
0563
0564 RealType guess = 0;
0565 RealType factor = 5;
0566 if(r * r * r * (1-Q) * p > 0.005)
0567 guess = detail::inverse_negative_binomial_cornish_fisher(r, p, RealType(1-p), RealType(1-Q), Q, Policy());
0568
0569 if(guess < 10)
0570 {
0571
0572
0573
0574 guess = (std::min)(RealType(r * 2), RealType(10));
0575 }
0576 else
0577 factor = (Q < sqrt(tools::epsilon<RealType>())) ? 2 : (guess < 20 ? 1.2f : 1.1f);
0578 BOOST_MATH_INSTRUMENT_CODE("guess = " << guess);
0579
0580
0581
0582 std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0583 typedef typename Policy::discrete_quantile_type discrete_type;
0584 return detail::inverse_discrete_quantile(
0585 dist,
0586 Q,
0587 true,
0588 guess,
0589 factor,
0590 RealType(1),
0591 discrete_type(),
0592 max_iter);
0593 }
0594
0595 }
0596 }
0597
0598
0599
0600
0601 #include <boost/math/distributions/detail/derived_accessors.hpp>
0602
0603 #if defined (BOOST_MSVC)
0604 # pragma warning(pop)
0605 #endif
0606
0607 #endif