| 1 | // Copyright John Maddock 2006. |
| 2 | // Use, modification and distribution are subject to the |
| 3 | // Boost Software License, Version 1.0. (See accompanying file |
| 4 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 5 | |
| 6 | #ifndef BOOST_STATS_WEIBULL_HPP |
| 7 | #define BOOST_STATS_WEIBULL_HPP |
| 8 | |
| 9 | // http://www.itl.nist.gov/div898/handbook/eda/section3/eda3668.htm |
| 10 | // http://mathworld.wolfram.com/WeibullDistribution.html |
| 11 | |
| 12 | #include <boost/math/distributions/fwd.hpp> |
| 13 | #include <boost/math/special_functions/gamma.hpp> |
| 14 | #include <boost/math/special_functions/log1p.hpp> |
| 15 | #include <boost/math/special_functions/expm1.hpp> |
| 16 | #include <boost/math/distributions/detail/common_error_handling.hpp> |
| 17 | #include <boost/math/distributions/complement.hpp> |
| 18 | |
| 19 | #include <utility> |
| 20 | |
| 21 | namespace boost{ namespace math |
| 22 | { |
| 23 | namespace detail{ |
| 24 | |
| 25 | template <class RealType, class Policy> |
| 26 | inline bool check_weibull_shape( |
| 27 | const char* function, |
| 28 | RealType shape, |
| 29 | RealType* result, const Policy& pol) |
| 30 | { |
| 31 | if((shape <= 0) || !(boost::math::isfinite)(shape)) |
| 32 | { |
| 33 | *result = policies::raise_domain_error<RealType>( |
| 34 | function, |
| 35 | "Shape parameter is %1%, but must be > 0 !" , shape, pol); |
| 36 | return false; |
| 37 | } |
| 38 | return true; |
| 39 | } |
| 40 | |
| 41 | template <class RealType, class Policy> |
| 42 | inline bool check_weibull_x( |
| 43 | const char* function, |
| 44 | RealType const& x, |
| 45 | RealType* result, const Policy& pol) |
| 46 | { |
| 47 | if((x < 0) || !(boost::math::isfinite)(x)) |
| 48 | { |
| 49 | *result = policies::raise_domain_error<RealType>( |
| 50 | function, |
| 51 | "Random variate is %1% but must be >= 0 !" , x, pol); |
| 52 | return false; |
| 53 | } |
| 54 | return true; |
| 55 | } |
| 56 | |
| 57 | template <class RealType, class Policy> |
| 58 | inline bool check_weibull( |
| 59 | const char* function, |
| 60 | RealType scale, |
| 61 | RealType shape, |
| 62 | RealType* result, const Policy& pol) |
| 63 | { |
| 64 | return check_scale(function, scale, result, pol) && check_weibull_shape(function, shape, result, pol); |
| 65 | } |
| 66 | |
| 67 | } // namespace detail |
| 68 | |
| 69 | template <class RealType = double, class Policy = policies::policy<> > |
| 70 | class weibull_distribution |
| 71 | { |
| 72 | public: |
| 73 | using value_type = RealType; |
| 74 | using policy_type = Policy; |
| 75 | |
| 76 | explicit weibull_distribution(RealType l_shape, RealType l_scale = 1) |
| 77 | : m_shape(l_shape), m_scale(l_scale) |
| 78 | { |
| 79 | RealType result; |
| 80 | detail::check_weibull("boost::math::weibull_distribution<%1%>::weibull_distribution" , l_scale, l_shape, &result, Policy()); |
| 81 | } |
| 82 | |
| 83 | RealType shape()const |
| 84 | { |
| 85 | return m_shape; |
| 86 | } |
| 87 | |
| 88 | RealType scale()const |
| 89 | { |
| 90 | return m_scale; |
| 91 | } |
| 92 | private: |
| 93 | // |
| 94 | // Data members: |
| 95 | // |
| 96 | RealType m_shape; // distribution shape |
| 97 | RealType m_scale; // distribution scale |
| 98 | }; |
| 99 | |
| 100 | using weibull = weibull_distribution<double>; |
| 101 | |
| 102 | #ifdef __cpp_deduction_guides |
| 103 | template <class RealType> |
| 104 | weibull_distribution(RealType)->weibull_distribution<typename boost::math::tools::promote_args<RealType>::type>; |
| 105 | template <class RealType> |
| 106 | weibull_distribution(RealType,RealType)->weibull_distribution<typename boost::math::tools::promote_args<RealType>::type>; |
| 107 | #endif |
| 108 | |
| 109 | template <class RealType, class Policy> |
| 110 | inline std::pair<RealType, RealType> range(const weibull_distribution<RealType, Policy>& /*dist*/) |
| 111 | { // Range of permissible values for random variable x. |
| 112 | using boost::math::tools::max_value; |
| 113 | return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>()); |
| 114 | } |
| 115 | |
| 116 | template <class RealType, class Policy> |
| 117 | inline std::pair<RealType, RealType> support(const weibull_distribution<RealType, Policy>& /*dist*/) |
| 118 | { // Range of supported values for random variable x. |
| 119 | // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. |
| 120 | using boost::math::tools::max_value; |
| 121 | using boost::math::tools::min_value; |
| 122 | return std::pair<RealType, RealType>(min_value<RealType>(), max_value<RealType>()); |
| 123 | // A discontinuity at x == 0, so only support down to min_value. |
| 124 | } |
| 125 | |
| 126 | template <class RealType, class Policy> |
| 127 | inline RealType pdf(const weibull_distribution<RealType, Policy>& dist, const RealType& x) |
| 128 | { |
| 129 | BOOST_MATH_STD_USING // for ADL of std functions |
| 130 | |
| 131 | static const char* function = "boost::math::pdf(const weibull_distribution<%1%>, %1%)" ; |
| 132 | |
| 133 | RealType shape = dist.shape(); |
| 134 | RealType scale = dist.scale(); |
| 135 | |
| 136 | RealType result = 0; |
| 137 | if(false == detail::check_weibull(function, scale, shape, &result, Policy())) |
| 138 | return result; |
| 139 | if(false == detail::check_weibull_x(function, x, &result, Policy())) |
| 140 | return result; |
| 141 | |
| 142 | if(x == 0) |
| 143 | { |
| 144 | if(shape == 1) |
| 145 | { |
| 146 | return 1 / scale; |
| 147 | } |
| 148 | if(shape > 1) |
| 149 | { |
| 150 | return 0; |
| 151 | } |
| 152 | return policies::raise_overflow_error<RealType>(function, 0, Policy()); |
| 153 | } |
| 154 | result = exp(-pow(x / scale, shape)); |
| 155 | result *= pow(x / scale, shape - 1) * shape / scale; |
| 156 | |
| 157 | return result; |
| 158 | } |
| 159 | |
| 160 | template <class RealType, class Policy> |
| 161 | inline RealType logpdf(const weibull_distribution<RealType, Policy>& dist, const RealType& x) |
| 162 | { |
| 163 | BOOST_MATH_STD_USING // for ADL of std functions |
| 164 | |
| 165 | static const char* function = "boost::math::logpdf(const weibull_distribution<%1%>, %1%)" ; |
| 166 | |
| 167 | RealType shape = dist.shape(); |
| 168 | RealType scale = dist.scale(); |
| 169 | |
| 170 | RealType result = 0; |
| 171 | if(false == detail::check_weibull(function, scale, shape, &result, Policy())) |
| 172 | return result; |
| 173 | if(false == detail::check_weibull_x(function, x, &result, Policy())) |
| 174 | return result; |
| 175 | |
| 176 | if(x == 0) |
| 177 | { |
| 178 | if(shape == 1) |
| 179 | { |
| 180 | return log(1 / scale); |
| 181 | } |
| 182 | if(shape > 1) |
| 183 | { |
| 184 | return 0; |
| 185 | } |
| 186 | return policies::raise_overflow_error<RealType>(function, 0, Policy()); |
| 187 | } |
| 188 | |
| 189 | result = log(shape) - shape * log(scale) + log(x) * (shape - 1) - pow(x / scale, shape); |
| 190 | |
| 191 | return result; |
| 192 | } |
| 193 | |
| 194 | template <class RealType, class Policy> |
| 195 | inline RealType cdf(const weibull_distribution<RealType, Policy>& dist, const RealType& x) |
| 196 | { |
| 197 | BOOST_MATH_STD_USING // for ADL of std functions |
| 198 | |
| 199 | static const char* function = "boost::math::cdf(const weibull_distribution<%1%>, %1%)" ; |
| 200 | |
| 201 | RealType shape = dist.shape(); |
| 202 | RealType scale = dist.scale(); |
| 203 | |
| 204 | RealType result = 0; |
| 205 | if(false == detail::check_weibull(function, scale, shape, &result, Policy())) |
| 206 | return result; |
| 207 | if(false == detail::check_weibull_x(function, x, &result, Policy())) |
| 208 | return result; |
| 209 | |
| 210 | result = -boost::math::expm1(-pow(x / scale, shape), Policy()); |
| 211 | |
| 212 | return result; |
| 213 | } |
| 214 | |
| 215 | template <class RealType, class Policy> |
| 216 | inline RealType logcdf(const weibull_distribution<RealType, Policy>& dist, const RealType& x) |
| 217 | { |
| 218 | BOOST_MATH_STD_USING // for ADL of std functions |
| 219 | |
| 220 | static const char* function = "boost::math::logcdf(const weibull_distribution<%1%>, %1%)" ; |
| 221 | |
| 222 | RealType shape = dist.shape(); |
| 223 | RealType scale = dist.scale(); |
| 224 | |
| 225 | RealType result = 0; |
| 226 | if(false == detail::check_weibull(function, scale, shape, &result, Policy())) |
| 227 | return result; |
| 228 | if(false == detail::check_weibull_x(function, x, &result, Policy())) |
| 229 | return result; |
| 230 | |
| 231 | result = log1p(-exp(-pow(x / scale, shape)), Policy()); |
| 232 | |
| 233 | return result; |
| 234 | } |
| 235 | |
| 236 | template <class RealType, class Policy> |
| 237 | inline RealType quantile(const weibull_distribution<RealType, Policy>& dist, const RealType& p) |
| 238 | { |
| 239 | BOOST_MATH_STD_USING // for ADL of std functions |
| 240 | |
| 241 | static const char* function = "boost::math::quantile(const weibull_distribution<%1%>, %1%)" ; |
| 242 | |
| 243 | RealType shape = dist.shape(); |
| 244 | RealType scale = dist.scale(); |
| 245 | |
| 246 | RealType result = 0; |
| 247 | if(false == detail::check_weibull(function, scale, shape, &result, Policy())) |
| 248 | return result; |
| 249 | if(false == detail::check_probability(function, p, &result, Policy())) |
| 250 | return result; |
| 251 | |
| 252 | if(p == 1) |
| 253 | return policies::raise_overflow_error<RealType>(function, 0, Policy()); |
| 254 | |
| 255 | result = scale * pow(-boost::math::log1p(-p, Policy()), 1 / shape); |
| 256 | |
| 257 | return result; |
| 258 | } |
| 259 | |
| 260 | template <class RealType, class Policy> |
| 261 | inline RealType cdf(const complemented2_type<weibull_distribution<RealType, Policy>, RealType>& c) |
| 262 | { |
| 263 | BOOST_MATH_STD_USING // for ADL of std functions |
| 264 | |
| 265 | static const char* function = "boost::math::cdf(const weibull_distribution<%1%>, %1%)" ; |
| 266 | |
| 267 | RealType shape = c.dist.shape(); |
| 268 | RealType scale = c.dist.scale(); |
| 269 | |
| 270 | RealType result = 0; |
| 271 | if(false == detail::check_weibull(function, scale, shape, &result, Policy())) |
| 272 | return result; |
| 273 | if(false == detail::check_weibull_x(function, c.param, &result, Policy())) |
| 274 | return result; |
| 275 | |
| 276 | result = exp(-pow(c.param / scale, shape)); |
| 277 | |
| 278 | return result; |
| 279 | } |
| 280 | |
| 281 | template <class RealType, class Policy> |
| 282 | inline RealType logcdf(const complemented2_type<weibull_distribution<RealType, Policy>, RealType>& c) |
| 283 | { |
| 284 | BOOST_MATH_STD_USING // for ADL of std functions |
| 285 | |
| 286 | static const char* function = "boost::math::logcdf(const weibull_distribution<%1%>, %1%)" ; |
| 287 | |
| 288 | RealType shape = c.dist.shape(); |
| 289 | RealType scale = c.dist.scale(); |
| 290 | |
| 291 | RealType result = 0; |
| 292 | if(false == detail::check_weibull(function, scale, shape, &result, Policy())) |
| 293 | return result; |
| 294 | if(false == detail::check_weibull_x(function, c.param, &result, Policy())) |
| 295 | return result; |
| 296 | |
| 297 | result = -pow(c.param / scale, shape); |
| 298 | |
| 299 | return result; |
| 300 | } |
| 301 | |
| 302 | template <class RealType, class Policy> |
| 303 | inline RealType quantile(const complemented2_type<weibull_distribution<RealType, Policy>, RealType>& c) |
| 304 | { |
| 305 | BOOST_MATH_STD_USING // for ADL of std functions |
| 306 | |
| 307 | static const char* function = "boost::math::quantile(const weibull_distribution<%1%>, %1%)" ; |
| 308 | |
| 309 | RealType shape = c.dist.shape(); |
| 310 | RealType scale = c.dist.scale(); |
| 311 | RealType q = c.param; |
| 312 | |
| 313 | RealType result = 0; |
| 314 | if(false == detail::check_weibull(function, scale, shape, &result, Policy())) |
| 315 | return result; |
| 316 | if(false == detail::check_probability(function, q, &result, Policy())) |
| 317 | return result; |
| 318 | |
| 319 | if(q == 0) |
| 320 | return policies::raise_overflow_error<RealType>(function, 0, Policy()); |
| 321 | |
| 322 | result = scale * pow(-log(q), 1 / shape); |
| 323 | |
| 324 | return result; |
| 325 | } |
| 326 | |
| 327 | template <class RealType, class Policy> |
| 328 | inline RealType mean(const weibull_distribution<RealType, Policy>& dist) |
| 329 | { |
| 330 | BOOST_MATH_STD_USING // for ADL of std functions |
| 331 | |
| 332 | static const char* function = "boost::math::mean(const weibull_distribution<%1%>)" ; |
| 333 | |
| 334 | RealType shape = dist.shape(); |
| 335 | RealType scale = dist.scale(); |
| 336 | |
| 337 | RealType result = 0; |
| 338 | if(false == detail::check_weibull(function, scale, shape, &result, Policy())) |
| 339 | return result; |
| 340 | |
| 341 | result = scale * boost::math::tgamma(1 + 1 / shape, Policy()); |
| 342 | return result; |
| 343 | } |
| 344 | |
| 345 | template <class RealType, class Policy> |
| 346 | inline RealType variance(const weibull_distribution<RealType, Policy>& dist) |
| 347 | { |
| 348 | RealType shape = dist.shape(); |
| 349 | RealType scale = dist.scale(); |
| 350 | |
| 351 | static const char* function = "boost::math::variance(const weibull_distribution<%1%>)" ; |
| 352 | |
| 353 | RealType result = 0; |
| 354 | if(false == detail::check_weibull(function, scale, shape, &result, Policy())) |
| 355 | { |
| 356 | return result; |
| 357 | } |
| 358 | result = boost::math::tgamma(1 + 1 / shape, Policy()); |
| 359 | result *= -result; |
| 360 | result += boost::math::tgamma(1 + 2 / shape, Policy()); |
| 361 | result *= scale * scale; |
| 362 | return result; |
| 363 | } |
| 364 | |
| 365 | template <class RealType, class Policy> |
| 366 | inline RealType mode(const weibull_distribution<RealType, Policy>& dist) |
| 367 | { |
| 368 | BOOST_MATH_STD_USING // for ADL of std function pow. |
| 369 | |
| 370 | static const char* function = "boost::math::mode(const weibull_distribution<%1%>)" ; |
| 371 | |
| 372 | RealType shape = dist.shape(); |
| 373 | RealType scale = dist.scale(); |
| 374 | |
| 375 | RealType result = 0; |
| 376 | if(false == detail::check_weibull(function, scale, shape, &result, Policy())) |
| 377 | { |
| 378 | return result; |
| 379 | } |
| 380 | if(shape <= 1) |
| 381 | return 0; |
| 382 | result = scale * pow((shape - 1) / shape, 1 / shape); |
| 383 | return result; |
| 384 | } |
| 385 | |
| 386 | template <class RealType, class Policy> |
| 387 | inline RealType median(const weibull_distribution<RealType, Policy>& dist) |
| 388 | { |
| 389 | BOOST_MATH_STD_USING // for ADL of std function pow. |
| 390 | |
| 391 | static const char* function = "boost::math::median(const weibull_distribution<%1%>)" ; |
| 392 | |
| 393 | RealType shape = dist.shape(); // Wikipedia k |
| 394 | RealType scale = dist.scale(); // Wikipedia lambda |
| 395 | |
| 396 | RealType result = 0; |
| 397 | if(false == detail::check_weibull(function, scale, shape, &result, Policy())) |
| 398 | { |
| 399 | return result; |
| 400 | } |
| 401 | using boost::math::constants::ln_two; |
| 402 | result = scale * pow(ln_two<RealType>(), 1 / shape); |
| 403 | return result; |
| 404 | } |
| 405 | |
| 406 | template <class RealType, class Policy> |
| 407 | inline RealType skewness(const weibull_distribution<RealType, Policy>& dist) |
| 408 | { |
| 409 | BOOST_MATH_STD_USING // for ADL of std functions |
| 410 | |
| 411 | static const char* function = "boost::math::skewness(const weibull_distribution<%1%>)" ; |
| 412 | |
| 413 | RealType shape = dist.shape(); |
| 414 | RealType scale = dist.scale(); |
| 415 | |
| 416 | RealType result = 0; |
| 417 | if(false == detail::check_weibull(function, scale, shape, &result, Policy())) |
| 418 | { |
| 419 | return result; |
| 420 | } |
| 421 | |
| 422 | RealType g1 = boost::math::tgamma(1 + 1 / shape, Policy()); |
| 423 | RealType g2 = boost::math::tgamma(1 + 2 / shape, Policy()); |
| 424 | RealType g3 = boost::math::tgamma(1 + 3 / shape, Policy()); |
| 425 | RealType d = pow(g2 - g1 * g1, RealType(1.5)); |
| 426 | |
| 427 | result = (2 * g1 * g1 * g1 - 3 * g1 * g2 + g3) / d; |
| 428 | return result; |
| 429 | } |
| 430 | |
| 431 | template <class RealType, class Policy> |
| 432 | inline RealType kurtosis_excess(const weibull_distribution<RealType, Policy>& dist) |
| 433 | { |
| 434 | BOOST_MATH_STD_USING // for ADL of std functions |
| 435 | |
| 436 | static const char* function = "boost::math::kurtosis_excess(const weibull_distribution<%1%>)" ; |
| 437 | |
| 438 | RealType shape = dist.shape(); |
| 439 | RealType scale = dist.scale(); |
| 440 | |
| 441 | RealType result = 0; |
| 442 | if(false == detail::check_weibull(function, scale, shape, &result, Policy())) |
| 443 | return result; |
| 444 | |
| 445 | RealType g1 = boost::math::tgamma(1 + 1 / shape, Policy()); |
| 446 | RealType g2 = boost::math::tgamma(1 + 2 / shape, Policy()); |
| 447 | RealType g3 = boost::math::tgamma(1 + 3 / shape, Policy()); |
| 448 | RealType g4 = boost::math::tgamma(1 + 4 / shape, Policy()); |
| 449 | RealType g1_2 = g1 * g1; |
| 450 | RealType g1_4 = g1_2 * g1_2; |
| 451 | RealType d = g2 - g1_2; |
| 452 | d *= d; |
| 453 | |
| 454 | result = -6 * g1_4 + 12 * g1_2 * g2 - 3 * g2 * g2 - 4 * g1 * g3 + g4; |
| 455 | result /= d; |
| 456 | return result; |
| 457 | } |
| 458 | |
| 459 | template <class RealType, class Policy> |
| 460 | inline RealType kurtosis(const weibull_distribution<RealType, Policy>& dist) |
| 461 | { |
| 462 | return kurtosis_excess(dist) + 3; |
| 463 | } |
| 464 | |
| 465 | template <class RealType, class Policy> |
| 466 | inline RealType entropy(const weibull_distribution<RealType, Policy>& dist) |
| 467 | { |
| 468 | using std::log; |
| 469 | RealType k = dist.shape(); |
| 470 | RealType lambda = dist.scale(); |
| 471 | return constants::euler<RealType>()*(1-1/k) + log(lambda/k) + 1; |
| 472 | } |
| 473 | |
| 474 | } // namespace math |
| 475 | } // namespace boost |
| 476 | |
| 477 | // This include must be at the end, *after* the accessors |
| 478 | // for this distribution have been defined, in order to |
| 479 | // keep compilers that support two-phase lookup happy. |
| 480 | #include <boost/math/distributions/detail/derived_accessors.hpp> |
| 481 | |
| 482 | #endif // BOOST_STATS_WEIBULL_HPP |
| 483 | |
| 484 | |
| 485 | |