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
|