annotate any/include/boost/math/distributions/negative_binomial.hpp @ 160:cff480c41f97

Add some cross-platform Boost headers
author Chris Cannam <cannam@all-day-breakfast.com>
date Sat, 16 Feb 2019 16:31:25 +0000
parents
children
rev   line source
cannam@160 1 // boost\math\special_functions\negative_binomial.hpp
cannam@160 2
cannam@160 3 // Copyright Paul A. Bristow 2007.
cannam@160 4 // Copyright John Maddock 2007.
cannam@160 5
cannam@160 6 // Use, modification and distribution are subject to the
cannam@160 7 // Boost Software License, Version 1.0.
cannam@160 8 // (See accompanying file LICENSE_1_0.txt
cannam@160 9 // or copy at http://www.boost.org/LICENSE_1_0.txt)
cannam@160 10
cannam@160 11 // http://en.wikipedia.org/wiki/negative_binomial_distribution
cannam@160 12 // http://mathworld.wolfram.com/NegativeBinomialDistribution.html
cannam@160 13 // http://documents.wolfram.com/teachersedition/Teacher/Statistics/DiscreteDistributions.html
cannam@160 14
cannam@160 15 // The negative binomial distribution NegativeBinomialDistribution[n, p]
cannam@160 16 // is the distribution of the number (k) of failures that occur in a sequence of trials before
cannam@160 17 // r successes have occurred, where the probability of success in each trial is p.
cannam@160 18
cannam@160 19 // In a sequence of Bernoulli trials or events
cannam@160 20 // (independent, yes or no, succeed or fail) with success_fraction probability p,
cannam@160 21 // negative_binomial is the probability that k or fewer failures
cannam@160 22 // preceed the r th trial's success.
cannam@160 23 // random variable k is the number of failures (NOT the probability).
cannam@160 24
cannam@160 25 // Negative_binomial distribution is a discrete probability distribution.
cannam@160 26 // But note that the negative binomial distribution
cannam@160 27 // (like others including the binomial, Poisson & Bernoulli)
cannam@160 28 // is strictly defined as a discrete function: only integral values of k are envisaged.
cannam@160 29 // However because of the method of calculation using a continuous gamma function,
cannam@160 30 // it is convenient to treat it as if a continous function,
cannam@160 31 // and permit non-integral values of k.
cannam@160 32
cannam@160 33 // However, by default the policy is to use discrete_quantile_policy.
cannam@160 34
cannam@160 35 // To enforce the strict mathematical model, users should use conversion
cannam@160 36 // on k outside this function to ensure that k is integral.
cannam@160 37
cannam@160 38 // MATHCAD cumulative negative binomial pnbinom(k, n, p)
cannam@160 39
cannam@160 40 // Implementation note: much greater speed, and perhaps greater accuracy,
cannam@160 41 // might be achieved for extreme values by using a normal approximation.
cannam@160 42 // This is NOT been tested or implemented.
cannam@160 43
cannam@160 44 #ifndef BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP
cannam@160 45 #define BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP
cannam@160 46
cannam@160 47 #include <boost/math/distributions/fwd.hpp>
cannam@160 48 #include <boost/math/special_functions/beta.hpp> // for ibeta(a, b, x) == Ix(a, b).
cannam@160 49 #include <boost/math/distributions/complement.hpp> // complement.
cannam@160 50 #include <boost/math/distributions/detail/common_error_handling.hpp> // error checks domain_error & logic_error.
cannam@160 51 #include <boost/math/special_functions/fpclassify.hpp> // isnan.
cannam@160 52 #include <boost/math/tools/roots.hpp> // for root finding.
cannam@160 53 #include <boost/math/distributions/detail/inv_discrete_quantile.hpp>
cannam@160 54
cannam@160 55 #include <boost/type_traits/is_floating_point.hpp>
cannam@160 56 #include <boost/type_traits/is_integral.hpp>
cannam@160 57 #include <boost/type_traits/is_same.hpp>
cannam@160 58 #include <boost/mpl/if.hpp>
cannam@160 59
cannam@160 60 #include <limits> // using std::numeric_limits;
cannam@160 61 #include <utility>
cannam@160 62
cannam@160 63 #if defined (BOOST_MSVC)
cannam@160 64 # pragma warning(push)
cannam@160 65 // This believed not now necessary, so commented out.
cannam@160 66 //# pragma warning(disable: 4702) // unreachable code.
cannam@160 67 // in domain_error_imp in error_handling.
cannam@160 68 #endif
cannam@160 69
cannam@160 70 namespace boost
cannam@160 71 {
cannam@160 72 namespace math
cannam@160 73 {
cannam@160 74 namespace negative_binomial_detail
cannam@160 75 {
cannam@160 76 // Common error checking routines for negative binomial distribution functions:
cannam@160 77 template <class RealType, class Policy>
cannam@160 78 inline bool check_successes(const char* function, const RealType& r, RealType* result, const Policy& pol)
cannam@160 79 {
cannam@160 80 if( !(boost::math::isfinite)(r) || (r <= 0) )
cannam@160 81 {
cannam@160 82 *result = policies::raise_domain_error<RealType>(
cannam@160 83 function,
cannam@160 84 "Number of successes argument is %1%, but must be > 0 !", r, pol);
cannam@160 85 return false;
cannam@160 86 }
cannam@160 87 return true;
cannam@160 88 }
cannam@160 89 template <class RealType, class Policy>
cannam@160 90 inline bool check_success_fraction(const char* function, const RealType& p, RealType* result, const Policy& pol)
cannam@160 91 {
cannam@160 92 if( !(boost::math::isfinite)(p) || (p < 0) || (p > 1) )
cannam@160 93 {
cannam@160 94 *result = policies::raise_domain_error<RealType>(
cannam@160 95 function,
cannam@160 96 "Success fraction argument is %1%, but must be >= 0 and <= 1 !", p, pol);
cannam@160 97 return false;
cannam@160 98 }
cannam@160 99 return true;
cannam@160 100 }
cannam@160 101 template <class RealType, class Policy>
cannam@160 102 inline bool check_dist(const char* function, const RealType& r, const RealType& p, RealType* result, const Policy& pol)
cannam@160 103 {
cannam@160 104 return check_success_fraction(function, p, result, pol)
cannam@160 105 && check_successes(function, r, result, pol);
cannam@160 106 }
cannam@160 107 template <class RealType, class Policy>
cannam@160 108 inline bool check_dist_and_k(const char* function, const RealType& r, const RealType& p, RealType k, RealType* result, const Policy& pol)
cannam@160 109 {
cannam@160 110 if(check_dist(function, r, p, result, pol) == false)
cannam@160 111 {
cannam@160 112 return false;
cannam@160 113 }
cannam@160 114 if( !(boost::math::isfinite)(k) || (k < 0) )
cannam@160 115 { // Check k failures.
cannam@160 116 *result = policies::raise_domain_error<RealType>(
cannam@160 117 function,
cannam@160 118 "Number of failures argument is %1%, but must be >= 0 !", k, pol);
cannam@160 119 return false;
cannam@160 120 }
cannam@160 121 return true;
cannam@160 122 } // Check_dist_and_k
cannam@160 123
cannam@160 124 template <class RealType, class Policy>
cannam@160 125 inline bool check_dist_and_prob(const char* function, const RealType& r, RealType p, RealType prob, RealType* result, const Policy& pol)
cannam@160 126 {
cannam@160 127 if((check_dist(function, r, p, result, pol) && detail::check_probability(function, prob, result, pol)) == false)
cannam@160 128 {
cannam@160 129 return false;
cannam@160 130 }
cannam@160 131 return true;
cannam@160 132 } // check_dist_and_prob
cannam@160 133 } // namespace negative_binomial_detail
cannam@160 134
cannam@160 135 template <class RealType = double, class Policy = policies::policy<> >
cannam@160 136 class negative_binomial_distribution
cannam@160 137 {
cannam@160 138 public:
cannam@160 139 typedef RealType value_type;
cannam@160 140 typedef Policy policy_type;
cannam@160 141
cannam@160 142 negative_binomial_distribution(RealType r, RealType p) : m_r(r), m_p(p)
cannam@160 143 { // Constructor.
cannam@160 144 RealType result;
cannam@160 145 negative_binomial_detail::check_dist(
cannam@160 146 "negative_binomial_distribution<%1%>::negative_binomial_distribution",
cannam@160 147 m_r, // Check successes r > 0.
cannam@160 148 m_p, // Check success_fraction 0 <= p <= 1.
cannam@160 149 &result, Policy());
cannam@160 150 } // negative_binomial_distribution constructor.
cannam@160 151
cannam@160 152 // Private data getter class member functions.
cannam@160 153 RealType success_fraction() const
cannam@160 154 { // Probability of success as fraction in range 0 to 1.
cannam@160 155 return m_p;
cannam@160 156 }
cannam@160 157 RealType successes() const
cannam@160 158 { // Total number of successes r.
cannam@160 159 return m_r;
cannam@160 160 }
cannam@160 161
cannam@160 162 static RealType find_lower_bound_on_p(
cannam@160 163 RealType trials,
cannam@160 164 RealType successes,
cannam@160 165 RealType alpha) // alpha 0.05 equivalent to 95% for one-sided test.
cannam@160 166 {
cannam@160 167 static const char* function = "boost::math::negative_binomial<%1%>::find_lower_bound_on_p";
cannam@160 168 RealType result = 0; // of error checks.
cannam@160 169 RealType failures = trials - successes;
cannam@160 170 if(false == detail::check_probability(function, alpha, &result, Policy())
cannam@160 171 && negative_binomial_detail::check_dist_and_k(
cannam@160 172 function, successes, RealType(0), failures, &result, Policy()))
cannam@160 173 {
cannam@160 174 return result;
cannam@160 175 }
cannam@160 176 // Use complement ibeta_inv function for lower bound.
cannam@160 177 // This is adapted from the corresponding binomial formula
cannam@160 178 // here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm
cannam@160 179 // This is a Clopper-Pearson interval, and may be overly conservative,
cannam@160 180 // see also "A Simple Improved Inferential Method for Some
cannam@160 181 // Discrete Distributions" Yong CAI and K. KRISHNAMOORTHY
cannam@160 182 // http://www.ucs.louisiana.edu/~kxk4695/Discrete_new.pdf
cannam@160 183 //
cannam@160 184 return ibeta_inv(successes, failures + 1, alpha, static_cast<RealType*>(0), Policy());
cannam@160 185 } // find_lower_bound_on_p
cannam@160 186
cannam@160 187 static RealType find_upper_bound_on_p(
cannam@160 188 RealType trials,
cannam@160 189 RealType successes,
cannam@160 190 RealType alpha) // alpha 0.05 equivalent to 95% for one-sided test.
cannam@160 191 {
cannam@160 192 static const char* function = "boost::math::negative_binomial<%1%>::find_upper_bound_on_p";
cannam@160 193 RealType result = 0; // of error checks.
cannam@160 194 RealType failures = trials - successes;
cannam@160 195 if(false == negative_binomial_detail::check_dist_and_k(
cannam@160 196 function, successes, RealType(0), failures, &result, Policy())
cannam@160 197 && detail::check_probability(function, alpha, &result, Policy()))
cannam@160 198 {
cannam@160 199 return result;
cannam@160 200 }
cannam@160 201 if(failures == 0)
cannam@160 202 return 1;
cannam@160 203 // Use complement ibetac_inv function for upper bound.
cannam@160 204 // Note adjusted failures value: *not* failures+1 as usual.
cannam@160 205 // This is adapted from the corresponding binomial formula
cannam@160 206 // here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm
cannam@160 207 // This is a Clopper-Pearson interval, and may be overly conservative,
cannam@160 208 // see also "A Simple Improved Inferential Method for Some
cannam@160 209 // Discrete Distributions" Yong CAI and K. KRISHNAMOORTHY
cannam@160 210 // http://www.ucs.louisiana.edu/~kxk4695/Discrete_new.pdf
cannam@160 211 //
cannam@160 212 return ibetac_inv(successes, failures, alpha, static_cast<RealType*>(0), Policy());
cannam@160 213 } // find_upper_bound_on_p
cannam@160 214
cannam@160 215 // Estimate number of trials :
cannam@160 216 // "How many trials do I need to be P% sure of seeing k or fewer failures?"
cannam@160 217
cannam@160 218 static RealType find_minimum_number_of_trials(
cannam@160 219 RealType k, // number of failures (k >= 0).
cannam@160 220 RealType p, // success fraction 0 <= p <= 1.
cannam@160 221 RealType alpha) // risk level threshold 0 <= alpha <= 1.
cannam@160 222 {
cannam@160 223 static const char* function = "boost::math::negative_binomial<%1%>::find_minimum_number_of_trials";
cannam@160 224 // Error checks:
cannam@160 225 RealType result = 0;
cannam@160 226 if(false == negative_binomial_detail::check_dist_and_k(
cannam@160 227 function, RealType(1), p, k, &result, Policy())
cannam@160 228 && detail::check_probability(function, alpha, &result, Policy()))
cannam@160 229 { return result; }
cannam@160 230
cannam@160 231 result = ibeta_inva(k + 1, p, alpha, Policy()); // returns n - k
cannam@160 232 return result + k;
cannam@160 233 } // RealType find_number_of_failures
cannam@160 234
cannam@160 235 static RealType find_maximum_number_of_trials(
cannam@160 236 RealType k, // number of failures (k >= 0).
cannam@160 237 RealType p, // success fraction 0 <= p <= 1.
cannam@160 238 RealType alpha) // risk level threshold 0 <= alpha <= 1.
cannam@160 239 {
cannam@160 240 static const char* function = "boost::math::negative_binomial<%1%>::find_maximum_number_of_trials";
cannam@160 241 // Error checks:
cannam@160 242 RealType result = 0;
cannam@160 243 if(false == negative_binomial_detail::check_dist_and_k(
cannam@160 244 function, RealType(1), p, k, &result, Policy())
cannam@160 245 && detail::check_probability(function, alpha, &result, Policy()))
cannam@160 246 { return result; }
cannam@160 247
cannam@160 248 result = ibetac_inva(k + 1, p, alpha, Policy()); // returns n - k
cannam@160 249 return result + k;
cannam@160 250 } // RealType find_number_of_trials complemented
cannam@160 251
cannam@160 252 private:
cannam@160 253 RealType m_r; // successes.
cannam@160 254 RealType m_p; // success_fraction
cannam@160 255 }; // template <class RealType, class Policy> class negative_binomial_distribution
cannam@160 256
cannam@160 257 typedef negative_binomial_distribution<double> negative_binomial; // Reserved name of type double.
cannam@160 258
cannam@160 259 template <class RealType, class Policy>
cannam@160 260 inline const std::pair<RealType, RealType> range(const negative_binomial_distribution<RealType, Policy>& /* dist */)
cannam@160 261 { // Range of permissible values for random variable k.
cannam@160 262 using boost::math::tools::max_value;
cannam@160 263 return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>()); // max_integer?
cannam@160 264 }
cannam@160 265
cannam@160 266 template <class RealType, class Policy>
cannam@160 267 inline const std::pair<RealType, RealType> support(const negative_binomial_distribution<RealType, Policy>& /* dist */)
cannam@160 268 { // Range of supported values for random variable k.
cannam@160 269 // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
cannam@160 270 using boost::math::tools::max_value;
cannam@160 271 return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>()); // max_integer?
cannam@160 272 }
cannam@160 273
cannam@160 274 template <class RealType, class Policy>
cannam@160 275 inline RealType mean(const negative_binomial_distribution<RealType, Policy>& dist)
cannam@160 276 { // Mean of Negative Binomial distribution = r(1-p)/p.
cannam@160 277 return dist.successes() * (1 - dist.success_fraction() ) / dist.success_fraction();
cannam@160 278 } // mean
cannam@160 279
cannam@160 280 //template <class RealType, class Policy>
cannam@160 281 //inline RealType median(const negative_binomial_distribution<RealType, Policy>& dist)
cannam@160 282 //{ // Median of negative_binomial_distribution is not defined.
cannam@160 283 // return policies::raise_domain_error<RealType>(BOOST_CURRENT_FUNCTION, "Median is not implemented, result is %1%!", std::numeric_limits<RealType>::quiet_NaN());
cannam@160 284 //} // median
cannam@160 285 // Now implemented via quantile(half) in derived accessors.
cannam@160 286
cannam@160 287 template <class RealType, class Policy>
cannam@160 288 inline RealType mode(const negative_binomial_distribution<RealType, Policy>& dist)
cannam@160 289 { // Mode of Negative Binomial distribution = floor[(r-1) * (1 - p)/p]
cannam@160 290 BOOST_MATH_STD_USING // ADL of std functions.
cannam@160 291 return floor((dist.successes() -1) * (1 - dist.success_fraction()) / dist.success_fraction());
cannam@160 292 } // mode
cannam@160 293
cannam@160 294 template <class RealType, class Policy>
cannam@160 295 inline RealType skewness(const negative_binomial_distribution<RealType, Policy>& dist)
cannam@160 296 { // skewness of Negative Binomial distribution = 2-p / (sqrt(r(1-p))
cannam@160 297 BOOST_MATH_STD_USING // ADL of std functions.
cannam@160 298 RealType p = dist.success_fraction();
cannam@160 299 RealType r = dist.successes();
cannam@160 300
cannam@160 301 return (2 - p) /
cannam@160 302 sqrt(r * (1 - p));
cannam@160 303 } // skewness
cannam@160 304
cannam@160 305 template <class RealType, class Policy>
cannam@160 306 inline RealType kurtosis(const negative_binomial_distribution<RealType, Policy>& dist)
cannam@160 307 { // kurtosis of Negative Binomial distribution
cannam@160 308 // http://en.wikipedia.org/wiki/Negative_binomial is kurtosis_excess so add 3
cannam@160 309 RealType p = dist.success_fraction();
cannam@160 310 RealType r = dist.successes();
cannam@160 311 return 3 + (6 / r) + ((p * p) / (r * (1 - p)));
cannam@160 312 } // kurtosis
cannam@160 313
cannam@160 314 template <class RealType, class Policy>
cannam@160 315 inline RealType kurtosis_excess(const negative_binomial_distribution<RealType, Policy>& dist)
cannam@160 316 { // kurtosis excess of Negative Binomial distribution
cannam@160 317 // http://mathworld.wolfram.com/Kurtosis.html table of kurtosis_excess
cannam@160 318 RealType p = dist.success_fraction();
cannam@160 319 RealType r = dist.successes();
cannam@160 320 return (6 - p * (6-p)) / (r * (1-p));
cannam@160 321 } // kurtosis_excess
cannam@160 322
cannam@160 323 template <class RealType, class Policy>
cannam@160 324 inline RealType variance(const negative_binomial_distribution<RealType, Policy>& dist)
cannam@160 325 { // Variance of Binomial distribution = r (1-p) / p^2.
cannam@160 326 return dist.successes() * (1 - dist.success_fraction())
cannam@160 327 / (dist.success_fraction() * dist.success_fraction());
cannam@160 328 } // variance
cannam@160 329
cannam@160 330 // RealType standard_deviation(const negative_binomial_distribution<RealType, Policy>& dist)
cannam@160 331 // standard_deviation provided by derived accessors.
cannam@160 332 // RealType hazard(const negative_binomial_distribution<RealType, Policy>& dist)
cannam@160 333 // hazard of Negative Binomial distribution provided by derived accessors.
cannam@160 334 // RealType chf(const negative_binomial_distribution<RealType, Policy>& dist)
cannam@160 335 // chf of Negative Binomial distribution provided by derived accessors.
cannam@160 336
cannam@160 337 template <class RealType, class Policy>
cannam@160 338 inline RealType pdf(const negative_binomial_distribution<RealType, Policy>& dist, const RealType& k)
cannam@160 339 { // Probability Density/Mass Function.
cannam@160 340 BOOST_FPU_EXCEPTION_GUARD
cannam@160 341
cannam@160 342 static const char* function = "boost::math::pdf(const negative_binomial_distribution<%1%>&, %1%)";
cannam@160 343
cannam@160 344 RealType r = dist.successes();
cannam@160 345 RealType p = dist.success_fraction();
cannam@160 346 RealType result = 0;
cannam@160 347 if(false == negative_binomial_detail::check_dist_and_k(
cannam@160 348 function,
cannam@160 349 r,
cannam@160 350 dist.success_fraction(),
cannam@160 351 k,
cannam@160 352 &result, Policy()))
cannam@160 353 {
cannam@160 354 return result;
cannam@160 355 }
cannam@160 356
cannam@160 357 result = (p/(r + k)) * ibeta_derivative(r, static_cast<RealType>(k+1), p, Policy());
cannam@160 358 // Equivalent to:
cannam@160 359 // return exp(lgamma(r + k) - lgamma(r) - lgamma(k+1)) * pow(p, r) * pow((1-p), k);
cannam@160 360 return result;
cannam@160 361 } // negative_binomial_pdf
cannam@160 362
cannam@160 363 template <class RealType, class Policy>
cannam@160 364 inline RealType cdf(const negative_binomial_distribution<RealType, Policy>& dist, const RealType& k)
cannam@160 365 { // Cumulative Distribution Function of Negative Binomial.
cannam@160 366 static const char* function = "boost::math::cdf(const negative_binomial_distribution<%1%>&, %1%)";
cannam@160 367 using boost::math::ibeta; // Regularized incomplete beta function.
cannam@160 368 // k argument may be integral, signed, or unsigned, or floating point.
cannam@160 369 // If necessary, it has already been promoted from an integral type.
cannam@160 370 RealType p = dist.success_fraction();
cannam@160 371 RealType r = dist.successes();
cannam@160 372 // Error check:
cannam@160 373 RealType result = 0;
cannam@160 374 if(false == negative_binomial_detail::check_dist_and_k(
cannam@160 375 function,
cannam@160 376 r,
cannam@160 377 dist.success_fraction(),
cannam@160 378 k,
cannam@160 379 &result, Policy()))
cannam@160 380 {
cannam@160 381 return result;
cannam@160 382 }
cannam@160 383
cannam@160 384 RealType probability = ibeta(r, static_cast<RealType>(k+1), p, Policy());
cannam@160 385 // Ip(r, k+1) = ibeta(r, k+1, p)
cannam@160 386 return probability;
cannam@160 387 } // cdf Cumulative Distribution Function Negative Binomial.
cannam@160 388
cannam@160 389 template <class RealType, class Policy>
cannam@160 390 inline RealType cdf(const complemented2_type<negative_binomial_distribution<RealType, Policy>, RealType>& c)
cannam@160 391 { // Complemented Cumulative Distribution Function Negative Binomial.
cannam@160 392
cannam@160 393 static const char* function = "boost::math::cdf(const negative_binomial_distribution<%1%>&, %1%)";
cannam@160 394 using boost::math::ibetac; // Regularized incomplete beta function complement.
cannam@160 395 // k argument may be integral, signed, or unsigned, or floating point.
cannam@160 396 // If necessary, it has already been promoted from an integral type.
cannam@160 397 RealType const& k = c.param;
cannam@160 398 negative_binomial_distribution<RealType, Policy> const& dist = c.dist;
cannam@160 399 RealType p = dist.success_fraction();
cannam@160 400 RealType r = dist.successes();
cannam@160 401 // Error check:
cannam@160 402 RealType result = 0;
cannam@160 403 if(false == negative_binomial_detail::check_dist_and_k(
cannam@160 404 function,
cannam@160 405 r,
cannam@160 406 p,
cannam@160 407 k,
cannam@160 408 &result, Policy()))
cannam@160 409 {
cannam@160 410 return result;
cannam@160 411 }
cannam@160 412 // Calculate cdf negative binomial using the incomplete beta function.
cannam@160 413 // Use of ibeta here prevents cancellation errors in calculating
cannam@160 414 // 1-p if p is very small, perhaps smaller than machine epsilon.
cannam@160 415 // Ip(k+1, r) = ibetac(r, k+1, p)
cannam@160 416 // constrain_probability here?
cannam@160 417 RealType probability = ibetac(r, static_cast<RealType>(k+1), p, Policy());
cannam@160 418 // Numerical errors might cause probability to be slightly outside the range < 0 or > 1.
cannam@160 419 // This might cause trouble downstream, so warn, possibly throw exception, but constrain to the limits.
cannam@160 420 return probability;
cannam@160 421 } // cdf Cumulative Distribution Function Negative Binomial.
cannam@160 422
cannam@160 423 template <class RealType, class Policy>
cannam@160 424 inline RealType quantile(const negative_binomial_distribution<RealType, Policy>& dist, const RealType& P)
cannam@160 425 { // Quantile, percentile/100 or Percent Point Negative Binomial function.
cannam@160 426 // Return the number of expected failures k for a given probability p.
cannam@160 427
cannam@160 428 // Inverse cumulative Distribution Function or Quantile (percentile / 100) of negative_binomial Probability.
cannam@160 429 // MAthCAD pnbinom return smallest k such that negative_binomial(k, n, p) >= probability.
cannam@160 430 // k argument may be integral, signed, or unsigned, or floating point.
cannam@160 431 // BUT Cephes/CodeCogs says: finds argument p (0 to 1) such that cdf(k, n, p) = y
cannam@160 432 static const char* function = "boost::math::quantile(const negative_binomial_distribution<%1%>&, %1%)";
cannam@160 433 BOOST_MATH_STD_USING // ADL of std functions.
cannam@160 434
cannam@160 435 RealType p = dist.success_fraction();
cannam@160 436 RealType r = dist.successes();
cannam@160 437 // Check dist and P.
cannam@160 438 RealType result = 0;
cannam@160 439 if(false == negative_binomial_detail::check_dist_and_prob
cannam@160 440 (function, r, p, P, &result, Policy()))
cannam@160 441 {
cannam@160 442 return result;
cannam@160 443 }
cannam@160 444
cannam@160 445 // Special cases.
cannam@160 446 if (P == 1)
cannam@160 447 { // Would need +infinity failures for total confidence.
cannam@160 448 result = policies::raise_overflow_error<RealType>(
cannam@160 449 function,
cannam@160 450 "Probability argument is 1, which implies infinite failures !", Policy());
cannam@160 451 return result;
cannam@160 452 // usually means return +std::numeric_limits<RealType>::infinity();
cannam@160 453 // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
cannam@160 454 }
cannam@160 455 if (P == 0)
cannam@160 456 { // No failures are expected if P = 0.
cannam@160 457 return 0; // Total trials will be just dist.successes.
cannam@160 458 }
cannam@160 459 if (P <= pow(dist.success_fraction(), dist.successes()))
cannam@160 460 { // p <= pdf(dist, 0) == cdf(dist, 0)
cannam@160 461 return 0;
cannam@160 462 }
cannam@160 463 if(p == 0)
cannam@160 464 { // Would need +infinity failures for total confidence.
cannam@160 465 result = policies::raise_overflow_error<RealType>(
cannam@160 466 function,
cannam@160 467 "Success fraction is 0, which implies infinite failures !", Policy());
cannam@160 468 return result;
cannam@160 469 // usually means return +std::numeric_limits<RealType>::infinity();
cannam@160 470 // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
cannam@160 471 }
cannam@160 472 /*
cannam@160 473 // Calculate quantile of negative_binomial using the inverse incomplete beta function.
cannam@160 474 using boost::math::ibeta_invb;
cannam@160 475 return ibeta_invb(r, p, P, Policy()) - 1; //
cannam@160 476 */
cannam@160 477 RealType guess = 0;
cannam@160 478 RealType factor = 5;
cannam@160 479 if(r * r * r * P * p > 0.005)
cannam@160 480 guess = detail::inverse_negative_binomial_cornish_fisher(r, p, RealType(1-p), P, RealType(1-P), Policy());
cannam@160 481
cannam@160 482 if(guess < 10)
cannam@160 483 {
cannam@160 484 //
cannam@160 485 // Cornish-Fisher Negative binomial approximation not accurate in this area:
cannam@160 486 //
cannam@160 487 guess = (std::min)(RealType(r * 2), RealType(10));
cannam@160 488 }
cannam@160 489 else
cannam@160 490 factor = (1-P < sqrt(tools::epsilon<RealType>())) ? 2 : (guess < 20 ? 1.2f : 1.1f);
cannam@160 491 BOOST_MATH_INSTRUMENT_CODE("guess = " << guess);
cannam@160 492 //
cannam@160 493 // Max iterations permitted:
cannam@160 494 //
cannam@160 495 boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
cannam@160 496 typedef typename Policy::discrete_quantile_type discrete_type;
cannam@160 497 return detail::inverse_discrete_quantile(
cannam@160 498 dist,
cannam@160 499 P,
cannam@160 500 false,
cannam@160 501 guess,
cannam@160 502 factor,
cannam@160 503 RealType(1),
cannam@160 504 discrete_type(),
cannam@160 505 max_iter);
cannam@160 506 } // RealType quantile(const negative_binomial_distribution dist, p)
cannam@160 507
cannam@160 508 template <class RealType, class Policy>
cannam@160 509 inline RealType quantile(const complemented2_type<negative_binomial_distribution<RealType, Policy>, RealType>& c)
cannam@160 510 { // Quantile or Percent Point Binomial function.
cannam@160 511 // Return the number of expected failures k for a given
cannam@160 512 // complement of the probability Q = 1 - P.
cannam@160 513 static const char* function = "boost::math::quantile(const negative_binomial_distribution<%1%>&, %1%)";
cannam@160 514 BOOST_MATH_STD_USING
cannam@160 515
cannam@160 516 // Error checks:
cannam@160 517 RealType Q = c.param;
cannam@160 518 const negative_binomial_distribution<RealType, Policy>& dist = c.dist;
cannam@160 519 RealType p = dist.success_fraction();
cannam@160 520 RealType r = dist.successes();
cannam@160 521 RealType result = 0;
cannam@160 522 if(false == negative_binomial_detail::check_dist_and_prob(
cannam@160 523 function,
cannam@160 524 r,
cannam@160 525 p,
cannam@160 526 Q,
cannam@160 527 &result, Policy()))
cannam@160 528 {
cannam@160 529 return result;
cannam@160 530 }
cannam@160 531
cannam@160 532 // Special cases:
cannam@160 533 //
cannam@160 534 if(Q == 1)
cannam@160 535 { // There may actually be no answer to this question,
cannam@160 536 // since the probability of zero failures may be non-zero,
cannam@160 537 return 0; // but zero is the best we can do:
cannam@160 538 }
cannam@160 539 if(Q == 0)
cannam@160 540 { // Probability 1 - Q == 1 so infinite failures to achieve certainty.
cannam@160 541 // Would need +infinity failures for total confidence.
cannam@160 542 result = policies::raise_overflow_error<RealType>(
cannam@160 543 function,
cannam@160 544 "Probability argument complement is 0, which implies infinite failures !", Policy());
cannam@160 545 return result;
cannam@160 546 // usually means return +std::numeric_limits<RealType>::infinity();
cannam@160 547 // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
cannam@160 548 }
cannam@160 549 if (-Q <= boost::math::powm1(dist.success_fraction(), dist.successes(), Policy()))
cannam@160 550 { // q <= cdf(complement(dist, 0)) == pdf(dist, 0)
cannam@160 551 return 0; //
cannam@160 552 }
cannam@160 553 if(p == 0)
cannam@160 554 { // Success fraction is 0 so infinite failures to achieve certainty.
cannam@160 555 // Would need +infinity failures for total confidence.
cannam@160 556 result = policies::raise_overflow_error<RealType>(
cannam@160 557 function,
cannam@160 558 "Success fraction is 0, which implies infinite failures !", Policy());
cannam@160 559 return result;
cannam@160 560 // usually means return +std::numeric_limits<RealType>::infinity();
cannam@160 561 // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
cannam@160 562 }
cannam@160 563 //return ibetac_invb(r, p, Q, Policy()) -1;
cannam@160 564 RealType guess = 0;
cannam@160 565 RealType factor = 5;
cannam@160 566 if(r * r * r * (1-Q) * p > 0.005)
cannam@160 567 guess = detail::inverse_negative_binomial_cornish_fisher(r, p, RealType(1-p), RealType(1-Q), Q, Policy());
cannam@160 568
cannam@160 569 if(guess < 10)
cannam@160 570 {
cannam@160 571 //
cannam@160 572 // Cornish-Fisher Negative binomial approximation not accurate in this area:
cannam@160 573 //
cannam@160 574 guess = (std::min)(RealType(r * 2), RealType(10));
cannam@160 575 }
cannam@160 576 else
cannam@160 577 factor = (Q < sqrt(tools::epsilon<RealType>())) ? 2 : (guess < 20 ? 1.2f : 1.1f);
cannam@160 578 BOOST_MATH_INSTRUMENT_CODE("guess = " << guess);
cannam@160 579 //
cannam@160 580 // Max iterations permitted:
cannam@160 581 //
cannam@160 582 boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
cannam@160 583 typedef typename Policy::discrete_quantile_type discrete_type;
cannam@160 584 return detail::inverse_discrete_quantile(
cannam@160 585 dist,
cannam@160 586 Q,
cannam@160 587 true,
cannam@160 588 guess,
cannam@160 589 factor,
cannam@160 590 RealType(1),
cannam@160 591 discrete_type(),
cannam@160 592 max_iter);
cannam@160 593 } // quantile complement
cannam@160 594
cannam@160 595 } // namespace math
cannam@160 596 } // namespace boost
cannam@160 597
cannam@160 598 // This include must be at the end, *after* the accessors
cannam@160 599 // for this distribution have been defined, in order to
cannam@160 600 // keep compilers that support two-phase lookup happy.
cannam@160 601 #include <boost/math/distributions/detail/derived_accessors.hpp>
cannam@160 602
cannam@160 603 #if defined (BOOST_MSVC)
cannam@160 604 # pragma warning(pop)
cannam@160 605 #endif
cannam@160 606
cannam@160 607 #endif // BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP