To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

The primary repository for this project is hosted at https://github.com/sonic-visualiser/sv-dependency-builds .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / any / include / boost / math / distributions / hyperexponential.hpp @ 160:cff480c41f97

History | View | Annotate | Download (22 KB)

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/distributions/complement.hpp>
21
#include <boost/math/distributions/detail/common_error_handling.hpp>
22
#include <boost/math/distributions/exponential.hpp>
23
#include <boost/math/policies/policy.hpp>
24
#include <boost/math/special_functions/fpclassify.hpp>
25
#include <boost/math/tools/precision.hpp>
26
#include <boost/math/tools/roots.hpp>
27
#include <boost/range/begin.hpp>
28
#include <boost/range/end.hpp>
29
#include <boost/range/size.hpp>
30
#include <boost/type_traits/has_pre_increment.hpp>
31
#include <cstddef>
32
#include <iterator>
33
#include <limits>
34
#include <numeric>
35
#include <utility>
36
#include <vector>
37

    
38
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
39
# include <initializer_list>
40
#endif
41

    
42
#ifdef _MSC_VER
43
# pragma warning (push)
44
# pragma warning(disable:4127) // conditional expression is constant
45
# pragma warning(disable:4389) // '==' : signed/unsigned mismatch in test_tools
46
#endif // _MSC_VER
47

    
48
namespace boost { namespace math {
49

    
50
namespace detail {
51

    
52
template <typename Dist>
53
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);
54

    
55
} // Namespace detail
56

    
57

    
58
template <typename RealT, typename PolicyT>
59
class hyperexponential_distribution;
60

    
61

    
62
namespace /*<unnamed>*/ { namespace hyperexp_detail {
63

    
64
template <typename T>
65
void normalize(std::vector<T>& v)
66
{
67
   if(!v.size())
68
      return;  // Our error handlers will get this later
69
    const T sum = std::accumulate(v.begin(), v.end(), static_cast<T>(0));
70
    T final_sum = 0;
71
    const typename std::vector<T>::iterator end = --v.end();
72
    for (typename std::vector<T>::iterator it = v.begin();
73
         it != end;
74
         ++it)
75
    {
76
        *it /= sum;
77
        final_sum += *it;
78
    }
79
    *end = 1 - final_sum;  // avoids round off errors, ensures the probs really do sum to 1.
80
}
81

    
82
template <typename RealT, typename PolicyT>
83
bool check_probabilities(char const* function, std::vector<RealT> const& probabilities, RealT* presult, PolicyT const& pol)
84
{
85
    BOOST_MATH_STD_USING
86
    const std::size_t n = probabilities.size();
87
    RealT sum = 0;
88
    for (std::size_t i = 0; i < n; ++i)
89
    {
90
        if (probabilities[i] < 0
91
            || probabilities[i] > 1
92
            || !(boost::math::isfinite)(probabilities[i]))
93
        {
94
            *presult = policies::raise_domain_error<RealT>(function,
95
                                                           "The elements of parameter \"probabilities\" must be >= 0 and <= 1, but at least one of them was: %1%.",
96
                                                           probabilities[i],
97
                                                           pol);
98
            return false;
99
        }
100
        sum += probabilities[i];
101
    }
102

    
103
    //
104
    // We try to keep phase probabilities correctly normalized in the distribution constructors,
105
    // however in practice we have to allow for a very slight divergence from a sum of exactly 1:
106
    //
107
    if (fabs(sum - 1) > tools::epsilon<RealT>() * 2)
108
    {
109
        *presult = policies::raise_domain_error<RealT>(function,
110
                                                       "The elements of parameter \"probabilities\" must sum to 1, but their sum is: %1%.",
111
                                                       sum,
112
                                                       pol);
113
        return false;
114
    }
115

    
116
    return true;
117
}
118

    
119
template <typename RealT, typename PolicyT>
120
bool check_rates(char const* function, std::vector<RealT> const& rates, RealT* presult, PolicyT const& pol)
121
{
122
    const std::size_t n = rates.size();
123
    for (std::size_t i = 0; i < n; ++i)
124
    {
125
        if (rates[i] <= 0
126
            || !(boost::math::isfinite)(rates[i]))
127
        {
128
            *presult = policies::raise_domain_error<RealT>(function,
129
                                                           "The elements of parameter \"rates\" must be > 0, but at least one of them is: %1%.",
130
                                                           rates[i],
131
                                                           pol);
132
            return false;
133
        }
134
    }
135
    return true;
136
}
137

    
138
template <typename RealT, typename PolicyT>
139
bool check_dist(char const* function, std::vector<RealT> const& probabilities, std::vector<RealT> const& rates, RealT* presult, PolicyT const& pol)
140
{
141
    BOOST_MATH_STD_USING
142
    if (probabilities.size() != rates.size())
143
    {
144
        *presult = policies::raise_domain_error<RealT>(function,
145
                                                       "The parameters \"probabilities\" and \"rates\" must have the same length, but their size differ by: %1%.",
146
                                                       fabs(static_cast<RealT>(probabilities.size())-static_cast<RealT>(rates.size())),
147
                                                       pol);
148
        return false;
149
    }
150

    
151
    return check_probabilities(function, probabilities, presult, pol)
152
           && check_rates(function, rates, presult, pol);
153
}
154

    
155
template <typename RealT, typename PolicyT>
156
bool check_x(char const* function, RealT x, RealT* presult, PolicyT const& pol)
157
{
158
    if (x < 0 || (boost::math::isnan)(x))
159
    {
160
        *presult = policies::raise_domain_error<RealT>(function, "The random variable must be >= 0, but is: %1%.", x, pol);
161
        return false;
162
    }
163
    return true;
164
}
165

    
166
template <typename RealT, typename PolicyT>
167
bool check_probability(char const* function, RealT p, RealT* presult, PolicyT const& pol)
168
{
169
    if (p < 0 || p > 1 || (boost::math::isnan)(p))
170
    {
171
        *presult = policies::raise_domain_error<RealT>(function, "The probability be >= 0 and <= 1, but is: %1%.", p, pol);
172
        return false;
173
    }
174
    return true;
175
}
176

    
177
template <typename RealT, typename PolicyT>
178
RealT quantile_impl(hyperexponential_distribution<RealT, PolicyT> const& dist, RealT const& p, bool comp)
179
{
180
    // Don't have a closed form so try to numerically solve the inverse CDF...
181

    
182
    typedef typename policies::evaluation<RealT, PolicyT>::type value_type;
183
    typedef typename policies::normalise<PolicyT,
184
                                         policies::promote_float<false>,
185
                                         policies::promote_double<false>,
186
                                         policies::discrete_quantile<>,
187
                                         policies::assert_undefined<> >::type forwarding_policy;
188

    
189
    static const char* function = comp ? "boost::math::quantile(const boost::math::complemented2_type<boost::math::hyperexponential_distribution<%1%>, %1%>&)"
190
                                       : "boost::math::quantile(const boost::math::hyperexponential_distribution<%1%>&, %1%)";
191

    
192
    RealT result = 0;
193

    
194
    if (!check_probability(function, p, &result, PolicyT()))
195
    {
196
        return result;
197
    }
198

    
199
    const std::size_t n = dist.num_phases();
200
    const std::vector<RealT> probs = dist.probabilities();
201
    const std::vector<RealT> rates = dist.rates();
202

    
203
    // A possible (but inaccurate) approximation is given below, where the
204
    // quantile is given by the weighted sum of exponential quantiles:
205
    RealT guess = 0;
206
    if (comp)
207
    {
208
        for (std::size_t i = 0; i < n; ++i)
209
        {
210
            const exponential_distribution<RealT,PolicyT> exp(rates[i]);
211

    
212
            guess += probs[i]*quantile(complement(exp, p));
213
        }
214
    }
215
    else
216
    {
217
        for (std::size_t i = 0; i < n; ++i)
218
        {
219
            const exponential_distribution<RealT,PolicyT> exp(rates[i]);
220

    
221
            guess += probs[i]*quantile(exp, p);
222
        }
223
    }
224

    
225
    // Fast return in case the Hyper-Exponential is essentially an Exponential
226
    if (n == 1)
227
    {
228
        return guess;
229
    }
230

    
231
    value_type q;
232
    q = detail::generic_quantile(hyperexponential_distribution<RealT,forwarding_policy>(probs, rates),
233
                                 p,
234
                                 guess,
235
                                 comp,
236
                                 function);
237

    
238
    result = policies::checked_narrowing_cast<RealT,forwarding_policy>(q, function);
239

    
240
    return result;
241
}
242

    
243
}} // Namespace <unnamed>::hyperexp_detail
244

    
245

    
246
template <typename RealT = double, typename PolicyT = policies::policy<> >
247
class hyperexponential_distribution
248
{
249
    public: typedef RealT value_type;
250
    public: typedef PolicyT policy_type;
251

    
252

    
253
    public: hyperexponential_distribution()
254
    : probs_(1, 1),
255
      rates_(1, 1)
256
    {
257
        RealT err;
258
        hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
259
                                    probs_,
260
                                    rates_,
261
                                    &err,
262
                                    PolicyT());
263
    }
264

    
265
    // Four arg constructor: no ambiguity here, the arguments must be two pairs of iterators:
266
    public: template <typename ProbIterT, typename RateIterT>
267
            hyperexponential_distribution(ProbIterT prob_first, ProbIterT prob_last,
268
                                          RateIterT rate_first, RateIterT rate_last)
269
    : probs_(prob_first, prob_last),
270
      rates_(rate_first, rate_last)
271
    {
272
        hyperexp_detail::normalize(probs_);
273
        RealT err;
274
        hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
275
                                    probs_,
276
                                    rates_,
277
                                    &err,
278
                                    PolicyT());
279
    }
