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 / inverse_gaussian.hpp @ 160:cff480c41f97

History | View | Annotate | Download (19.8 KB)

1
//  Copyright John Maddock 2010.
2
//  Copyright Paul A. Bristow 2010.
3

    
4
//  Use, modification and distribution are subject to the
5
//  Boost Software License, Version 1.0. (See accompanying file
6
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7

    
8
#ifndef BOOST_STATS_INVERSE_GAUSSIAN_HPP
9
#define BOOST_STATS_INVERSE_GAUSSIAN_HPP
10

    
11
#ifdef _MSC_VER
12
#pragma warning(disable: 4512) // assignment operator could not be generated
13
#endif
14

    
15
// http://en.wikipedia.org/wiki/Normal-inverse_Gaussian_distribution
16
// http://mathworld.wolfram.com/InverseGaussianDistribution.html
17

    
18
// The normal-inverse Gaussian distribution
19
// also called the Wald distribution (some sources limit this to when mean = 1).
20

    
21
// It is the continuous probability distribution
22
// that is defined as the normal variance-mean mixture where the mixing density is the 
23
// inverse Gaussian distribution. The tails of the distribution decrease more slowly
24
// than the normal distribution. It is therefore suitable to model phenomena
25
// where numerically large values are more probable than is the case for the normal distribution.
26

    
27
// The Inverse Gaussian distribution was first studied in relationship to Brownian motion.
28
// In 1956 M.C.K. Tweedie used the name 'Inverse Gaussian' because there is an inverse 
29
// relationship between the time to cover a unit distance and distance covered in unit time.
30

    
31
// Examples are returns from financial assets and turbulent wind speeds. 
32
// The normal-inverse Gaussian distributions form
33
// a subclass of the generalised hyperbolic distributions.
34

    
35
// See also
36

    
37
// http://en.wikipedia.org/wiki/Normal_distribution
38
// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3661.htm
39
// Also:
40
// Weisstein, Eric W. "Normal Distribution."
41
// From MathWorld--A Wolfram Web Resource.
42
// http://mathworld.wolfram.com/NormalDistribution.html
43

    
44
// http://www.jstatsoft.org/v26/i04/paper General class of inverse Gaussian distributions.
45
// ig package - withdrawn but at http://cran.r-project.org/src/contrib/Archive/ig/
46

    
47
// http://www.stat.ucl.ac.be/ISdidactique/Rhelp/library/SuppDists/html/inverse_gaussian.html
48
// R package for dinverse_gaussian, ...
49

    
50
// http://www.statsci.org/s/inverse_gaussian.s  and http://www.statsci.org/s/inverse_gaussian.html
51

    
52
//#include <boost/math/distributions/fwd.hpp>
53
#include <boost/math/special_functions/erf.hpp> // for erf/erfc.
54
#include <boost/math/distributions/complement.hpp>
55
#include <boost/math/distributions/detail/common_error_handling.hpp>
56
#include <boost/math/distributions/normal.hpp>
57
#include <boost/math/distributions/gamma.hpp> // for gamma function
58
// using boost::math::gamma_p;
59

    
60
#include <boost/math/tools/tuple.hpp>
61
//using std::tr1::tuple;
62
//using std::tr1::make_tuple;
63
#include <boost/math/tools/roots.hpp>
64
//using boost::math::tools::newton_raphson_iterate;
65

    
66
#include <utility>
67

    
68
namespace boost{ namespace math{
69

    
70
template <class RealType = double, class Policy = policies::policy<> >
71
class inverse_gaussian_distribution
72
{
73
public:
74
   typedef RealType value_type;
75
   typedef Policy policy_type;
76

    
77
   inverse_gaussian_distribution(RealType l_mean = 1, RealType l_scale = 1)
78
      : m_mean(l_mean), m_scale(l_scale)
79
   { // Default is a 1,1 inverse_gaussian distribution.
80
     static const char* function = "boost::math::inverse_gaussian_distribution<%1%>::inverse_gaussian_distribution";
81

    
82
     RealType result;
83
     detail::check_scale(function, l_scale, &result, Policy());
84
     detail::check_location(function, l_mean, &result, Policy());
85
     detail::check_x_gt0(function, l_mean, &result, Policy());
86
   }
87

    
88
   RealType mean()const
89
   { // alias for location.
90
      return m_mean; // aka mu
91
   }
92

    
93
   // Synonyms, provided to allow generic use of find_location and find_scale.
94
   RealType location()const
95
   { // location, aka mu.
96
      return m_mean;
97
   }
98
   RealType scale()const
99
   { // scale, aka lambda.
100
      return m_scale;
101
   }
102

    
103
   RealType shape()const
104
   { // shape, aka phi = lambda/mu.
105
      return m_scale / m_mean;
106
   }
107

    
108
private:
109
   //
110
   // Data members:
111
   //
112
   RealType m_mean;  // distribution mean or location, aka mu.
113
   RealType m_scale;    // distribution standard deviation or scale, aka lambda.
114
}; // class normal_distribution
115

    
116
typedef inverse_gaussian_distribution<double> inverse_gaussian;
117

    
118
template <class RealType, class Policy>
119
inline const std::pair<RealType, RealType> range(const inverse_gaussian_distribution<RealType, Policy>& /*dist*/)
120
{ // Range of permissible values for random variable x, zero to max.
121
   using boost::math::tools::max_value;
122
   return std::pair<RealType, RealType>(static_cast<RealType>(0.), max_value<RealType>()); // - to + max value.
123
}
124

    
125
template <class RealType, class Policy>
126
inline const std::pair<RealType, RealType> support(const inverse_gaussian_distribution<RealType, Policy>& /*dist*/)
127
{ // Range of supported values for random variable x, zero to max.
128
  // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
129
   using boost::math::tools::max_value;
130
   return std::pair<RealType, RealType>(static_cast<RealType>(0.),  max_value<RealType>()); // - to + max value.
131
}
132

    
133
template <class RealType, class Policy>
134
inline RealType pdf(const inverse_gaussian_distribution<RealType, Policy>& dist, const RealType& x)
135
{ // Probability Density Function
136
   BOOST_MATH_STD_USING  // for ADL of std functions
137

    
138
   RealType scale = dist.scale();
139
   RealType mean = dist.mean();
140
   RealType result = 0;
141
   static const char* function = "boost::math::pdf(const inverse_gaussian_distribution<%1%>&, %1%)";
142
   if(false == detail::check_scale(function, scale, &result, Policy()))
143
   {
144
      return result;
145
   }
146
   if(false == detail::check_location(function, mean, &result, Policy()))
147
   {
148
      return result;
149
   }
150
   if(false == detail::check_x_gt0(function, mean, &result, Policy()))
151
   {
152
      return result;
153
   }
154
   if(false == detail::check_positive_x(function, x, &result, Policy()))
155
   {
156
      return result;
157
   }
158

    
159
   if (x == 0)
160
   {
161
     return 0; // Convenient, even if not defined mathematically.
162
   }
163

    
164
   result =
165
     sqrt(scale / (constants::two_pi<RealType>() * x * x * x))
166
    * exp(-scale * (x - mean) * (x - mean) / (2 * x * mean * mean));
167
   return result;
168
} // pdf
169

    
170
template <class RealType, class Policy>
171
inline RealType cdf(const inverse_gaussian_distribution<RealType, Policy>& dist, const RealType& x)
172
{ // Cumulative Density Function.
173
   BOOST_MATH_STD_USING  // for ADL of std functions.
174

    
175
   RealType scale = dist.scale();
176
   RealType mean = dist.mean();
177
   static const char* function = "boost::math::cdf(const inverse_gaussian_distribution<%1%>&, %1%)";
178
   RealType result = 0;
179
   if(false == detail::check_scale(function, scale, &result, Policy()))
180
   {
181
      return result;
182
   }
183
   if(false == detail::check_location(function, mean, &result, Policy()))
184
   {
185
      return result;
186
   }
187
   if (false == detail::check_x_gt0(function, mean, &result, Policy()))
188
   {
189
      return result;
190
   }
191
   if(false == detail::check_positive_x(function, x, &result, Policy()))
192
   {
193
     return result;
194
   }
195
   if (x == 0)
196
   {
197
     return 0; // Convenient, even if not defined mathematically.
198
   }
199
   // Problem with this formula for large scale > 1000 or small x, 
200
   //result = 0.5 * (erf(sqrt(scale / x) * ((x / mean) - 1) / constants::root_two<RealType>(), Policy()) + 1)
201
   //  + exp(2 * scale / mean) / 2 
202
   //  * (1 - erf(sqrt(scale / x) * (x / mean + 1) / constants::root_two<RealType>(), Policy()));
203
   // so use normal distribution version:
204
   // Wikipedia CDF equation http://en.wikipedia.org/wiki/Inverse_Gaussian_distribution.
205

    
206
   normal_distribution<RealType> n01;
207

    
208
   RealType n0 = sqrt(scale / x);
209
   n0 *= ((x / mean) -1);
210
   RealType n1 = cdf(n01, n0);
211
   RealType expfactor = exp(2 * scale / mean);
212
   RealType n3 = - sqrt(scale / x);
213
   n3 *= (x / mean) + 1;
214
   RealType n4 = cdf(n01, n3);
215
   result = n1 + expfactor * n4;
216
   return result;
217
} // cdf
218

    
219
template <class RealType, class Policy>
220
struct inverse_gaussian_quantile_functor
221
{ 
222

    
223
  inverse_gaussian_quantile_functor(const boost::math::inverse_gaussian_distribution<RealType, Policy> dist, RealType const& p)
224
    : distribution(dist), prob(p)
225
  {
226
  }
227
  boost::math::tuple<RealType, RealType> operator()(RealType const& x)
228
  {
229
    RealType c = cdf(distribution, x);
230
    RealType fx = c - prob;  // Difference cdf - value - to minimize.
231
    RealType dx = pdf(distribution, x); // pdf is 1st derivative.
232
    // return both function evaluation difference f(x) and 1st derivative f'(x).
233
    return boost::math::make_tuple(fx, dx);
234
  }
235
  private:
236
  const boost::math::inverse_gaussian_distribution<RealType, Policy> distribution;
237
  RealType prob; 
238
};
239

    
240
template <class RealType, class Policy>
241
struct inverse_gaussian_quantile_complement_functor
242
{ 
243
    inverse_gaussian_quantile_complement_functor(const boost::math::inverse_gaussian_distribution<RealType, Policy> dist, RealType const& p)
244
    : distribution(dist), prob(p)
245
  {
246
  }
247
  boost::math::tuple<RealType, RealType> operator()(RealType const& x)
248
  {
249
    RealType c = cdf(complement(distribution, x));
250
    RealType fx = c - prob;  // Difference cdf - value - to minimize.
251
    RealType dx = -pdf(distribution, x); // pdf is 1st derivative.
252
    // return both function evaluation difference f(x) and 1st derivative f'(x).
253
    //return std::tr1::make_tuple(fx, dx); if available.
254
    return boost::math::make_tuple(fx, dx);
255
  }
256
  private:
257
  const boost::math::inverse_gaussian_distribution<RealType, Policy> distribution;
258
  RealType prob; 
259
};
260

    
261
namespace detail
262
{
263
  template <class RealType>
264
  inline RealType guess_ig(RealType p, RealType mu = 1, RealType lambda = 1)
265
  { // guess at random variate value x for inverse gaussian quantile.
266
      BOOST_MATH_STD_USING
267
      using boost::math::policies::policy;
268
      // Error type.
269
      using boost::math::policies::overflow_error;
270
      // Action.
271
      using boost::math::policies::ignore_error;
272

    
273
      typedef policy<
274
        overflow_error<ignore_error> // Ignore overflow (return infinity)
275
      > no_overthrow_policy;
276

    
277
    RealType x; // result is guess at random variate value x.
278
    RealType phi = lambda / mu;
279
    if (phi > 2.)
280
    { // Big phi, so starting to look like normal Gaussian distribution.
281
      //    x=(qnorm(p,0,1,true,false) - 0.5 * sqrt(mu/lambda)) / sqrt(lambda/mu);
282
      // Whitmore, G.A. and Yalovsky, M.
283
      // A normalising logarithmic transformation for inverse Gaussian random variables,
284
      // Technometrics 20-2, 207-208 (1978), but using expression from
285
      // V Seshadri, Inverse Gaussian distribution (1998) ISBN 0387 98618 9, page 6.
286
 
287
      normal_distribution<RealType, no_overthrow_policy> n01;
288
      x = mu * exp(quantile(n01, p) / sqrt(phi) - 1/(2 * phi));
289
     }
290
    else
291
    { // phi < 2 so much less symmetrical with long tail,
292
      // so use gamma distribution as an approximation.
293
      using boost::math::gamma_distribution;
294

    
295
      // Define the distribution, using gamma_nooverflow:
296
      typedef gamma_distribution<RealType, no_overthrow_policy> gamma_nooverflow;
297

    
298
      gamma_nooverflow g(static_cast<RealType>(0.5), static_cast<RealType>(1.));
299

    
300
      // gamma_nooverflow g(static_cast<RealType>(0.5), static_cast<RealType>(1.));
301
      // R qgamma(0.2, 0.5, 1)  0.0320923
302
      RealType qg = quantile(complement(g, p));
303
      //RealType qg1 = qgamma(1.- p, 0.5, 1.0, true, false);
304
      x = lambda / (qg * 2);
305
      // 
306
      if (x > mu/2) // x > mu /2?
307
      { // x too large for the gamma approximation to work well.
308
        //x = qgamma(p, 0.5, 1.0); // qgamma(0.270614, 0.5, 1) = 0.05983807
309
        RealType q = quantile(g, p);
310
       // x = mu * exp(q * static_cast<RealType>(0.1));  // Said to improve at high p
311
       // x = mu * x;  // Improves at high p?
312
        x = mu * exp(q / sqrt(phi) - 1/(2 * phi));
313
      }
314
    }
315
    return x;
316
  }  // guess_ig
317
} // namespace detail
318

    
319
template <class RealType, class Policy>
320
inline RealType quantile(const inverse_gaussian_distribution<RealType, Policy>& dist, const RealType& p)
321
{
322
   BOOST_MATH_STD_USING  // for ADL of std functions.
323
   // No closed form exists so guess and use Newton Raphson iteration.
324

    
325
   RealType mean = dist.mean();
326
   RealType scale = dist.scale();
327
   static const char* function = "boost::math::quantile(const inverse_gaussian_distribution<%1%>&, %1%)";
328

    
329
   RealType result = 0;
330
   if(false == detail::check_scale(function, scale, &result, Policy()))
331
      return result;
332
   if(false == detail::check_location(function, mean, &result, Policy()))
333
      return result;
334
   if (false == detail::check_x_gt0(function, mean, &result, Policy()))
335
      return result;
336
   if(false == detail::check_probability(function, p, &result, Policy()))
337
      return result;
338
   if (p == 0)
339
   {
340
     return 0; // Convenient, even if not defined mathematically?
341
   }
342
   if (p == 1)
343
   { // overflow 
344
      result = policies::raise_overflow_error<RealType>(function,
345
        "probability parameter is 1, but must be < 1!", Policy());
346
      return result; // std::numeric_limits<RealType>::infinity();
347
   }
348

    
349
  RealType guess = detail::guess_ig(p, dist.mean(), dist.scale());
350
  using boost::math::tools::max_value;
351

    
352
  RealType min = 0.; // Minimum possible value is bottom of range of distribution.
353
  RealType max = max_value<RealType>();// Maximum possible value is top of range. 
354
  // int digits = std::numeric_limits<RealType>::digits; // Maximum possible binary digits accuracy for type T.
355
  // digits used to control how accurate to try to make the result.
356
  // To allow user to control accuracy versus speed,
357
  int get_digits = policies::digits<RealType, Policy>();// get digits from policy, 
358
  boost::uintmax_t m = policies::get_max_root_iterations<Policy>(); // and max iterations.
359
  using boost::math::tools::newton_raphson_iterate;
360
  result =
361
    newton_raphson_iterate(inverse_gaussian_quantile_functor<RealType, Policy>(dist, p), guess, min, max, get_digits, m);
362
   return result;
363
} // quantile
364

    
365
template <class RealType, class Policy>
366
inline RealType cdf(const complemented2_type<inverse_gaussian_distribution<RealType, Policy>, RealType>& c)
367
{
368
   BOOST_MATH_STD_USING  // for ADL of std functions.
369

    
370
   RealType scale = c.dist.scale();
371
   RealType mean = c.dist.mean();
372
   RealType x = c.param;
373
   static const char* function = "boost::math::cdf(const complement(inverse_gaussian_distribution<%1%>&), %1%)";
374
   // infinite arguments not supported.
375
   //if((boost::math::isinf)(x))
376
   //{
377
   //  if(x < 0) return 1; // cdf complement -infinity is unity.
378
   //  return 0; // cdf complement +infinity is zero
379
   //}
380
   // These produce MSVC 4127 warnings, so the above used instead.
381
   //if(std::numeric_limits<RealType>::has_infinity && x == std::numeric_limits<RealType>::infinity())
382
   //{ // cdf complement +infinity is zero.
383
   //  return 0;
384
   //}
385
   //if(std::numeric_limits<RealType>::has_infinity && x == -std::numeric_limits<RealType>::infinity())
386
   //{ // cdf complement -infinity is unity.
387
   //  return 1;
388
   //}
389
   RealType result = 0;
390
   if(false == detail::check_scale(function, scale, &result, Policy()))
391
      return result;
392
   if(false == detail::check_location(function, mean, &result, Policy()))
393
      return result;
394
   if (false == detail::check_x_gt0(function, mean, &result, Policy()))
395
      return result;
396
   if(false == detail::check_positive_x(function, x, &result, Policy()))
397
      return result;
398

    
399
   normal_distribution<RealType> n01;
400
   RealType n0 = sqrt(scale / x);
401
   n0 *= ((x / mean) -1);
402
   RealType cdf_1 = cdf(complement(n01, n0));
403

    
404
   RealType expfactor = exp(2 * scale / mean);
405
   RealType n3 = - sqrt(scale / x);
406
   n3 *= (x / mean) + 1;
407

    
408
   //RealType n5 = +sqrt(scale/x) * ((x /mean) + 1); // note now positive sign.
409
   RealType n6 = cdf(complement(n01, +sqrt(scale/x) * ((x /mean) + 1)));
410
   // RealType n4 = cdf(n01, n3); // = 
411
   result = cdf_1 - expfactor * n6; 
412
   return result;
413
} // cdf complement
414

    
415
template <class RealType, class Policy>
416
inline RealType quantile(const complemented2_type<inverse_gaussian_distribution<RealType, Policy>, RealType>& c)
417
{
418
   BOOST_MATH_STD_USING  // for ADL of std functions
419

    
420
   RealType scale = c.dist.scale();
421
   RealType mean = c.dist.mean();
422
   static const char* function = "boost::math::quantile(const complement(inverse_gaussian_distribution<%1%>&), %1%)";
423
   RealType result = 0;
424
   if(false == detail::check_scale(function, scale, &result, Policy()))
425
      return result;
426
   if(false == detail::check_location(function, mean, &result, Policy()))
427
      return result;
428
   if (false == detail::check_x_gt0(function, mean, &result, Policy()))
429
      return result;
430
   RealType q = c.param;
431
   if(false == detail::check_probability(function, q, &result, Policy()))
432
      return result;
433

    
434
   RealType guess = detail::guess_ig(q, mean, scale);
435
   // Complement.
436
   using boost::math::tools::max_value;
437

    
438
  RealType min = 0.; // Minimum possible value is bottom of range of distribution.
439
  RealType max = max_value<RealType>();// Maximum possible value is top of range. 
440
  // int digits = std::numeric_limits<RealType>::digits; // Maximum possible binary digits accuracy for type T.
441
  // digits used to control how accurate to try to make the result.
442
  int get_digits = policies::digits<RealType, Policy>();
443
  boost::uintmax_t m = policies::get_max_root_iterations<Policy>();
444
  using boost::math::tools::newton_raphson_iterate;
445
  result =
446
    newton_raphson_iterate(inverse_gaussian_quantile_complement_functor<RealType, Policy>(c.dist, q), guess, min, max, get_digits, m);
447
   return result;
448
} // quantile
449

    
450
template <class RealType, class Policy>
451
inline RealType mean(const inverse_gaussian_distribution<RealType, Policy>& dist)
452
{ // aka mu
453
   return dist.mean();
454
}
455

    
456
template <class RealType, class Policy>
457
inline RealType scale(const inverse_gaussian_distribution<RealType, Policy>& dist)
458
{ // aka lambda
459
   return dist.scale();
460
}
461

    
462
template <class RealType, class Policy>
463
inline RealType shape(const inverse_gaussian_distribution<RealType, Policy>& dist)
464
{ // aka phi
465
   return dist.shape();
466
}
467

    
468
template <class RealType, class Policy>
469
inline RealType standard_deviation(const inverse_gaussian_distribution<RealType, Policy>& dist)
470
{
471
  BOOST_MATH_STD_USING
472
  RealType scale = dist.scale();
473
  RealType mean = dist.mean();
474
  RealType result = sqrt(mean * mean * mean / scale);
475
  return result;
476
}
477

    
478
template <class RealType, class Policy>
479
inline RealType mode(const inverse_gaussian_distribution<RealType, Policy>& dist)
480
{
481
  BOOST_MATH_STD_USING
482
  RealType scale = dist.scale();
483
  RealType  mean = dist.mean();
484
  RealType result = mean * (sqrt(1 + (9 * mean * mean)/(4 * scale * scale)) 
485
      - 3 * mean / (2 * scale));
486
  return result;
487
}
488

    
489
template <class RealType, class Policy>
490
inline RealType skewness(const inverse_gaussian_distribution<RealType, Policy>& dist)
491
{
492
  BOOST_MATH_STD_USING
493
  RealType scale = dist.scale();
494
  RealType  mean = dist.mean();
495
  RealType result = 3 * sqrt(mean/scale);
496
  return result;
497
}
498

    
499
template <class RealType, class Policy>
500
inline RealType kurtosis(const inverse_gaussian_distribution<RealType, Policy>& dist)
501
{
502
  RealType scale = dist.scale();
503
  RealType  mean = dist.mean();
504
  RealType result = 15 * mean / scale -3;
505
  return result;
506
}
507

    
508
template <class RealType, class Policy>
509
inline RealType kurtosis_excess(const inverse_gaussian_distribution<RealType, Policy>& dist)
510
{
511
  RealType scale = dist.scale();
512
  RealType  mean = dist.mean();
513
  RealType result = 15 * mean / scale;
514
  return result;
515
}
516

    
517
} // namespace math
518
} // namespace boost
519

    
520
// This include must be at the end, *after* the accessors
521
// for this distribution have been defined, in order to
522
// keep compilers that support two-phase lookup happy.
523
#include <boost/math/distributions/detail/derived_accessors.hpp>
524

    
525
#endif // BOOST_STATS_INVERSE_GAUSSIAN_HPP
526

    
527