]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/math/include/boost/math/distributions/inverse_gaussian.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / math / include / boost / math / distributions / inverse_gaussian.hpp
CommitLineData
7c673cae
FG
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
68namespace boost{ namespace math{
69
70template <class RealType = double, class Policy = policies::policy<> >
71class inverse_gaussian_distribution
72{
73public:
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
108private:
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
116typedef inverse_gaussian_distribution<double> inverse_gaussian;
117
118template <class RealType, class Policy>
119inline 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
125template <class RealType, class Policy>
126inline 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
133template <class RealType, class Policy>
134inline 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
170template <class RealType, class Policy>
171inline 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
219template <class RealType, class Policy>
220struct 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
240template <class RealType, class Policy>
241struct 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
261namespace 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
319template <class RealType, class Policy>
320inline 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
365template <class RealType, class Policy>
366inline 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
415template <class RealType, class Policy>
416inline 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
450template <class RealType, class Policy>
451inline RealType mean(const inverse_gaussian_distribution<RealType, Policy>& dist)
452{ // aka mu
453 return dist.mean();
454}
455
456template <class RealType, class Policy>
457inline RealType scale(const inverse_gaussian_distribution<RealType, Policy>& dist)
458{ // aka lambda
459 return dist.scale();
460}
461
462template <class RealType, class Policy>
463inline RealType shape(const inverse_gaussian_distribution<RealType, Policy>& dist)
464{ // aka phi
465 return dist.shape();
466}
467
468template <class RealType, class Policy>
469inline 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
478template <class RealType, class Policy>
479inline 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
489template <class RealType, class Policy>
490inline 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
499template <class RealType, class Policy>
500inline 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
508template <class RealType, class Policy>
509inline 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