File indexing completed on 2025-01-18 09:39:41
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_STATS_INVERSE_GAUSSIAN_HPP
0009 #define BOOST_STATS_INVERSE_GAUSSIAN_HPP
0010
0011 #ifdef _MSC_VER
0012 #pragma warning(disable: 4512)
0013 #endif
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053 #include <boost/math/special_functions/erf.hpp> // for erf/erfc.
0054 #include <boost/math/distributions/complement.hpp>
0055 #include <boost/math/distributions/detail/common_error_handling.hpp>
0056 #include <boost/math/distributions/normal.hpp>
0057 #include <boost/math/distributions/gamma.hpp> // for gamma function
0058
0059 #include <boost/math/tools/tuple.hpp>
0060 #include <boost/math/tools/roots.hpp>
0061
0062 #include <utility>
0063
0064 namespace boost{ namespace math{
0065
0066 template <class RealType = double, class Policy = policies::policy<> >
0067 class inverse_gaussian_distribution
0068 {
0069 public:
0070 using value_type = RealType;
0071 using policy_type = Policy;
0072
0073 explicit inverse_gaussian_distribution(RealType l_mean = 1, RealType l_scale = 1)
0074 : m_mean(l_mean), m_scale(l_scale)
0075 {
0076 static const char* function = "boost::math::inverse_gaussian_distribution<%1%>::inverse_gaussian_distribution";
0077
0078 RealType result;
0079 detail::check_scale(function, l_scale, &result, Policy());
0080 detail::check_location(function, l_mean, &result, Policy());
0081 detail::check_x_gt0(function, l_mean, &result, Policy());
0082 }
0083
0084 RealType mean()const
0085 {
0086 return m_mean;
0087 }
0088
0089
0090 RealType location()const
0091 {
0092 return m_mean;
0093 }
0094 RealType scale()const
0095 {
0096 return m_scale;
0097 }
0098
0099 RealType shape()const
0100 {
0101 return m_scale / m_mean;
0102 }
0103
0104 private:
0105
0106
0107
0108 RealType m_mean;
0109 RealType m_scale;
0110 };
0111
0112 using inverse_gaussian = inverse_gaussian_distribution<double>;
0113
0114 #ifdef __cpp_deduction_guides
0115 template <class RealType>
0116 inverse_gaussian_distribution(RealType)->inverse_gaussian_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0117 template <class RealType>
0118 inverse_gaussian_distribution(RealType,RealType)->inverse_gaussian_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0119 #endif
0120
0121 template <class RealType, class Policy>
0122 inline std::pair<RealType, RealType> range(const inverse_gaussian_distribution<RealType, Policy>& )
0123 {
0124 using boost::math::tools::max_value;
0125 return std::pair<RealType, RealType>(static_cast<RealType>(0.), max_value<RealType>());
0126 }
0127
0128 template <class RealType, class Policy>
0129 inline std::pair<RealType, RealType> support(const inverse_gaussian_distribution<RealType, Policy>& )
0130 {
0131
0132 using boost::math::tools::max_value;
0133 return std::pair<RealType, RealType>(static_cast<RealType>(0.), max_value<RealType>());
0134 }
0135
0136 template <class RealType, class Policy>
0137 inline RealType pdf(const inverse_gaussian_distribution<RealType, Policy>& dist, const RealType& x)
0138 {
0139 BOOST_MATH_STD_USING
0140
0141 RealType scale = dist.scale();
0142 RealType mean = dist.mean();
0143 RealType result = 0;
0144 static const char* function = "boost::math::pdf(const inverse_gaussian_distribution<%1%>&, %1%)";
0145 if(false == detail::check_scale(function, scale, &result, Policy()))
0146 {
0147 return result;
0148 }
0149 if(false == detail::check_location(function, mean, &result, Policy()))
0150 {
0151 return result;
0152 }
0153 if(false == detail::check_x_gt0(function, mean, &result, Policy()))
0154 {
0155 return result;
0156 }
0157 if(false == detail::check_positive_x(function, x, &result, Policy()))
0158 {
0159 return result;
0160 }
0161
0162 if (x == 0)
0163 {
0164 return 0;
0165 }
0166
0167 result =
0168 sqrt(scale / (constants::two_pi<RealType>() * x * x * x))
0169 * exp(-scale * (x - mean) * (x - mean) / (2 * x * mean * mean));
0170 return result;
0171 }
0172
0173 template <class RealType, class Policy>
0174 inline RealType logpdf(const inverse_gaussian_distribution<RealType, Policy>& dist, const RealType& x)
0175 {
0176 BOOST_MATH_STD_USING
0177
0178 RealType scale = dist.scale();
0179 RealType mean = dist.mean();
0180 RealType result = -std::numeric_limits<RealType>::infinity();
0181 static const char* function = "boost::math::logpdf(const inverse_gaussian_distribution<%1%>&, %1%)";
0182 if(false == detail::check_scale(function, scale, &result, Policy()))
0183 {
0184 return result;
0185 }
0186 if(false == detail::check_location(function, mean, &result, Policy()))
0187 {
0188 return result;
0189 }
0190 if(false == detail::check_x_gt0(function, mean, &result, Policy()))
0191 {
0192 return result;
0193 }
0194 if(false == detail::check_positive_x(function, x, &result, Policy()))
0195 {
0196 return result;
0197 }
0198
0199 if (x == 0)
0200 {
0201 return std::numeric_limits<RealType>::quiet_NaN();
0202 }
0203
0204 const RealType two_pi = boost::math::constants::two_pi<RealType>();
0205
0206 result = (-scale*pow(mean - x, RealType(2))/(mean*mean*x) + log(scale) - 3*log(x) - log(two_pi)) / 2;
0207 return result;
0208 }
0209
0210 template <class RealType, class Policy>
0211 inline RealType cdf(const inverse_gaussian_distribution<RealType, Policy>& dist, const RealType& x)
0212 {
0213 BOOST_MATH_STD_USING
0214
0215 RealType scale = dist.scale();
0216 RealType mean = dist.mean();
0217 static const char* function = "boost::math::cdf(const inverse_gaussian_distribution<%1%>&, %1%)";
0218 RealType result = 0;
0219 if(false == detail::check_scale(function, scale, &result, Policy()))
0220 {
0221 return result;
0222 }
0223 if(false == detail::check_location(function, mean, &result, Policy()))
0224 {
0225 return result;
0226 }
0227 if (false == detail::check_x_gt0(function, mean, &result, Policy()))
0228 {
0229 return result;
0230 }
0231 if(false == detail::check_positive_x(function, x, &result, Policy()))
0232 {
0233 return result;
0234 }
0235 if (x == 0)
0236 {
0237 return 0;
0238 }
0239
0240
0241
0242
0243 normal_distribution<RealType> n01;
0244
0245 RealType n0 = sqrt(scale / x);
0246 n0 *= ((x / mean) -1);
0247 RealType n1 = cdf(n01, n0);
0248 RealType expfactor = exp(2 * scale / mean);
0249 RealType n3 = - sqrt(scale / x);
0250 n3 *= (x / mean) + 1;
0251 RealType n4 = cdf(n01, n3);
0252 result = n1 + expfactor * n4;
0253 return result;
0254 }
0255
0256 template <class RealType, class Policy>
0257 struct inverse_gaussian_quantile_functor
0258 {
0259
0260 inverse_gaussian_quantile_functor(const boost::math::inverse_gaussian_distribution<RealType, Policy> dist, RealType const& p)
0261 : distribution(dist), prob(p)
0262 {
0263 }
0264 boost::math::tuple<RealType, RealType> operator()(RealType const& x)
0265 {
0266 RealType c = cdf(distribution, x);
0267 RealType fx = c - prob;
0268 RealType dx = pdf(distribution, x);
0269
0270 return boost::math::make_tuple(fx, dx);
0271 }
0272 private:
0273 const boost::math::inverse_gaussian_distribution<RealType, Policy> distribution;
0274 RealType prob;
0275 };
0276
0277 template <class RealType, class Policy>
0278 struct inverse_gaussian_quantile_complement_functor
0279 {
0280 inverse_gaussian_quantile_complement_functor(const boost::math::inverse_gaussian_distribution<RealType, Policy> dist, RealType const& p)
0281 : distribution(dist), prob(p)
0282 {
0283 }
0284 boost::math::tuple<RealType, RealType> operator()(RealType const& x)
0285 {
0286 RealType c = cdf(complement(distribution, x));
0287 RealType fx = c - prob;
0288 RealType dx = -pdf(distribution, x);
0289
0290
0291 return boost::math::make_tuple(fx, dx);
0292 }
0293 private:
0294 const boost::math::inverse_gaussian_distribution<RealType, Policy> distribution;
0295 RealType prob;
0296 };
0297
0298 namespace detail
0299 {
0300 template <class RealType>
0301 inline RealType guess_ig(RealType p, RealType mu = 1, RealType lambda = 1)
0302 {
0303 BOOST_MATH_STD_USING
0304 using boost::math::policies::policy;
0305
0306 using boost::math::policies::overflow_error;
0307
0308 using boost::math::policies::ignore_error;
0309
0310 using no_overthrow_policy = policy<overflow_error<ignore_error>>;
0311
0312 RealType x;
0313 RealType phi = lambda / mu;
0314 if (phi > 2.)
0315 {
0316
0317
0318
0319
0320
0321
0322 normal_distribution<RealType, no_overthrow_policy> n01;
0323 x = mu * exp(quantile(n01, p) / sqrt(phi) - 1/(2 * phi));
0324 }
0325 else
0326 {
0327
0328 using boost::math::gamma_distribution;
0329
0330
0331 using gamma_nooverflow = gamma_distribution<RealType, no_overthrow_policy>;
0332
0333 gamma_nooverflow g(static_cast<RealType>(0.5), static_cast<RealType>(1.));
0334
0335
0336 RealType qg = quantile(complement(g, p));
0337 x = lambda / (qg * 2);
0338
0339 if (x > mu/2)
0340 {
0341
0342 RealType q = quantile(g, p);
0343
0344
0345 x = mu * exp(q / sqrt(phi) - 1/(2 * phi));
0346 }
0347 }
0348 return x;
0349 }
0350 }
0351
0352 template <class RealType, class Policy>
0353 inline RealType quantile(const inverse_gaussian_distribution<RealType, Policy>& dist, const RealType& p)
0354 {
0355 BOOST_MATH_STD_USING
0356
0357
0358 RealType mean = dist.mean();
0359 RealType scale = dist.scale();
0360 static const char* function = "boost::math::quantile(const inverse_gaussian_distribution<%1%>&, %1%)";
0361
0362 RealType result = 0;
0363 if(false == detail::check_scale(function, scale, &result, Policy()))
0364 return result;
0365 if(false == detail::check_location(function, mean, &result, Policy()))
0366 return result;
0367 if (false == detail::check_x_gt0(function, mean, &result, Policy()))
0368 return result;
0369 if(false == detail::check_probability(function, p, &result, Policy()))
0370 return result;
0371 if (p == 0)
0372 {
0373 return 0;
0374 }
0375 if (p == 1)
0376 {
0377 result = policies::raise_overflow_error<RealType>(function,
0378 "probability parameter is 1, but must be < 1!", Policy());
0379 return result;
0380 }
0381
0382 RealType guess = detail::guess_ig(p, dist.mean(), dist.scale());
0383 using boost::math::tools::max_value;
0384
0385 RealType min = static_cast<RealType>(0);
0386 RealType max = max_value<RealType>();
0387
0388
0389
0390 int get_digits = policies::digits<RealType, Policy>();
0391 std::uintmax_t m = policies::get_max_root_iterations<Policy>();
0392 using boost::math::tools::newton_raphson_iterate;
0393 result =
0394 newton_raphson_iterate(inverse_gaussian_quantile_functor<RealType, Policy>(dist, p), guess, min, max, get_digits, m);
0395 return result;
0396 }
0397
0398 template <class RealType, class Policy>
0399 inline RealType cdf(const complemented2_type<inverse_gaussian_distribution<RealType, Policy>, RealType>& c)
0400 {
0401 BOOST_MATH_STD_USING
0402
0403 RealType scale = c.dist.scale();
0404 RealType mean = c.dist.mean();
0405 RealType x = c.param;
0406 static const char* function = "boost::math::cdf(const complement(inverse_gaussian_distribution<%1%>&), %1%)";
0407
0408 RealType result = 0;
0409 if(false == detail::check_scale(function, scale, &result, Policy()))
0410 return result;
0411 if(false == detail::check_location(function, mean, &result, Policy()))
0412 return result;
0413 if (false == detail::check_x_gt0(function, mean, &result, Policy()))
0414 return result;
0415 if(false == detail::check_positive_x(function, x, &result, Policy()))
0416 return result;
0417
0418 normal_distribution<RealType> n01;
0419 RealType n0 = sqrt(scale / x);
0420 n0 *= ((x / mean) -1);
0421 RealType cdf_1 = cdf(complement(n01, n0));
0422
0423 RealType expfactor = exp(2 * scale / mean);
0424 RealType n3 = - sqrt(scale / x);
0425 n3 *= (x / mean) + 1;
0426
0427
0428 RealType n6 = cdf(complement(n01, +sqrt(scale/x) * ((x /mean) + 1)));
0429
0430 result = cdf_1 - expfactor * n6;
0431 return result;
0432 }
0433
0434 template <class RealType, class Policy>
0435 inline RealType quantile(const complemented2_type<inverse_gaussian_distribution<RealType, Policy>, RealType>& c)
0436 {
0437 BOOST_MATH_STD_USING
0438
0439 RealType scale = c.dist.scale();
0440 RealType mean = c.dist.mean();
0441 static const char* function = "boost::math::quantile(const complement(inverse_gaussian_distribution<%1%>&), %1%)";
0442 RealType result = 0;
0443 if(false == detail::check_scale(function, scale, &result, Policy()))
0444 return result;
0445 if(false == detail::check_location(function, mean, &result, Policy()))
0446 return result;
0447 if (false == detail::check_x_gt0(function, mean, &result, Policy()))
0448 return result;
0449 RealType q = c.param;
0450 if(false == detail::check_probability(function, q, &result, Policy()))
0451 return result;
0452
0453 RealType guess = detail::guess_ig(q, mean, scale);
0454
0455 using boost::math::tools::max_value;
0456
0457 RealType min = static_cast<RealType>(0);
0458 RealType max = max_value<RealType>();
0459
0460
0461 int get_digits = policies::digits<RealType, Policy>();
0462 std::uintmax_t m = policies::get_max_root_iterations<Policy>();
0463 using boost::math::tools::newton_raphson_iterate;
0464 result =
0465 newton_raphson_iterate(inverse_gaussian_quantile_complement_functor<RealType, Policy>(c.dist, q), guess, min, max, get_digits, m);
0466 return result;
0467 }
0468
0469 template <class RealType, class Policy>
0470 inline RealType mean(const inverse_gaussian_distribution<RealType, Policy>& dist)
0471 {
0472 return dist.mean();
0473 }
0474
0475 template <class RealType, class Policy>
0476 inline RealType scale(const inverse_gaussian_distribution<RealType, Policy>& dist)
0477 {
0478 return dist.scale();
0479 }
0480
0481 template <class RealType, class Policy>
0482 inline RealType shape(const inverse_gaussian_distribution<RealType, Policy>& dist)
0483 {
0484 return dist.shape();
0485 }
0486
0487 template <class RealType, class Policy>
0488 inline RealType standard_deviation(const inverse_gaussian_distribution<RealType, Policy>& dist)
0489 {
0490 BOOST_MATH_STD_USING
0491 RealType scale = dist.scale();
0492 RealType mean = dist.mean();
0493 RealType result = sqrt(mean * mean * mean / scale);
0494 return result;
0495 }
0496
0497 template <class RealType, class Policy>
0498 inline RealType mode(const inverse_gaussian_distribution<RealType, Policy>& dist)
0499 {
0500 BOOST_MATH_STD_USING
0501 RealType scale = dist.scale();
0502 RealType mean = dist.mean();
0503 RealType result = mean * (sqrt(1 + (9 * mean * mean)/(4 * scale * scale))
0504 - 3 * mean / (2 * scale));
0505 return result;
0506 }
0507
0508 template <class RealType, class Policy>
0509 inline RealType skewness(const inverse_gaussian_distribution<RealType, Policy>& dist)
0510 {
0511 BOOST_MATH_STD_USING
0512 RealType scale = dist.scale();
0513 RealType mean = dist.mean();
0514 RealType result = 3 * sqrt(mean/scale);
0515 return result;
0516 }
0517
0518 template <class RealType, class Policy>
0519 inline RealType kurtosis(const inverse_gaussian_distribution<RealType, Policy>& dist)
0520 {
0521 RealType scale = dist.scale();
0522 RealType mean = dist.mean();
0523 RealType result = 15 * mean / scale -3;
0524 return result;
0525 }
0526
0527 template <class RealType, class Policy>
0528 inline RealType kurtosis_excess(const inverse_gaussian_distribution<RealType, Policy>& dist)
0529 {
0530 RealType scale = dist.scale();
0531 RealType mean = dist.mean();
0532 RealType result = 15 * mean / scale;
0533 return result;
0534 }
0535
0536 }
0537 }
0538
0539
0540
0541
0542 #include <boost/math/distributions/detail/derived_accessors.hpp>
0543
0544 #endif
0545
0546