280

    
281
    // Two arg constructor from 2 ranges, we SFINAE this out of existance if
282
    // either argument type is incrementable as in that case the type is
283
    // probably an iterator:
284
    public: template <typename ProbRangeT, typename RateRangeT>
285
            hyperexponential_distribution(ProbRangeT const& prob_range,
286
                                          RateRangeT const& rate_range,
287
                                          typename boost::disable_if_c<boost::has_pre_increment<ProbRangeT>::value || boost::has_pre_increment<RateRangeT>::value>::type* = 0)
288
    : probs_(boost::begin(prob_range), boost::end(prob_range)),
289
      rates_(boost::begin(rate_range), boost::end(rate_range))
290
    {
291
        hyperexp_detail::normalize(probs_);
292

    
293
        RealT err;
294
        hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
295
                                    probs_,
296
                                    rates_,
297
                                    &err,
298
                                    PolicyT());
299
    }
300

    
301
    // Two arg constructor for a pair of iterators: we SFINAE this out of
302
    // existance if neither argument types are incrementable.
303
    // Note that we allow different argument types here to allow for
304
    // construction from an array plus a pointer into that array.
305
    public: template <typename RateIterT, typename RateIterT2>
306
            hyperexponential_distribution(RateIterT const& rate_first, 
307
                                          RateIterT2 const& rate_last, 
308
                                          typename boost::enable_if_c<boost::has_pre_increment<RateIterT>::value || boost::has_pre_increment<RateIterT2>::value>::type* = 0)
