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