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