hyperexponential.hpp 21 KB

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