hyperexponential.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. // Copyright 2014 Marco Guazzone (marco.guazzone@gmail.com)
  2. //
  3. // Use, modification and distribution are subject to the
  4. // Boost Software License, Version 1.0. (See accompanying file
  5. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // This module implements the Hyper-Exponential distribution.
  8. //
  9. // References:
  10. // - "Queueing Theory in Manufacturing Systems Analysis and Design" by H.T. Papadopolous, C. Heavey and J. Browne (Chapman & Hall/CRC, 1993)
  11. // - http://reference.wolfram.com/language/ref/HyperexponentialDistribution.html
  12. // - http://en.wikipedia.org/wiki/Hyperexponential_distribution
  13. //
  14. #ifndef BOOST_MATH_DISTRIBUTIONS_HYPEREXPONENTIAL_HPP
  15. #define BOOST_MATH_DISTRIBUTIONS_HYPEREXPONENTIAL_HPP
  16. #include <boost/math/tools/cxx03_warn.hpp>
  17. #include <boost/math/distributions/complement.hpp>
  18. #include <boost/math/distributions/detail/common_error_handling.hpp>
  19. #include <boost/math/distributions/exponential.hpp>
  20. #include <boost/math/policies/policy.hpp>
  21. #include <boost/math/special_functions/fpclassify.hpp>
  22. #include <boost/math/tools/precision.hpp>
  23. #include <boost/math/tools/roots.hpp>
  24. #include <boost/math/tools/is_detected.hpp>
  25. #include <cstddef>
  26. #include <iterator>
  27. #include <limits>
  28. #include <numeric>
  29. #include <utility>
  30. #include <vector>
  31. #include <type_traits>
  32. #include <initializer_list>
  33. #ifdef _MSC_VER
  34. # pragma warning (push)
  35. # pragma warning(disable:4127) // conditional expression is constant
  36. # pragma warning(disable:4389) // '==' : signed/unsigned mismatch in test_tools
  37. #endif // _MSC_VER
  38. namespace boost { namespace math {
  39. namespace detail {
  40. template <typename Dist>
  41. 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);
  42. } // Namespace detail
  43. template <typename RealT, typename PolicyT>
  44. class hyperexponential_distribution;
  45. namespace /*<unnamed>*/ { namespace hyperexp_detail {
  46. template <typename T>
  47. void normalize(std::vector<T>& v)
  48. {
  49. if(!v.size())
  50. return; // Our error handlers will get this later
  51. const T sum = std::accumulate(v.begin(), v.end(), static_cast<T>(0));
  52. T final_sum = 0;
  53. const typename std::vector<T>::iterator end = --v.end();
  54. for (typename std::vector<T>::iterator it = v.begin();
  55. it != end;
  56. ++it)
  57. {
  58. *it /= sum;
  59. final_sum += *it;
  60. }
  61. *end = 1 - final_sum; // avoids round off errors, ensures the probs really do sum to 1.
  62. }
  63. template <typename RealT, typename PolicyT>
  64. bool check_probabilities(char const* function, std::vector<RealT> const& probabilities, RealT* presult, PolicyT const& pol)
  65. {
  66. BOOST_MATH_STD_USING
  67. const std::size_t n = probabilities.size();
  68. RealT sum = 0;
  69. for (std::size_t i = 0; i < n; ++i)
  70. {
  71. if (probabilities[i] < 0
  72. || probabilities[i] > 1
  73. || !(boost::math::isfinite)(probabilities[i]))
  74. {
  75. *presult = policies::raise_domain_error<RealT>(function,
  76. "The elements of parameter \"probabilities\" must be >= 0 and <= 1, but at least one of them was: %1%.",
  77. probabilities[i],
  78. pol);
  79. return false;
  80. }
  81. sum += probabilities[i];
  82. }
  83. //
  84. // We try to keep phase probabilities correctly normalized in the distribution constructors,
  85. // however in practice we have to allow for a very slight divergence from a sum of exactly 1:
  86. //
  87. if (fabs(sum - 1) > tools::epsilon<RealT>() * 2)
  88. {
  89. *presult = policies::raise_domain_error<RealT>(function,
  90. "The elements of parameter \"probabilities\" must sum to 1, but their sum is: %1%.",
  91. sum,
  92. pol);
  93. return false;
  94. }
  95. return true;
  96. }
  97. template <typename RealT, typename PolicyT>
  98. bool check_rates(char const* function, std::vector<RealT> const& rates, RealT* presult, PolicyT const& pol)
  99. {
  100. const std::size_t n = rates.size();
  101. for (std::size_t i = 0; i < n; ++i)
  102. {
  103. if (rates[i] <= 0
  104. || !(boost::math::isfinite)(rates[i]))
  105. {
  106. *presult = policies::raise_domain_error<RealT>(function,
  107. "The elements of parameter \"rates\" must be > 0, but at least one of them is: %1%.",
  108. rates[i],
  109. pol);
  110. return false;
  111. }
  112. }
  113. return true;
  114. }
  115. template <typename RealT, typename PolicyT>
  116. bool check_dist(char const* function, std::vector<RealT> const& probabilities, std::vector<RealT> const& rates, RealT* presult, PolicyT const& pol)
  117. {
  118. BOOST_MATH_STD_USING
  119. if (probabilities.size() != rates.size())
  120. {
  121. *presult = policies::raise_domain_error<RealT>(function,
  122. R"(The parameters "probabilities" and "rates" must have the same length, but their size differ by: %1%.)",
  123. fabs(static_cast<RealT>(probabilities.size())-static_cast<RealT>(rates.size())),
  124. pol);
  125. return false;
  126. }
  127. return check_probabilities(function, probabilities, presult, pol)
  128. && check_rates(function, rates, presult, pol);
  129. }
  130. template <typename RealT, typename PolicyT>
  131. bool check_x(char const* function, RealT x, RealT* presult, PolicyT const& pol)
  132. {
  133. if (x < 0 || (boost::math::isnan)(x))
  134. {
  135. *presult = policies::raise_domain_error<RealT>(function, "The random variable must be >= 0, but is: %1%.", x, pol);
  136. return false;
  137. }
  138. return true;
  139. }
  140. template <typename RealT, typename PolicyT>
  141. bool check_probability(char const* function, RealT p, RealT* presult, PolicyT const& pol)
  142. {
  143. if (p < 0 || p > 1 || (boost::math::isnan)(p))
  144. {
  145. *presult = policies::raise_domain_error<RealT>(function, "The probability be >= 0 and <= 1, but is: %1%.", p, pol);
  146. return false;
  147. }
  148. return true;
  149. }
  150. template <typename RealT, typename PolicyT>
  151. RealT quantile_impl(hyperexponential_distribution<RealT, PolicyT> const& dist, RealT const& p, bool comp)
  152. {
  153. // Don't have a closed form so try to numerically solve the inverse CDF...
  154. typedef typename policies::evaluation<RealT, PolicyT>::type value_type;
  155. typedef typename policies::normalise<PolicyT,
  156. policies::promote_float<false>,
  157. policies::promote_double<false>,
  158. policies::discrete_quantile<>,
  159. policies::assert_undefined<> >::type forwarding_policy;
  160. static const char* function = comp ? "boost::math::quantile(const boost::math::complemented2_type<boost::math::hyperexponential_distribution<%1%>, %1%>&)"
  161. : "boost::math::quantile(const boost::math::hyperexponential_distribution<%1%>&, %1%)";
  162. RealT result = 0;
  163. if (!check_probability(function, p, &result, PolicyT()))
  164. {
  165. return result;
  166. }
  167. const std::size_t n = dist.num_phases();
  168. const std::vector<RealT> probs = dist.probabilities();
  169. const std::vector<RealT> rates = dist.rates();
  170. // A possible (but inaccurate) approximation is given below, where the
  171. // quantile is given by the weighted sum of exponential quantiles:
  172. RealT guess = 0;
  173. if (comp)
  174. {
  175. for (std::size_t i = 0; i < n; ++i)
  176. {
  177. const exponential_distribution<RealT,PolicyT> exp(rates[i]);
  178. guess += probs[i]*quantile(complement(exp, p));
  179. }
  180. }
  181. else
  182. {
  183. for (std::size_t i = 0; i < n; ++i)
  184. {
  185. const exponential_distribution<RealT,PolicyT> exp(rates[i]);
  186. guess += probs[i]*quantile(exp, p);
  187. }
  188. }
  189. // Fast return in case the Hyper-Exponential is essentially an Exponential
  190. if (n == 1)
  191. {
  192. return guess;
  193. }
  194. value_type q;
  195. q = detail::generic_quantile(hyperexponential_distribution<RealT,forwarding_policy>(probs, rates),
  196. p,
  197. guess,
  198. comp,
  199. function);
  200. result = policies::checked_narrowing_cast<RealT,forwarding_policy>(q, function);
  201. return result;
  202. }
  203. }} // Namespace <unnamed>::hyperexp_detail
  204. template <typename RealT = double, typename PolicyT = policies::policy<> >
  205. class hyperexponential_distribution
  206. {
  207. public: typedef RealT value_type;
  208. public: typedef PolicyT policy_type;
  209. public: hyperexponential_distribution()
  210. : probs_(1, 1),
  211. rates_(1, 1)
  212. {
  213. RealT err;
  214. hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
  215. probs_,
  216. rates_,
  217. &err,
  218. PolicyT());
  219. }
  220. // Four arg constructor: no ambiguity here, the arguments must be two pairs of iterators:
  221. public: template <typename ProbIterT, typename RateIterT>
  222. hyperexponential_distribution(ProbIterT prob_first, ProbIterT prob_last,
  223. RateIterT rate_first, RateIterT rate_last)
  224. : probs_(prob_first, prob_last),
  225. rates_(rate_first, rate_last)
  226. {
  227. hyperexp_detail::normalize(probs_);
  228. RealT err;
  229. hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
  230. probs_,
  231. rates_,
  232. &err,
  233. PolicyT());
  234. }
  235. private: template <typename T, typename = void>
  236. struct is_iterator
  237. {
  238. static constexpr bool value = false;
  239. };
  240. template <typename T>
  241. struct is_iterator<T, boost::math::tools::void_t<typename std::iterator_traits<T>::difference_type>>
  242. {
  243. // std::iterator_traits<T>::difference_type returns void for invalid types
  244. static constexpr bool value = !std::is_same<typename std::iterator_traits<T>::difference_type, void>::value;
  245. };
  246. // Two arg constructor from 2 ranges, we SFINAE this out of existence if
  247. // either argument type is incrementable as in that case the type is
  248. // probably an iterator:
  249. public: template <typename ProbRangeT, typename RateRangeT,
  250. typename std::enable_if<!is_iterator<ProbRangeT>::value &&
  251. !is_iterator<RateRangeT>::value, bool>::type = true>
  252. hyperexponential_distribution(ProbRangeT const& prob_range,
  253. RateRangeT const& rate_range)
  254. : probs_(std::begin(prob_range), std::end(prob_range)),
  255. rates_(std::begin(rate_range), std::end(rate_range))
  256. {
  257. hyperexp_detail::normalize(probs_);
  258. RealT err;
  259. hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
  260. probs_,
  261. rates_,
  262. &err,
  263. PolicyT());
  264. }
  265. // Two arg constructor for a pair of iterators: we SFINAE this out of
  266. // existence if neither argument types are incrementable.
  267. // Note that we allow different argument types here to allow for
  268. // construction from an array plus a pointer into that array.
  269. public: template <typename RateIterT, typename RateIterT2,
  270. typename std::enable_if<is_iterator<RateIterT>::value ||
  271. is_iterator<RateIterT2>::value, bool>::type = true>
  272. hyperexponential_distribution(RateIterT const& rate_first,
  273. RateIterT2 const& rate_last)
  274. : probs_(std::distance(rate_first, rate_last), 1), // will be normalized below
  275. rates_(rate_first, rate_last)
  276. {
  277. hyperexp_detail::normalize(probs_);
  278. RealT err;
  279. hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
  280. probs_,
  281. rates_,
  282. &err,
  283. PolicyT());
  284. }
  285. // Initializer list constructor: allows for construction from array literals:
  286. public: hyperexponential_distribution(std::initializer_list<RealT> l1, std::initializer_list<RealT> l2)
  287. : probs_(l1.begin(), l1.end()),
  288. rates_(l2.begin(), l2.end())
  289. {
  290. hyperexp_detail::normalize(probs_);
  291. RealT err;
  292. hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
  293. probs_,
  294. rates_,
  295. &err,
  296. PolicyT());
  297. }
  298. public: hyperexponential_distribution(std::initializer_list<RealT> l1)
  299. : probs_(l1.size(), 1),
  300. rates_(l1.begin(), l1.end())
  301. {
  302. hyperexp_detail::normalize(probs_);
  303. RealT err;
  304. hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
  305. probs_,
  306. rates_,
  307. &err,
  308. PolicyT());
  309. }
  310. // Single argument constructor: argument must be a range.
  311. public: template <typename RateRangeT>
  312. hyperexponential_distribution(RateRangeT const& rate_range)
  313. : probs_(std::distance(std::begin(rate_range), std::end(rate_range)), 1), // will be normalized below
  314. rates_(std::begin(rate_range), std::end(rate_range))
  315. {
  316. hyperexp_detail::normalize(probs_);
  317. RealT err;
  318. hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
  319. probs_,
  320. rates_,
  321. &err,
  322. PolicyT());
  323. }
  324. public: std::vector<RealT> probabilities() const
  325. {
  326. return probs_;
  327. }
  328. public: std::vector<RealT> rates() const
  329. {
  330. return rates_;
  331. }
  332. public: std::size_t num_phases() const
  333. {
  334. return rates_.size();
  335. }
  336. private: std::vector<RealT> probs_;
  337. private: std::vector<RealT> rates_;
  338. }; // class hyperexponential_distribution
  339. // Convenient type synonym for double.
  340. typedef hyperexponential_distribution<double> hyperexponential;
  341. // Range of permissible values for random variable x
  342. template <typename RealT, typename PolicyT>
  343. std::pair<RealT,RealT> range(hyperexponential_distribution<RealT,PolicyT> const&)
  344. {
  345. if (std::numeric_limits<RealT>::has_infinity)
  346. {
  347. return std::make_pair(static_cast<RealT>(0), std::numeric_limits<RealT>::infinity()); // 0 to +inf.
  348. }
  349. return std::make_pair(static_cast<RealT>(0), tools::max_value<RealT>()); // 0 to +<max value>
  350. }
  351. // Range of supported values for random variable x.
  352. // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
  353. template <typename RealT, typename PolicyT>
  354. std::pair<RealT,RealT> support(hyperexponential_distribution<RealT,PolicyT> const&)
  355. {
  356. return std::make_pair(tools::min_value<RealT>(), tools::max_value<RealT>()); // <min value> to +<max value>.
  357. }
  358. template <typename RealT, typename PolicyT>
  359. RealT pdf(hyperexponential_distribution<RealT, PolicyT> const& dist, RealT const& x)
  360. {
  361. BOOST_MATH_STD_USING
  362. RealT result = 0;
  363. if (!hyperexp_detail::check_x("boost::math::pdf(const boost::math::hyperexponential_distribution<%1%>&, %1%)", x, &result, PolicyT()))
  364. {
  365. return result;
  366. }
  367. const std::size_t n = dist.num_phases();
  368. const std::vector<RealT> probs = dist.probabilities();
  369. const std::vector<RealT> rates = dist.rates();
  370. for (std::size_t i = 0; i < n; ++i)
  371. {
  372. const exponential_distribution<RealT,PolicyT> exp(rates[i]);
  373. result += probs[i]*pdf(exp, x);
  374. //result += probs[i]*rates[i]*exp(-rates[i]*x);
  375. }
  376. return result;
  377. }
  378. template <typename RealT, typename PolicyT>
  379. RealT cdf(hyperexponential_distribution<RealT, PolicyT> const& dist, RealT const& x)
  380. {
  381. RealT result = 0;
  382. if (!hyperexp_detail::check_x("boost::math::cdf(const boost::math::hyperexponential_distribution<%1%>&, %1%)", x, &result, PolicyT()))
  383. {
  384. return result;
  385. }
  386. const std::size_t n = dist.num_phases();
  387. const std::vector<RealT> probs = dist.probabilities();
  388. const std::vector<RealT> rates = dist.rates();
  389. for (std::size_t i = 0; i < n; ++i)
  390. {
  391. const exponential_distribution<RealT,PolicyT> exp(rates[i]);
  392. result += probs[i]*cdf(exp, x);
  393. }
  394. return result;
  395. }
  396. template <typename RealT, typename PolicyT>
  397. RealT quantile(hyperexponential_distribution<RealT, PolicyT> const& dist, RealT const& p)
  398. {
  399. return hyperexp_detail::quantile_impl(dist, p , false);
  400. }
  401. template <typename RealT, typename PolicyT>
  402. RealT cdf(complemented2_type<hyperexponential_distribution<RealT,PolicyT>, RealT> const& c)
  403. {
  404. RealT const& x = c.param;
  405. hyperexponential_distribution<RealT,PolicyT> const& dist = c.dist;
  406. RealT result = 0;
  407. if (!hyperexp_detail::check_x("boost::math::cdf(boost::math::complemented2_type<const boost::math::hyperexponential_distribution<%1%>&, %1%>)", x, &result, PolicyT()))
  408. {
  409. return result;
  410. }
  411. const std::size_t n = dist.num_phases();
  412. const std::vector<RealT> probs = dist.probabilities();
  413. const std::vector<RealT> rates = dist.rates();
  414. for (std::size_t i = 0; i < n; ++i)
  415. {
  416. const exponential_distribution<RealT,PolicyT> exp(rates[i]);
  417. result += probs[i]*cdf(complement(exp, x));
  418. }
  419. return result;
  420. }
  421. template <typename RealT, typename PolicyT>
  422. RealT quantile(complemented2_type<hyperexponential_distribution<RealT, PolicyT>, RealT> const& c)
  423. {
  424. RealT const& p = c.param;
  425. hyperexponential_distribution<RealT,PolicyT> const& dist = c.dist;
  426. return hyperexp_detail::quantile_impl(dist, p , true);
  427. }
  428. template <typename RealT, typename PolicyT>
  429. RealT mean(hyperexponential_distribution<RealT, PolicyT> const& dist)
  430. {
  431. RealT result = 0;
  432. const std::size_t n = dist.num_phases();
  433. const std::vector<RealT> probs = dist.probabilities();
  434. const std::vector<RealT> rates = dist.rates();
  435. for (std::size_t i = 0; i < n; ++i)
  436. {
  437. const exponential_distribution<RealT,PolicyT> exp(rates[i]);
  438. result += probs[i]*mean(exp);
  439. }
  440. return result;
  441. }
  442. template <typename RealT, typename PolicyT>
  443. RealT variance(hyperexponential_distribution<RealT, PolicyT> const& dist)
  444. {
  445. RealT result = 0;
  446. const std::size_t n = dist.num_phases();
  447. const std::vector<RealT> probs = dist.probabilities();
  448. const std::vector<RealT> rates = dist.rates();
  449. for (std::size_t i = 0; i < n; ++i)
  450. {
  451. result += probs[i]/(rates[i]*rates[i]);
  452. }
  453. const RealT mean = boost::math::mean(dist);
  454. result = 2*result-mean*mean;
  455. return result;
  456. }
  457. template <typename RealT, typename PolicyT>
  458. RealT skewness(hyperexponential_distribution<RealT,PolicyT> const& dist)
  459. {
  460. BOOST_MATH_STD_USING
  461. const std::size_t n = dist.num_phases();
  462. const std::vector<RealT> probs = dist.probabilities();
  463. const std::vector<RealT> rates = dist.rates();
  464. RealT s1 = 0; // \sum_{i=1}^n \frac{p_i}{\lambda_i}
  465. RealT s2 = 0; // \sum_{i=1}^n \frac{p_i}{\lambda_i^2}
  466. RealT s3 = 0; // \sum_{i=1}^n \frac{p_i}{\lambda_i^3}
  467. for (std::size_t i = 0; i < n; ++i)
  468. {
  469. const RealT p = probs[i];
  470. const RealT r = rates[i];
  471. const RealT r2 = r*r;
  472. const RealT r3 = r2*r;
  473. s1 += p/r;
  474. s2 += p/r2;
  475. s3 += p/r3;
  476. }
  477. const RealT s1s1 = s1*s1;
  478. const RealT num = (6*s3 - (3*(2*s2 - s1s1) + s1s1)*s1);
  479. const RealT den = (2*s2 - s1s1);
  480. return num / pow(den, static_cast<RealT>(1.5));
  481. }
  482. template <typename RealT, typename PolicyT>
  483. RealT kurtosis(hyperexponential_distribution<RealT,PolicyT> const& dist)
  484. {
  485. const std::size_t n = dist.num_phases();
  486. const std::vector<RealT> probs = dist.probabilities();
  487. const std::vector<RealT> rates = dist.rates();
  488. RealT s1 = 0; // \sum_{i=1}^n \frac{p_i}{\lambda_i}
  489. RealT s2 = 0; // \sum_{i=1}^n \frac{p_i}{\lambda_i^2}
  490. RealT s3 = 0; // \sum_{i=1}^n \frac{p_i}{\lambda_i^3}
  491. RealT s4 = 0; // \sum_{i=1}^n \frac{p_i}{\lambda_i^4}
  492. for (std::size_t i = 0; i < n; ++i)
  493. {
  494. const RealT p = probs[i];
  495. const RealT r = rates[i];
  496. const RealT r2 = r*r;
  497. const RealT r3 = r2*r;
  498. const RealT r4 = r3*r;
  499. s1 += p/r;
  500. s2 += p/r2;
  501. s3 += p/r3;
  502. s4 += p/r4;
  503. }
  504. const RealT s1s1 = s1*s1;
  505. const RealT num = (24*s4 - 24*s3*s1 + 3*(2*(2*s2 - s1s1) + s1s1)*s1s1);
  506. const RealT den = (2*s2 - s1s1);
  507. return num/(den*den);
  508. }
  509. template <typename RealT, typename PolicyT>
  510. RealT kurtosis_excess(hyperexponential_distribution<RealT,PolicyT> const& dist)
  511. {
  512. return kurtosis(dist) - 3;
  513. }
  514. template <typename RealT, typename PolicyT>
  515. RealT mode(hyperexponential_distribution<RealT,PolicyT> const& /*dist*/)
  516. {
  517. return 0;
  518. }
  519. }} // namespace boost::math
  520. #ifdef _MSC_VER
  521. #pragma warning (pop)
  522. #endif
  523. // This include must be at the end, *after* the accessors
  524. // for this distribution have been defined, in order to
  525. // keep compilers that support two-phase lookup happy.
  526. #include <boost/math/distributions/detail/derived_accessors.hpp>
  527. #include <boost/math/distributions/detail/generic_quantile.hpp>
  528. #endif // BOOST_MATH_DISTRIBUTIONS_HYPEREXPONENTIAL