inverse_gaussian.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. // Copyright John Maddock 2010.
  2. // Copyright Paul A. Bristow 2010.
  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. #ifndef BOOST_STATS_INVERSE_GAUSSIAN_HPP
  7. #define BOOST_STATS_INVERSE_GAUSSIAN_HPP
  8. #ifdef _MSC_VER
  9. #pragma warning(disable: 4512) // assignment operator could not be generated
  10. #endif
  11. // http://en.wikipedia.org/wiki/Normal-inverse_Gaussian_distribution
  12. // http://mathworld.wolfram.com/InverseGaussianDistribution.html
  13. // The normal-inverse Gaussian distribution
  14. // also called the Wald distribution (some sources limit this to when mean = 1).
  15. // It is the continuous probability distribution
  16. // that is defined as the normal variance-mean mixture where the mixing density is the
  17. // inverse Gaussian distribution. The tails of the distribution decrease more slowly
  18. // than the normal distribution. It is therefore suitable to model phenomena
  19. // where numerically large values are more probable than is the case for the normal distribution.
  20. // The Inverse Gaussian distribution was first studied in relationship to Brownian motion.
  21. // In 1956 M.C.K. Tweedie used the name 'Inverse Gaussian' because there is an inverse
  22. // relationship between the time to cover a unit distance and distance covered in unit time.
  23. // Examples are returns from financial assets and turbulent wind speeds.
  24. // The normal-inverse Gaussian distributions form
  25. // a subclass of the generalised hyperbolic distributions.
  26. // See also
  27. // http://en.wikipedia.org/wiki/Normal_distribution
  28. // http://www.itl.nist.gov/div898/handbook/eda/section3/eda3661.htm
  29. // Also:
  30. // Weisstein, Eric W. "Normal Distribution."
  31. // From MathWorld--A Wolfram Web Resource.
  32. // http://mathworld.wolfram.com/NormalDistribution.html
  33. // http://www.jstatsoft.org/v26/i04/paper General class of inverse Gaussian distributions.
  34. // ig package - withdrawn but at http://cran.r-project.org/src/contrib/Archive/ig/
  35. // http://www.stat.ucl.ac.be/ISdidactique/Rhelp/library/SuppDists/html/inverse_gaussian.html
  36. // R package for dinverse_gaussian, ...
  37. // http://www.statsci.org/s/inverse_gaussian.s and http://www.statsci.org/s/inverse_gaussian.html
  38. //#include <boost/math/distributions/fwd.hpp>
  39. #include <boost/math/special_functions/erf.hpp> // for erf/erfc.
  40. #include <boost/math/distributions/complement.hpp>
  41. #include <boost/math/distributions/detail/common_error_handling.hpp>
  42. #include <boost/math/distributions/normal.hpp>
  43. #include <boost/math/distributions/gamma.hpp> // for gamma function
  44. // using boost::math::gamma_p;
  45. #include <boost/math/tools/tuple.hpp>
  46. //using std::tr1::tuple;
  47. //using std::tr1::make_tuple;
  48. #include <boost/math/tools/roots.hpp>
  49. //using boost::math::tools::newton_raphson_iterate;
  50. #include <utility>
  51. namespace boost{ namespace math{
  52. template <class RealType = double, class Policy = policies::policy<> >
  53. class inverse_gaussian_distribution
  54. {
  55. public:
  56. typedef RealType value_type;
  57. typedef Policy policy_type;
  58. inverse_gaussian_distribution(RealType l_mean = 1, RealType l_scale = 1)
  59. : m_mean(l_mean), m_scale(l_scale)
  60. { // Default is a 1,1 inverse_gaussian distribution.
  61. static const char* function = "boost::math::inverse_gaussian_distribution<%1%>::inverse_gaussian_distribution";
  62. RealType result;
  63. detail::check_scale(function, l_scale, &result, Policy());
  64. detail::check_location(function, l_mean, &result, Policy());
  65. }
  66. RealType mean()const
  67. { // alias for location.
  68. return m_mean; // aka mu
  69. }
  70. // Synonyms, provided to allow generic use of find_location and find_scale.
  71. RealType location()const
  72. { // location, aka mu.
  73. return m_mean;
  74. }
  75. RealType scale()const
  76. { // scale, aka lambda.
  77. return m_scale;
  78. }
  79. RealType shape()const
  80. { // shape, aka phi = lambda/mu.
  81. return m_scale / m_mean;
  82. }
  83. private:
  84. //
  85. // Data members:
  86. //
  87. RealType m_mean; // distribution mean or location, aka mu.
  88. RealType m_scale; // distribution standard deviation or scale, aka lambda.
  89. }; // class normal_distribution
  90. typedef inverse_gaussian_distribution<double> inverse_gaussian;
  91. template <class RealType, class Policy>
  92. inline const std::pair<RealType, RealType> range(const inverse_gaussian_distribution<RealType, Policy>& /*dist*/)
  93. { // Range of permissible values for random variable x, zero to max.
  94. using boost::math::tools::max_value;
  95. return std::pair<RealType, RealType>(static_cast<RealType>(0.), max_value<RealType>()); // - to + max value.
  96. }
  97. template <class RealType, class Policy>
  98. inline const std::pair<RealType, RealType> support(const inverse_gaussian_distribution<RealType, Policy>& /*dist*/)
  99. { // Range of supported values for random variable x, zero to max.
  100. // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
  101. using boost::math::tools::max_value;
  102. return std::pair<RealType, RealType>(static_cast<RealType>(0.), max_value<RealType>()); // - to + max value.
  103. }
  104. template <class RealType, class Policy>
  105. inline RealType pdf(const inverse_gaussian_distribution<RealType, Policy>& dist, const RealType& x)
  106. { // Probability Density Function
  107. BOOST_MATH_STD_USING // for ADL of std functions
  108. RealType scale = dist.scale();
  109. RealType mean = dist.mean();
  110. RealType result = 0;
  111. static const char* function = "boost::math::pdf(const inverse_gaussian_distribution<%1%>&, %1%)";
  112. if(false == detail::check_scale(function, scale, &result, Policy()))
  113. {
  114. return result;
  115. }
  116. if(false == detail::check_location(function, mean, &result, Policy()))
  117. {
  118. return result;
  119. }
  120. if(false == detail::check_positive_x(function, x, &result, Policy()))
  121. {
  122. return result;
  123. }
  124. if (x == 0)
  125. {
  126. return 0; // Convenient, even if not defined mathematically.
  127. }
  128. result =
  129. sqrt(scale / (constants::two_pi<RealType>() * x * x * x))
  130. * exp(-scale * (x - mean) * (x - mean) / (2 * x * mean * mean));
  131. return result;
  132. } // pdf
  133. template <class RealType, class Policy>
  134. inline RealType cdf(const inverse_gaussian_distribution<RealType, Policy>& dist, const RealType& x)
  135. { // Cumulative Density Function.
  136. BOOST_MATH_STD_USING // for ADL of std functions.
  137. RealType scale = dist.scale();
  138. RealType mean = dist.mean();
  139. static const char* function = "boost::math::cdf(const inverse_gaussian_distribution<%1%>&, %1%)";
  140. RealType result = 0;
  141. if(false == detail::check_scale(function, scale, &result, Policy()))
  142. {
  143. return result;
  144. }
  145. if(false == detail::check_location(function, mean, &result, Policy()))
  146. {
  147. return result;
  148. }
  149. if(false == detail::check_positive_x(function, x, &result, Policy()))
  150. {
  151. return result;
  152. }
  153. if (x == 0)
  154. {
  155. return 0; // Convenient, even if not defined mathematically.
  156. }
  157. // Problem with this formula for large scale > 1000 or small x,
  158. //result = 0.5 * (erf(sqrt(scale / x) * ((x / mean) - 1) / constants::root_two<RealType>(), Policy()) + 1)
  159. // + exp(2 * scale / mean) / 2
  160. // * (1 - erf(sqrt(scale / x) * (x / mean + 1) / constants::root_two<RealType>(), Policy()));
  161. // so use normal distribution version:
  162. // Wikipedia CDF equation http://en.wikipedia.org/wiki/Inverse_Gaussian_distribution.
  163. normal_distribution<RealType> n01;
  164. RealType n0 = sqrt(scale / x);
  165. n0 *= ((x / mean) -1);
  166. RealType n1 = cdf(n01, n0);
  167. RealType expfactor = exp(2 * scale / mean);
  168. RealType n3 = - sqrt(scale / x);
  169. n3 *= (x / mean) + 1;
  170. RealType n4 = cdf(n01, n3);
  171. result = n1 + expfactor * n4;
  172. return result;
  173. } // cdf
  174. template <class RealType, class Policy>
  175. struct inverse_gaussian_quantile_functor
  176. {
  177. inverse_gaussian_quantile_functor(const boost::math::inverse_gaussian_distribution<RealType, Policy> dist, RealType const& p)
  178. : distribution(dist), prob(p)
  179. {
  180. }
  181. boost::math::tuple<RealType, RealType> operator()(RealType const& x)
  182. {
  183. RealType c = cdf(distribution, x);
  184. RealType fx = c - prob; // Difference cdf - value - to minimize.
  185. RealType dx = pdf(distribution, x); // pdf is 1st derivative.
  186. // return both function evaluation difference f(x) and 1st derivative f'(x).
  187. return boost::math::make_tuple(fx, dx);
  188. }
  189. private:
  190. const boost::math::inverse_gaussian_distribution<RealType, Policy> distribution;
  191. RealType prob;
  192. };
  193. template <class RealType, class Policy>
  194. struct inverse_gaussian_quantile_complement_functor
  195. {
  196. inverse_gaussian_quantile_complement_functor(const boost::math::inverse_gaussian_distribution<RealType, Policy> dist, RealType const& p)
  197. : distribution(dist), prob(p)
  198. {
  199. }
  200. boost::math::tuple<RealType, RealType> operator()(RealType const& x)
  201. {
  202. RealType c = cdf(complement(distribution, x));
  203. RealType fx = c - prob; // Difference cdf - value - to minimize.
  204. RealType dx = -pdf(distribution, x); // pdf is 1st derivative.
  205. // return both function evaluation difference f(x) and 1st derivative f'(x).
  206. //return std::tr1::make_tuple(fx, dx); if available.
  207. return boost::math::make_tuple(fx, dx);
  208. }
  209. private:
  210. const boost::math::inverse_gaussian_distribution<RealType, Policy> distribution;
  211. RealType prob;
  212. };
  213. namespace detail
  214. {
  215. template <class RealType>
  216. inline RealType guess_ig(RealType p, RealType mu = 1, RealType lambda = 1)
  217. { // guess at random variate value x for inverse gaussian quantile.
  218. BOOST_MATH_STD_USING
  219. using boost::math::policies::policy;
  220. // Error type.
  221. using boost::math::policies::overflow_error;
  222. // Action.
  223. using boost::math::policies::ignore_error;
  224. typedef policy<
  225. overflow_error<ignore_error> // Ignore overflow (return infinity)
  226. > no_overthrow_policy;
  227. RealType x; // result is guess at random variate value x.
  228. RealType phi = lambda / mu;
  229. if (phi > 2.)
  230. { // Big phi, so starting to look like normal Gaussian distribution.
  231. // x=(qnorm(p,0,1,true,false) - 0.5 * sqrt(mu/lambda)) / sqrt(lambda/mu);
  232. // Whitmore, G.A. and Yalovsky, M.
  233. // A normalising logarithmic transformation for inverse Gaussian random variables,
  234. // Technometrics 20-2, 207-208 (1978), but using expression from
  235. // V Seshadri, Inverse Gaussian distribution (1998) ISBN 0387 98618 9, page 6.
  236. normal_distribution<RealType, no_overthrow_policy> n01;
  237. x = mu * exp(quantile(n01, p) / sqrt(phi) - 1/(2 * phi));
  238. }
  239. else
  240. { // phi < 2 so much less symmetrical with long tail,
  241. // so use gamma distribution as an approximation.
  242. using boost::math::gamma_distribution;
  243. // Define the distribution, using gamma_nooverflow:
  244. typedef gamma_distribution<RealType, no_overthrow_policy> gamma_nooverflow;
  245. gamma_nooverflow g(static_cast<RealType>(0.5), static_cast<RealType>(1.));
  246. // gamma_nooverflow g(static_cast<RealType>(0.5), static_cast<RealType>(1.));
  247. // R qgamma(0.2, 0.5, 1) 0.0320923
  248. RealType qg = quantile(complement(g, p));
  249. //RealType qg1 = qgamma(1.- p, 0.5, 1.0, true, false);
  250. x = lambda / (qg * 2);
  251. //
  252. if (x > mu/2) // x > mu /2?
  253. { // x too large for the gamma approximation to work well.
  254. //x = qgamma(p, 0.5, 1.0); // qgamma(0.270614, 0.5, 1) = 0.05983807
  255. RealType q = quantile(g, p);
  256. // x = mu * exp(q * static_cast<RealType>(0.1)); // Said to improve at high p
  257. // x = mu * x; // Improves at high p?
  258. x = mu * exp(q / sqrt(phi) - 1/(2 * phi));
  259. }
  260. }
  261. return x;
  262. } // guess_ig
  263. } // namespace detail
  264. template <class RealType, class Policy>
  265. inline RealType quantile(const inverse_gaussian_distribution<RealType, Policy>& dist, const RealType& p)
  266. {
  267. BOOST_MATH_STD_USING // for ADL of std functions.
  268. // No closed form exists so guess and use Newton Raphson iteration.
  269. RealType mean = dist.mean();
  270. RealType scale = dist.scale();
  271. static const char* function = "boost::math::quantile(const inverse_gaussian_distribution<%1%>&, %1%)";
  272. RealType result = 0;
  273. if(false == detail::check_scale(function, scale, &result, Policy()))
  274. return result;
  275. if(false == detail::check_location(function, mean, &result, Policy()))
  276. return result;
  277. if(false == detail::check_probability(function, p, &result, Policy()))
  278. return result;
  279. if (p == 0)
  280. {
  281. return 0; // Convenient, even if not defined mathematically?
  282. }
  283. if (p == 1)
  284. { // overflow
  285. result = policies::raise_overflow_error<RealType>(function,
  286. "probability parameter is 1, but must be < 1!", Policy());
  287. return result; // std::numeric_limits<RealType>::infinity();
  288. }
  289. RealType guess = detail::guess_ig(p, dist.mean(), dist.scale());
  290. using boost::math::tools::max_value;
  291. RealType min = 0.; // Minimum possible value is bottom of range of distribution.
  292. RealType max = max_value<RealType>();// Maximum possible value is top of range.
  293. // int digits = std::numeric_limits<RealType>::digits; // Maximum possible binary digits accuracy for type T.
  294. // digits used to control how accurate to try to make the result.
  295. // To allow user to control accuracy versus speed,
  296. int get_digits = policies::digits<RealType, Policy>();// get digits from policy,
  297. boost::uintmax_t m = policies::get_max_root_iterations<Policy>(); // and max iterations.
  298. using boost::math::tools::newton_raphson_iterate;
  299. result =
  300. newton_raphson_iterate(inverse_gaussian_quantile_functor<RealType, Policy>(dist, p), guess, min, max, get_digits, m);
  301. return result;
  302. } // quantile
  303. template <class RealType, class Policy>
  304. inline RealType cdf(const complemented2_type<inverse_gaussian_distribution<RealType, Policy>, RealType>& c)
  305. {
  306. BOOST_MATH_STD_USING // for ADL of std functions.
  307. RealType scale = c.dist.scale();
  308. RealType mean = c.dist.mean();
  309. RealType x = c.param;
  310. static const char* function = "boost::math::cdf(const complement(inverse_gaussian_distribution<%1%>&), %1%)";
  311. // infinite arguments not supported.
  312. //if((boost::math::isinf)(x))
  313. //{
  314. // if(x < 0) return 1; // cdf complement -infinity is unity.
  315. // return 0; // cdf complement +infinity is zero
  316. //}
  317. // These produce MSVC 4127 warnings, so the above used instead.
  318. //if(std::numeric_limits<RealType>::has_infinity && x == std::numeric_limits<RealType>::infinity())
  319. //{ // cdf complement +infinity is zero.
  320. // return 0;
  321. //}
  322. //if(std::numeric_limits<RealType>::has_infinity && x == -std::numeric_limits<RealType>::infinity())
  323. //{ // cdf complement -infinity is unity.
  324. // return 1;
  325. //}
  326. RealType result = 0;
  327. if(false == detail::check_scale(function, scale, &result, Policy()))
  328. return result;
  329. if(false == detail::check_location(function, mean, &result, Policy()))
  330. return result;
  331. if(false == detail::check_positive_x(function, x, &result, Policy()))
  332. return result;
  333. normal_distribution<RealType> n01;
  334. RealType n0 = sqrt(scale / x);
  335. n0 *= ((x / mean) -1);
  336. RealType cdf_1 = cdf(complement(n01, n0));
  337. RealType expfactor = exp(2 * scale / mean);
  338. RealType n3 = - sqrt(scale / x);
  339. n3 *= (x / mean) + 1;
  340. //RealType n5 = +sqrt(scale/x) * ((x /mean) + 1); // note now positive sign.
  341. RealType n6 = cdf(complement(n01, +sqrt(scale/x) * ((x /mean) + 1)));
  342. // RealType n4 = cdf(n01, n3); // =
  343. result = cdf_1 - expfactor * n6;
  344. return result;
  345. } // cdf complement
  346. template <class RealType, class Policy>
  347. inline RealType quantile(const complemented2_type<inverse_gaussian_distribution<RealType, Policy>, RealType>& c)
  348. {
  349. BOOST_MATH_STD_USING // for ADL of std functions
  350. RealType scale = c.dist.scale();
  351. RealType mean = c.dist.mean();
  352. static const char* function = "boost::math::quantile(const complement(inverse_gaussian_distribution<%1%>&), %1%)";
  353. RealType result = 0;
  354. if(false == detail::check_scale(function, scale, &result, Policy()))
  355. return result;
  356. if(false == detail::check_location(function, mean, &result, Policy()))
  357. return result;
  358. RealType q = c.param;
  359. if(false == detail::check_probability(function, q, &result, Policy()))
  360. return result;
  361. RealType guess = detail::guess_ig(q, mean, scale);
  362. // Complement.
  363. using boost::math::tools::max_value;
  364. RealType min = 0.; // Minimum possible value is bottom of range of distribution.
  365. RealType max = max_value<RealType>();// Maximum possible value is top of range.
  366. // int digits = std::numeric_limits<RealType>::digits; // Maximum possible binary digits accuracy for type T.
  367. // digits used to control how accurate to try to make the result.
  368. int get_digits = policies::digits<RealType, Policy>();
  369. boost::uintmax_t m = policies::get_max_root_iterations<Policy>();
  370. using boost::math::tools::newton_raphson_iterate;
  371. result =
  372. newton_raphson_iterate(inverse_gaussian_quantile_complement_functor<RealType, Policy>(c.dist, q), guess, min, max, get_digits, m);
  373. return result;
  374. } // quantile
  375. template <class RealType, class Policy>
  376. inline RealType mean(const inverse_gaussian_distribution<RealType, Policy>& dist)
  377. { // aka mu
  378. return dist.mean();
  379. }
  380. template <class RealType, class Policy>
  381. inline RealType scale(const inverse_gaussian_distribution<RealType, Policy>& dist)
  382. { // aka lambda
  383. return dist.scale();
  384. }
  385. template <class RealType, class Policy>
  386. inline RealType shape(const inverse_gaussian_distribution<RealType, Policy>& dist)
  387. { // aka phi
  388. return dist.shape();
  389. }
  390. template <class RealType, class Policy>
  391. inline RealType standard_deviation(const inverse_gaussian_distribution<RealType, Policy>& dist)
  392. {
  393. BOOST_MATH_STD_USING
  394. RealType scale = dist.scale();
  395. RealType mean = dist.mean();
  396. RealType result = sqrt(mean * mean * mean / scale);
  397. return result;
  398. }
  399. template <class RealType, class Policy>
  400. inline RealType mode(const inverse_gaussian_distribution<RealType, Policy>& dist)
  401. {
  402. BOOST_MATH_STD_USING
  403. RealType scale = dist.scale();
  404. RealType mean = dist.mean();
  405. RealType result = mean * (sqrt(1 + (9 * mean * mean)/(4 * scale * scale))
  406. - 3 * mean / (2 * scale));
  407. return result;
  408. }
  409. template <class RealType, class Policy>
  410. inline RealType skewness(const inverse_gaussian_distribution<RealType, Policy>& dist)
  411. {
  412. BOOST_MATH_STD_USING
  413. RealType scale = dist.scale();
  414. RealType mean = dist.mean();
  415. RealType result = 3 * sqrt(mean/scale);
  416. return result;
  417. }
  418. template <class RealType, class Policy>
  419. inline RealType kurtosis(const inverse_gaussian_distribution<RealType, Policy>& dist)
  420. {
  421. RealType scale = dist.scale();
  422. RealType mean = dist.mean();
  423. RealType result = 15 * mean / scale -3;
  424. return result;
  425. }
  426. template <class RealType, class Policy>
  427. inline RealType kurtosis_excess(const inverse_gaussian_distribution<RealType, Policy>& dist)
  428. {
  429. RealType scale = dist.scale();
  430. RealType mean = dist.mean();
  431. RealType result = 15 * mean / scale;
  432. return result;
  433. }
  434. } // namespace math
  435. } // namespace boost
  436. // This include must be at the end, *after* the accessors
  437. // for this distribution have been defined, in order to
  438. // keep compilers that support two-phase lookup happy.
  439. #include <boost/math/distributions/detail/derived_accessors.hpp>
  440. #endif // BOOST_STATS_INVERSE_GAUSSIAN_HPP