gamma.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. // Copyright John Maddock 2006.
  2. // Copyright Matt Borland 2024.
  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_GAMMA_HPP
  7. #define BOOST_STATS_GAMMA_HPP
  8. // http://www.itl.nist.gov/div898/handbook/eda/section3/eda366b.htm
  9. // http://mathworld.wolfram.com/GammaDistribution.html
  10. // http://en.wikipedia.org/wiki/Gamma_distribution
  11. #include <boost/math/tools/config.hpp>
  12. #include <boost/math/tools/tuple.hpp>
  13. #include <boost/math/tools/numeric_limits.hpp>
  14. #include <boost/math/distributions/fwd.hpp>
  15. #include <boost/math/special_functions/gamma.hpp>
  16. #include <boost/math/special_functions/digamma.hpp>
  17. #include <boost/math/distributions/detail/common_error_handling.hpp>
  18. #include <boost/math/distributions/complement.hpp>
  19. namespace boost{ namespace math
  20. {
  21. namespace detail
  22. {
  23. template <class RealType, class Policy>
  24. BOOST_MATH_GPU_ENABLED inline bool check_gamma_shape(
  25. const char* function,
  26. RealType shape,
  27. RealType* result, const Policy& pol)
  28. {
  29. if((shape <= 0) || !(boost::math::isfinite)(shape))
  30. {
  31. *result = policies::raise_domain_error<RealType>(
  32. function,
  33. "Shape parameter is %1%, but must be > 0 !", shape, pol);
  34. return false;
  35. }
  36. return true;
  37. }
  38. template <class RealType, class Policy>
  39. BOOST_MATH_GPU_ENABLED inline bool check_gamma_x(
  40. const char* function,
  41. RealType const& x,
  42. RealType* result, const Policy& pol)
  43. {
  44. if((x < 0) || !(boost::math::isfinite)(x))
  45. {
  46. *result = policies::raise_domain_error<RealType>(
  47. function,
  48. "Random variate is %1% but must be >= 0 !", x, pol);
  49. return false;
  50. }
  51. return true;
  52. }
  53. template <class RealType, class Policy>
  54. BOOST_MATH_GPU_ENABLED inline bool check_gamma(
  55. const char* function,
  56. RealType scale,
  57. RealType shape,
  58. RealType* result, const Policy& pol)
  59. {
  60. return check_scale(function, scale, result, pol) && check_gamma_shape(function, shape, result, pol);
  61. }
  62. } // namespace detail
  63. template <class RealType = double, class Policy = policies::policy<> >
  64. class gamma_distribution
  65. {
  66. public:
  67. using value_type = RealType;
  68. using policy_type = Policy;
  69. BOOST_MATH_GPU_ENABLED explicit gamma_distribution(RealType l_shape, RealType l_scale = 1)
  70. : m_shape(l_shape), m_scale(l_scale)
  71. {
  72. RealType result;
  73. detail::check_gamma("boost::math::gamma_distribution<%1%>::gamma_distribution", l_scale, l_shape, &result, Policy());
  74. }
  75. BOOST_MATH_GPU_ENABLED RealType shape()const
  76. {
  77. return m_shape;
  78. }
  79. BOOST_MATH_GPU_ENABLED RealType scale()const
  80. {
  81. return m_scale;
  82. }
  83. private:
  84. //
  85. // Data members:
  86. //
  87. RealType m_shape; // distribution shape
  88. RealType m_scale; // distribution scale
  89. };
  90. // NO typedef because of clash with name of gamma function.
  91. #ifdef __cpp_deduction_guides
  92. template <class RealType>
  93. gamma_distribution(RealType)->gamma_distribution<typename boost::math::tools::promote_args<RealType>::type>;
  94. template <class RealType>
  95. gamma_distribution(RealType,RealType)->gamma_distribution<typename boost::math::tools::promote_args<RealType>::type>;
  96. #endif
  97. template <class RealType, class Policy>
  98. BOOST_MATH_GPU_ENABLED inline boost::math::pair<RealType, RealType> range(const gamma_distribution<RealType, Policy>& /* dist */)
  99. { // Range of permissible values for random variable x.
  100. using boost::math::tools::max_value;
  101. return boost::math::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
  102. }
  103. template <class RealType, class Policy>
  104. BOOST_MATH_GPU_ENABLED inline boost::math::pair<RealType, RealType> support(const gamma_distribution<RealType, Policy>& /* dist */)
  105. { // Range of supported values for random variable x.
  106. // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
  107. using boost::math::tools::max_value;
  108. using boost::math::tools::min_value;
  109. return boost::math::pair<RealType, RealType>(min_value<RealType>(), max_value<RealType>());
  110. }
  111. template <class RealType, class Policy>
  112. BOOST_MATH_GPU_ENABLED inline RealType pdf(const gamma_distribution<RealType, Policy>& dist, const RealType& x)
  113. {
  114. BOOST_MATH_STD_USING // for ADL of std functions
  115. constexpr auto function = "boost::math::pdf(const gamma_distribution<%1%>&, %1%)";
  116. RealType shape = dist.shape();
  117. RealType scale = dist.scale();
  118. RealType result = 0;
  119. if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
  120. return result;
  121. if(false == detail::check_gamma_x(function, x, &result, Policy()))
  122. return result;
  123. if(x == 0)
  124. {
  125. return 0;
  126. }
  127. result = gamma_p_derivative(shape, x / scale, Policy()) / scale;
  128. return result;
  129. } // pdf
  130. template <class RealType, class Policy>
  131. BOOST_MATH_GPU_ENABLED inline RealType logpdf(const gamma_distribution<RealType, Policy>& dist, const RealType& x)
  132. {
  133. BOOST_MATH_STD_USING // for ADL of std functions
  134. using boost::math::lgamma;
  135. constexpr auto function = "boost::math::logpdf(const gamma_distribution<%1%>&, %1%)";
  136. RealType k = dist.shape();
  137. RealType theta = dist.scale();
  138. RealType result = -boost::math::numeric_limits<RealType>::infinity();
  139. if(false == detail::check_gamma(function, theta, k, &result, Policy()))
  140. return result;
  141. if(false == detail::check_gamma_x(function, x, &result, Policy()))
  142. return result;
  143. if(x == 0)
  144. {
  145. return boost::math::numeric_limits<RealType>::quiet_NaN();
  146. }
  147. result = -k*log(theta) + (k-1)*log(x) - lgamma(k) - (x/theta);
  148. return result;
  149. } // logpdf
  150. template <class RealType, class Policy>
  151. BOOST_MATH_GPU_ENABLED inline RealType cdf(const gamma_distribution<RealType, Policy>& dist, const RealType& x)
  152. {
  153. BOOST_MATH_STD_USING // for ADL of std functions
  154. constexpr auto function = "boost::math::cdf(const gamma_distribution<%1%>&, %1%)";
  155. RealType shape = dist.shape();
  156. RealType scale = dist.scale();
  157. RealType result = 0;
  158. if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
  159. return result;
  160. if(false == detail::check_gamma_x(function, x, &result, Policy()))
  161. return result;
  162. result = boost::math::gamma_p(shape, x / scale, Policy());
  163. return result;
  164. } // cdf
  165. template <class RealType, class Policy>
  166. BOOST_MATH_GPU_ENABLED inline RealType quantile(const gamma_distribution<RealType, Policy>& dist, const RealType& p)
  167. {
  168. BOOST_MATH_STD_USING // for ADL of std functions
  169. constexpr auto function = "boost::math::quantile(const gamma_distribution<%1%>&, %1%)";
  170. RealType shape = dist.shape();
  171. RealType scale = dist.scale();
  172. RealType result = 0;
  173. if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
  174. return result;
  175. if(false == detail::check_probability(function, p, &result, Policy()))
  176. return result;
  177. if(p == 1)
  178. return policies::raise_overflow_error<RealType>(function, 0, Policy());
  179. result = gamma_p_inv(shape, p, Policy()) * scale;
  180. return result;
  181. }
  182. template <class RealType, class Policy>
  183. BOOST_MATH_GPU_ENABLED inline RealType cdf(const complemented2_type<gamma_distribution<RealType, Policy>, RealType>& c)
  184. {
  185. BOOST_MATH_STD_USING // for ADL of std functions
  186. constexpr auto function = "boost::math::quantile(const gamma_distribution<%1%>&, %1%)";
  187. RealType shape = c.dist.shape();
  188. RealType scale = c.dist.scale();
  189. RealType result = 0;
  190. if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
  191. return result;
  192. if(false == detail::check_gamma_x(function, c.param, &result, Policy()))
  193. return result;
  194. result = gamma_q(shape, c.param / scale, Policy());
  195. return result;
  196. }
  197. template <class RealType, class Policy>
  198. BOOST_MATH_GPU_ENABLED inline RealType quantile(const complemented2_type<gamma_distribution<RealType, Policy>, RealType>& c)
  199. {
  200. BOOST_MATH_STD_USING // for ADL of std functions
  201. constexpr auto function = "boost::math::quantile(const gamma_distribution<%1%>&, %1%)";
  202. RealType shape = c.dist.shape();
  203. RealType scale = c.dist.scale();
  204. RealType q = c.param;
  205. RealType result = 0;
  206. if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
  207. return result;
  208. if(false == detail::check_probability(function, q, &result, Policy()))
  209. return result;
  210. if(q == 0)
  211. return policies::raise_overflow_error<RealType>(function, 0, Policy());
  212. result = gamma_q_inv(shape, q, Policy()) * scale;
  213. return result;
  214. }
  215. template <class RealType, class Policy>
  216. BOOST_MATH_GPU_ENABLED inline RealType mean(const gamma_distribution<RealType, Policy>& dist)
  217. {
  218. BOOST_MATH_STD_USING // for ADL of std functions
  219. constexpr auto function = "boost::math::mean(const gamma_distribution<%1%>&)";
  220. RealType shape = dist.shape();
  221. RealType scale = dist.scale();
  222. RealType result = 0;
  223. if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
  224. return result;
  225. result = shape * scale;
  226. return result;
  227. }
  228. template <class RealType, class Policy>
  229. BOOST_MATH_GPU_ENABLED inline RealType variance(const gamma_distribution<RealType, Policy>& dist)
  230. {
  231. BOOST_MATH_STD_USING // for ADL of std functions
  232. constexpr auto function = "boost::math::variance(const gamma_distribution<%1%>&)";
  233. RealType shape = dist.shape();
  234. RealType scale = dist.scale();
  235. RealType result = 0;
  236. if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
  237. return result;
  238. result = shape * scale * scale;
  239. return result;
  240. }
  241. template <class RealType, class Policy>
  242. BOOST_MATH_GPU_ENABLED inline RealType mode(const gamma_distribution<RealType, Policy>& dist)
  243. {
  244. BOOST_MATH_STD_USING // for ADL of std functions
  245. constexpr auto function = "boost::math::mode(const gamma_distribution<%1%>&)";
  246. RealType shape = dist.shape();
  247. RealType scale = dist.scale();
  248. RealType result = 0;
  249. if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
  250. return result;
  251. if(shape < 1)
  252. return policies::raise_domain_error<RealType>(
  253. function,
  254. "The mode of the gamma distribution is only defined for values of the shape parameter >= 1, but got %1%.",
  255. shape, Policy());
  256. result = (shape - 1) * scale;
  257. return result;
  258. }
  259. //template <class RealType, class Policy>
  260. //inline RealType median(const gamma_distribution<RealType, Policy>& dist)
  261. //{ // Rely on default definition in derived accessors.
  262. //}
  263. template <class RealType, class Policy>
  264. BOOST_MATH_GPU_ENABLED inline RealType skewness(const gamma_distribution<RealType, Policy>& dist)
  265. {
  266. BOOST_MATH_STD_USING // for ADL of std functions
  267. constexpr auto function = "boost::math::skewness(const gamma_distribution<%1%>&)";
  268. RealType shape = dist.shape();
  269. RealType scale = dist.scale();
  270. RealType result = 0;
  271. if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
  272. return result;
  273. result = 2 / sqrt(shape);
  274. return result;
  275. }
  276. template <class RealType, class Policy>
  277. BOOST_MATH_GPU_ENABLED inline RealType kurtosis_excess(const gamma_distribution<RealType, Policy>& dist)
  278. {
  279. BOOST_MATH_STD_USING // for ADL of std functions
  280. constexpr auto function = "boost::math::kurtosis_excess(const gamma_distribution<%1%>&)";
  281. RealType shape = dist.shape();
  282. RealType scale = dist.scale();
  283. RealType result = 0;
  284. if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
  285. return result;
  286. result = 6 / shape;
  287. return result;
  288. }
  289. template <class RealType, class Policy>
  290. BOOST_MATH_GPU_ENABLED inline RealType kurtosis(const gamma_distribution<RealType, Policy>& dist)
  291. {
  292. return kurtosis_excess(dist) + 3;
  293. }
  294. template <class RealType, class Policy>
  295. BOOST_MATH_GPU_ENABLED inline RealType entropy(const gamma_distribution<RealType, Policy>& dist)
  296. {
  297. BOOST_MATH_STD_USING
  298. RealType k = dist.shape();
  299. RealType theta = dist.scale();
  300. return k + log(theta) + boost::math::lgamma(k) + (1-k)*digamma(k);
  301. }
  302. } // namespace math
  303. } // namespace boost
  304. // This include must be at the end, *after* the accessors
  305. // for this distribution have been defined, in order to
  306. // keep compilers that support two-phase lookup happy.
  307. #include <boost/math/distributions/detail/derived_accessors.hpp>
  308. #endif // BOOST_STATS_GAMMA_HPP