inverse_gaussian.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  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. detail::check_x_gt0(function, l_mean, &result, Policy());
  66. }
  67. RealType mean()const
  68. { // alias for location.
  69. return m_mean; // aka mu
  70. }
  71. // Synonyms, provided to allow generic use of find_location and find_scale.
  72. RealType location()const
  73. { // location, aka mu.
  74. return m_mean;
  75. }
  76. RealType scale()const
  77. { // scale, aka lambda.
  78. return m_scale;
  79. }
  80. RealType shape()const
  81. { // shape, aka phi = lambda/mu.
  82. return m_scale / m_mean;
  83. }
  84. private:
  85. //
  86. // Data members:
  87. //
  88. RealType m_mean; // distribution mean or location, aka mu.
  89. RealType m_scale; // distribution standard deviation or scale, aka lambda.
  90. }; // class normal_distribution
  91. typedef inverse_gaussian_distribution<double> inverse_gaussian;
  92. template <class RealType, class Policy>
  93. inline const std::pair<RealType, RealType> range(const inverse_gaussian_distribution<RealType, Policy>& /*dist*/)
  94. { // Range of permissible values for random variable x, zero to max.
  95. using boost::math::tools::max_value;
  96. return std::pair<RealType, RealType>(static_cast<RealType>(0.), max_value<RealType>()); // - to + max value.
  97. }
  98. template <class RealType, class Policy>
  99. inline const std::pair<RealType, RealType> support(const inverse_gaussian_distribution<RealType, Policy>& /*dist*/)
  100. { // Range of supported values for random variable x, zero to max.
  101. // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
  102. using boost::math::tools::max_value;
  103. return std::pair<RealType, RealType>(static_cast<RealType>(0.), max_value<RealType>()); // - to + max value.
  104. }
  105. template <class RealType, class Policy>
  106. inline RealType pdf(const inverse_gaussian_distribution<RealType, Policy>& dist, const RealType& x)
  107. { // Probability Density Function
  108. BOOST_MATH_STD_USING // for ADL of std functions
  109. RealType scale = dist.scale();
  110. RealType mean = dist.mean();
  111. RealType result = 0;
  112. static const char* function = "boost::math::pdf(const inverse_gaussian_distribution<%1%>&, %1%)";
  113. if(false == detail::check_scale(function, scale, &result, Policy()))
  114. {
  115. return result;
  116. }
  117. if(false == detail::check_location(function, mean, &result, Policy()))
  118. {
  119. return result;
  120. }
  121. if(false == detail::check_x_gt0(function, mean, &result, Policy()))
  122. {
  123. return result;
  124. }
  125. if(false == detail::check_positive_x(function, x, &result, Policy()))
  126. {
  127. return result;
  128. }
  129. if (x == 0)
  130. {
  131. return 0; // Convenient, even if not defined mathematically.
  132. }
  133. result =
  134. sqrt(scale / (constants::two_pi<RealType>() * x * x * x))
  135. * exp(-scale * (x - mean) * (x - mean) / (2 * x * mean * mean));
  136. return result;
  137. } // pdf
  138. template <class RealType, class Policy>
  139. inline RealType cdf(const inverse_gaussian_distribution<RealType, Policy>& dist, const RealType& x)
  140. { // Cumulative Density Function.
  141. BOOST_MATH_STD_USING // for ADL of std functions.
  142. RealType scale = dist.scale();
  143. RealType mean = dist.mean();
  144. static const char* function = "boost::math::cdf(const inverse_gaussian_distribution<%1%>&, %1%)";
  145. RealType result = 0;
  146. if(false == detail::check_scale(function, scale, &result, Policy()))
  147. {
  148. return result;
  149. }
  150. if(false == detail::check_location(function, mean, &result, Policy()))
  151. {
  152. return result;
  153. }
  154. if (false == detail::check_x_gt0(function, mean, &result, Policy()))
  155. {
  156. return result;
  157. }
  158. if(false == detail::check_positive_x(function, x, &result, Policy()))
  159. {
  160. return result;
  161. }
  162. if (x == 0)
  163. {
  164. return 0; // Convenient, even if not defined mathematically.
  165. }
  166. // Problem with this formula for large scale > 1000 or small x,
  167. //result = 0.5 * (erf(sqrt(scale / x) * ((x / mean) - 1) / constants::root_two<RealType>(), Policy()) + 1)
  168. // + exp(2 * scale / mean) / 2
  169. // * (1 - erf(sqrt(scale / x) * (x / mean + 1) / constants::root_two<RealType>(), Policy()));
  170. // so use normal distribution version:
  171. // Wikipedia CDF equation http://en.wikipedia.org/wiki/Inverse_Gaussian_distribution.
  172. normal_distribution<RealType> n01;
  173. RealType n0 = sqrt(scale / x);
  174. n0 *= ((x / mean) -1);
  175. RealType n1 = cdf(n01, n0);
  176. RealType expfactor = exp(2 * scale / mean);
  177. RealType n3 = - sqrt(scale / x);
  178. n3 *= (x / mean) + 1;
  179. RealType n4 = cdf(n01, n3);
  180. result = n1 + expfactor * n4;
  181. return result;
  182. } // cdf
  183. template <class RealType, class Policy>
  184. struct inverse_gaussian_quantile_functor
  185. {
  186. inverse_gaussian_quantile_functor(const boost::math::inverse_gaussian_distribution<RealType, Policy> dist, RealType const& p)
  187. : distribution(dist), prob(p)
  188. {
  189. }
  190. boost::math::tuple<RealType, RealType> operator()(RealType const& x)
  191. {
  192. RealType c = cdf(distribution, x);
  193. RealType fx = c - prob; // Difference cdf - value - to minimize.
  194. RealType dx = pdf(distribution, x); // pdf is 1st derivative.
  195. // return both function evaluation difference f(x) and 1st derivative f'(x).
  196. return boost::math::make_tuple(fx, dx);
  197. }
  198. private:
  199. const boost::math::inverse_gaussian_distribution<RealType, Policy> distribution;
  200. RealType prob;
  201. };
  202. template <class RealType, class Policy>
  203. struct inverse_gaussian_quantile_complement_functor
  204. {
  205. inverse_gaussian_quantile_complement_functor(const boost::math::inverse_gaussian_distribution<RealType, Policy> dist, RealType const& p)
  206. : distribution(dist), prob(p)
  207. {
  208. }
  209. boost::math::tuple<RealType, RealType> operator()(RealType const& x)
  210. {
  211. RealType c = cdf(complement(distribution, x));
  212. RealType fx = c - prob; // Difference cdf - value - to minimize.
  213. RealType dx = -pdf(distribution, x); // pdf is 1st derivative.
  214. // return both function evaluation difference f(x) and 1st derivative f'(x).
  215. //return std::tr1::make_tuple(fx, dx); if available.
  216. return boost::math::make_tuple(fx, dx);
  217. }
  218. private:
  219. const boost::math::inverse_gaussian_distribution<RealType, Policy> distribution;
  220. RealType prob;
  221. };
  222. namespace detail
  223. {
  224. template <class RealType>
  225. inline RealType guess_ig(RealType p, RealType mu = 1, RealType lambda = 1)
  226. { // guess at random variate value x for inverse gaussian quantile.
  227. BOOST_MATH_STD_USING
  228. using boost::math::policies::policy;
  229. // Error type.
  230. using boost::math::policies::overflow_error;
  231. // Action.
  232. using boost::math::policies::ignore_error;
  233. typedef policy<
  234. overflow_error<ignore_error> // Ignore overflow (return infinity)
  235. > no_overthrow_policy;
  236. RealType x; // result is guess at random variate value x.
  237. RealType phi = lambda / mu;
  238. if (phi > 2.)
  239. { // Big phi, so starting to look like normal Gaussian distribution.
  240. // x=(qnorm(p,0,1,true,false) - 0.5 * sqrt(mu/lambda)) / sqrt(lambda/mu);
  241. // Whitmore, G.A. and Yalovsky, M.
  242. // A normalising logarithmic transformation for inverse Gaussian random variables,
  243. // Technometrics 20-2, 207-208 (1978), but using expression from
  244. // V Seshadri, Inverse Gaussian distribution (1998) ISBN 0387 98618 9, page 6.
  245. normal_distribution<RealType, no_overthrow_policy> n01;
  246. x = mu * exp(quantile(n01, p) / sqrt(phi) - 1/(2 * phi));
  247. }
  248. else
  249. { // phi < 2 so much less symmetrical with long tail,
  250. // so use gamma distribution as an approximation.
  251. using boost::math::gamma_distribution;
  252. // Define the distribution, using gamma_nooverflow:
  253. typedef gamma_distribution<RealType, no_overthrow_policy> gamma_nooverflow;
  254. gamma_nooverflow g(static_cast<RealType>(0.5), static_cast<RealType>(1.));
  255. // gamma_nooverflow g(static_cast<RealType>(0.5), static_cast<RealType>(1.));
  256. // R qgamma(0.2, 0.5, 1) 0.0320923
  257. RealType qg = quantile(complement(g, p));
  258. //RealType qg1 = qgamma(1.- p, 0.5, 1.0, true, false);
  259. x = lambda / (qg * 2);
  260. //
  261. if (x > mu/2) // x > mu /2?
  262. { // x too large for the gamma approximation to work well.
  263. //x = qgamma(p, 0.5, 1.0); // qgamma(0.270614, 0.5, 1) = 0.05983807
  264. RealType q = quantile(g, p);
  265. // x = mu * exp(q * static_cast<RealType>(0.1)); // Said to improve at high p
  266. // x = mu * x; // Improves at high p?
  267. x = mu * exp(q / sqrt(phi) - 1/(2 * phi));
  268. }
  269. }
  270. return x;
  271. } // guess_ig
  272. } // namespace detail
  273. template <class RealType, class Policy>
  274. inline RealType quantile(const inverse_gaussian_distribution<RealType, Policy>& dist, const RealType& p)
  275. {
  276. BOOST_MATH_STD_USING // for ADL of std functions.
  277. // No closed form exists so guess and use Newton Raphson iteration.
  278. RealType mean = dist.mean();
  279. RealType scale = dist.scale();
  280. static const char* function = "boost::math::quantile(const inverse_gaussian_distribution<%1%>&, %1%)";
  281. RealType result = 0;
  282. if(false == detail::check_scale(function, scale, &result, Policy()))
  283. return result;
  284. if(false == detail::check_location(function, mean, &result, Policy()))
  285. return result;
  286. if (false == detail::check_x_gt0(function, mean, &result, Policy()))
  287. return result;
  288. if(false == detail::check_probability(function, p, &result, Policy()))
  289. return result;
  290. if (p == 0)
  291. {
  292. return 0; // Convenient, even if not defined mathematically?
  293. }
  294. if (p == 1)
  295. { // overflow
  296. result = policies::raise_overflow_error<RealType>(function,
  297. "probability parameter is 1, but must be < 1!", Policy());
  298. return result; // std::numeric_limits<RealType>::infinity();
  299. }
  300. RealType guess = detail::guess_ig(p, dist.mean(), dist.scale());
  301. using boost::math::tools::max_value;
  302. RealType min = 0.; // Minimum possible value is bottom of range of distribution.
  303. RealType max = max_value<RealType>();// Maximum possible value is top of range.
  304. // int digits = std::numeric_limits<RealType>::digits; // Maximum possible binary digits accuracy for type T.
  305. // digits used to control how accurate to try to make the result.
  306. // To allow user to control accuracy versus speed,
  307. int get_digits = policies::digits<RealType, Policy>();// get digits from policy,
  308. boost::uintmax_t m = policies::get_max_root_iterations<Policy>(); // and max iterations.
  309. using boost::math::tools::newton_raphson_iterate;
  310. result =
  311. newton_raphson_iterate(inverse_gaussian_quantile_functor<RealType, Policy>(dist, p), guess, min, max, get_digits, m);
  312. return result;
  313. } // quantile
  314. template <class RealType, class Policy>
  315. inline RealType cdf(const complemented2_type<inverse_gaussian_distribution<RealType, Policy>, RealType>& c)
  316. {
  317. BOOST_MATH_STD_USING // for ADL of std functions.
  318. RealType scale = c.dist.scale();
  319. RealType mean = c.dist.mean();
  320. RealType x = c.param;
  321. static const char* function = "boost::math::cdf(const complement(inverse_gaussian_distribution<%1%>&), %1%)";
  322. // infinite arguments not supported.
  323. //if((boost::math::isinf)(x))
  324. //{
  325. // if(x < 0) return 1; // cdf complement -infinity is unity.
  326. // return 0; // cdf complement +infinity is zero
  327. //}
  328. // These produce MSVC 4127 warnings, so the above used instead.
  329. //if(std::numeric_limits<RealType>::has_infinity && x == std::numeric_limits<RealType>::infinity())
  330. //{ // cdf complement +infinity is zero.
  331. // return 0;
  332. //}
  333. //if(std::numeric_limits<RealType>::has_infinity && x == -std::numeric_limits<RealType>::infinity())
  334. //{ // cdf complement -infinity is unity.
  335. // return 1;
  336. //}
  337. RealType result = 0;
  338. if(false == detail::check_scale(function, scale, &result, Policy()))
  339. return result;
  340. if(false == detail::check_location(function, mean, &result, Policy()))
  341. return result;
  342. if (false == detail::check_x_gt0(function, mean, &result, Policy()))
  343. return result;
  344. if(false == detail::check_positive_x(function, x, &result, Policy()))
  345. return result;
  346. normal_distribution<RealType> n01;
  347. RealType n0 = sqrt(scale / x);
  348. n0 *= ((x / mean) -1);
  349. RealType cdf_1 = cdf(complement(n01, n0));
  350. RealType expfactor = exp(2 * scale / mean);
  351. RealType n3 = - sqrt(scale / x);
  352. n3 *= (x / mean) + 1;
  353. //RealType n5 = +sqrt(scale/x) * ((x /mean) + 1); // note now positive sign.
  354. RealType n6 = cdf(complement(n01, +sqrt(scale/x) * ((x /mean) + 1)));
  355. // RealType n4 = cdf(n01, n3); // =
  356. result = cdf_1 - expfactor * n6;
  357. return result;
  358. } // cdf complement
  359. template <class RealType, class Policy>
  360. inline RealType quantile(const complemented2_type<inverse_gaussian_distribution<RealType, Policy>, RealType>& c)
  361. {
  362. BOOST_MATH_STD_USING // for ADL of std functions
  363. RealType scale = c.dist.scale();
  364. RealType mean = c.dist.mean();
  365. static const char* function = "boost::math::quantile(const complement(inverse_gaussian_distribution<%1%>&), %1%)";
  366. RealType result = 0;
  367. if(false == detail::check_scale(function, scale, &result, Policy()))
  368. return result;
  369. if(false == detail::check_location(function, mean, &result, Policy()))
  370. return result;
  371. if (false == detail::check_x_gt0(function, mean, &result, Policy()))
  372. return result;
  373. RealType q = c.param;
  374. if(false == detail::check_probability(function, q, &result, Policy()))
  375. return result;
  376. RealType guess = detail::guess_ig(q, mean, scale);
  377. // Complement.
  378. using boost::math::tools::max_value;
  379. RealType min = 0.; // Minimum possible value is bottom of range of distribution.
  380. RealType max = max_value<RealType>();// Maximum possible value is top of range.
  381. // int digits = std::numeric_limits<RealType>::digits; // Maximum possible binary digits accuracy for type T.
  382. // digits used to control how accurate to try to make the result.
  383. int get_digits = policies::digits<RealType, Policy>();
  384. boost::uintmax_t m = policies::get_max_root_iterations<Policy>();
  385. using boost::math::tools::newton_raphson_iterate;
  386. result =
  387. newton_raphson_iterate(inverse_gaussian_quantile_complement_functor<RealType, Policy>(c.dist, q), guess, min, max, get_digits, m);
  388. return result;
  389. } // quantile
  390. template <class RealType, class Policy>
  391. inline RealType mean(const inverse_gaussian_distribution<RealType, Policy>& dist)
  392. { // aka mu
  393. return dist.mean();
  394. }
  395. template <class RealType, class Policy>
  396. inline RealType scale(const inverse_gaussian_distribution<RealType, Policy>& dist)
  397. { // aka lambda
  398. return dist.scale();
  399. }
  400. template <class RealType, class Policy>
  401. inline RealType shape(const inverse_gaussian_distribution<RealType, Policy>& dist)
  402. { // aka phi
  403. return dist.shape();
  404. }
  405. template <class RealType, class Policy>
  406. inline RealType standard_deviation(const inverse_gaussian_distribution<RealType, Policy>& dist)
  407. {
  408. BOOST_MATH_STD_USING
  409. RealType scale = dist.scale();
  410. RealType mean = dist.mean();
  411. RealType result = sqrt(mean * mean * mean / scale);
  412. return result;
  413. }
  414. template <class RealType, class Policy>
  415. inline RealType mode(const inverse_gaussian_distribution<RealType, Policy>& dist)
  416. {
  417. BOOST_MATH_STD_USING
  418. RealType scale = dist.scale();
  419. RealType mean = dist.mean();
  420. RealType result = mean * (sqrt(1 + (9 * mean * mean)/(4 * scale * scale))
  421. - 3 * mean / (2 * scale));
  422. return result;
  423. }
  424. template <class RealType, class Policy>
  425. inline RealType skewness(const inverse_gaussian_distribution<RealType, Policy>& dist)
  426. {
  427. BOOST_MATH_STD_USING
  428. RealType scale = dist.scale();
  429. RealType mean = dist.mean();
  430. RealType result = 3 * sqrt(mean/scale);
  431. return result;
  432. }
  433. template <class RealType, class Policy>
  434. inline RealType kurtosis(const inverse_gaussian_distribution<RealType, Policy>& dist)
  435. {
  436. RealType scale = dist.scale();
  437. RealType mean = dist.mean();
  438. RealType result = 15 * mean / scale -3;
  439. return result;
  440. }
  441. template <class RealType, class Policy>
  442. inline RealType kurtosis_excess(const inverse_gaussian_distribution<RealType, Policy>& dist)
  443. {
  444. RealType scale = dist.scale();
  445. RealType mean = dist.mean();
  446. RealType result = 15 * mean / scale;
  447. return result;
  448. }
  449. } // namespace math
  450. } // namespace boost
  451. // This include must be at the end, *after* the accessors
  452. // for this distribution have been defined, in order to
  453. // keep compilers that support two-phase lookup happy.
  454. #include <boost/math/distributions/detail/derived_accessors.hpp>
  455. #endif // BOOST_STATS_INVERSE_GAUSSIAN_HPP