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 #ifndef BOOST_MATH_DISTRIBUTIONS_HYPEREXPONENTIAL_HPP
0016 #define BOOST_MATH_DISTRIBUTIONS_HYPEREXPONENTIAL_HPP
0017
0018 #include <boost/math/tools/cxx03_warn.hpp>
0019 #include <boost/math/distributions/complement.hpp>
0020 #include <boost/math/distributions/detail/common_error_handling.hpp>
0021 #include <boost/math/distributions/exponential.hpp>
0022 #include <boost/math/policies/policy.hpp>
0023 #include <boost/math/special_functions/fpclassify.hpp>
0024 #include <boost/math/tools/precision.hpp>
0025 #include <boost/math/tools/roots.hpp>
0026 #include <boost/math/tools/is_detected.hpp>
0027 #include <cstddef>
0028 #include <iterator>
0029 #include <limits>
0030 #include <numeric>
0031 #include <utility>
0032 #include <vector>
0033 #include <type_traits>
0034 #include <initializer_list>
0035
0036
0037 #ifdef _MSC_VER
0038 # pragma warning (push)
0039 # pragma warning(disable:4127)
0040 # pragma warning(disable:4389)
0041 #endif
0042
0043 namespace boost { namespace math {
0044
0045 namespace detail {
0046
0047 template <typename Dist>
0048 typename Dist::value_type generic_quantile(const Dist& dist, const typename Dist::value_type& p, const typename Dist::value_type& guess, bool comp, const char* function);
0049
0050 }
0051
0052
0053 template <typename RealT, typename PolicyT>
0054 class hyperexponential_distribution;
0055
0056
0057 namespace { namespace hyperexp_detail {
0058
0059 template <typename T>
0060 void normalize(std::vector<T>& v)
0061 {
0062 if(!v.size())
0063 return;
0064 const T sum = std::accumulate(v.begin(), v.end(), static_cast<T>(0));
0065 T final_sum = 0;
0066 const typename std::vector<T>::iterator end = --v.end();
0067 for (typename std::vector<T>::iterator it = v.begin();
0068 it != end;
0069 ++it)
0070 {
0071 *it /= sum;
0072 final_sum += *it;
0073 }
0074 *end = 1 - final_sum;
0075 }
0076
0077 template <typename RealT, typename PolicyT>
0078 bool check_probabilities(char const* function, std::vector<RealT> const& probabilities, RealT* presult, PolicyT const& pol)
0079 {
0080 BOOST_MATH_STD_USING
0081 const std::size_t n = probabilities.size();
0082 RealT sum = 0;
0083 for (std::size_t i = 0; i < n; ++i)
0084 {
0085 if (probabilities[i] < 0
0086 || probabilities[i] > 1
0087 || !(boost::math::isfinite)(probabilities[i]))
0088 {
0089 *presult = policies::raise_domain_error<RealT>(function,
0090 "The elements of parameter \"probabilities\" must be >= 0 and <= 1, but at least one of them was: %1%.",
0091 probabilities[i],
0092 pol);
0093 return false;
0094 }
0095 sum += probabilities[i];
0096 }
0097
0098
0099
0100
0101
0102 if (fabs(sum - 1) > tools::epsilon<RealT>() * 2)
0103 {
0104 *presult = policies::raise_domain_error<RealT>(function,
0105 "The elements of parameter \"probabilities\" must sum to 1, but their sum is: %1%.",
0106 sum,
0107 pol);
0108 return false;
0109 }
0110
0111 return true;
0112 }
0113
0114 template <typename RealT, typename PolicyT>
0115 bool check_rates(char const* function, std::vector<RealT> const& rates, RealT* presult, PolicyT const& pol)
0116 {
0117 const std::size_t n = rates.size();
0118 for (std::size_t i = 0; i < n; ++i)
0119 {
0120 if (rates[i] <= 0
0121 || !(boost::math::isfinite)(rates[i]))
0122 {
0123 *presult = policies::raise_domain_error<RealT>(function,
0124 "The elements of parameter \"rates\" must be > 0, but at least one of them is: %1%.",
0125 rates[i],
0126 pol);
0127 return false;
0128 }
0129 }
0130 return true;
0131 }
0132
0133 template <typename RealT, typename PolicyT>
0134 bool check_dist(char const* function, std::vector<RealT> const& probabilities, std::vector<RealT> const& rates, RealT* presult, PolicyT const& pol)
0135 {
0136 BOOST_MATH_STD_USING
0137 if (probabilities.size() != rates.size())
0138 {
0139 *presult = policies::raise_domain_error<RealT>(function,
0140 R"(The parameters "probabilities" and "rates" must have the same length, but their size differ by: %1%.)",
0141 fabs(static_cast<RealT>(probabilities.size())-static_cast<RealT>(rates.size())),
0142 pol);
0143 return false;
0144 }
0145
0146 return check_probabilities(function, probabilities, presult, pol)
0147 && check_rates(function, rates, presult, pol);
0148 }
0149
0150 template <typename RealT, typename PolicyT>
0151 bool check_x(char const* function, RealT x, RealT* presult, PolicyT const& pol)
0152 {
0153 if (x < 0 || (boost::math::isnan)(x))
0154 {
0155 *presult = policies::raise_domain_error<RealT>(function, "The random variable must be >= 0, but is: %1%.", x, pol);
0156 return false;
0157 }
0158 return true;
0159 }
0160
0161 template <typename RealT, typename PolicyT>
0162 bool check_probability(char const* function, RealT p, RealT* presult, PolicyT const& pol)
0163 {
0164 if (p < 0 || p > 1 || (boost::math::isnan)(p))
0165 {
0166 *presult = policies::raise_domain_error<RealT>(function, "The probability be >= 0 and <= 1, but is: %1%.", p, pol);
0167 return false;
0168 }
0169 return true;
0170 }
0171
0172 template <typename RealT, typename PolicyT>
0173 RealT quantile_impl(hyperexponential_distribution<RealT, PolicyT> const& dist, RealT const& p, bool comp)
0174 {
0175
0176
0177 typedef typename policies::evaluation<RealT, PolicyT>::type value_type;
0178 typedef typename policies::normalise<PolicyT,
0179 policies::promote_float<false>,
0180 policies::promote_double<false>,
0181 policies::discrete_quantile<>,
0182 policies::assert_undefined<> >::type forwarding_policy;
0183
0184 static const char* function = comp ? "boost::math::quantile(const boost::math::complemented2_type<boost::math::hyperexponential_distribution<%1%>, %1%>&)"
0185 : "boost::math::quantile(const boost::math::hyperexponential_distribution<%1%>&, %1%)";
0186
0187 RealT result = 0;
0188
0189 if (!check_probability(function, p, &result, PolicyT()))
0190 {
0191 return result;
0192 }
0193
0194 const std::size_t n = dist.num_phases();
0195 const std::vector<RealT> probs = dist.probabilities();
0196 const std::vector<RealT> rates = dist.rates();
0197
0198
0199
0200 RealT guess = 0;
0201 if (comp)
0202 {
0203 for (std::size_t i = 0; i < n; ++i)
0204 {
0205 const exponential_distribution<RealT,PolicyT> exp(rates[i]);
0206
0207 guess += probs[i]*quantile(complement(exp, p));
0208 }
0209 }
0210 else
0211 {
0212 for (std::size_t i = 0; i < n; ++i)
0213 {
0214 const exponential_distribution<RealT,PolicyT> exp(rates[i]);
0215
0216 guess += probs[i]*quantile(exp, p);
0217 }
0218 }
0219
0220
0221 if (n == 1)
0222 {
0223 return guess;
0224 }
0225
0226 value_type q;
0227 q = detail::generic_quantile(hyperexponential_distribution<RealT,forwarding_policy>(probs, rates),
0228 p,
0229 guess,
0230 comp,
0231 function);
0232
0233 result = policies::checked_narrowing_cast<RealT,forwarding_policy>(q, function);
0234
0235 return result;
0236 }
0237
0238 }}
0239
0240
0241 template <typename RealT = double, typename PolicyT = policies::policy<> >
0242 class hyperexponential_distribution
0243 {
0244 public: typedef RealT value_type;
0245 public: typedef PolicyT policy_type;
0246
0247
0248 public: hyperexponential_distribution()
0249 : probs_(1, 1),
0250 rates_(1, 1)
0251 {
0252 RealT err;
0253 hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
0254 probs_,
0255 rates_,
0256 &err,
0257 PolicyT());
0258 }
0259
0260
0261 public: template <typename ProbIterT, typename RateIterT>
0262 hyperexponential_distribution(ProbIterT prob_first, ProbIterT prob_last,
0263 RateIterT rate_first, RateIterT rate_last)
0264 : probs_(prob_first, prob_last),
0265 rates_(rate_first, rate_last)
0266 {
0267 hyperexp_detail::normalize(probs_);
0268 RealT err;
0269 hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
0270 probs_,
0271 rates_,
0272 &err,
0273 PolicyT());
0274 }
0275 private: template <typename T, typename = void>
0276 struct is_iterator
0277 {
0278 static constexpr bool value = false;
0279 };
0280
0281 template <typename T>
0282 struct is_iterator<T, boost::math::tools::void_t<typename std::iterator_traits<T>::difference_type>>
0283 {
0284
0285 static constexpr bool value = !std::is_same<typename std::iterator_traits<T>::difference_type, void>::value;
0286 };
0287
0288
0289
0290
0291 public: template <typename ProbRangeT, typename RateRangeT,
0292 typename std::enable_if<!is_iterator<ProbRangeT>::value &&
0293 !is_iterator<RateRangeT>::value, bool>::type = true>
0294 hyperexponential_distribution(ProbRangeT const& prob_range,
0295 RateRangeT const& rate_range)
0296 : probs_(std::begin(prob_range), std::end(prob_range)),
0297 rates_(std::begin(rate_range), std::end(rate_range))
0298 {
0299 hyperexp_detail::normalize(probs_);
0300
0301 RealT err;
0302 hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
0303 probs_,
0304 rates_,
0305 &err,
0306 PolicyT());
0307 }
0308
0309
0310
0311
0312
0313 public: template <typename RateIterT, typename RateIterT2,
0314 typename std::enable_if<is_iterator<RateIterT>::value ||
0315 is_iterator<RateIterT2>::value, bool>::type = true>
0316 hyperexponential_distribution(RateIterT const& rate_first,
0317 RateIterT2 const& rate_last)
0318 : probs_(std::distance(rate_first, rate_last), 1),
0319 rates_(rate_first, rate_last)
0320 {
0321 hyperexp_detail::normalize(probs_);
0322
0323 RealT err;
0324 hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
0325 probs_,
0326 rates_,
0327 &err,
0328 PolicyT());
0329 }
0330
0331
0332 public: hyperexponential_distribution(std::initializer_list<RealT> l1, std::initializer_list<RealT> l2)
0333 : probs_(l1.begin(), l1.end()),
0334 rates_(l2.begin(), l2.end())
0335 {
0336 hyperexp_detail::normalize(probs_);
0337
0338 RealT err;
0339 hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
0340 probs_,
0341 rates_,
0342 &err,
0343 PolicyT());
0344 }
0345
0346 public: hyperexponential_distribution(std::initializer_list<RealT> l1)
0347 : probs_(l1.size(), 1),
0348 rates_(l1.begin(), l1.end())
0349 {
0350 hyperexp_detail::normalize(probs_);
0351
0352 RealT err;
0353 hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
0354 probs_,
0355 rates_,
0356 &err,
0357 PolicyT());
0358 }
0359
0360
0361 public: template <typename RateRangeT>
0362 hyperexponential_distribution(RateRangeT const& rate_range)
0363 : probs_(std::distance(std::begin(rate_range), std::end(rate_range)), 1),
0364 rates_(std::begin(rate_range), std::end(rate_range))
0365 {
0366 hyperexp_detail::normalize(probs_);
0367
0368 RealT err;
0369 hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
0370 probs_,
0371 rates_,
0372 &err,
0373 PolicyT());
0374 }
0375
0376 public: std::vector<RealT> probabilities() const
0377 {
0378 return probs_;
0379 }
0380
0381 public: std::vector<RealT> rates() const
0382 {
0383 return rates_;
0384 }
0385
0386 public: std::size_t num_phases() const
0387 {
0388 return rates_.size();
0389 }
0390
0391
0392 private: std::vector<RealT> probs_;
0393 private: std::vector<RealT> rates_;
0394 };
0395
0396
0397
0398 typedef hyperexponential_distribution<double> hyperexponential;
0399
0400
0401
0402 template <typename RealT, typename PolicyT>
0403 std::pair<RealT,RealT> range(hyperexponential_distribution<RealT,PolicyT> const&)
0404 {
0405 if (std::numeric_limits<RealT>::has_infinity)
0406 {
0407 return std::make_pair(static_cast<RealT>(0), std::numeric_limits<RealT>::infinity());
0408 }
0409
0410 return std::make_pair(static_cast<RealT>(0), tools::max_value<RealT>());
0411 }
0412
0413
0414
0415 template <typename RealT, typename PolicyT>
0416 std::pair<RealT,RealT> support(hyperexponential_distribution<RealT,PolicyT> const&)
0417 {
0418 return std::make_pair(tools::min_value<RealT>(), tools::max_value<RealT>());
0419 }
0420
0421 template <typename RealT, typename PolicyT>
0422 RealT pdf(hyperexponential_distribution<RealT, PolicyT> const& dist, RealT const& x)
0423 {
0424 BOOST_MATH_STD_USING
0425 RealT result = 0;
0426
0427 if (!hyperexp_detail::check_x("boost::math::pdf(const boost::math::hyperexponential_distribution<%1%>&, %1%)", x, &result, PolicyT()))
0428 {
0429 return result;
0430 }
0431
0432 const std::size_t n = dist.num_phases();
0433 const std::vector<RealT> probs = dist.probabilities();
0434 const std::vector<RealT> rates = dist.rates();
0435
0436 for (std::size_t i = 0; i < n; ++i)
0437 {
0438 const exponential_distribution<RealT,PolicyT> exp(rates[i]);
0439
0440 result += probs[i]*pdf(exp, x);
0441
0442 }
0443
0444 return result;
0445 }
0446
0447 template <typename RealT, typename PolicyT>
0448 RealT cdf(hyperexponential_distribution<RealT, PolicyT> const& dist, RealT const& x)
0449 {
0450 RealT result = 0;
0451
0452 if (!hyperexp_detail::check_x("boost::math::cdf(const boost::math::hyperexponential_distribution<%1%>&, %1%)", x, &result, PolicyT()))
0453 {
0454 return result;
0455 }
0456
0457 const std::size_t n = dist.num_phases();
0458 const std::vector<RealT> probs = dist.probabilities();
0459 const std::vector<RealT> rates = dist.rates();
0460
0461 for (std::size_t i = 0; i < n; ++i)
0462 {
0463 const exponential_distribution<RealT,PolicyT> exp(rates[i]);
0464
0465 result += probs[i]*cdf(exp, x);
0466 }
0467
0468 return result;
0469 }
0470
0471 template <typename RealT, typename PolicyT>
0472 RealT quantile(hyperexponential_distribution<RealT, PolicyT> const& dist, RealT const& p)
0473 {
0474 return hyperexp_detail::quantile_impl(dist, p , false);
0475 }
0476
0477 template <typename RealT, typename PolicyT>
0478 RealT cdf(complemented2_type<hyperexponential_distribution<RealT,PolicyT>, RealT> const& c)
0479 {
0480 RealT const& x = c.param;
0481 hyperexponential_distribution<RealT,PolicyT> const& dist = c.dist;
0482
0483 RealT result = 0;
0484
0485 if (!hyperexp_detail::check_x("boost::math::cdf(boost::math::complemented2_type<const boost::math::hyperexponential_distribution<%1%>&, %1%>)", x, &result, PolicyT()))
0486 {
0487 return result;
0488 }
0489
0490 const std::size_t n = dist.num_phases();
0491 const std::vector<RealT> probs = dist.probabilities();
0492 const std::vector<RealT> rates = dist.rates();
0493
0494 for (std::size_t i = 0; i < n; ++i)
0495 {
0496 const exponential_distribution<RealT,PolicyT> exp(rates[i]);
0497
0498 result += probs[i]*cdf(complement(exp, x));
0499 }
0500
0501 return result;
0502 }
0503
0504
0505 template <typename RealT, typename PolicyT>
0506 RealT quantile(complemented2_type<hyperexponential_distribution<RealT, PolicyT>, RealT> const& c)
0507 {
0508 RealT const& p = c.param;
0509 hyperexponential_distribution<RealT,PolicyT> const& dist = c.dist;
0510
0511 return hyperexp_detail::quantile_impl(dist, p , true);
0512 }
0513
0514 template <typename RealT, typename PolicyT>
0515 RealT mean(hyperexponential_distribution<RealT, PolicyT> const& dist)
0516 {
0517 RealT result = 0;
0518
0519 const std::size_t n = dist.num_phases();
0520 const std::vector<RealT> probs = dist.probabilities();
0521 const std::vector<RealT> rates = dist.rates();
0522
0523 for (std::size_t i = 0; i < n; ++i)
0524 {
0525 const exponential_distribution<RealT,PolicyT> exp(rates[i]);
0526
0527 result += probs[i]*mean(exp);
0528 }
0529
0530 return result;
0531 }
0532
0533 template <typename RealT, typename PolicyT>
0534 RealT variance(hyperexponential_distribution<RealT, PolicyT> const& dist)
0535 {
0536 RealT result = 0;
0537
0538 const std::size_t n = dist.num_phases();
0539 const std::vector<RealT> probs = dist.probabilities();
0540 const std::vector<RealT> rates = dist.rates();
0541
0542 for (std::size_t i = 0; i < n; ++i)
0543 {
0544 result += probs[i]/(rates[i]*rates[i]);
0545 }
0546
0547 const RealT mean = boost::math::mean(dist);
0548
0549 result = 2*result-mean*mean;
0550
0551 return result;
0552 }
0553
0554 template <typename RealT, typename PolicyT>
0555 RealT skewness(hyperexponential_distribution<RealT,PolicyT> const& dist)
0556 {
0557 BOOST_MATH_STD_USING
0558 const std::size_t n = dist.num_phases();
0559 const std::vector<RealT> probs = dist.probabilities();
0560 const std::vector<RealT> rates = dist.rates();
0561
0562 RealT s1 = 0;
0563 RealT s2 = 0;
0564 RealT s3 = 0;
0565 for (std::size_t i = 0; i < n; ++i)
0566 {
0567 const RealT p = probs[i];
0568 const RealT r = rates[i];
0569 const RealT r2 = r*r;
0570 const RealT r3 = r2*r;
0571
0572 s1 += p/r;
0573 s2 += p/r2;
0574 s3 += p/r3;
0575 }
0576
0577 const RealT s1s1 = s1*s1;
0578
0579 const RealT num = (6*s3 - (3*(2*s2 - s1s1) + s1s1)*s1);
0580 const RealT den = (2*s2 - s1s1);
0581
0582 return num / pow(den, static_cast<RealT>(1.5));
0583 }
0584
0585 template <typename RealT, typename PolicyT>
0586 RealT kurtosis(hyperexponential_distribution<RealT,PolicyT> const& dist)
0587 {
0588 const std::size_t n = dist.num_phases();
0589 const std::vector<RealT> probs = dist.probabilities();
0590 const std::vector<RealT> rates = dist.rates();
0591
0592 RealT s1 = 0;
0593 RealT s2 = 0;
0594 RealT s3 = 0;
0595 RealT s4 = 0;
0596 for (std::size_t i = 0; i < n; ++i)
0597 {
0598 const RealT p = probs[i];
0599 const RealT r = rates[i];
0600 const RealT r2 = r*r;
0601 const RealT r3 = r2*r;
0602 const RealT r4 = r3*r;
0603
0604 s1 += p/r;
0605 s2 += p/r2;
0606 s3 += p/r3;
0607 s4 += p/r4;
0608 }
0609
0610 const RealT s1s1 = s1*s1;
0611
0612 const RealT num = (24*s4 - 24*s3*s1 + 3*(2*(2*s2 - s1s1) + s1s1)*s1s1);
0613 const RealT den = (2*s2 - s1s1);
0614
0615 return num/(den*den);
0616 }
0617
0618 template <typename RealT, typename PolicyT>
0619 RealT kurtosis_excess(hyperexponential_distribution<RealT,PolicyT> const& dist)
0620 {
0621 return kurtosis(dist) - 3;
0622 }
0623
0624 template <typename RealT, typename PolicyT>
0625 RealT mode(hyperexponential_distribution<RealT,PolicyT> const& )
0626 {
0627 return 0;
0628 }
0629
0630 }}
0631
0632 #ifdef _MSC_VER
0633 #pragma warning (pop)
0634 #endif
0635
0636
0637
0638 #include <boost/math/distributions/detail/derived_accessors.hpp>
0639 #include <boost/math/distributions/detail/generic_quantile.hpp>
0640
0641 #endif