Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-06-30 08:18:23

0001 // boost\math\distributions\non_central_beta.hpp
0002 
0003 // Copyright John Maddock 2008.
0004 
0005 // Use, modification and distribution are subject to the
0006 // Boost Software License, Version 1.0.
0007 // (See accompanying file LICENSE_1_0.txt
0008 // or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 
0010 #ifndef BOOST_MATH_SPECIAL_NON_CENTRAL_BETA_HPP
0011 #define BOOST_MATH_SPECIAL_NON_CENTRAL_BETA_HPP
0012 
0013 #include <boost/math/distributions/fwd.hpp>
0014 #include <boost/math/special_functions/beta.hpp> // for incomplete gamma. gamma_q
0015 #include <boost/math/distributions/complement.hpp> // complements
0016 #include <boost/math/distributions/beta.hpp> // central distribution
0017 #include <boost/math/distributions/detail/generic_mode.hpp>
0018 #include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
0019 #include <boost/math/special_functions/fpclassify.hpp> // isnan.
0020 #include <boost/math/special_functions/trunc.hpp>
0021 #include <boost/math/tools/roots.hpp> // for root finding.
0022 #include <boost/math/tools/series.hpp>
0023 
0024 namespace boost
0025 {
0026    namespace math
0027    {
0028 
0029       template <class RealType, class Policy>
0030       class non_central_beta_distribution;
0031 
0032       namespace detail{
0033 
0034          template <class T, class Policy>
0035          T non_central_beta_p(T a, T b, T lam, T x, T y, const Policy& pol, T init_val = 0)
0036          {
0037             BOOST_MATH_STD_USING
0038                using namespace boost::math;
0039             //
0040             // Variables come first:
0041             //
0042             std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0043             T errtol = boost::math::policies::get_epsilon<T, Policy>();
0044             T l2 = lam / 2;
0045             //
0046             // k is the starting point for iteration, and is the
0047             // maximum of the poisson weighting term,
0048             // note that unlike other similar code, we do not set
0049             // k to zero, when l2 is small, as forward iteration
0050             // is unstable:
0051             //
0052             long long k = lltrunc(l2);
0053             if(k == 0)
0054                k = 1;
0055                // Starting Poisson weight:
0056             T pois = gamma_p_derivative(T(k+1), l2, pol);
0057             if(pois == 0)
0058                return init_val;
0059             // recurance term:
0060             T xterm;
0061             // Starting beta term:
0062             T beta = x < y
0063                ? detail::ibeta_imp(T(a + k), b, x, pol, false, true, &xterm)
0064                : detail::ibeta_imp(b, T(a + k), y, pol, true, true, &xterm);
0065 
0066             while (fabs(beta * pois) < tools::min_value<T>())
0067             {
0068                if ((k == 0) || (pois == 0))
0069                   return init_val;
0070                k /= 2;
0071                pois = gamma_p_derivative(T(k + 1), l2, pol);
0072                beta = x < y
0073                   ? detail::ibeta_imp(T(a + k), b, x, pol, false, true, &xterm)
0074                   : detail::ibeta_imp(b, T(a + k), y, pol, true, true, &xterm);
0075             }
0076 
0077             xterm *= y / (a + b + k - 1);
0078             T poisf(pois), betaf(beta), xtermf(xterm);
0079             T sum = init_val;
0080 
0081             if((beta == 0) && (xterm == 0))
0082                return init_val;
0083 
0084             //
0085             // Backwards recursion first, this is the stable
0086             // direction for recursion:
0087             //
0088             T last_term = 0;
0089             std::uintmax_t count = k;
0090             for(auto i = k; i >= 0; --i)
0091             {
0092                T term = beta * pois;
0093                sum += term;
0094                if(((fabs(term/sum) < errtol) && (fabs(last_term) >= fabs(term))) || (term == 0))
0095                {
0096                   count = k - i;
0097                   break;
0098                }
0099                pois *= i / l2;
0100                beta += xterm;
0101 
0102                if (a + b + i != 2)
0103                {
0104                   xterm *= (a + i - 1) / (x * (a + b + i - 2));
0105                }
0106                
0107                last_term = term;
0108             }
0109             last_term = 0;
0110             for(auto i = k + 1; ; ++i)
0111             {
0112                poisf *= l2 / i;
0113                xtermf *= (x * (a + b + i - 2)) / (a + i - 1);
0114                betaf -= xtermf;
0115 
0116                T term = poisf * betaf;
0117                sum += term;
0118                if(((fabs(term/sum) < errtol) && (fabs(last_term) >= fabs(term))) || (term == 0))
0119                {
0120                   break;
0121                }
0122                last_term = term;
0123                if(static_cast<std::uintmax_t>(count + i - k) > max_iter)
0124                {
0125                   return policies::raise_evaluation_error("cdf(non_central_beta_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol); // LCOV_EXCL_LINE
0126                }
0127             }
0128             return sum;
0129          }
0130 
0131          template <class T, class Policy>
0132          T non_central_beta_q(T a, T b, T lam, T x, T y, const Policy& pol, T init_val = 0)
0133          {
0134             BOOST_MATH_STD_USING
0135                using namespace boost::math;
0136             //
0137             // Variables come first:
0138             //
0139             std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0140             T errtol = boost::math::policies::get_epsilon<T, Policy>();
0141             T l2 = lam / 2;
0142             //
0143             // k is the starting point for iteration, and is the
0144             // maximum of the poisson weighting term:
0145             //
0146             long long k = lltrunc(l2);
0147             T pois;
0148             if(k <= 30)
0149             {
0150                //
0151                // Might as well start at 0 since we'll likely have this number of terms anyway:
0152                //
0153                if(a + b > 1)
0154                   k = 0;
0155                else if(k == 0)
0156                   k = 1;
0157             }
0158             if(k == 0)
0159             {
0160                // Starting Poisson weight:
0161                pois = exp(-l2);
0162             }
0163             else
0164             {
0165                // Starting Poisson weight:
0166                pois = gamma_p_derivative(T(k+1), l2, pol);
0167             }
0168             if(pois == 0)
0169                return init_val;
0170             // recurance term:
0171             T xterm;
0172             // Starting beta term:
0173             T beta = x < y
0174                ? detail::ibeta_imp(T(a + k), b, x, pol, true, true, &xterm)
0175                : detail::ibeta_imp(b, T(a + k), y, pol, false, true, &xterm);
0176 
0177             xterm *= y / (a + b + k - 1);
0178             T poisf(pois), betaf(beta), xtermf(xterm);
0179             T sum = init_val;
0180             if((beta == 0) && (xterm == 0))
0181                return init_val;
0182             //
0183             // Forwards recursion first, this is the stable
0184             // direction for recursion, and the location
0185             // of the bulk of the sum:
0186             //
0187             T last_term = 0;
0188             std::uintmax_t count = 0;
0189             for(auto i = k + 1; ; ++i)
0190             {
0191                poisf *= l2 / i;
0192                xtermf *= (x * (a + b + i - 2)) / (a + i - 1);
0193                betaf += xtermf;
0194 
0195                T term = poisf * betaf;
0196                sum += term;
0197                if((fabs(term/sum) < errtol) && (last_term >= term))
0198                {
0199                   count = i - k;
0200                   break;
0201                }
0202                if(static_cast<std::uintmax_t>(i - k) > max_iter)
0203                {
0204                   return policies::raise_evaluation_error("cdf(non_central_beta_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol); // LCOV_EXCL_LINE
0205                }
0206                last_term = term;
0207             }
0208             for(auto i = k; i >= 0; --i)
0209             {
0210                T term = beta * pois;
0211                sum += term;
0212                if(fabs(term/sum) < errtol)
0213                {
0214                   break;
0215                }
0216                if(static_cast<std::uintmax_t>(count + k - i) > max_iter)
0217                {
0218                   return policies::raise_evaluation_error("cdf(non_central_beta_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol); // LCOV_EXCL_LINE
0219                }
0220                pois *= i / l2;
0221                beta -= xterm;
0222                if (a + b + i - 2 != 0)
0223                {
0224                    xterm *= (a + i - 1) / (x * (a + b + i - 2));
0225                }
0226             }
0227             return sum;
0228          }
0229 
0230          template <class RealType, class Policy>
0231          inline RealType non_central_beta_cdf(RealType x, RealType y, RealType a, RealType b, RealType l, bool invert, const Policy&)
0232          {
0233             typedef typename policies::evaluation<RealType, Policy>::type value_type;
0234             typedef typename policies::normalise<
0235                Policy,
0236                policies::promote_float<false>,
0237                policies::promote_double<false>,
0238                policies::discrete_quantile<>,
0239                policies::assert_undefined<> >::type forwarding_policy;
0240 
0241             BOOST_MATH_STD_USING
0242 
0243             if(x == 0)
0244                return invert ? 1.0f : 0.0f;
0245             if(y == 0)
0246                return invert ? 0.0f : 1.0f;
0247             value_type result;
0248             value_type c = a + b + l / 2;
0249             value_type cross = 1 - (b / c) * (1 + l / (2 * c * c));
0250             if(l == 0)
0251                result = cdf(boost::math::beta_distribution<RealType, Policy>(a, b), x);
0252             else if(x > cross)
0253             {
0254                // Complement is the smaller of the two:
0255                result = detail::non_central_beta_q(
0256                   static_cast<value_type>(a),
0257                   static_cast<value_type>(b),
0258                   static_cast<value_type>(l),
0259                   static_cast<value_type>(x),
0260                   static_cast<value_type>(y),
0261                   forwarding_policy(),
0262                   static_cast<value_type>(invert ? 0 : -1));
0263                invert = !invert;
0264             }
0265             else
0266             {
0267                result = detail::non_central_beta_p(
0268                   static_cast<value_type>(a),
0269                   static_cast<value_type>(b),
0270                   static_cast<value_type>(l),
0271                   static_cast<value_type>(x),
0272                   static_cast<value_type>(y),
0273                   forwarding_policy(),
0274                   static_cast<value_type>(invert ? -1 : 0));
0275             }
0276             if(invert)
0277                result = -result;
0278             return policies::checked_narrowing_cast<RealType, forwarding_policy>(
0279                result,
0280                "boost::math::non_central_beta_cdf<%1%>(%1%, %1%, %1%)");
0281          }
0282 
0283          template <class T, class Policy>
0284          struct nc_beta_quantile_functor
0285          {
0286             nc_beta_quantile_functor(const non_central_beta_distribution<T,Policy>& d, T t, bool c)
0287                : dist(d), target(t), comp(c) {}
0288 
0289             T operator()(const T& x)
0290             {
0291                return comp ?
0292                   T(target - cdf(complement(dist, x)))
0293                   : T(cdf(dist, x) - target);
0294             }
0295 
0296          private:
0297             non_central_beta_distribution<T,Policy> dist;
0298             T target;
0299             bool comp;
0300          };
0301 
0302          //
0303          // This is more or less a copy of bracket_and_solve_root, but
0304          // modified to search only the interval [0,1] using similar
0305          // heuristics.
0306          //
0307          template <class F, class T, class Tol, class Policy>
0308          std::pair<T, T> bracket_and_solve_root_01(F f, const T& guess, T factor, bool rising, Tol tol, std::uintmax_t& max_iter, const Policy& pol)
0309          {
0310             BOOST_MATH_STD_USING
0311                static const char* function = "boost::math::tools::bracket_and_solve_root_01<%1%>";
0312             //
0313             // Set up initial brackets:
0314             //
0315             T a = guess;
0316             T b = a;
0317             T fa = f(a);
0318             T fb = fa;
0319             //
0320             // Set up invocation count:
0321             //
0322             std::uintmax_t count = max_iter - 1;
0323 
0324             if((fa < 0) == (guess < 0 ? !rising : rising))
0325             {
0326                //
0327                // Zero is to the right of b, so walk upwards
0328                // until we find it:
0329                //
0330                while((boost::math::sign)(fb) == (boost::math::sign)(fa))
0331                {
0332                   if(count == 0)
0333                   {
0334                      b = policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", b, pol); // LCOV_EXCL_LINE
0335                      return std::make_pair(a, b);
0336                   }
0337                   //
0338                   // Heuristic: every 20 iterations we double the growth factor in case the
0339                   // initial guess was *really* bad !
0340                   //
0341                   if((max_iter - count) % 20 == 0)
0342                      factor *= 2;
0343                   //
0344                   // Now go ahead and move are guess by "factor",
0345                   // we do this by reducing 1-guess by factor:
0346                   //
0347                   a = b;
0348                   fa = fb;
0349                   b = 1 - ((1 - b) / factor);
0350                   fb = f(b);
0351                   --count;
0352                   BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count);
0353                }
0354             }
0355             else
0356             {
0357                //
0358                // Zero is to the left of a, so walk downwards
0359                // until we find it:
0360                //
0361                while((boost::math::sign)(fb) == (boost::math::sign)(fa))
0362                {
0363                   if(fabs(a) < tools::min_value<T>())
0364                   {
0365                      // Escape route just in case the answer is zero!
0366                      max_iter -= count;
0367                      max_iter += 1;
0368                      return a > 0 ? std::make_pair(T(0), T(a)) : std::make_pair(T(a), T(0));
0369                   }
0370                   if(count == 0)
0371                   {
0372                      a = policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", a, pol); // LCOV_EXCL_LINE
0373                      return std::make_pair(a, b);
0374                   }
0375                   //
0376                   // Heuristic: every 20 iterations we double the growth factor in case the
0377                   // initial guess was *really* bad !
0378                   //
0379                   if((max_iter - count) % 20 == 0)
0380                      factor *= 2;
0381                   //
0382                   // Now go ahead and move are guess by "factor":
0383                   //
0384                   b = a;
0385                   fb = fa;
0386                   a /= factor;
0387                   fa = f(a);
0388                   --count;
0389                   BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count);
0390                }
0391             }
0392             max_iter -= count;
0393             max_iter += 1;
0394             std::pair<T, T> r = toms748_solve(
0395                f,
0396                (a < 0 ? b : a),
0397                (a < 0 ? a : b),
0398                (a < 0 ? fb : fa),
0399                (a < 0 ? fa : fb),
0400                tol,
0401                count,
0402                pol);
0403             max_iter += count;
0404             BOOST_MATH_INSTRUMENT_CODE("max_iter = " << max_iter << " count = " << count);
0405             return r;
0406          }
0407 
0408          template <class RealType, class Policy>
0409          RealType nc_beta_quantile(const non_central_beta_distribution<RealType, Policy>& dist, const RealType& p, bool comp)
0410          {
0411             static const char* function = "quantile(non_central_beta_distribution<%1%>, %1%)";
0412             typedef typename policies::evaluation<RealType, Policy>::type value_type;
0413             typedef typename policies::normalise<
0414                Policy,
0415                policies::promote_float<false>,
0416                policies::promote_double<false>,
0417                policies::discrete_quantile<>,
0418                policies::assert_undefined<> >::type forwarding_policy;
0419 
0420             value_type a = dist.alpha();
0421             value_type b = dist.beta();
0422             value_type l = dist.non_centrality();
0423             value_type r;
0424             if(!beta_detail::check_alpha(
0425                function,
0426                a, &r, Policy())
0427                ||
0428             !beta_detail::check_beta(
0429                function,
0430                b, &r, Policy())
0431                ||
0432             !detail::check_non_centrality(
0433                function,
0434                l,
0435                &r,
0436                Policy())
0437                ||
0438             !detail::check_probability(
0439                function,
0440                static_cast<value_type>(p),
0441                &r,
0442                Policy()))
0443                   return static_cast<RealType>(r);
0444             //
0445             // Special cases first:
0446             //
0447             if(p == 0)
0448                return comp
0449                ? 1.0f
0450                : 0.0f;
0451             if(p == 1)
0452                return !comp
0453                ? 1.0f
0454                : 0.0f;
0455 
0456             value_type c = a + b + l / 2;
0457             value_type mean = 1 - (b / c) * (1 + l / (2 * c * c));
0458             /*
0459             //
0460             // Calculate a normal approximation to the quantile,
0461             // uses mean and variance approximations from:
0462             // Algorithm AS 310:
0463             // Computing the Non-Central Beta Distribution Function
0464             // R. Chattamvelli; R. Shanmugam
0465             // Applied Statistics, Vol. 46, No. 1. (1997), pp. 146-156.
0466             //
0467             // Unfortunately, when this is wrong it tends to be *very*
0468             // wrong, so it's disabled for now, even though it often
0469             // gets the initial guess quite close.  Probably we could
0470             // do much better by factoring in the skewness if only
0471             // we could calculate it....
0472             //
0473             value_type delta = l / 2;
0474             value_type delta2 = delta * delta;
0475             value_type delta3 = delta * delta2;
0476             value_type delta4 = delta2 * delta2;
0477             value_type G = c * (c + 1) + delta;
0478             value_type alpha = a + b;
0479             value_type alpha2 = alpha * alpha;
0480             value_type eta = (2 * alpha + 1) * (2 * alpha + 1) + 1;
0481             value_type H = 3 * alpha2 + 5 * alpha + 2;
0482             value_type F = alpha2 * (alpha + 1) + H * delta
0483                + (2 * alpha + 4) * delta2 + delta3;
0484             value_type P = (3 * alpha + 1) * (9 * alpha + 17)
0485                + 2 * alpha * (3 * alpha + 2) * (3 * alpha + 4) + 15;
0486             value_type Q = 54 * alpha2 + 162 * alpha + 130;
0487             value_type R = 6 * (6 * alpha + 11);
0488             value_type D = delta
0489                * (H * H + 2 * P * delta + Q * delta2 + R * delta3 + 9 * delta4);
0490             value_type variance = (b / G)
0491                * (1 + delta * (l * l + 3 * l + eta) / (G * G))
0492                - (b * b / F) * (1 + D / (F * F));
0493             value_type sd = sqrt(variance);
0494 
0495             value_type guess = comp
0496                ? quantile(complement(normal_distribution<RealType, Policy>(static_cast<RealType>(mean), static_cast<RealType>(sd)), p))
0497                : quantile(normal_distribution<RealType, Policy>(static_cast<RealType>(mean), static_cast<RealType>(sd)), p);
0498 
0499             if(guess >= 1)
0500                guess = mean;
0501             if(guess <= tools::min_value<value_type>())
0502                guess = mean;
0503             */
0504             value_type guess = mean;
0505             detail::nc_beta_quantile_functor<value_type, Policy>
0506                f(non_central_beta_distribution<value_type, Policy>(a, b, l), p, comp);
0507             tools::eps_tolerance<value_type> tol(policies::digits<RealType, Policy>());
0508             std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0509 
0510             std::pair<value_type, value_type> ir
0511                = bracket_and_solve_root_01(
0512                   f, guess, value_type(2.5), true, tol,
0513                   max_iter, Policy());
0514             value_type result = ir.first + (ir.second - ir.first) / 2;
0515 
0516             if(max_iter >= policies::get_max_root_iterations<Policy>())
0517             {
0518                // LCOV_EXCL_START
0519                return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
0520                   " either there is no answer to quantile of the non central beta distribution"
0521                   " or the answer is infinite.  Current best guess is %1%",
0522                   policies::checked_narrowing_cast<RealType, forwarding_policy>(
0523                      result,
0524                      function), Policy());
0525                // LCOV_EXCL_STOP
0526             }
0527             return policies::checked_narrowing_cast<RealType, forwarding_policy>(
0528                result,
0529                function);
0530          }
0531 
0532          template <class T, class Policy>
0533          T non_central_beta_pdf(T a, T b, T lam, T x, T y, const Policy& pol)
0534          {
0535             BOOST_MATH_STD_USING
0536             //
0537             // Special cases:
0538             //
0539             if((x == 0) || (y == 0))
0540                return 0;
0541             //
0542             // Variables come first:
0543             //
0544             std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0545             T errtol = boost::math::policies::get_epsilon<T, Policy>();
0546             T l2 = lam / 2;
0547             //
0548             // k is the starting point for iteration, and is the
0549             // maximum of the poisson weighting term:
0550             //
0551             long long k = lltrunc(l2);
0552             // Starting Poisson weight:
0553             T pois = gamma_p_derivative(T(k+1), l2, pol);
0554             // Starting beta term:
0555             T beta = x < y ?
0556                ibeta_derivative(a + k, b, x, pol)
0557                : ibeta_derivative(b, a + k, y, pol);
0558 
0559             while (fabs(beta * pois) < tools::min_value<T>())
0560             {
0561                if ((k == 0) || (pois == 0))
0562                   return 0;  // Nothing else we can do!
0563                //
0564                // We only get here when a+k and b are large and x is small,
0565                // in that case reduce k (bisect) until both terms are finite:
0566                //
0567                k /= 2;
0568                pois = gamma_p_derivative(T(k + 1), l2, pol);
0569                // Starting beta term:
0570                beta = x < y ?
0571                   ibeta_derivative(a + k, b, x, pol)
0572                   : ibeta_derivative(b, a + k, y, pol);
0573             }
0574 
0575 
0576             T sum = 0;
0577             T poisf(pois);
0578             T betaf(beta);
0579 
0580             //
0581             // Stable backwards recursion first:
0582             //
0583             std::uintmax_t count = k;
0584             T ratio = 0;
0585             T old_ratio = 0;
0586             for(auto i = k; i >= 0; --i)
0587             {
0588                T term = beta * pois;
0589                sum += term;
0590                ratio = fabs(term / sum);
0591                if(((ratio < errtol) && (ratio < old_ratio)) || (term == 0))
0592                {
0593                   count = k - i;
0594                   break;
0595                }
0596                ratio = old_ratio;
0597                pois *= i / l2;
0598 
0599                if (a + b + i != 1)
0600                {
0601                   beta *= (a + i - 1) / (x * (a + i + b - 1));
0602                }
0603             }
0604             old_ratio = 0;
0605             for(auto i = k + 1; ; ++i)
0606             {
0607                poisf *= l2 / i;
0608                betaf *= x * (a + b + i - 1) / (a + i - 1);
0609 
0610                T term = poisf * betaf;
0611                sum += term;
0612                ratio = fabs(term / sum);
0613                if(((ratio < errtol) && (ratio < old_ratio)) || (term == 0))
0614                {
0615                   break;
0616                }
0617                old_ratio = ratio;
0618                if(static_cast<std::uintmax_t>(count + i - k) > max_iter)
0619                {
0620                   return policies::raise_evaluation_error("pdf(non_central_beta_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol); // LCOV_EXCL_LINE
0621                }
0622             }
0623             return sum;
0624          }
0625 
0626          template <class RealType, class Policy>
0627          RealType nc_beta_pdf(const non_central_beta_distribution<RealType, Policy>& dist, const RealType& x)
0628          {
0629             BOOST_MATH_STD_USING
0630             static const char* function = "pdf(non_central_beta_distribution<%1%>, %1%)";
0631             typedef typename policies::evaluation<RealType, Policy>::type value_type;
0632             typedef typename policies::normalise<
0633                Policy,
0634                policies::promote_float<false>,
0635                policies::promote_double<false>,
0636                policies::discrete_quantile<>,
0637                policies::assert_undefined<> >::type forwarding_policy;
0638 
0639             value_type a = dist.alpha();
0640             value_type b = dist.beta();
0641             value_type l = dist.non_centrality();
0642             value_type r;
0643             if(!beta_detail::check_alpha(
0644                function,
0645                a, &r, Policy())
0646                ||
0647             !beta_detail::check_beta(
0648                function,
0649                b, &r, Policy())
0650                ||
0651             !detail::check_non_centrality(
0652                function,
0653                l,
0654                &r,
0655                Policy())
0656                ||
0657             !beta_detail::check_x(
0658                function,
0659                static_cast<value_type>(x),
0660                &r,
0661                Policy()))
0662                   return static_cast<RealType>(r);
0663 
0664             if(l == 0)
0665                return pdf(boost::math::beta_distribution<RealType, Policy>(dist.alpha(), dist.beta()), x);
0666             return policies::checked_narrowing_cast<RealType, forwarding_policy>(
0667                non_central_beta_pdf(a, b, l, static_cast<value_type>(x), value_type(1 - static_cast<value_type>(x)), forwarding_policy()),
0668                "function");
0669          }
0670 
0671          template <class T>
0672          struct hypergeometric_2F2_sum
0673          {
0674             typedef T result_type;
0675             hypergeometric_2F2_sum(T a1_, T a2_, T b1_, T b2_, T z_) : a1(a1_), a2(a2_), b1(b1_), b2(b2_), z(z_), term(1), k(0) {}
0676             T operator()()
0677             {
0678                T result = term;
0679                term *= a1 * a2 / (b1 * b2);
0680                a1 += 1;
0681                a2 += 1;
0682                b1 += 1;
0683                b2 += 1;
0684                k += 1;
0685                term /= k;
0686                term *= z;
0687                return result;
0688             }
0689             T a1, a2, b1, b2, z, term, k;
0690          };
0691 
0692          template <class T, class Policy>
0693          T hypergeometric_2F2(T a1, T a2, T b1, T b2, T z, const Policy& pol)
0694          {
0695             typedef typename policies::evaluation<T, Policy>::type value_type;
0696 
0697             const char* function = "boost::math::detail::hypergeometric_2F2<%1%>(%1%,%1%,%1%,%1%,%1%)";
0698 
0699             hypergeometric_2F2_sum<value_type> s(a1, a2, b1, b2, z);
0700             std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0701 
0702             value_type result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<value_type, Policy>(), max_iter);
0703 
0704             policies::check_series_iterations<T>(function, max_iter, pol);
0705             return policies::checked_narrowing_cast<T, Policy>(result, function);
0706          }
0707 
0708       } // namespace detail
0709 
0710       template <class RealType = double, class Policy = policies::policy<> >
0711       class non_central_beta_distribution
0712       {
0713       public:
0714          typedef RealType value_type;
0715          typedef Policy policy_type;
0716 
0717          non_central_beta_distribution(RealType a_, RealType b_, RealType lambda) : a(a_), b(b_), ncp(lambda)
0718          {
0719             const char* function = "boost::math::non_central_beta_distribution<%1%>::non_central_beta_distribution(%1%,%1%)";
0720             RealType r;
0721             beta_detail::check_alpha(
0722                function,
0723                a, &r, Policy());
0724             beta_detail::check_beta(
0725                function,
0726                b, &r, Policy());
0727             detail::check_non_centrality(
0728                function,
0729                lambda,
0730                &r,
0731                Policy());
0732          } // non_central_beta_distribution constructor.
0733 
0734          RealType alpha() const
0735          { // Private data getter function.
0736             return a;
0737          }
0738          RealType beta() const
0739          { // Private data getter function.
0740             return b;
0741          }
0742          RealType non_centrality() const
0743          { // Private data getter function.
0744             return ncp;
0745          }
0746       private:
0747          // Data member, initialized by constructor.
0748          RealType a;   // alpha.
0749          RealType b;   // beta.
0750          RealType ncp; // non-centrality parameter
0751       }; // template <class RealType, class Policy> class non_central_beta_distribution
0752 
0753       typedef non_central_beta_distribution<double> non_central_beta; // Reserved name of type double.
0754 
0755       #ifdef __cpp_deduction_guides
0756       template <class RealType>
0757       non_central_beta_distribution(RealType,RealType,RealType)->non_central_beta_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0758       #endif
0759 
0760       // Non-member functions to give properties of the distribution.
0761 
0762       template <class RealType, class Policy>
0763       inline const std::pair<RealType, RealType> range(const non_central_beta_distribution<RealType, Policy>& /* dist */)
0764       { // Range of permissible values for random variable k.
0765          using boost::math::tools::max_value;
0766          return std::pair<RealType, RealType>(static_cast<RealType>(0), static_cast<RealType>(1));
0767       }
0768 
0769       template <class RealType, class Policy>
0770       inline const std::pair<RealType, RealType> support(const non_central_beta_distribution<RealType, Policy>& /* dist */)
0771       { // Range of supported values for random variable k.
0772          // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
0773          using boost::math::tools::max_value;
0774          return std::pair<RealType, RealType>(static_cast<RealType>(0), static_cast<RealType>(1));
0775       }
0776 
0777       template <class RealType, class Policy>
0778       inline RealType mode(const non_central_beta_distribution<RealType, Policy>& dist)
0779       { // mode.
0780          static const char* function = "mode(non_central_beta_distribution<%1%> const&)";
0781 
0782          RealType a = dist.alpha();
0783          RealType b = dist.beta();
0784          RealType l = dist.non_centrality();
0785          RealType r;
0786          if(!beta_detail::check_alpha(
0787                function,
0788                a, &r, Policy())
0789                ||
0790             !beta_detail::check_beta(
0791                function,
0792                b, &r, Policy())
0793                ||
0794             !detail::check_non_centrality(
0795                function,
0796                l,
0797                &r,
0798                Policy()))
0799                   return static_cast<RealType>(r);
0800          RealType c = a + b + l / 2;
0801          RealType mean = 1 - (b / c) * (1 + l / (2 * c * c));
0802          return detail::generic_find_mode_01(
0803             dist,
0804             mean,
0805             function);
0806       }
0807 
0808       //
0809       // We don't have the necessary information to implement
0810       // these at present.  These are just disabled for now,
0811       // prototypes retained so we can fill in the blanks
0812       // later:
0813       //
0814       template <class RealType, class Policy>
0815       inline RealType mean(const non_central_beta_distribution<RealType, Policy>& dist)
0816       {
0817          BOOST_MATH_STD_USING
0818          RealType a = dist.alpha();
0819          RealType b = dist.beta();
0820          RealType d = dist.non_centrality();
0821          RealType apb = a + b;
0822          return exp(-d / 2) * a * detail::hypergeometric_2F2<RealType, Policy>(1 + a, apb, a, 1 + apb, d / 2, Policy()) / apb;
0823       } // mean
0824 
0825       template <class RealType, class Policy>
0826       inline RealType variance(const non_central_beta_distribution<RealType, Policy>& dist)
0827       { 
0828          //
0829          // Relative error of this function may be arbitrarily large... absolute
0830          // error will be small however... that's the best we can do for now.
0831          //
0832          BOOST_MATH_STD_USING
0833          RealType a = dist.alpha();
0834          RealType b = dist.beta();
0835          RealType d = dist.non_centrality();
0836          RealType apb = a + b;
0837          RealType result = detail::hypergeometric_2F2(RealType(1 + a), apb, a, RealType(1 + apb), RealType(d / 2), Policy());
0838          result *= result * -exp(-d) * a * a / (apb * apb);
0839          result += exp(-d / 2) * a * (1 + a) * detail::hypergeometric_2F2(RealType(2 + a), apb, a, RealType(2 + apb), RealType(d / 2), Policy()) / (apb * (1 + apb));
0840          return result;
0841       }
0842 
0843       // RealType standard_deviation(const non_central_beta_distribution<RealType, Policy>& dist)
0844       // standard_deviation provided by derived accessors.
0845       template <class RealType, class Policy>
0846       inline RealType skewness(const non_central_beta_distribution<RealType, Policy>& /*dist*/)
0847       { // skewness = sqrt(l).
0848          const char* function = "boost::math::non_central_beta_distribution<%1%>::skewness()";
0849          typedef typename Policy::assert_undefined_type assert_type;
0850          static_assert(assert_type::value == 0, "Assert type is undefined.");
0851 
0852          return policies::raise_evaluation_error<RealType>(function, "This function is not yet implemented, the only sensible result is %1%.", // LCOV_EXCL_LINE
0853             std::numeric_limits<RealType>::quiet_NaN(), Policy()); // infinity?  LCOV_EXCL_LINE
0854       }
0855 
0856       template <class RealType, class Policy>
0857       inline RealType kurtosis_excess(const non_central_beta_distribution<RealType, Policy>& /*dist*/)
0858       {
0859          const char* function = "boost::math::non_central_beta_distribution<%1%>::kurtosis_excess()";
0860          typedef typename Policy::assert_undefined_type assert_type;
0861          static_assert(assert_type::value == 0, "Assert type is undefined.");
0862 
0863          return policies::raise_evaluation_error<RealType>(function, "This function is not yet implemented, the only sensible result is %1%.", // LCOV_EXCL_LINE
0864             std::numeric_limits<RealType>::quiet_NaN(), Policy()); // infinity?  LCOV_EXCL_LINE
0865       } // kurtosis_excess
0866 
0867       template <class RealType, class Policy>
0868       inline RealType kurtosis(const non_central_beta_distribution<RealType, Policy>& dist)
0869       {
0870          return kurtosis_excess(dist) + 3;
0871       }
0872 
0873       template <class RealType, class Policy>
0874       inline RealType pdf(const non_central_beta_distribution<RealType, Policy>& dist, const RealType& x)
0875       { // Probability Density/Mass Function.
0876          return detail::nc_beta_pdf(dist, x);
0877       } // pdf
0878 
0879       template <class RealType, class Policy>
0880       RealType cdf(const non_central_beta_distribution<RealType, Policy>& dist, const RealType& x)
0881       {
0882          const char* function = "boost::math::non_central_beta_distribution<%1%>::cdf(%1%)";
0883             RealType a = dist.alpha();
0884             RealType b = dist.beta();
0885             RealType l = dist.non_centrality();
0886             RealType r;
0887             if(!beta_detail::check_alpha(
0888                function,
0889                a, &r, Policy())
0890                ||
0891             !beta_detail::check_beta(
0892                function,
0893                b, &r, Policy())
0894                ||
0895             !detail::check_non_centrality(
0896                function,
0897                l,
0898                &r,
0899                Policy())
0900                ||
0901             !beta_detail::check_x(
0902                function,
0903                x,
0904                &r,
0905                Policy()))
0906                   return static_cast<RealType>(r);
0907 
0908          if(l == 0)
0909             return cdf(beta_distribution<RealType, Policy>(a, b), x);
0910 
0911          return detail::non_central_beta_cdf(x, RealType(1 - x), a, b, l, false, Policy());
0912       } // cdf
0913 
0914       template <class RealType, class Policy>
0915       RealType cdf(const complemented2_type<non_central_beta_distribution<RealType, Policy>, RealType>& c)
0916       { // Complemented Cumulative Distribution Function
0917          const char* function = "boost::math::non_central_beta_distribution<%1%>::cdf(%1%)";
0918          non_central_beta_distribution<RealType, Policy> const& dist = c.dist;
0919             RealType a = dist.alpha();
0920             RealType b = dist.beta();
0921             RealType l = dist.non_centrality();
0922             RealType x = c.param;
0923             RealType r;
0924             if(!beta_detail::check_alpha(
0925                function,
0926                a, &r, Policy())
0927                ||
0928             !beta_detail::check_beta(
0929                function,
0930                b, &r, Policy())
0931                ||
0932             !detail::check_non_centrality(
0933                function,
0934                l,
0935                &r,
0936                Policy())
0937                ||
0938             !beta_detail::check_x(
0939                function,
0940                x,
0941                &r,
0942                Policy()))
0943                   return static_cast<RealType>(r);
0944 
0945          if(l == 0)
0946             return cdf(complement(beta_distribution<RealType, Policy>(a, b), x));
0947 
0948          return detail::non_central_beta_cdf(x, RealType(1 - x), a, b, l, true, Policy());
0949       } // ccdf
0950 
0951       template <class RealType, class Policy>
0952       inline RealType quantile(const non_central_beta_distribution<RealType, Policy>& dist, const RealType& p)
0953       { // Quantile (or Percent Point) function.
0954          return detail::nc_beta_quantile(dist, p, false);
0955       } // quantile
0956 
0957       template <class RealType, class Policy>
0958       inline RealType quantile(const complemented2_type<non_central_beta_distribution<RealType, Policy>, RealType>& c)
0959       { // Quantile (or Percent Point) function.
0960          return detail::nc_beta_quantile(c.dist, c.param, true);
0961       } // quantile complement.
0962 
0963    } // namespace math
0964 } // namespace boost
0965 
0966 // This include must be at the end, *after* the accessors
0967 // for this distribution have been defined, in order to
0968 // keep compilers that support two-phase lookup happy.
0969 #include <boost/math/distributions/detail/derived_accessors.hpp>
0970 
0971 #endif // BOOST_MATH_SPECIAL_NON_CENTRAL_BETA_HPP
0972