309
    : probs_(std::distance(rate_first, rate_last), 1), // will be normalized below
310
      rates_(rate_first, rate_last)
311
    {
312
        hyperexp_detail::normalize(probs_);
313

    
314
        RealT err;
315
        hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
316
                                    probs_,
317
                                    rates_,
318
                                    &err,
319
                                    PolicyT());
320
    }
321

    
322
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
323
      // Initializer list constructor: allows for construction from array literals:
324
public: hyperexponential_distribution(std::initializer_list<RealT> l1, std::initializer_list<RealT> l2)
325
      : probs_(l1.begin(), l1.end()),
326
        rates_(l2.begin(), l2.end())
327
      {
328
         hyperexp_detail::normalize(probs_);
329

    
330
         RealT err;
331
         hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
332
            probs_,
333
            rates_,
334
            &err,
335
            PolicyT());
336
      }
337

    
338
public: hyperexponential_distribution(std::initializer_list<RealT> l1)
339
      : probs_(l1.size(), 1),
340
        rates_(l1.begin(), l1.end())
341
      {
342
         hyperexp_detail::normalize(probs_);
343

    
344
         RealT err;
345
         hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
346
            probs_,
347
            rates_,
348
            &err,
349
            PolicyT());
350
      }
351
#endif // !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
352

    
353
    // Single argument constructor: argument must be a range.
