annotate DEPENDENCIES/generic/include/boost/math/distributions/skew_normal.hpp @ 125:34e428693f5d vext

Vext -> Repoint
author Chris Cannam
date Thu, 14 Jun 2018 11:15:39 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 // Copyright Benjamin Sobotta 2012
Chris@16 2
Chris@16 3 // Use, modification and distribution are subject to the
Chris@16 4 // Boost Software License, Version 1.0. (See accompanying file
Chris@16 5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Chris@16 6
Chris@16 7 #ifndef BOOST_STATS_SKEW_NORMAL_HPP
Chris@16 8 #define BOOST_STATS_SKEW_NORMAL_HPP
Chris@16 9
Chris@16 10 // http://en.wikipedia.org/wiki/Skew_normal_distribution
Chris@16 11 // http://azzalini.stat.unipd.it/SN/
Chris@16 12 // Also:
Chris@16 13 // Azzalini, A. (1985). "A class of distributions which includes the normal ones".
Chris@16 14 // Scand. J. Statist. 12: 171-178.
Chris@16 15
Chris@16 16 #include <boost/math/distributions/fwd.hpp> // TODO add skew_normal distribution to fwd.hpp!
Chris@16 17 #include <boost/math/special_functions/owens_t.hpp> // Owen's T function
Chris@16 18 #include <boost/math/distributions/complement.hpp>
Chris@16 19 #include <boost/math/distributions/normal.hpp>
Chris@16 20 #include <boost/math/distributions/detail/common_error_handling.hpp>
Chris@16 21 #include <boost/math/constants/constants.hpp>
Chris@16 22 #include <boost/math/tools/tuple.hpp>
Chris@16 23 #include <boost/math/tools/roots.hpp> // Newton-Raphson
Chris@16 24 #include <boost/assert.hpp>
Chris@16 25 #include <boost/math/distributions/detail/generic_mode.hpp> // pdf max finder.
Chris@16 26
Chris@16 27 #include <utility>
Chris@16 28 #include <algorithm> // std::lower_bound, std::distance
Chris@16 29
Chris@16 30 namespace boost{ namespace math{
Chris@16 31
Chris@16 32 namespace detail
Chris@16 33 {
Chris@16 34 template <class RealType, class Policy>
Chris@16 35 inline bool check_skew_normal_shape(
Chris@16 36 const char* function,
Chris@16 37 RealType shape,
Chris@16 38 RealType* result,
Chris@16 39 const Policy& pol)
Chris@16 40 {
Chris@16 41 if(!(boost::math::isfinite)(shape))
Chris@16 42 {
Chris@16 43 *result =
Chris@16 44 policies::raise_domain_error<RealType>(function,
Chris@16 45 "Shape parameter is %1%, but must be finite!",
Chris@16 46 shape, pol);
Chris@16 47 return false;
Chris@16 48 }
Chris@16 49 return true;
Chris@16 50 }
Chris@16 51
Chris@16 52 } // namespace detail
Chris@16 53
Chris@16 54 template <class RealType = double, class Policy = policies::policy<> >
Chris@16 55 class skew_normal_distribution
Chris@16 56 {
Chris@16 57 public:
Chris@16 58 typedef RealType value_type;
Chris@16 59 typedef Policy policy_type;
Chris@16 60
Chris@16 61 skew_normal_distribution(RealType l_location = 0, RealType l_scale = 1, RealType l_shape = 0)
Chris@16 62 : location_(l_location), scale_(l_scale), shape_(l_shape)
Chris@16 63 { // Default is a 'standard' normal distribution N01. (shape=0 results in the normal distribution with no skew)
Chris@16 64 static const char* function = "boost::math::skew_normal_distribution<%1%>::skew_normal_distribution";
Chris@16 65
Chris@16 66 RealType result;
Chris@16 67 detail::check_scale(function, l_scale, &result, Policy());
Chris@16 68 detail::check_location(function, l_location, &result, Policy());
Chris@16 69 detail::check_skew_normal_shape(function, l_shape, &result, Policy());
Chris@16 70 }
Chris@16 71
Chris@16 72 RealType location()const
Chris@16 73 {
Chris@16 74 return location_;
Chris@16 75 }
Chris@16 76
Chris@16 77 RealType scale()const
Chris@16 78 {
Chris@16 79 return scale_;
Chris@16 80 }
Chris@16 81
Chris@16 82 RealType shape()const
Chris@16 83 {
Chris@16 84 return shape_;
Chris@16 85 }
Chris@16 86
Chris@16 87
Chris@16 88 private:
Chris@16 89 //
Chris@16 90 // Data members:
Chris@16 91 //
Chris@16 92 RealType location_; // distribution location.
Chris@16 93 RealType scale_; // distribution scale.
Chris@16 94 RealType shape_; // distribution shape.
Chris@16 95 }; // class skew_normal_distribution
Chris@16 96
Chris@16 97 typedef skew_normal_distribution<double> skew_normal;
Chris@16 98
Chris@16 99 template <class RealType, class Policy>
Chris@16 100 inline const std::pair<RealType, RealType> range(const skew_normal_distribution<RealType, Policy>& /*dist*/)
Chris@16 101 { // Range of permissible values for random variable x.
Chris@16 102 using boost::math::tools::max_value;
Chris@16 103 return std::pair<RealType, RealType>(
Chris@16 104 std::numeric_limits<RealType>::has_infinity ? -std::numeric_limits<RealType>::infinity() : -max_value<RealType>(),
Chris@16 105 std::numeric_limits<RealType>::has_infinity ? std::numeric_limits<RealType>::infinity() : max_value<RealType>()); // - to + max value.
Chris@16 106 }
Chris@16 107
Chris@16 108 template <class RealType, class Policy>
Chris@16 109 inline const std::pair<RealType, RealType> support(const skew_normal_distribution<RealType, Policy>& /*dist*/)
Chris@16 110 { // Range of supported values for random variable x.
Chris@16 111 // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
Chris@16 112
Chris@16 113 using boost::math::tools::max_value;
Chris@16 114 return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>()); // - to + max value.
Chris@16 115 }
Chris@16 116
Chris@16 117 template <class RealType, class Policy>
Chris@16 118 inline RealType pdf(const skew_normal_distribution<RealType, Policy>& dist, const RealType& x)
Chris@16 119 {
Chris@16 120 const RealType scale = dist.scale();
Chris@16 121 const RealType location = dist.location();
Chris@16 122 const RealType shape = dist.shape();
Chris@16 123
Chris@16 124 static const char* function = "boost::math::pdf(const skew_normal_distribution<%1%>&, %1%)";
Chris@16 125 if((boost::math::isinf)(x))
Chris@16 126 {
Chris@16 127 return 0; // pdf + and - infinity is zero.
Chris@16 128 }
Chris@16 129 // Below produces MSVC 4127 warnings, so the above used instead.
Chris@16 130 //if(std::numeric_limits<RealType>::has_infinity && abs(x) == std::numeric_limits<RealType>::infinity())
Chris@16 131 //{ // pdf + and - infinity is zero.
Chris@16 132 // return 0;
Chris@16 133 //}
Chris@16 134
Chris@16 135 RealType result = 0;
Chris@16 136 if(false == detail::check_scale(function, scale, &result, Policy()))
Chris@16 137 {
Chris@16 138 return result;
Chris@16 139 }
Chris@16 140 if(false == detail::check_location(function, location, &result, Policy()))
Chris@16 141 {
Chris@16 142 return result;
Chris@16 143 }
Chris@16 144 if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
Chris@16 145 {
Chris@16 146 return result;
Chris@16 147 }
Chris@16 148 if(false == detail::check_x(function, x, &result, Policy()))
Chris@16 149 {
Chris@16 150 return result;
Chris@16 151 }
Chris@16 152
Chris@16 153 const RealType transformed_x = (x-location)/scale;
Chris@16 154
Chris@16 155 normal_distribution<RealType, Policy> std_normal;
Chris@16 156
Chris@16 157 result = pdf(std_normal, transformed_x) * cdf(std_normal, shape*transformed_x) * 2 / scale;
Chris@16 158
Chris@16 159 return result;
Chris@16 160 } // pdf
Chris@16 161
Chris@16 162 template <class RealType, class Policy>
Chris@16 163 inline RealType cdf(const skew_normal_distribution<RealType, Policy>& dist, const RealType& x)
Chris@16 164 {
Chris@16 165 const RealType scale = dist.scale();
Chris@16 166 const RealType location = dist.location();
Chris@16 167 const RealType shape = dist.shape();
Chris@16 168
Chris@16 169 static const char* function = "boost::math::cdf(const skew_normal_distribution<%1%>&, %1%)";
Chris@16 170 RealType result = 0;
Chris@16 171 if(false == detail::check_scale(function, scale, &result, Policy()))
Chris@16 172 {
Chris@16 173 return result;
Chris@16 174 }
Chris@16 175 if(false == detail::check_location(function, location, &result, Policy()))
Chris@16 176 {
Chris@16 177 return result;
Chris@16 178 }
Chris@16 179 if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
Chris@16 180 {
Chris@16 181 return result;
Chris@16 182 }
Chris@16 183 if((boost::math::isinf)(x))
Chris@16 184 {
Chris@16 185 if(x < 0) return 0; // -infinity
Chris@16 186 return 1; // + infinity
Chris@16 187 }
Chris@16 188 // These produce MSVC 4127 warnings, so the above used instead.
Chris@16 189 //if(std::numeric_limits<RealType>::has_infinity && x == std::numeric_limits<RealType>::infinity())
Chris@16 190 //{ // cdf +infinity is unity.
Chris@16 191 // return 1;
Chris@16 192 //}
Chris@16 193 //if(std::numeric_limits<RealType>::has_infinity && x == -std::numeric_limits<RealType>::infinity())
Chris@16 194 //{ // cdf -infinity is zero.
Chris@16 195 // return 0;
Chris@16 196 //}
Chris@16 197 if(false == detail::check_x(function, x, &result, Policy()))
Chris@16 198 {
Chris@16 199 return result;
Chris@16 200 }
Chris@16 201
Chris@16 202 const RealType transformed_x = (x-location)/scale;
Chris@16 203
Chris@16 204 normal_distribution<RealType, Policy> std_normal;
Chris@16 205
Chris@16 206 result = cdf(std_normal, transformed_x) - owens_t(transformed_x, shape)*static_cast<RealType>(2);
Chris@16 207
Chris@16 208 return result;
Chris@16 209 } // cdf
Chris@16 210
Chris@16 211 template <class RealType, class Policy>
Chris@16 212 inline RealType cdf(const complemented2_type<skew_normal_distribution<RealType, Policy>, RealType>& c)
Chris@16 213 {
Chris@16 214 const RealType scale = c.dist.scale();
Chris@16 215 const RealType location = c.dist.location();
Chris@16 216 const RealType shape = c.dist.shape();
Chris@16 217 const RealType x = c.param;
Chris@16 218
Chris@16 219 static const char* function = "boost::math::cdf(const complement(skew_normal_distribution<%1%>&), %1%)";
Chris@16 220
Chris@16 221 if((boost::math::isinf)(x))
Chris@16 222 {
Chris@16 223 if(x < 0) return 1; // cdf complement -infinity is unity.
Chris@16 224 return 0; // cdf complement +infinity is zero
Chris@16 225 }
Chris@16 226 // These produce MSVC 4127 warnings, so the above used instead.
Chris@16 227 //if(std::numeric_limits<RealType>::has_infinity && x == std::numeric_limits<RealType>::infinity())
Chris@16 228 //{ // cdf complement +infinity is zero.
Chris@16 229 // return 0;
Chris@16 230 //}
Chris@16 231 //if(std::numeric_limits<RealType>::has_infinity && x == -std::numeric_limits<RealType>::infinity())
Chris@16 232 //{ // cdf complement -infinity is unity.
Chris@16 233 // return 1;
Chris@16 234 //}
Chris@16 235 RealType result = 0;
Chris@16 236 if(false == detail::check_scale(function, scale, &result, Policy()))
Chris@16 237 return result;
Chris@16 238 if(false == detail::check_location(function, location, &result, Policy()))
Chris@16 239 return result;
Chris@16 240 if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
Chris@16 241 return result;
Chris@16 242 if(false == detail::check_x(function, x, &result, Policy()))
Chris@16 243 return result;
Chris@16 244
Chris@16 245 const RealType transformed_x = (x-location)/scale;
Chris@16 246
Chris@16 247 normal_distribution<RealType, Policy> std_normal;
Chris@16 248
Chris@16 249 result = cdf(complement(std_normal, transformed_x)) + owens_t(transformed_x, shape)*static_cast<RealType>(2);
Chris@16 250 return result;
Chris@16 251 } // cdf complement
Chris@16 252
Chris@16 253 template <class RealType, class Policy>
Chris@16 254 inline RealType location(const skew_normal_distribution<RealType, Policy>& dist)
Chris@16 255 {
Chris@16 256 return dist.location();
Chris@16 257 }
Chris@16 258
Chris@16 259 template <class RealType, class Policy>
Chris@16 260 inline RealType scale(const skew_normal_distribution<RealType, Policy>& dist)
Chris@16 261 {
Chris@16 262 return dist.scale();
Chris@16 263 }
Chris@16 264
Chris@16 265 template <class RealType, class Policy>
Chris@16 266 inline RealType shape(const skew_normal_distribution<RealType, Policy>& dist)
Chris@16 267 {
Chris@16 268 return dist.shape();
Chris@16 269 }
Chris@16 270
Chris@16 271 template <class RealType, class Policy>
Chris@16 272 inline RealType mean(const skew_normal_distribution<RealType, Policy>& dist)
Chris@16 273 {
Chris@16 274 BOOST_MATH_STD_USING // for ADL of std functions
Chris@16 275
Chris@16 276 using namespace boost::math::constants;
Chris@16 277
Chris@16 278 //const RealType delta = dist.shape() / sqrt(static_cast<RealType>(1)+dist.shape()*dist.shape());
Chris@16 279
Chris@16 280 //return dist.location() + dist.scale() * delta * root_two_div_pi<RealType>();
Chris@16 281
Chris@16 282 return dist.location() + dist.scale() * dist.shape() / sqrt(pi<RealType>()+pi<RealType>()*dist.shape()*dist.shape()) * root_two<RealType>();
Chris@16 283 }
Chris@16 284
Chris@16 285 template <class RealType, class Policy>
Chris@16 286 inline RealType variance(const skew_normal_distribution<RealType, Policy>& dist)
Chris@16 287 {
Chris@16 288 using namespace boost::math::constants;
Chris@16 289
Chris@16 290 const RealType delta2 = static_cast<RealType>(1) / (static_cast<RealType>(1)+static_cast<RealType>(1)/(dist.shape()*dist.shape()));
Chris@16 291 //const RealType inv_delta2 = static_cast<RealType>(1)+static_cast<RealType>(1)/(dist.shape()*dist.shape());
Chris@16 292
Chris@16 293 RealType variance = dist.scale()*dist.scale()*(static_cast<RealType>(1)-two_div_pi<RealType>()*delta2);
Chris@16 294 //RealType variance = dist.scale()*dist.scale()*(static_cast<RealType>(1)-two_div_pi<RealType>()/inv_delta2);
Chris@16 295
Chris@16 296 return variance;
Chris@16 297 }
Chris@16 298
Chris@16 299 namespace detail
Chris@16 300 {
Chris@16 301 /*
Chris@16 302 TODO No closed expression for mode, so use max of pdf.
Chris@16 303 */
Chris@16 304
Chris@16 305 template <class RealType, class Policy>
Chris@16 306 inline RealType mode_fallback(const skew_normal_distribution<RealType, Policy>& dist)
Chris@16 307 { // mode.
Chris@16 308 static const char* function = "mode(skew_normal_distribution<%1%> const&)";
Chris@16 309 const RealType scale = dist.scale();
Chris@16 310 const RealType location = dist.location();
Chris@16 311 const RealType shape = dist.shape();
Chris@16 312
Chris@16 313 RealType result;
Chris@16 314 if(!detail::check_scale(
Chris@16 315 function,
Chris@16 316 scale, &result, Policy())
Chris@16 317 ||
Chris@16 318 !detail::check_skew_normal_shape(
Chris@16 319 function,
Chris@16 320 shape,
Chris@16 321 &result,
Chris@16 322 Policy()))
Chris@16 323 return result;
Chris@16 324
Chris@16 325 if( shape == 0 )
Chris@16 326 {
Chris@16 327 return location;
Chris@16 328 }
Chris@16 329
Chris@16 330 if( shape < 0 )
Chris@16 331 {
Chris@16 332 skew_normal_distribution<RealType, Policy> D(0, 1, -shape);
Chris@16 333 result = mode_fallback(D);
Chris@16 334 result = location-scale*result;
Chris@16 335 return result;
Chris@16 336 }
Chris@16 337
Chris@16 338 BOOST_MATH_STD_USING
Chris@16 339
Chris@16 340 // 21 elements
Chris@16 341 static const RealType shapes[] = {
Chris@16 342 0.0,
Chris@16 343 1.000000000000000e-004,
Chris@16 344 2.069138081114790e-004,
Chris@16 345 4.281332398719396e-004,
Chris@16 346 8.858667904100824e-004,
Chris@16 347 1.832980710832436e-003,
Chris@16 348 3.792690190732250e-003,
Chris@16 349 7.847599703514606e-003,
Chris@16 350 1.623776739188722e-002,
Chris@16 351 3.359818286283781e-002,
Chris@16 352 6.951927961775606e-002,
Chris@16 353 1.438449888287663e-001,
Chris@16 354 2.976351441631319e-001,
Chris@16 355 6.158482110660261e-001,
Chris@16 356 1.274274985703135e+000,
Chris@16 357 2.636650898730361e+000,
Chris@16 358 5.455594781168514e+000,
Chris@16 359 1.128837891684688e+001,
Chris@16 360 2.335721469090121e+001,
Chris@16 361 4.832930238571753e+001,
Chris@16 362 1.000000000000000e+002};
Chris@16 363
Chris@16 364 // 21 elements
Chris@16 365 static const RealType guess[] = {
Chris@16 366 0.0,
Chris@16 367 5.000050000525391e-005,
Chris@16 368 1.500015000148736e-004,
Chris@16 369 3.500035000350010e-004,
Chris@16 370 7.500075000752560e-004,
Chris@16 371 1.450014500145258e-003,
Chris@16 372 3.050030500305390e-003,
Chris@16 373 6.250062500624765e-003,
Chris@16 374 1.295012950129504e-002,
Chris@16 375 2.675026750267495e-002,
Chris@16 376 5.525055250552491e-002,
Chris@16 377 1.132511325113255e-001,
Chris@16 378 2.249522495224952e-001,
Chris@16 379 3.992539925399257e-001,
Chris@16 380 5.353553535535358e-001,
Chris@16 381 4.954549545495457e-001,
Chris@16 382 3.524535245352451e-001,
Chris@16 383 2.182521825218249e-001,
Chris@16 384 1.256512565125654e-001,
Chris@16 385 6.945069450694508e-002,
Chris@16 386 3.735037350373460e-002
Chris@16 387 };
Chris@16 388
Chris@16 389 const RealType* result_ptr = std::lower_bound(shapes, shapes+21, shape);
Chris@16 390
Chris@16 391 typedef typename std::iterator_traits<RealType*>::difference_type diff_type;
Chris@16 392
Chris@16 393 const diff_type d = std::distance(shapes, result_ptr);
Chris@16 394
Chris@16 395 BOOST_ASSERT(d > static_cast<diff_type>(0));
Chris@16 396
Chris@16 397 // refine
Chris@16 398 if(d < static_cast<diff_type>(21)) // shape smaller 100
Chris@16 399 {
Chris@16 400 result = guess[d-static_cast<diff_type>(1)]
Chris@16 401 + (guess[d]-guess[d-static_cast<diff_type>(1)])/(shapes[d]-shapes[d-static_cast<diff_type>(1)])
Chris@16 402 * (shape-shapes[d-static_cast<diff_type>(1)]);
Chris@16 403 }
Chris@16 404 else // shape greater 100
Chris@16 405 {
Chris@16 406 result = 1e-4;
Chris@16 407 }
Chris@16 408
Chris@16 409 skew_normal_distribution<RealType, Policy> helper(0, 1, shape);
Chris@16 410
Chris@16 411 result = detail::generic_find_mode_01(helper, result, function);
Chris@16 412
Chris@16 413 result = result*scale + location;
Chris@16 414
Chris@16 415 return result;
Chris@16 416 } // mode_fallback
Chris@16 417
Chris@16 418
Chris@16 419 /*
Chris@16 420 * TODO No closed expression for mode, so use f'(x) = 0
Chris@16 421 */
Chris@16 422 template <class RealType, class Policy>
Chris@16 423 struct skew_normal_mode_functor
Chris@16 424 {
Chris@16 425 skew_normal_mode_functor(const boost::math::skew_normal_distribution<RealType, Policy> dist)
Chris@16 426 : distribution(dist)
Chris@16 427 {
Chris@16 428 }
Chris@16 429
Chris@16 430 boost::math::tuple<RealType, RealType> operator()(RealType const& x)
Chris@16 431 {
Chris@16 432 normal_distribution<RealType, Policy> std_normal;
Chris@16 433 const RealType shape = distribution.shape();
Chris@16 434 const RealType pdf_x = pdf(distribution, x);
Chris@16 435 const RealType normpdf_x = pdf(std_normal, x);
Chris@16 436 const RealType normpdf_ax = pdf(std_normal, x*shape);
Chris@16 437 RealType fx = static_cast<RealType>(2)*shape*normpdf_ax*normpdf_x - x*pdf_x;
Chris@16 438 RealType dx = static_cast<RealType>(2)*shape*x*normpdf_x*normpdf_ax*(static_cast<RealType>(1) + shape*shape) + pdf_x + x*fx;
Chris@16 439 // return both function evaluation difference f(x) and 1st derivative f'(x).
Chris@16 440 return boost::math::make_tuple(fx, -dx);
Chris@16 441 }
Chris@16 442 private:
Chris@16 443 const boost::math::skew_normal_distribution<RealType, Policy> distribution;
Chris@16 444 };
Chris@16 445
Chris@16 446 } // namespace detail
Chris@16 447
Chris@16 448 template <class RealType, class Policy>
Chris@16 449 inline RealType mode(const skew_normal_distribution<RealType, Policy>& dist)
Chris@16 450 {
Chris@16 451 const RealType scale = dist.scale();
Chris@16 452 const RealType location = dist.location();
Chris@16 453 const RealType shape = dist.shape();
Chris@16 454
Chris@16 455 static const char* function = "boost::math::mode(const skew_normal_distribution<%1%>&, %1%)";
Chris@16 456
Chris@16 457 RealType result = 0;
Chris@16 458 if(false == detail::check_scale(function, scale, &result, Policy()))
Chris@16 459 return result;
Chris@16 460 if(false == detail::check_location(function, location, &result, Policy()))
Chris@16 461 return result;
Chris@16 462 if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
Chris@16 463 return result;
Chris@16 464
Chris@16 465 if( shape == 0 )
Chris@16 466 {
Chris@16 467 return location;
Chris@16 468 }
Chris@16 469
Chris@16 470 if( shape < 0 )
Chris@16 471 {
Chris@16 472 skew_normal_distribution<RealType, Policy> D(0, 1, -shape);
Chris@16 473 result = mode(D);
Chris@16 474 result = location-scale*result;
Chris@16 475 return result;
Chris@16 476 }
Chris@16 477
Chris@16 478 // 21 elements
Chris@16 479 static const RealType shapes[] = {
Chris@16 480 0.0,
Chris@16 481 static_cast<RealType>(1.000000000000000e-004),
Chris@16 482 static_cast<RealType>(2.069138081114790e-004),
Chris@16 483 static_cast<RealType>(4.281332398719396e-004),
Chris@16 484 static_cast<RealType>(8.858667904100824e-004),
Chris@16 485 static_cast<RealType>(1.832980710832436e-003),
Chris@16 486 static_cast<RealType>(3.792690190732250e-003),
Chris@16 487 static_cast<RealType>(7.847599703514606e-003),
Chris@16 488 static_cast<RealType>(1.623776739188722e-002),
Chris@16 489 static_cast<RealType>(3.359818286283781e-002),
Chris@16 490 static_cast<RealType>(6.951927961775606e-002),
Chris@16 491 static_cast<RealType>(1.438449888287663e-001),
Chris@16 492 static_cast<RealType>(2.976351441631319e-001),
Chris@16 493 static_cast<RealType>(6.158482110660261e-001),
Chris@16 494 static_cast<RealType>(1.274274985703135e+000),
Chris@16 495 static_cast<RealType>(2.636650898730361e+000),
Chris@16 496 static_cast<RealType>(5.455594781168514e+000),
Chris@16 497 static_cast<RealType>(1.128837891684688e+001),
Chris@16 498 static_cast<RealType>(2.335721469090121e+001),
Chris@16 499 static_cast<RealType>(4.832930238571753e+001),
Chris@16 500 static_cast<RealType>(1.000000000000000e+002)
Chris@16 501 };
Chris@16 502
Chris@16 503 // 21 elements
Chris@16 504 static const RealType guess[] = {
Chris@16 505 0.0,
Chris@16 506 static_cast<RealType>(5.000050000525391e-005),
Chris@16 507 static_cast<RealType>(1.500015000148736e-004),
Chris@16 508 static_cast<RealType>(3.500035000350010e-004),
Chris@16 509 static_cast<RealType>(7.500075000752560e-004),
Chris@16 510 static_cast<RealType>(1.450014500145258e-003),
Chris@16 511 static_cast<RealType>(3.050030500305390e-003),
Chris@16 512 static_cast<RealType>(6.250062500624765e-003),
Chris@16 513 static_cast<RealType>(1.295012950129504e-002),
Chris@16 514 static_cast<RealType>(2.675026750267495e-002),
Chris@16 515 static_cast<RealType>(5.525055250552491e-002),
Chris@16 516 static_cast<RealType>(1.132511325113255e-001),
Chris@16 517 static_cast<RealType>(2.249522495224952e-001),
Chris@16 518 static_cast<RealType>(3.992539925399257e-001),
Chris@16 519 static_cast<RealType>(5.353553535535358e-001),
Chris@16 520 static_cast<RealType>(4.954549545495457e-001),
Chris@16 521 static_cast<RealType>(3.524535245352451e-001),
Chris@16 522 static_cast<RealType>(2.182521825218249e-001),
Chris@16 523 static_cast<RealType>(1.256512565125654e-001),
Chris@16 524 static_cast<RealType>(6.945069450694508e-002),
Chris@16 525 static_cast<RealType>(3.735037350373460e-002)
Chris@16 526 };
Chris@16 527
Chris@16 528 const RealType* result_ptr = std::lower_bound(shapes, shapes+21, shape);
Chris@16 529
Chris@16 530 typedef typename std::iterator_traits<RealType*>::difference_type diff_type;
Chris@16 531
Chris@16 532 const diff_type d = std::distance(shapes, result_ptr);
Chris@16 533
Chris@16 534 BOOST_ASSERT(d > static_cast<diff_type>(0));
Chris@16 535
Chris@16 536 // TODO: make the search bounds smarter, depending on the shape parameter
Chris@16 537 RealType search_min = 0; // below zero was caught above
Chris@16 538 RealType search_max = 0.55f; // will never go above 0.55
Chris@16 539
Chris@16 540 // refine
Chris@16 541 if(d < static_cast<diff_type>(21)) // shape smaller 100
Chris@16 542 {
Chris@16 543 // it is safe to assume that d > 0, because shape==0.0 is caught earlier
Chris@16 544 result = guess[d-static_cast<diff_type>(1)]
Chris@16 545 + (guess[d]-guess[d-static_cast<diff_type>(1)])/(shapes[d]-shapes[d-static_cast<diff_type>(1)])
Chris@16 546 * (shape-shapes[d-static_cast<diff_type>(1)]);
Chris@16 547 }
Chris@16 548 else // shape greater 100
Chris@16 549 {
Chris@16 550 result = 1e-4f;
Chris@16 551 search_max = guess[19]; // set 19 instead of 20 to have a safety margin because the table may not be exact @ shape=100
Chris@16 552 }
Chris@16 553
Chris@16 554 const int get_digits = policies::digits<RealType, Policy>();// get digits from policy,
Chris@16 555 boost::uintmax_t m = policies::get_max_root_iterations<Policy>(); // and max iterations.
Chris@16 556
Chris@16 557 skew_normal_distribution<RealType, Policy> helper(0, 1, shape);
Chris@16 558
Chris@16 559 result = tools::newton_raphson_iterate(detail::skew_normal_mode_functor<RealType, Policy>(helper), result,
Chris@16 560 search_min, search_max, get_digits, m);
Chris@16 561
Chris@16 562 result = result*scale + location;
Chris@16 563
Chris@16 564 return result;
Chris@16 565 }
Chris@16 566
Chris@16 567
Chris@16 568
Chris@16 569 template <class RealType, class Policy>
Chris@16 570 inline RealType skewness(const skew_normal_distribution<RealType, Policy>& dist)
Chris@16 571 {
Chris@16 572 BOOST_MATH_STD_USING // for ADL of std functions
Chris@16 573 using namespace boost::math::constants;
Chris@16 574
Chris@16 575 static const RealType factor = four_minus_pi<RealType>()/static_cast<RealType>(2);
Chris@16 576 const RealType delta = dist.shape() / sqrt(static_cast<RealType>(1)+dist.shape()*dist.shape());
Chris@16 577
Chris@16 578 return factor * pow(root_two_div_pi<RealType>() * delta, 3) /
Chris@16 579 pow(static_cast<RealType>(1)-two_div_pi<RealType>()*delta*delta, static_cast<RealType>(1.5));
Chris@16 580 }
Chris@16 581
Chris@16 582 template <class RealType, class Policy>
Chris@16 583 inline RealType kurtosis(const skew_normal_distribution<RealType, Policy>& dist)
Chris@16 584 {
Chris@16 585 return kurtosis_excess(dist)+static_cast<RealType>(3);
Chris@16 586 }
Chris@16 587
Chris@16 588 template <class RealType, class Policy>
Chris@16 589 inline RealType kurtosis_excess(const skew_normal_distribution<RealType, Policy>& dist)
Chris@16 590 {
Chris@16 591 using namespace boost::math::constants;
Chris@16 592
Chris@16 593 static const RealType factor = pi_minus_three<RealType>()*static_cast<RealType>(2);
Chris@16 594
Chris@16 595 const RealType delta2 = static_cast<RealType>(1) / (static_cast<RealType>(1)+static_cast<RealType>(1)/(dist.shape()*dist.shape()));
Chris@16 596
Chris@16 597 const RealType x = static_cast<RealType>(1)-two_div_pi<RealType>()*delta2;
Chris@16 598 const RealType y = two_div_pi<RealType>() * delta2;
Chris@16 599
Chris@16 600 return factor * y*y / (x*x);
Chris@16 601 }
Chris@16 602
Chris@16 603 namespace detail
Chris@16 604 {
Chris@16 605
Chris@16 606 template <class RealType, class Policy>
Chris@16 607 struct skew_normal_quantile_functor
Chris@16 608 {
Chris@16 609 skew_normal_quantile_functor(const boost::math::skew_normal_distribution<RealType, Policy> dist, RealType const& p)
Chris@16 610 : distribution(dist), prob(p)
Chris@16 611 {
Chris@16 612 }
Chris@16 613
Chris@16 614 boost::math::tuple<RealType, RealType> operator()(RealType const& x)
Chris@16 615 {
Chris@16 616 RealType c = cdf(distribution, x);
Chris@16 617 RealType fx = c - prob; // Difference cdf - value - to minimize.
Chris@16 618 RealType dx = pdf(distribution, x); // pdf is 1st derivative.
Chris@16 619 // return both function evaluation difference f(x) and 1st derivative f'(x).
Chris@16 620 return boost::math::make_tuple(fx, dx);
Chris@16 621 }
Chris@16 622 private:
Chris@16 623 const boost::math::skew_normal_distribution<RealType, Policy> distribution;
Chris@16 624 RealType prob;
Chris@16 625 };
Chris@16 626
Chris@16 627 } // namespace detail
Chris@16 628
Chris@16 629 template <class RealType, class Policy>
Chris@16 630 inline RealType quantile(const skew_normal_distribution<RealType, Policy>& dist, const RealType& p)
Chris@16 631 {
Chris@16 632 const RealType scale = dist.scale();
Chris@16 633 const RealType location = dist.location();
Chris@16 634 const RealType shape = dist.shape();
Chris@16 635
Chris@16 636 static const char* function = "boost::math::quantile(const skew_normal_distribution<%1%>&, %1%)";
Chris@16 637
Chris@16 638 RealType result = 0;
Chris@16 639 if(false == detail::check_scale(function, scale, &result, Policy()))
Chris@16 640 return result;
Chris@16 641 if(false == detail::check_location(function, location, &result, Policy()))
Chris@16 642 return result;
Chris@16 643 if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
Chris@16 644 return result;
Chris@16 645 if(false == detail::check_probability(function, p, &result, Policy()))
Chris@16 646 return result;
Chris@16 647
Chris@16 648 // Compute initial guess via Cornish-Fisher expansion.
Chris@16 649 RealType x = -boost::math::erfc_inv(2 * p, Policy()) * constants::root_two<RealType>();
Chris@16 650
Chris@16 651 // Avoid unnecessary computations if there is no skew.
Chris@16 652 if(shape != 0)
Chris@16 653 {
Chris@16 654 const RealType skew = skewness(dist);
Chris@16 655 const RealType exk = kurtosis_excess(dist);
Chris@16 656
Chris@16 657 x = x + (x*x-static_cast<RealType>(1))*skew/static_cast<RealType>(6)
Chris@16 658 + x*(x*x-static_cast<RealType>(3))*exk/static_cast<RealType>(24)
Chris@16 659 - x*(static_cast<RealType>(2)*x*x-static_cast<RealType>(5))*skew*skew/static_cast<RealType>(36);
Chris@16 660 } // if(shape != 0)
Chris@16 661
Chris@16 662 result = standard_deviation(dist)*x+mean(dist);
Chris@16 663
Chris@16 664 // handle special case of non-skew normal distribution.
Chris@16 665 if(shape == 0)
Chris@16 666 return result;
Chris@16 667
Chris@16 668 // refine the result by numerically searching the root of (p-cdf)
Chris@16 669
Chris@16 670 const RealType search_min = range(dist).first;
Chris@16 671 const RealType search_max = range(dist).second;
Chris@16 672
Chris@16 673 const int get_digits = policies::digits<RealType, Policy>();// get digits from policy,
Chris@16 674 boost::uintmax_t m = policies::get_max_root_iterations<Policy>(); // and max iterations.
Chris@16 675
Chris@16 676 result = tools::newton_raphson_iterate(detail::skew_normal_quantile_functor<RealType, Policy>(dist, p), result,
Chris@16 677 search_min, search_max, get_digits, m);
Chris@16 678
Chris@16 679 return result;
Chris@16 680 } // quantile
Chris@16 681
Chris@16 682 template <class RealType, class Policy>
Chris@16 683 inline RealType quantile(const complemented2_type<skew_normal_distribution<RealType, Policy>, RealType>& c)
Chris@16 684 {
Chris@16 685 const RealType scale = c.dist.scale();
Chris@16 686 const RealType location = c.dist.location();
Chris@16 687 const RealType shape = c.dist.shape();
Chris@16 688
Chris@16 689 static const char* function = "boost::math::quantile(const complement(skew_normal_distribution<%1%>&), %1%)";
Chris@16 690 RealType result = 0;
Chris@16 691 if(false == detail::check_scale(function, scale, &result, Policy()))
Chris@16 692 return result;
Chris@16 693 if(false == detail::check_location(function, location, &result, Policy()))
Chris@16 694 return result;
Chris@16 695 if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
Chris@16 696 return result;
Chris@16 697 RealType q = c.param;
Chris@16 698 if(false == detail::check_probability(function, q, &result, Policy()))
Chris@16 699 return result;
Chris@16 700
Chris@16 701 skew_normal_distribution<RealType, Policy> D(-location, scale, -shape);
Chris@16 702
Chris@16 703 result = -quantile(D, q);
Chris@16 704
Chris@16 705 return result;
Chris@16 706 } // quantile
Chris@16 707
Chris@16 708
Chris@16 709 } // namespace math
Chris@16 710 } // namespace boost
Chris@16 711
Chris@16 712 // This include must be at the end, *after* the accessors
Chris@16 713 // for this distribution have been defined, in order to
Chris@16 714 // keep compilers that support two-phase lookup happy.
Chris@16 715 #include <boost/math/distributions/detail/derived_accessors.hpp>
Chris@16 716
Chris@16 717 #endif // BOOST_STATS_SKEW_NORMAL_HPP
Chris@16 718
Chris@16 719