inverse_gamma.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. // inverse_gamma.hpp
  2. // Copyright Paul A. Bristow 2010.
  3. // Copyright John Maddock 2010.
  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. #ifndef BOOST_STATS_INVERSE_GAMMA_HPP
  8. #define BOOST_STATS_INVERSE_GAMMA_HPP
  9. // Inverse Gamma Distribution is a two-parameter family
  10. // of continuous probability distributions
  11. // on the positive real line, which is the distribution of
  12. // the reciprocal of a variable distributed according to the gamma distribution.
  13. // http://en.wikipedia.org/wiki/Inverse-gamma_distribution
  14. // http://rss.acs.unt.edu/Rdoc/library/pscl/html/igamma.html
  15. // See also gamma distribution at gamma.hpp:
  16. // http://www.itl.nist.gov/div898/handbook/eda/section3/eda366b.htm
  17. // http://mathworld.wolfram.com/GammaDistribution.html
  18. // http://en.wikipedia.org/wiki/Gamma_distribution
  19. #include <boost/math/distributions/fwd.hpp>
  20. #include <boost/math/special_functions/gamma.hpp>
  21. #include <boost/math/distributions/detail/common_error_handling.hpp>
  22. #include <boost/math/distributions/complement.hpp>
  23. #include <utility>
  24. #include <cfenv>
  25. namespace boost{ namespace math
  26. {
  27. namespace detail
  28. {
  29. template <class RealType, class Policy>
  30. inline bool check_inverse_gamma_shape(
  31. const char* function, // inverse_gamma
  32. RealType shape, // shape aka alpha
  33. RealType* result, // to update, perhaps with NaN
  34. const Policy& pol)
  35. { // Sources say shape argument must be > 0
  36. // but seems logical to allow shape zero as special case,
  37. // returning pdf and cdf zero (but not < 0).
  38. // (Functions like mean, variance with other limits on shape are checked
  39. // in version including an operator & limit below).
  40. if((shape < 0) || !(boost::math::isfinite)(shape))
  41. {
  42. *result = policies::raise_domain_error<RealType>(
  43. function,
  44. "Shape parameter is %1%, but must be >= 0 !", shape, pol);
  45. return false;
  46. }
  47. return true;
  48. } //bool check_inverse_gamma_shape
  49. template <class RealType, class Policy>
  50. inline bool check_inverse_gamma_x(
  51. const char* function,
  52. RealType const& x,
  53. RealType* result, const Policy& pol)
  54. {
  55. if((x < 0) || !(boost::math::isfinite)(x))
  56. {
  57. *result = policies::raise_domain_error<RealType>(
  58. function,
  59. "Random variate is %1% but must be >= 0 !", x, pol);
  60. return false;
  61. }
  62. return true;
  63. }
  64. template <class RealType, class Policy>
  65. inline bool check_inverse_gamma(
  66. const char* function, // TODO swap these over, so shape is first.
  67. RealType scale, // scale aka beta
  68. RealType shape, // shape aka alpha
  69. RealType* result, const Policy& pol)
  70. {
  71. return check_scale(function, scale, result, pol)
  72. && check_inverse_gamma_shape(function, shape, result, pol);
  73. } // bool check_inverse_gamma
  74. } // namespace detail
  75. template <class RealType = double, class Policy = policies::policy<> >
  76. class inverse_gamma_distribution
  77. {
  78. public:
  79. using value_type = RealType;
  80. using policy_type = Policy;
  81. explicit inverse_gamma_distribution(RealType l_shape = 1, RealType l_scale = 1)
  82. : m_shape(l_shape), m_scale(l_scale)
  83. {
  84. RealType result;
  85. detail::check_inverse_gamma(
  86. "boost::math::inverse_gamma_distribution<%1%>::inverse_gamma_distribution",
  87. l_scale, l_shape, &result, Policy());
  88. }
  89. RealType shape()const
  90. {
  91. return m_shape;
  92. }
  93. RealType scale()const
  94. {
  95. return m_scale;
  96. }
  97. private:
  98. //
  99. // Data members:
  100. //
  101. RealType m_shape; // distribution shape
  102. RealType m_scale; // distribution scale
  103. };
  104. using inverse_gamma = inverse_gamma_distribution<double>;
  105. // typedef - but potential clash with name of inverse gamma *function*.
  106. // but there is a typedef for the gamma distribution (gamma)
  107. #ifdef __cpp_deduction_guides
  108. template <class RealType>
  109. inverse_gamma_distribution(RealType)->inverse_gamma_distribution<typename boost::math::tools::promote_args<RealType>::type>;
  110. template <class RealType>
  111. inverse_gamma_distribution(RealType,RealType)->inverse_gamma_distribution<typename boost::math::tools::promote_args<RealType>::type>;
  112. #endif
  113. // Allow random variable x to be zero, treated as a special case (unlike some definitions).
  114. template <class RealType, class Policy>
  115. inline std::pair<RealType, RealType> range(const inverse_gamma_distribution<RealType, Policy>& /* dist */)
  116. { // Range of permissible values for random variable x.
  117. using boost::math::tools::max_value;
  118. return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
  119. }
  120. template <class RealType, class Policy>
  121. inline std::pair<RealType, RealType> support(const inverse_gamma_distribution<RealType, Policy>& /* dist */)
  122. { // Range of supported values for random variable x.
  123. // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
  124. using boost::math::tools::max_value;
  125. using boost::math::tools::min_value;
  126. return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
  127. }
  128. template <class RealType, class Policy>
  129. inline RealType pdf(const inverse_gamma_distribution<RealType, Policy>& dist, const RealType& x)
  130. {
  131. BOOST_MATH_STD_USING // for ADL of std functions
  132. static const char* function = "boost::math::pdf(const inverse_gamma_distribution<%1%>&, %1%)";
  133. RealType shape = dist.shape();
  134. RealType scale = dist.scale();
  135. RealType result = 0;
  136. if(false == detail::check_inverse_gamma(function, scale, shape, &result, Policy()))
  137. { // distribution parameters bad.
  138. return result;
  139. }
  140. if(x == 0)
  141. { // Treat random variate zero as a special case.
  142. return 0;
  143. }
  144. else if(false == detail::check_inverse_gamma_x(function, x, &result, Policy()))
  145. { // x bad.
  146. return result;
  147. }
  148. result = scale / x;
  149. if(result < tools::min_value<RealType>())
  150. return 0; // random variable is infinite or so close as to make no difference.
  151. result = gamma_p_derivative(shape, result, Policy()) * scale;
  152. if(0 != result)
  153. {
  154. if(x < 0)
  155. {
  156. // x * x may under or overflow, likewise our result,
  157. // so be extra careful about the arithmetic:
  158. RealType lim = tools::max_value<RealType>() * x;
  159. if(lim < result)
  160. return policies::raise_overflow_error<RealType, Policy>(function, "PDF is infinite.", Policy());
  161. result /= x;
  162. if(lim < result)
  163. return policies::raise_overflow_error<RealType, Policy>(function, "PDF is infinite.", Policy());
  164. result /= x;
  165. }
  166. result /= (x * x);
  167. }
  168. return result;
  169. } // pdf
  170. template <class RealType, class Policy>
  171. inline RealType logpdf(const inverse_gamma_distribution<RealType, Policy>& dist, const RealType& x)
  172. {
  173. BOOST_MATH_STD_USING // for ADL of std functions
  174. using boost::math::lgamma;
  175. static const char* function = "boost::math::logpdf(const inverse_gamma_distribution<%1%>&, %1%)";
  176. RealType shape = dist.shape();
  177. RealType scale = dist.scale();
  178. RealType result = -std::numeric_limits<RealType>::infinity();
  179. if(false == detail::check_inverse_gamma(function, scale, shape, &result, Policy()))
  180. { // distribution parameters bad.
  181. return result;
  182. }
  183. if(x == 0)
  184. { // Treat random variate zero as a special case.
  185. return result;
  186. }
  187. else if(false == detail::check_inverse_gamma_x(function, x, &result, Policy()))
  188. { // x bad.
  189. return result;
  190. }
  191. result = scale / x;
  192. if(result < tools::min_value<RealType>())
  193. return result; // random variable is infinite or so close as to make no difference.
  194. // x * x may under or overflow, likewise our result
  195. if (!(boost::math::isfinite)(x*x))
  196. {
  197. return policies::raise_overflow_error<RealType, Policy>(function, "PDF is infinite.", Policy());
  198. }
  199. return shape * log(scale) + (-shape-1)*log(x) - lgamma(shape) - (scale/x);
  200. } // pdf
  201. template <class RealType, class Policy>
  202. inline RealType cdf(const inverse_gamma_distribution<RealType, Policy>& dist, const RealType& x)
  203. {
  204. BOOST_MATH_STD_USING // for ADL of std functions
  205. static const char* function = "boost::math::cdf(const inverse_gamma_distribution<%1%>&, %1%)";
  206. RealType shape = dist.shape();
  207. RealType scale = dist.scale();
  208. RealType result = 0;
  209. if(false == detail::check_inverse_gamma(function, scale, shape, &result, Policy()))
  210. { // distribution parameters bad.
  211. return result;
  212. }
  213. if (x == 0)
  214. { // Treat zero as a special case.
  215. return 0;
  216. }
  217. else if(false == detail::check_inverse_gamma_x(function, x, &result, Policy()))
  218. { // x bad
  219. return result;
  220. }
  221. result = boost::math::gamma_q(shape, scale / x, Policy());
  222. // result = tgamma(shape, scale / x) / tgamma(shape); // naive using tgamma
  223. return result;
  224. } // cdf
  225. template <class RealType, class Policy>
  226. inline RealType quantile(const inverse_gamma_distribution<RealType, Policy>& dist, const RealType& p)
  227. {
  228. BOOST_MATH_STD_USING // for ADL of std functions
  229. using boost::math::gamma_q_inv;
  230. static const char* function = "boost::math::quantile(const inverse_gamma_distribution<%1%>&, %1%)";
  231. RealType shape = dist.shape();
  232. RealType scale = dist.scale();
  233. RealType result = 0;
  234. if(false == detail::check_inverse_gamma(function, scale, shape, &result, Policy()))
  235. return result;
  236. if(false == detail::check_probability(function, p, &result, Policy()))
  237. return result;
  238. if(p == 1)
  239. {
  240. return policies::raise_overflow_error<RealType>(function, 0, Policy());
  241. }
  242. result = gamma_q_inv(shape, p, Policy());
  243. if((result < 1) && (result * tools::max_value<RealType>() < scale))
  244. return policies::raise_overflow_error<RealType, Policy>(function, "Value of random variable in inverse gamma distribution quantile is infinite.", Policy());
  245. result = scale / result;
  246. return result;
  247. }
  248. template <class RealType, class Policy>
  249. inline RealType cdf(const complemented2_type<inverse_gamma_distribution<RealType, Policy>, RealType>& c)
  250. {
  251. BOOST_MATH_STD_USING // for ADL of std functions
  252. static const char* function = "boost::math::quantile(const gamma_distribution<%1%>&, %1%)";
  253. RealType shape = c.dist.shape();
  254. RealType scale = c.dist.scale();
  255. RealType result = 0;
  256. if(false == detail::check_inverse_gamma(function, scale, shape, &result, Policy()))
  257. return result;
  258. if(false == detail::check_inverse_gamma_x(function, c.param, &result, Policy()))
  259. return result;
  260. if(c.param == 0)
  261. return 1; // Avoid division by zero
  262. result = gamma_p(shape, scale/c.param, Policy());
  263. return result;
  264. }
  265. template <class RealType, class Policy>
  266. inline RealType quantile(const complemented2_type<inverse_gamma_distribution<RealType, Policy>, RealType>& c)
  267. {
  268. BOOST_MATH_STD_USING // for ADL of std functions
  269. static const char* function = "boost::math::quantile(const inverse_gamma_distribution<%1%>&, %1%)";
  270. RealType shape = c.dist.shape();
  271. RealType scale = c.dist.scale();
  272. RealType q = c.param;
  273. RealType result = 0;
  274. if(false == detail::check_inverse_gamma(function, scale, shape, &result, Policy()))
  275. return result;
  276. if(false == detail::check_probability(function, q, &result, Policy()))
  277. return result;
  278. if(q == 0)
  279. {
  280. return policies::raise_overflow_error<RealType>(function, 0, Policy());
  281. }
  282. result = gamma_p_inv(shape, q, Policy());
  283. if((result < 1) && (result * tools::max_value<RealType>() < scale))
  284. return policies::raise_overflow_error<RealType, Policy>(function, "Value of random variable in inverse gamma distribution quantile is infinite.", Policy());
  285. result = scale / result;
  286. return result;
  287. }
  288. template <class RealType, class Policy>
  289. inline RealType mean(const inverse_gamma_distribution<RealType, Policy>& dist)
  290. {
  291. BOOST_MATH_STD_USING // for ADL of std functions
  292. static const char* function = "boost::math::mean(const inverse_gamma_distribution<%1%>&)";
  293. RealType shape = dist.shape();
  294. RealType scale = dist.scale();
  295. RealType result = 0;
  296. if(false == detail::check_scale(function, scale, &result, Policy()))
  297. {
  298. return result;
  299. }
  300. if((shape <= 1) || !(boost::math::isfinite)(shape))
  301. {
  302. result = policies::raise_domain_error<RealType>(
  303. function,
  304. "Shape parameter is %1%, but for a defined mean it must be > 1", shape, Policy());
  305. return result;
  306. }
  307. result = scale / (shape - 1);
  308. return result;
  309. } // mean
  310. template <class RealType, class Policy>
  311. inline RealType variance(const inverse_gamma_distribution<RealType, Policy>& dist)
  312. {
  313. BOOST_MATH_STD_USING // for ADL of std functions
  314. static const char* function = "boost::math::variance(const inverse_gamma_distribution<%1%>&)";
  315. RealType shape = dist.shape();
  316. RealType scale = dist.scale();
  317. RealType result = 0;
  318. if(false == detail::check_scale(function, scale, &result, Policy()))
  319. {
  320. return result;
  321. }
  322. if((shape <= 2) || !(boost::math::isfinite)(shape))
  323. {
  324. result = policies::raise_domain_error<RealType>(
  325. function,
  326. "Shape parameter is %1%, but for a defined variance it must be > 2", shape, Policy());
  327. return result;
  328. }
  329. result = (scale * scale) / ((shape - 1) * (shape -1) * (shape -2));
  330. return result;
  331. }
  332. template <class RealType, class Policy>
  333. inline RealType mode(const inverse_gamma_distribution<RealType, Policy>& dist)
  334. {
  335. BOOST_MATH_STD_USING // for ADL of std functions
  336. static const char* function = "boost::math::mode(const inverse_gamma_distribution<%1%>&)";
  337. RealType shape = dist.shape();
  338. RealType scale = dist.scale();
  339. RealType result = 0;
  340. if(false == detail::check_inverse_gamma(function, scale, shape, &result, Policy()))
  341. {
  342. return result;
  343. }
  344. // Only defined for shape >= 0, but is checked by check_inverse_gamma.
  345. result = scale / (shape + 1);
  346. return result;
  347. }
  348. //template <class RealType, class Policy>
  349. //inline RealType median(const gamma_distribution<RealType, Policy>& dist)
  350. //{ // Wikipedia does not define median,
  351. // so rely on default definition quantile(0.5) in derived accessors.
  352. // return result.
  353. //}
  354. template <class RealType, class Policy>
  355. inline RealType skewness(const inverse_gamma_distribution<RealType, Policy>& dist)
  356. {
  357. BOOST_MATH_STD_USING // for ADL of std functions
  358. static const char* function = "boost::math::skewness(const inverse_gamma_distribution<%1%>&)";
  359. RealType shape = dist.shape();
  360. RealType scale = dist.scale();
  361. RealType result = 0;
  362. if(false == detail::check_scale(function, scale, &result, Policy()))
  363. {
  364. return result;
  365. }
  366. if((shape <= 3) || !(boost::math::isfinite)(shape))
  367. {
  368. result = policies::raise_domain_error<RealType>(
  369. function,
  370. "Shape parameter is %1%, but for a defined skewness it must be > 3", shape, Policy());
  371. return result;
  372. }
  373. result = (4 * sqrt(shape - 2) ) / (shape - 3);
  374. return result;
  375. }
  376. template <class RealType, class Policy>
  377. inline RealType kurtosis_excess(const inverse_gamma_distribution<RealType, Policy>& dist)
  378. {
  379. BOOST_MATH_STD_USING // for ADL of std functions
  380. static const char* function = "boost::math::kurtosis_excess(const inverse_gamma_distribution<%1%>&)";
  381. RealType shape = dist.shape();
  382. RealType scale = dist.scale();
  383. RealType result = 0;
  384. if(false == detail::check_scale(function, scale, &result, Policy()))
  385. {
  386. return result;
  387. }
  388. if((shape <= 4) || !(boost::math::isfinite)(shape))
  389. {
  390. result = policies::raise_domain_error<RealType>(
  391. function,
  392. "Shape parameter is %1%, but for a defined kurtosis excess it must be > 4", shape, Policy());
  393. return result;
  394. }
  395. result = (30 * shape - 66) / ((shape - 3) * (shape - 4));
  396. return result;
  397. }
  398. template <class RealType, class Policy>
  399. inline RealType kurtosis(const inverse_gamma_distribution<RealType, Policy>& dist)
  400. {
  401. static const char* function = "boost::math::kurtosis(const inverse_gamma_distribution<%1%>&)";
  402. RealType shape = dist.shape();
  403. RealType scale = dist.scale();
  404. RealType result = 0;
  405. if(false == detail::check_scale(function, scale, &result, Policy()))
  406. {
  407. return result;
  408. }
  409. if((shape <= 4) || !(boost::math::isfinite)(shape))
  410. {
  411. result = policies::raise_domain_error<RealType>(
  412. function,
  413. "Shape parameter is %1%, but for a defined kurtosis it must be > 4", shape, Policy());
  414. return result;
  415. }
  416. return kurtosis_excess(dist) + 3;
  417. }
  418. } // namespace math
  419. } // namespace boost
  420. // This include must be at the end, *after* the accessors
  421. // for this distribution have been defined, in order to
  422. // keep compilers that support two-phase lookup happy.
  423. #include <boost/math/distributions/detail/derived_accessors.hpp>
  424. #endif // BOOST_STATS_INVERSE_GAMMA_HPP