Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/boost/math/distributions/skew_normal.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 //  Copyright Benjamin Sobotta 2012
0002 
0003 //  Use, modification and distribution are subject to the
0004 //  Boost Software License, Version 1.0. (See accompanying file
0005 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 #ifndef BOOST_STATS_SKEW_NORMAL_HPP
0008 #define BOOST_STATS_SKEW_NORMAL_HPP
0009 
0010 // http://en.wikipedia.org/wiki/Skew_normal_distribution
0011 // http://azzalini.stat.unipd.it/SN/
0012 // Also:
0013 // Azzalini, A. (1985). "A class of distributions which includes the normal ones".
0014 // Scand. J. Statist. 12: 171-178.
0015 
0016 #include <boost/math/distributions/fwd.hpp> // TODO add skew_normal distribution to fwd.hpp!
0017 #include <boost/math/special_functions/owens_t.hpp> // Owen's T function
0018 #include <boost/math/distributions/complement.hpp>
0019 #include <boost/math/distributions/normal.hpp>
0020 #include <boost/math/distributions/detail/common_error_handling.hpp>
0021 #include <boost/math/constants/constants.hpp>
0022 #include <boost/math/tools/tuple.hpp>
0023 #include <boost/math/tools/roots.hpp> // Newton-Raphson
0024 #include <boost/math/tools/assert.hpp>
0025 #include <boost/math/distributions/detail/generic_mode.hpp> // pdf max finder.
0026 
0027 #include <utility>
0028 #include <algorithm> // std::lower_bound, std::distance
0029 
0030 #ifdef BOOST_MATH_INSTRUMENT_SKEW_NORMAL_ITERATIONS
0031 extern std::uintmax_t global_iter_count;
0032 #endif
0033 
0034 namespace boost{ namespace math{
0035 
0036   namespace detail
0037   {
0038     template <class RealType, class Policy>
0039     inline bool check_skew_normal_shape(
0040       const char* function,
0041       RealType shape,
0042       RealType* result,
0043       const Policy& pol)
0044     {
0045       if(!(boost::math::isfinite)(shape))
0046       {
0047         *result =
0048           policies::raise_domain_error<RealType>(function,
0049           "Shape parameter is %1%, but must be finite!",
0050           shape, pol);
0051         return false;
0052       }
0053       return true;
0054     }
0055 
0056   } // namespace detail
0057 
0058   template <class RealType = double, class Policy = policies::policy<> >
0059   class skew_normal_distribution
0060   {
0061   public:
0062     typedef RealType value_type;
0063     typedef Policy policy_type;
0064 
0065     skew_normal_distribution(RealType l_location = 0, RealType l_scale = 1, RealType l_shape = 0)
0066       : location_(l_location), scale_(l_scale), shape_(l_shape)
0067     { // Default is a 'standard' normal distribution N01. (shape=0 results in the normal distribution with no skew)
0068       static const char* function = "boost::math::skew_normal_distribution<%1%>::skew_normal_distribution";
0069 
0070       RealType result;
0071       detail::check_scale(function, l_scale, &result, Policy());
0072       detail::check_location(function, l_location, &result, Policy());
0073       detail::check_skew_normal_shape(function, l_shape, &result, Policy());
0074     }
0075 
0076     RealType location()const
0077     {
0078       return location_;
0079     }
0080 
0081     RealType scale()const
0082     {
0083       return scale_;
0084     }
0085 
0086     RealType shape()const
0087     {
0088       return shape_;
0089     }
0090 
0091 
0092   private:
0093     //
0094     // Data members:
0095     //
0096     RealType location_;  // distribution location.
0097     RealType scale_;    // distribution scale.
0098     RealType shape_;    // distribution shape.
0099   }; // class skew_normal_distribution
0100 
0101   typedef skew_normal_distribution<double> skew_normal;
0102 
0103   #ifdef __cpp_deduction_guides
0104   template <class RealType>
0105   skew_normal_distribution(RealType)->skew_normal_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0106   template <class RealType>
0107   skew_normal_distribution(RealType,RealType)->skew_normal_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0108   template <class RealType>
0109   skew_normal_distribution(RealType,RealType,RealType)->skew_normal_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0110   #endif
0111 
0112   template <class RealType, class Policy>
0113   inline const std::pair<RealType, RealType> range(const skew_normal_distribution<RealType, Policy>& /*dist*/)
0114   { // Range of permissible values for random variable x.
0115     using boost::math::tools::max_value;
0116     return std::pair<RealType, RealType>(
0117        std::numeric_limits<RealType>::has_infinity ? -std::numeric_limits<RealType>::infinity() : -max_value<RealType>(),
0118        std::numeric_limits<RealType>::has_infinity ? std::numeric_limits<RealType>::infinity() : max_value<RealType>()); // - to + max value.
0119   }
0120 
0121   template <class RealType, class Policy>
0122   inline const std::pair<RealType, RealType> support(const skew_normal_distribution<RealType, Policy>& /*dist*/)
0123   { // Range of supported values for random variable x.
0124     // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
0125 
0126     using boost::math::tools::max_value;
0127     return std::pair<RealType, RealType>(-max_value<RealType>(),  max_value<RealType>()); // - to + max value.
0128   }
0129 
0130   template <class RealType, class Policy>
0131   inline RealType pdf(const skew_normal_distribution<RealType, Policy>& dist, const RealType& x)
0132   {
0133     const RealType scale = dist.scale();
0134     const RealType location = dist.location();
0135     const RealType shape = dist.shape();
0136 
0137     static const char* function = "boost::math::pdf(const skew_normal_distribution<%1%>&, %1%)";
0138 
0139     RealType result = 0;
0140     if(false == detail::check_scale(function, scale, &result, Policy()))
0141     {
0142       return result;
0143     }
0144     if(false == detail::check_location(function, location, &result, Policy()))
0145     {
0146       return result;
0147     }
0148     if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
0149     {
0150       return result;
0151     }
0152     if((boost::math::isinf)(x))
0153     {
0154        return 0; // pdf + and - infinity is zero.
0155     }
0156     // Below produces MSVC 4127 warnings, so the above used instead.
0157     //if(std::numeric_limits<RealType>::has_infinity && abs(x) == std::numeric_limits<RealType>::infinity())
0158     //{ // pdf + and - infinity is zero.
0159     //  return 0;
0160     //}
0161     if(false == detail::check_x(function, x, &result, Policy()))
0162     {
0163       return result;
0164     }
0165 
0166     const RealType transformed_x = (x-location)/scale;
0167 
0168     normal_distribution<RealType, Policy> std_normal;
0169 
0170     result = pdf(std_normal, transformed_x) * cdf(std_normal, shape*transformed_x) * 2 / scale;
0171 
0172     return result;
0173   } // pdf
0174 
0175   template <class RealType, class Policy>
0176   inline RealType cdf(const skew_normal_distribution<RealType, Policy>& dist, const RealType& x)
0177   {
0178     const RealType scale = dist.scale();
0179     const RealType location = dist.location();
0180     const RealType shape = dist.shape();
0181 
0182     static const char* function = "boost::math::cdf(const skew_normal_distribution<%1%>&, %1%)";
0183     RealType result = 0;
0184     if(false == detail::check_scale(function, scale, &result, Policy()))
0185     {
0186       return result;
0187     }
0188     if(false == detail::check_location(function, location, &result, Policy()))
0189     {
0190       return result;
0191     }
0192     if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
0193     {
0194       return result;
0195     }
0196     if((boost::math::isinf)(x))
0197     {
0198       if(x < 0) return 0; // -infinity
0199       return 1; // + infinity
0200     }
0201     // These produce MSVC 4127 warnings, so the above used instead.
0202     //if(std::numeric_limits<RealType>::has_infinity && x == std::numeric_limits<RealType>::infinity())
0203     //{ // cdf +infinity is unity.
0204     //  return 1;
0205     //}
0206     //if(std::numeric_limits<RealType>::has_infinity && x == -std::numeric_limits<RealType>::infinity())
0207     //{ // cdf -infinity is zero.
0208     //  return 0;
0209     //}
0210     if(false == detail::check_x(function, x, &result, Policy()))
0211     {
0212       return result;
0213     }
0214 
0215     const RealType transformed_x = (x-location)/scale;
0216 
0217     normal_distribution<RealType, Policy> std_normal;
0218 
0219     result = cdf(std_normal, transformed_x) - owens_t(transformed_x, shape)*static_cast<RealType>(2);
0220 
0221     return result;
0222   } // cdf
0223 
0224   template <class RealType, class Policy>
0225   inline RealType cdf(const complemented2_type<skew_normal_distribution<RealType, Policy>, RealType>& c)
0226   {
0227     const RealType scale = c.dist.scale();
0228     const RealType location = c.dist.location();
0229     const RealType shape = c.dist.shape();
0230     const RealType x = c.param;
0231 
0232     static const char* function = "boost::math::cdf(const complement(skew_normal_distribution<%1%>&), %1%)";
0233 
0234     if((boost::math::isinf)(x))
0235     {
0236       if(x < 0) return 1; // cdf complement -infinity is unity.
0237       return 0; // cdf complement +infinity is zero
0238     }
0239     // These produce MSVC 4127 warnings, so the above used instead.
0240     //if(std::numeric_limits<RealType>::has_infinity && x == std::numeric_limits<RealType>::infinity())
0241     //{ // cdf complement +infinity is zero.
0242     //  return 0;
0243     //}
0244     //if(std::numeric_limits<RealType>::has_infinity && x == -std::numeric_limits<RealType>::infinity())
0245     //{ // cdf complement -infinity is unity.
0246     //  return 1;
0247     //}
0248     RealType result = 0;
0249     if(false == detail::check_scale(function, scale, &result, Policy()))
0250       return result;
0251     if(false == detail::check_location(function, location, &result, Policy()))
0252       return result;
0253     if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
0254       return result;
0255     if(false == detail::check_x(function, x, &result, Policy()))
0256       return result;
0257 
0258     const RealType transformed_x = (x-location)/scale;
0259 
0260     normal_distribution<RealType, Policy> std_normal;
0261 
0262     result = cdf(complement(std_normal, transformed_x)) + owens_t(transformed_x, shape)*static_cast<RealType>(2);
0263     return result;
0264   } // cdf complement
0265 
0266   template <class RealType, class Policy>
0267   inline RealType location(const skew_normal_distribution<RealType, Policy>& dist)
0268   {
0269     return dist.location();
0270   }
0271 
0272   template <class RealType, class Policy>
0273   inline RealType scale(const skew_normal_distribution<RealType, Policy>& dist)
0274   {
0275     return dist.scale();
0276   }
0277 
0278   template <class RealType, class Policy>
0279   inline RealType shape(const skew_normal_distribution<RealType, Policy>& dist)
0280   {
0281     return dist.shape();
0282   }
0283 
0284   template <class RealType, class Policy>
0285   inline RealType mean(const skew_normal_distribution<RealType, Policy>& dist)
0286   {
0287     BOOST_MATH_STD_USING  // for ADL of std functions
0288 
0289     using namespace boost::math::constants;
0290 
0291     //const RealType delta = dist.shape() / sqrt(static_cast<RealType>(1)+dist.shape()*dist.shape());
0292 
0293     //return dist.location() + dist.scale() * delta * root_two_div_pi<RealType>();
0294 
0295     return dist.location() + dist.scale() * dist.shape() / sqrt(pi<RealType>()+pi<RealType>()*dist.shape()*dist.shape()) * root_two<RealType>();
0296   }
0297 
0298   template <class RealType, class Policy>
0299   inline RealType variance(const skew_normal_distribution<RealType, Policy>& dist)
0300   {
0301     using namespace boost::math::constants;
0302 
0303     const RealType delta2 = dist.shape() != 0 ? static_cast<RealType>(1) / (static_cast<RealType>(1)+static_cast<RealType>(1)/(dist.shape()*dist.shape())) : static_cast<RealType>(0);
0304     //const RealType inv_delta2 = static_cast<RealType>(1)+static_cast<RealType>(1)/(dist.shape()*dist.shape());
0305 
0306     RealType variance = dist.scale()*dist.scale()*(static_cast<RealType>(1)-two_div_pi<RealType>()*delta2);
0307     //RealType variance = dist.scale()*dist.scale()*(static_cast<RealType>(1)-two_div_pi<RealType>()/inv_delta2);
0308 
0309     return variance;
0310   }
0311 
0312   namespace detail
0313   {
0314     /*
0315       TODO No closed expression for mode, so use max of pdf.
0316     */
0317 
0318     template <class RealType, class Policy>
0319     inline RealType mode_fallback(const skew_normal_distribution<RealType, Policy>& dist)
0320     { // mode.
0321         static const char* function = "mode(skew_normal_distribution<%1%> const&)";
0322         const RealType scale = dist.scale();
0323         const RealType location = dist.location();
0324         const RealType shape = dist.shape();
0325 
0326         RealType result;
0327         if(!detail::check_scale(
0328           function,
0329           scale, &result, Policy())
0330           ||
0331         !detail::check_skew_normal_shape(
0332           function,
0333           shape,
0334           &result,
0335           Policy()))
0336         return result;
0337 
0338         if( shape == 0 )
0339         {
0340           return location;
0341         }
0342 
0343         if( shape < 0 )
0344         {
0345           skew_normal_distribution<RealType, Policy> D(0, 1, -shape);
0346           result = mode_fallback(D);
0347           result = location-scale*result;
0348           return result;
0349         }
0350 
0351         BOOST_MATH_STD_USING
0352 
0353         // 21 elements
0354         static const RealType shapes[] = {
0355           0.0,
0356           1.000000000000000e-004,
0357           2.069138081114790e-004,
0358           4.281332398719396e-004,
0359           8.858667904100824e-004,
0360           1.832980710832436e-003,
0361           3.792690190732250e-003,
0362           7.847599703514606e-003,
0363           1.623776739188722e-002,
0364           3.359818286283781e-002,
0365           6.951927961775606e-002,
0366           1.438449888287663e-001,
0367           2.976351441631319e-001,
0368           6.158482110660261e-001,
0369           1.274274985703135e+000,
0370           2.636650898730361e+000,
0371           5.455594781168514e+000,
0372           1.128837891684688e+001,
0373           2.335721469090121e+001,
0374           4.832930238571753e+001,
0375           1.000000000000000e+002};
0376 
0377         // 21 elements
0378         static const RealType guess[] = {
0379           0.0,
0380           5.000050000525391e-005,
0381           1.500015000148736e-004,
0382           3.500035000350010e-004,
0383           7.500075000752560e-004,
0384           1.450014500145258e-003,
0385           3.050030500305390e-003,
0386           6.250062500624765e-003,
0387           1.295012950129504e-002,
0388           2.675026750267495e-002,
0389           5.525055250552491e-002,
0390           1.132511325113255e-001,
0391           2.249522495224952e-001,
0392           3.992539925399257e-001,
0393           5.353553535535358e-001,
0394           4.954549545495457e-001,
0395           3.524535245352451e-001,
0396           2.182521825218249e-001,
0397           1.256512565125654e-001,
0398           6.945069450694508e-002,
0399           3.735037350373460e-002
0400         };
0401 
0402         const RealType* result_ptr = std::lower_bound(shapes, shapes+21, shape);
0403 
0404         typedef typename std::iterator_traits<RealType*>::difference_type diff_type;
0405 
0406         const diff_type d = std::distance(shapes, result_ptr);
0407 
0408         BOOST_MATH_ASSERT(d > static_cast<diff_type>(0));
0409 
0410         // refine
0411         if(d < static_cast<diff_type>(21)) // shape smaller 100
0412         {
0413           result = guess[d-static_cast<diff_type>(1)]
0414             + (guess[d]-guess[d-static_cast<diff_type>(1)])/(shapes[d]-shapes[d-static_cast<diff_type>(1)])
0415             * (shape-shapes[d-static_cast<diff_type>(1)]);
0416         }
0417         else // shape greater 100
0418         {
0419           result = 1e-4;
0420         }
0421 
0422         skew_normal_distribution<RealType, Policy> helper(0, 1, shape);
0423 
0424         result = detail::generic_find_mode_01(helper, result, function);
0425 
0426         result = result*scale + location;
0427 
0428         return result;
0429     } // mode_fallback
0430 
0431 
0432     /*
0433      * TODO No closed expression for mode, so use f'(x) = 0
0434      */
0435     template <class RealType, class Policy>
0436     struct skew_normal_mode_functor
0437     {
0438       skew_normal_mode_functor(const boost::math::skew_normal_distribution<RealType, Policy> dist)
0439         : distribution(dist)
0440       {
0441       }
0442 
0443       boost::math::tuple<RealType, RealType> operator()(RealType const& x)
0444       {
0445         normal_distribution<RealType, Policy> std_normal;
0446         const RealType shape = distribution.shape();
0447         const RealType pdf_x = pdf(distribution, x);
0448         const RealType normpdf_x = pdf(std_normal, x);
0449         const RealType normpdf_ax = pdf(std_normal, x*shape);
0450         RealType fx = static_cast<RealType>(2)*shape*normpdf_ax*normpdf_x - x*pdf_x;
0451         RealType dx = static_cast<RealType>(2)*shape*x*normpdf_x*normpdf_ax*(static_cast<RealType>(1) + shape*shape) + pdf_x + x*fx;
0452         // return both function evaluation difference f(x) and 1st derivative f'(x).
0453         return boost::math::make_tuple(fx, -dx);
0454       }
0455     private:
0456       const boost::math::skew_normal_distribution<RealType, Policy> distribution;
0457     };
0458 
0459   } // namespace detail
0460 
0461   template <class RealType, class Policy>
0462   inline RealType mode(const skew_normal_distribution<RealType, Policy>& dist)
0463   {
0464     const RealType scale = dist.scale();
0465     const RealType location = dist.location();
0466     const RealType shape = dist.shape();
0467 
0468     static const char* function = "boost::math::mode(const skew_normal_distribution<%1%>&, %1%)";
0469 
0470     RealType result = 0;
0471     if(false == detail::check_scale(function, scale, &result, Policy()))
0472       return result;
0473     if(false == detail::check_location(function, location, &result, Policy()))
0474       return result;
0475     if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
0476       return result;
0477 
0478     if( shape == 0 )
0479     {
0480       return location;
0481     }
0482 
0483     if( shape < 0 )
0484     {
0485       skew_normal_distribution<RealType, Policy> D(0, 1, -shape);
0486       result = mode(D);
0487       result = location-scale*result;
0488       return result;
0489     }
0490 
0491     // 21 elements
0492     static const RealType shapes[] = {
0493       static_cast<RealType>(0.0),
0494       static_cast<RealType>(1.000000000000000e-004),
0495       static_cast<RealType>(2.069138081114790e-004),
0496       static_cast<RealType>(4.281332398719396e-004),
0497       static_cast<RealType>(8.858667904100824e-004),
0498       static_cast<RealType>(1.832980710832436e-003),
0499       static_cast<RealType>(3.792690190732250e-003),
0500       static_cast<RealType>(7.847599703514606e-003),
0501       static_cast<RealType>(1.623776739188722e-002),
0502       static_cast<RealType>(3.359818286283781e-002),
0503       static_cast<RealType>(6.951927961775606e-002),
0504       static_cast<RealType>(1.438449888287663e-001),
0505       static_cast<RealType>(2.976351441631319e-001),
0506       static_cast<RealType>(6.158482110660261e-001),
0507       static_cast<RealType>(1.274274985703135e+000),
0508       static_cast<RealType>(2.636650898730361e+000),
0509       static_cast<RealType>(5.455594781168514e+000),
0510       static_cast<RealType>(1.128837891684688e+001),
0511       static_cast<RealType>(2.335721469090121e+001),
0512       static_cast<RealType>(4.832930238571753e+001),
0513       static_cast<RealType>(1.000000000000000e+002)
0514     };
0515 
0516     // 21 elements
0517     static const RealType guess[] = {
0518       static_cast<RealType>(0.0),
0519       static_cast<RealType>(5.000050000525391e-005),
0520       static_cast<RealType>(1.500015000148736e-004),
0521       static_cast<RealType>(3.500035000350010e-004),
0522       static_cast<RealType>(7.500075000752560e-004),
0523       static_cast<RealType>(1.450014500145258e-003),
0524       static_cast<RealType>(3.050030500305390e-003),
0525       static_cast<RealType>(6.250062500624765e-003),
0526       static_cast<RealType>(1.295012950129504e-002),
0527       static_cast<RealType>(2.675026750267495e-002),
0528       static_cast<RealType>(5.525055250552491e-002),
0529       static_cast<RealType>(1.132511325113255e-001),
0530       static_cast<RealType>(2.249522495224952e-001),
0531       static_cast<RealType>(3.992539925399257e-001),
0532       static_cast<RealType>(5.353553535535358e-001),
0533       static_cast<RealType>(4.954549545495457e-001),
0534       static_cast<RealType>(3.524535245352451e-001),
0535       static_cast<RealType>(2.182521825218249e-001),
0536       static_cast<RealType>(1.256512565125654e-001),
0537       static_cast<RealType>(6.945069450694508e-002),
0538       static_cast<RealType>(3.735037350373460e-002)
0539     };
0540 
0541     const RealType* result_ptr = std::lower_bound(shapes, shapes+21, shape);
0542 
0543     typedef typename std::iterator_traits<RealType*>::difference_type diff_type;
0544 
0545     const diff_type d = std::distance(shapes, result_ptr);
0546 
0547     BOOST_MATH_ASSERT(d > static_cast<diff_type>(0));
0548 
0549     // TODO: make the search bounds smarter, depending on the shape parameter
0550     RealType search_min = 0; // below zero was caught above
0551     RealType search_max = 0.55f; // will never go above 0.55
0552 
0553     // refine
0554     if(d < static_cast<diff_type>(21)) // shape smaller 100
0555     {
0556       // it is safe to assume that d > 0, because shape==0.0 is caught earlier
0557       result = guess[d-static_cast<diff_type>(1)]
0558         + (guess[d]-guess[d-static_cast<diff_type>(1)])/(shapes[d]-shapes[d-static_cast<diff_type>(1)])
0559         * (shape-shapes[d-static_cast<diff_type>(1)]);
0560     }
0561     else // shape greater 100
0562     {
0563       result = 1e-4f;
0564       search_max = guess[19]; // set 19 instead of 20 to have a safety margin because the table may not be exact @ shape=100
0565     }
0566 
0567     const int get_digits = policies::digits<RealType, Policy>();// get digits from policy,
0568     std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>(); // and max iterations.
0569 
0570     skew_normal_distribution<RealType, Policy> helper(0, 1, shape);
0571 
0572     result = tools::newton_raphson_iterate(detail::skew_normal_mode_functor<RealType, Policy>(helper), result,
0573       search_min, search_max, get_digits, max_iter);
0574     if (max_iter >= policies::get_max_root_iterations<Policy>())
0575     {
0576        return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:" // LCOV_EXCL_LINE
0577           " either there is no answer to quantile or the answer is infinite.  Current best guess is %1%", result, Policy()); // LCOV_EXCL_LINE
0578     }
0579 
0580     result = result*scale + location;
0581 
0582     return result;
0583   }
0584 
0585 
0586 
0587   template <class RealType, class Policy>
0588   inline RealType skewness(const skew_normal_distribution<RealType, Policy>& dist)
0589   {
0590     BOOST_MATH_STD_USING  // for ADL of std functions
0591     using namespace boost::math::constants;
0592 
0593     static const RealType factor = four_minus_pi<RealType>()/static_cast<RealType>(2);
0594     const RealType delta = dist.shape() / sqrt(static_cast<RealType>(1)+dist.shape()*dist.shape());
0595 
0596     return static_cast<RealType>(factor * pow(root_two_div_pi<RealType>() * delta, 3) /
0597       pow(static_cast<RealType>(1)-two_div_pi<RealType>()*delta*delta, static_cast<RealType>(1.5)));
0598   }
0599 
0600   template <class RealType, class Policy>
0601   inline RealType kurtosis(const skew_normal_distribution<RealType, Policy>& dist)
0602   {
0603     return kurtosis_excess(dist)+static_cast<RealType>(3);
0604   }
0605 
0606   template <class RealType, class Policy>
0607   inline RealType kurtosis_excess(const skew_normal_distribution<RealType, Policy>& dist)
0608   {
0609     using namespace boost::math::constants;
0610 
0611     static const RealType factor = pi_minus_three<RealType>()*static_cast<RealType>(2);
0612 
0613     const RealType delta2 = dist.shape() != 0 ? static_cast<RealType>(1) / (static_cast<RealType>(1)+static_cast<RealType>(1)/(dist.shape()*dist.shape())) : static_cast<RealType>(0);
0614 
0615     const RealType x = static_cast<RealType>(1)-two_div_pi<RealType>()*delta2;
0616     const RealType y = two_div_pi<RealType>() * delta2;
0617 
0618     return factor * y*y / (x*x);
0619   }
0620 
0621   template <class RealType, class Policy>
0622   inline RealType quantile(const skew_normal_distribution<RealType, Policy>& dist, const RealType& p)
0623   {
0624     const RealType scale = dist.scale();
0625     const RealType location = dist.location();
0626     const RealType shape = dist.shape();
0627 
0628     static const char* function = "boost::math::quantile(const skew_normal_distribution<%1%>&, %1%)";
0629 
0630     RealType result = 0;
0631     if(false == detail::check_scale(function, scale, &result, Policy()))
0632       return result;
0633     if(false == detail::check_location(function, location, &result, Policy()))
0634       return result;
0635     if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
0636       return result;
0637     if(false == detail::check_probability(function, p, &result, Policy()))
0638       return result;
0639 
0640     // Compute initial guess via Cornish-Fisher expansion.
0641     RealType x = -boost::math::erfc_inv(2 * p, Policy()) * constants::root_two<RealType>();
0642 
0643     // Avoid unnecessary computations if there is no skew.
0644     if(shape != 0)
0645     {
0646       const RealType skew = skewness(dist);
0647       const RealType exk = kurtosis_excess(dist);
0648 
0649       x = x + (x*x-static_cast<RealType>(1))*skew/static_cast<RealType>(6)
0650       + x*(x*x-static_cast<RealType>(3))*exk/static_cast<RealType>(24)
0651       - x*(static_cast<RealType>(2)*x*x-static_cast<RealType>(5))*skew*skew/static_cast<RealType>(36);
0652     } // if(shape != 0)
0653 
0654     result = standard_deviation(dist)*x+mean(dist);
0655 
0656     // handle special case of non-skew normal distribution.
0657     if(shape == 0)
0658       return result;
0659 
0660     // refine the result by numerically searching the root of (p-cdf)
0661 
0662     const int get_digits = policies::digits<RealType, Policy>();// get digits from policy,
0663     std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>(); // and max iterations.
0664 
0665     if (result == 0)
0666        result = tools::min_value<RealType>(); // we need to be one side of zero or the other for the root finder to work.
0667 
0668     auto fun = [&, dist, p](const RealType& x)->RealType { return cdf(dist, x) - p; };
0669 
0670     RealType f_result = fun(result);
0671 
0672     if (f_result == 0)
0673        return result;
0674 
0675     if (f_result * result > 0)
0676     {
0677        // If the root is in the direction of zero, we need to check that we're the correct side of it:
0678        RealType f_zero = fun(static_cast<RealType>(0));
0679        if (f_zero * f_result > 0)
0680        {
0681           // we're the wrong side of zero:
0682           result = -result;
0683           f_result = fun(result);
0684        }
0685     }
0686 
0687     RealType scaling_factor = 1.25;
0688     if (f_result * result > 0)
0689     {
0690        // We're heading towards zero... it's a long way down so use a larger scaling factor:
0691        scaling_factor = 16;
0692     }
0693 
0694     auto p_result = tools::bracket_and_solve_root(fun, result, scaling_factor, true, tools::eps_tolerance<RealType>(get_digits), max_iter, Policy());
0695 
0696 #ifdef BOOST_MATH_INSTRUMENT_SKEW_NORMAL_ITERATIONS
0697     global_iter_count += max_iter;
0698 #endif
0699 
0700     result = (p_result.first + p_result.second) / 2;
0701 
0702     //
0703     // Try one last Newton step, just to close up the interval:
0704     //
0705     RealType step = fun(result) / pdf(dist, result);
0706 
0707     if (result - step <= p_result.first)
0708        result = p_result.first;
0709     else if (result - step >= p_result.second)
0710        result = p_result.second;
0711     else
0712        result -= step;
0713 
0714     if (max_iter >= policies::get_max_root_iterations<Policy>())
0715     {
0716        return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time: either there is no answer to quantile" // LCOV_EXCL_LINE
0717           " or the answer is infinite.  Current best guess is %1%", result, Policy());  // LCOV_EXCL_LINE
0718     }
0719 
0720     return result;
0721   } // quantile
0722 
0723   template <class RealType, class Policy>
0724   inline RealType quantile(const complemented2_type<skew_normal_distribution<RealType, Policy>, RealType>& c)
0725   {
0726     const RealType scale = c.dist.scale();
0727     const RealType location = c.dist.location();
0728     const RealType shape = c.dist.shape();
0729 
0730     static const char* function = "boost::math::quantile(const complement(skew_normal_distribution<%1%>&), %1%)";
0731     RealType result = 0;
0732     if(false == detail::check_scale(function, scale, &result, Policy()))
0733       return result;
0734     if(false == detail::check_location(function, location, &result, Policy()))
0735       return result;
0736     if(false == detail::check_skew_normal_shape(function, shape, &result, Policy()))
0737       return result;
0738     RealType q = c.param;
0739     if(false == detail::check_probability(function, q, &result, Policy()))
0740       return result;
0741 
0742     skew_normal_distribution<RealType, Policy> D(-location, scale, -shape);
0743 
0744     result = -quantile(D, q);
0745 
0746     return result;
0747   } // quantile
0748 
0749 
0750 } // namespace math
0751 } // namespace boost
0752 
0753 // This include must be at the end, *after* the accessors
0754 // for this distribution have been defined, in order to
0755 // keep compilers that support two-phase lookup happy.
0756 #include <boost/math/distributions/detail/derived_accessors.hpp>
0757 
0758 #endif // BOOST_STATS_SKEW_NORMAL_HPP
0759 
0760