354
    public: template <typename RateRangeT>
355
    hyperexponential_distribution(RateRangeT const& rate_range)
356
    : probs_(boost::size(rate_range), 1), // will be normalized below
357
      rates_(boost::begin(rate_range), boost::end(rate_range))
358
    {
359
        hyperexp_detail::normalize(probs_);
360

    
361
        RealT err;
362
        hyperexp_detail::check_dist("boost::math::hyperexponential_distribution<%1%>::hyperexponential_distribution",
363
                                    probs_,
364
                                    rates_,
365
                                    &err,
366
                                    PolicyT());
367
    }
368

    
369
    public: std::vector<RealT> probabilities() const
370
    {
371
        return probs_;
372
    }
373

    
374
    public: std::vector<RealT> rates() const
375
    {
376
        return rates_;
377
    }
378

    
379
    public: std::size_t num_phases() const
380
    {
381
        return rates_.size();
382
    }
383

    
384

    
385
    private: std::vector<RealT> probs_;
386
    private: std::vector<RealT> rates_;
387
}; // class hyperexponential_distribution
388

    
389

    
390
// Convenient type synonym for double.
391
typedef hyperexponential_distribution<double> hyperexponential;
392

    
393

    
394
// Range of permissible values for random variable x
395
template <typename RealT, typename PolicyT>
396
std::pair<RealT,RealT> range(hyperexponential_distribution<RealT,PolicyT> const&)
397
{
398
    if (std::numeric_limits<RealT>::has_infinity)
399
    {
400
        return std::make_pair(static_cast<RealT>(0), std::numeric_limits<RealT>::infinity()); // 0 to +inf.
401
    }
402

    
403
    return std::make_pair(static_cast<RealT>(0), tools::max_value<RealT>()); // 0 to +<max value>
404
}
405

    
406
// Range of supported values for random variable x.
407
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
408
template <typename RealT, typename PolicyT>
409
std::pair<RealT,RealT> support(hyperexponential_distribution<RealT,PolicyT> const&)
410
{
411
    return std::make_pair(tools::min_value<RealT>(), tools::max_value<RealT>()); // <min value> to +<max value>.
412
}
413

    
414
template <typename RealT, typename PolicyT>
415
RealT pdf(hyperexponential_distribution<RealT, PolicyT> const& dist, RealT const& x)
416
{
417
    BOOST_MATH_STD_USING
418
    RealT result = 0;
419

    
420
    if (!hyperexp_detail::check_x("boost::math::pdf(const boost::math::hyperexponential_distribution<%1%>&, %1%)", x, &result, PolicyT()))
421
    {
422
        return result;
423
    }
424

    
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

    
429
    for (std::size_t i = 0; i < n; ++i)
430
    {
431
        const exponential_distribution<RealT,PolicyT> exp(rates[i]);
432

    
433
        result += probs[i]*pdf(exp, x);
434
        //result += probs[i]*rates[i]*exp(-rates[i]*x);
435
    }
436

    
437
    return result;
438
}
439

    
440
template <typename RealT, typename PolicyT>
441
RealT cdf(hyperexponential_distribution<RealT, PolicyT> const& dist, RealT const& x)
442
{
443
    RealT result = 0;
444

    
445
    if (!hyperexp_detail::check_x("boost::math::cdf(const boost::math::hyperexponential_distribution<%1%>&, %1%)", x, &result, PolicyT()))
446
    {
447
        return result;
448
    }
449

    
450
    const std::size_t n = dist.num_phases();
451
    const std::vector<RealT> probs = dist.probabilities();
452
    const std::vector<RealT> rates = dist.rates();
453

    
454
    for (std::size_t i = 0; i < n; ++i)
455
    {
456
        const exponential_distribution<RealT,PolicyT> exp(rates[i]);
457

    
458
        result += probs[i]*cdf(exp, x);
459
    }
460

    
461
    return result;
462
}
463

    
464
template <typename RealT, typename PolicyT>
465
RealT quantile(hyperexponential_distribution<RealT, PolicyT> const& dist, RealT const& p)
466
{
467
    return hyperexp_detail::quantile_impl(dist, p , false);
468
}
469

    
470
template <typename RealT, typename PolicyT>
471
RealT cdf(complemented2_type<hyperexponential_distribution<RealT,PolicyT>, RealT> const& c)
472
{
473
    RealT const& x = c.param;
474
    hyperexponential_distribution<RealT,PolicyT> const& dist = c.dist;
475

    
476
    RealT result = 0;
477

    
478
    if (!hyperexp_detail::check_x("boost::math::cdf(boost::math::complemented2_type<const boost::math::hyperexponential_distribution<%1%>&, %1%>)", x, &result, PolicyT()))
479
    {
480
        return result;
481
    }
482

    
483
    const std::size_t n = dist.num_phases();
484
    const std::vector<RealT> probs = dist.probabilities();
485
    const std::vector<RealT> rates = dist.rates();
486

    
487
    for (std::size_t i = 0; i < n; ++i)
488
    {
489
        const exponential_distribution<RealT,PolicyT> exp(rates[i]);
490

    
491
        result += probs[i]*cdf(complement(exp, x));
492
    }
493

    
494
    return result;
495
}
496

    
497

    
498
template <typename RealT, typename PolicyT>
499
RealT quantile(complemented2_type<hyperexponential_distribution<RealT, PolicyT>, RealT> const& c)
500
{
501
    RealT const& p = c.param;
502
    hyperexponential_distribution<RealT,PolicyT> const& dist = c.dist;
503

    
504
    return hyperexp_detail::quantile_impl(dist, p , true);
505
}
506

    
507
template <typename RealT, typename PolicyT>
508
RealT mean(hyperexponential_distribution<RealT, PolicyT> const& dist)
509
{
510
    RealT result = 0;
511

    
512
    const std::size_t n = dist.num_phases();
513
    const std::vector<RealT> probs = dist.probabilities();
514
    const std::vector<RealT> rates = dist.rates();
515

    
516
    for (std::size_t i = 0; i < n; ++i)
517
    {
518
        const exponential_distribution<RealT,PolicyT> exp(rates[i]);
519

    
520
        result += probs[i]*mean(exp);
521
    }
522

    
523
    return result;
524
}
525

    
526
template <typename RealT, typename PolicyT>
527
RealT variance(hyperexponential_distribution<RealT, PolicyT> const& dist)
528
{
529
    RealT result = 0;
530

    
531
    const std::size_t n = dist.num_phases();
532
    const std::vector<RealT> probs = dist.probabilities();
533
    const std::vector<RealT> rates = dist.rates();
534

    
535
    for (std::size_t i = 0; i < n; ++i)
536
    {
537
        result += probs[i]/(rates[i]*rates[i]);
538
    }
539

    
540
    const RealT mean = boost::math::mean(dist);
541

    
542
    result = 2*result-mean*mean;
543

    
544
    return result;
545
}
546

    
547
template <typename RealT, typename PolicyT>
548
RealT skewness(hyperexponential_distribution<RealT,PolicyT> const& dist)
549
{
550
    BOOST_MATH_STD_USING
551
    const std::size_t n = dist.num_phases();
552
    const std::vector<RealT> probs = dist.probabilities();
553
    const std::vector<RealT> rates = dist.rates();
554

    
555
    RealT s1 = 0; // \sum_{i=1}^n \frac{p_i}{\lambda_i}
556
    RealT s2 = 0; // \sum_{i=1}^n \frac{p_i}{\lambda_i^2}
557
    RealT s3 = 0; // \sum_{i=1}^n \frac{p_i}{\lambda_i^3}
558
    for (std::size_t i = 0; i < n; ++i)
559
    {
560
        const RealT p = probs[i];
561
        const RealT r = rates[i];
562
        const RealT r2 = r*r;
563
        const RealT r3 = r2*r;
564

    
565
        s1 += p/r;
566
        s2 += p/r2;
567
        s3 += p/r3;
568
    }
569

    
570
    const RealT s1s1 = s1*s1;
571

    
572
    const RealT num = (6*s3 - (3*(2*s2 - s1s1) + s1s1)*s1);
573
    const RealT den = (2*s2 - s1s1);
574

    
575
    return num / pow(den, static_cast<RealT>(1.5));
576
}
577

    
578
template <typename RealT, typename PolicyT>
579
RealT kurtosis(hyperexponential_distribution<RealT,PolicyT> const& dist)
580
{
581
    const std::size_t n = dist.num_phases();
582
    const std::vector<RealT> probs = dist.probabilities();
583
    const std::vector<RealT> rates = dist.rates();
584

    
585
    RealT s1 = 0; // \sum_{i=1}^n \frac{p_i}{\lambda_i}
586
    RealT s2 = 0; // \sum_{i=1}^n \frac{p_i}{\lambda_i^2}
587
    RealT s3 = 0; // \sum_{i=1}^n \frac{p_i}{\lambda_i^3}
588
    RealT s4 = 0; // \sum_{i=1}^n \frac{p_i}{\lambda_i^4}
589
    for (std::size_t i = 0; i < n; ++i)
590
    {
591
        const RealT p = probs[i];
592
        const RealT r = rates[i];
593
        const RealT r2 = r*r;
594
        const RealT r3 = r2*r;
595
        const RealT r4 = r3*r;
596

    
597
        s1 += p/r;
598
        s2 += p/r2;
599
        s3 += p/r3;
600
        s4 += p/r4;
601
    }
602

    
603
    const RealT s1s1 = s1*s1;
604

    
605
    const RealT num = (24*s4 - 24*s3*s1 + 3*(2*(2*s2 - s1s1) + s1s1)*s1s1);
606
    const RealT den = (2*s2 - s1s1);
607

    
608
    return num/(den*den);
609
}
610

    
611
template <typename RealT, typename PolicyT>
612
RealT kurtosis_excess(hyperexponential_distribution<RealT,PolicyT> const& dist)
613
{
614
    return kurtosis(dist) - 3;
615
}
616

    
617
template <typename RealT, typename PolicyT>
618
RealT mode(hyperexponential_distribution<RealT,PolicyT> const& /*dist*/)
619
{
620
    return 0;
621
}
622

    
623
}} // namespace boost::math
624

    
625
#ifdef BOOST_MSVC
626
#pragma warning (pop)
627
#endif
628
// This include must be at the end, *after* the accessors
629
// for this distribution have been defined, in order to
630
// keep compilers that support two-phase lookup happy.
631
#include <boost/math/distributions/detail/derived_accessors.hpp>
632
#include <boost/math/distributions/detail/generic_quantile.hpp>
633

    
634
#endif // BOOST_MATH_DISTRIBUTIONS_HYPEREXPONENTIAL