annotate any/include/boost/math/distributions/inverse_gamma.hpp @ 160:cff480c41f97

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