inverse_gaussian.hpp 20 KB

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