File indexing completed on 2025-11-01 08:22:07
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_MATH_SPECIAL_NON_CENTRAL_CHI_SQUARE_HPP
0011 #define BOOST_MATH_SPECIAL_NON_CENTRAL_CHI_SQUARE_HPP
0012
0013 #include <boost/math/tools/config.hpp>
0014 #include <boost/math/tools/tuple.hpp>
0015 #include <boost/math/tools/cstdint.hpp>
0016 #include <boost/math/tools/numeric_limits.hpp>
0017 #include <boost/math/distributions/fwd.hpp>
0018 #include <boost/math/special_functions/gamma.hpp> // for incomplete gamma. gamma_q
0019 #include <boost/math/special_functions/bessel.hpp> // for cyl_bessel_i
0020 #include <boost/math/special_functions/round.hpp> // for llround
0021 #include <boost/math/distributions/complement.hpp> // complements
0022 #include <boost/math/distributions/chi_squared.hpp> // central distribution
0023 #include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
0024 #include <boost/math/special_functions/fpclassify.hpp> // isnan.
0025 #include <boost/math/tools/roots.hpp> // for root finding.
0026 #include <boost/math/distributions/detail/generic_mode.hpp>
0027 #include <boost/math/distributions/detail/generic_quantile.hpp>
0028 #include <boost/math/policies/policy.hpp>
0029
0030 namespace boost
0031 {
0032 namespace math
0033 {
0034
0035 template <class RealType, class Policy>
0036 class non_central_chi_squared_distribution;
0037
0038 namespace detail{
0039
0040 template <class T, class Policy>
0041 BOOST_MATH_GPU_ENABLED T non_central_chi_square_q(T x, T f, T theta, const Policy& pol, T init_sum = 0)
0042 {
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058 BOOST_MATH_STD_USING
0059
0060
0061 if(x == 0)
0062 return 1;
0063
0064
0065
0066
0067 T lambda = theta / 2;
0068 T del = f / 2;
0069 T y = x / 2;
0070 boost::math::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0071 T errtol = boost::math::policies::get_epsilon<T, Policy>();
0072 T sum = init_sum;
0073
0074
0075
0076
0077
0078
0079 long long k = llround(lambda, pol);
0080
0081 T poisf = boost::math::gamma_p_derivative(static_cast<T>(1 + k), lambda, pol);
0082 T poisb = poisf * k / lambda;
0083
0084 T gamf = boost::math::gamma_q(del + k, y, pol);
0085
0086 T xtermf = boost::math::gamma_p_derivative(del + 1 + k, y, pol);
0087 T xtermb = xtermf * (del + k) / y;
0088
0089 T gamb = gamf - xtermb;
0090
0091
0092
0093
0094
0095
0096 long long i;
0097 for(i = k; static_cast<boost::math::uintmax_t>(i-k) < max_iter; ++i)
0098 {
0099 T term = poisf * gamf;
0100 sum += term;
0101 poisf *= lambda / (i + 1);
0102 gamf += xtermf;
0103 xtermf *= y / (del + i + 1);
0104 if(((sum == 0) || (fabs(term / sum) < errtol)) && (term >= poisf * gamf))
0105 break;
0106 }
0107
0108 if(static_cast<boost::math::uintmax_t>(i-k) >= max_iter)
0109 return policies::raise_evaluation_error("cdf(non_central_chi_squared_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol);
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119 for(i = k - 1; i >= 0; --i)
0120 {
0121 T term = poisb * gamb;
0122 sum += term;
0123 poisb *= i / lambda;
0124 xtermb *= (del + i) / y;
0125 gamb -= xtermb;
0126 if((sum == 0) || (fabs(term / sum) < errtol))
0127 break;
0128 }
0129
0130 return sum;
0131 }
0132
0133 template <class T, class Policy>
0134 BOOST_MATH_GPU_ENABLED T non_central_chi_square_p_ding(T x, T f, T theta, const Policy& pol, T init_sum = 0)
0135 {
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151 BOOST_MATH_STD_USING
0152
0153 if(x == 0)
0154 return 0;
0155 T tk = boost::math::gamma_p_derivative(f/2 + 1, x/2, pol);
0156 T lambda = theta / 2;
0157 T vk = exp(-lambda);
0158 T uk = vk;
0159 T sum = init_sum + tk * vk;
0160 if(sum == 0)
0161 return sum;
0162
0163 boost::math::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0164 T errtol = boost::math::policies::get_epsilon<T, Policy>();
0165
0166 int i;
0167 T lterm(0), term(0);
0168 for(i = 1; static_cast<boost::math::uintmax_t>(i) < max_iter; ++i)
0169 {
0170 tk = tk * x / (f + 2 * i);
0171 uk = uk * lambda / i;
0172 vk = vk + uk;
0173 lterm = term;
0174 term = vk * tk;
0175 sum += term;
0176 if((fabs(term / sum) < errtol) && (term <= lterm))
0177 break;
0178 }
0179
0180 if(static_cast<boost::math::uintmax_t>(i) >= max_iter)
0181 return policies::raise_evaluation_error("cdf(non_central_chi_squared_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol);
0182 return sum;
0183 }
0184
0185
0186 template <class T, class Policy>
0187 BOOST_MATH_GPU_ENABLED T non_central_chi_square_p(T y, T n, T lambda, const Policy& pol, T init_sum)
0188 {
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202 BOOST_MATH_STD_USING
0203
0204 if(y == 0)
0205 return 0;
0206 boost::math::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0207 T errtol = boost::math::policies::get_epsilon<T, Policy>();
0208 T errorf(0), errorb(0);
0209
0210 T x = y / 2;
0211 T del = lambda / 2;
0212
0213
0214
0215
0216
0217
0218
0219 long long k = llround(del, pol);
0220 T a = n / 2 + k;
0221
0222 T gamkf = boost::math::gamma_p(a, x, pol);
0223
0224 if(lambda == 0)
0225 return gamkf;
0226
0227 T gamkb = gamkf;
0228
0229 T poiskf = gamma_p_derivative(static_cast<T>(k+1), del, pol);
0230
0231 T poiskb = poiskf;
0232
0233 T xtermf = boost::math::gamma_p_derivative(a, x, pol);
0234
0235 T xtermb = xtermf * x / a;
0236 T sum = init_sum + poiskf * gamkf;
0237 if(sum == 0)
0238 return sum;
0239 int i = 1;
0240
0241
0242
0243
0244 while(i <= k)
0245 {
0246 xtermb *= (a - i + 1) / x;
0247 gamkb += xtermb;
0248 poiskb = poiskb * (k - i + 1) / del;
0249 errorf = errorb;
0250 errorb = gamkb * poiskb;
0251 sum += errorb;
0252 if((fabs(errorb / sum) < errtol) && (errorb <= errorf))
0253 break;
0254 ++i;
0255 }
0256 i = 1;
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266 do
0267 {
0268 xtermf = xtermf * x / (a + i - 1);
0269 gamkf = gamkf - xtermf;
0270 poiskf = poiskf * del / (k + i);
0271 errorf = poiskf * gamkf;
0272 sum += errorf;
0273 ++i;
0274 }while((fabs(errorf / sum) > errtol) && (static_cast<boost::math::uintmax_t>(i) < max_iter));
0275
0276
0277 if(static_cast<boost::math::uintmax_t>(i) >= max_iter)
0278 return policies::raise_evaluation_error("cdf(non_central_chi_squared_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol);
0279
0280 return sum;
0281 }
0282
0283 template <class T, class Policy>
0284 BOOST_MATH_GPU_ENABLED T non_central_chi_square_pdf(T x, T n, T lambda, const Policy& pol)
0285 {
0286
0287
0288
0289 BOOST_MATH_STD_USING
0290 boost::math::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0291 T errtol = boost::math::policies::get_epsilon<T, Policy>();
0292 T x2 = x / 2;
0293 T n2 = n / 2;
0294 T l2 = lambda / 2;
0295 T sum = 0;
0296 long long k = lltrunc(l2);
0297 T pois = gamma_p_derivative(static_cast<T>(k + 1), l2, pol) * gamma_p_derivative(static_cast<T>(n2 + k), x2);
0298 if(pois == 0)
0299 return 0;
0300 T poisb = pois;
0301 for(long long i = k; ; ++i)
0302 {
0303 sum += pois;
0304 if(pois / sum < errtol)
0305 break;
0306 if(static_cast<boost::math::uintmax_t>(i - k) >= max_iter)
0307 return policies::raise_evaluation_error("pdf(non_central_chi_squared_distribution<%1%>, %1%)", "Series did not converge, closest value was %1%", sum, pol);
0308 pois *= l2 * x2 / ((i + 1) * (n2 + i));
0309 }
0310 for(long long i = k - 1; i >= 0; --i)
0311 {
0312 poisb *= (i + 1) * (n2 + i) / (l2 * x2);
0313 sum += poisb;
0314 if(poisb / sum < errtol)
0315 break;
0316 }
0317 return sum / 2;
0318 }
0319
0320 template <class RealType, class Policy>
0321 BOOST_MATH_GPU_ENABLED inline RealType non_central_chi_squared_cdf(RealType x, RealType k, RealType l, bool invert, const Policy&)
0322 {
0323 typedef typename policies::evaluation<RealType, Policy>::type value_type;
0324 typedef typename policies::normalise<
0325 Policy,
0326 policies::promote_float<false>,
0327 policies::promote_double<false>,
0328 policies::discrete_quantile<>,
0329 policies::assert_undefined<> >::type forwarding_policy;
0330
0331 BOOST_MATH_STD_USING
0332 value_type result;
0333 if(l == 0)
0334 return invert == false ? cdf(boost::math::chi_squared_distribution<RealType, Policy>(k), x) : cdf(complement(boost::math::chi_squared_distribution<RealType, Policy>(k), x));
0335 else if(x > k + l)
0336 {
0337
0338 result = detail::non_central_chi_square_q(
0339 static_cast<value_type>(x),
0340 static_cast<value_type>(k),
0341 static_cast<value_type>(l),
0342 forwarding_policy(),
0343 static_cast<value_type>(invert ? 0 : -1));
0344 invert = !invert;
0345 }
0346 else if(l < 200)
0347 {
0348
0349
0350 result = detail::non_central_chi_square_p_ding(
0351 static_cast<value_type>(x),
0352 static_cast<value_type>(k),
0353 static_cast<value_type>(l),
0354 forwarding_policy(),
0355 static_cast<value_type>(invert ? -1 : 0));
0356 }
0357 else
0358 {
0359
0360
0361
0362
0363
0364 result = detail::non_central_chi_square_p(
0365 static_cast<value_type>(x),
0366 static_cast<value_type>(k),
0367 static_cast<value_type>(l),
0368 forwarding_policy(),
0369 static_cast<value_type>(invert ? -1 : 0));
0370 }
0371 if(invert)
0372 result = -result;
0373 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
0374 result,
0375 "boost::math::non_central_chi_squared_cdf<%1%>(%1%, %1%, %1%)");
0376 }
0377
0378 template <class T, class Policy>
0379 struct nccs_quantile_functor
0380 {
0381 BOOST_MATH_GPU_ENABLED nccs_quantile_functor(const non_central_chi_squared_distribution<T,Policy>& d, T t, bool c)
0382 : dist(d), target(t), comp(c) {}
0383
0384 BOOST_MATH_GPU_ENABLED T operator()(const T& x)
0385 {
0386 return comp ?
0387 target - cdf(complement(dist, x))
0388 : cdf(dist, x) - target;
0389 }
0390
0391 private:
0392 non_central_chi_squared_distribution<T,Policy> dist;
0393 T target;
0394 bool comp;
0395 };
0396
0397 template <class RealType, class Policy>
0398 BOOST_MATH_GPU_ENABLED RealType nccs_quantile(const non_central_chi_squared_distribution<RealType, Policy>& dist, const RealType& p, bool comp)
0399 {
0400 BOOST_MATH_STD_USING
0401 constexpr auto function = "quantile(non_central_chi_squared_distribution<%1%>, %1%)";
0402 typedef typename policies::evaluation<RealType, Policy>::type value_type;
0403 typedef typename policies::normalise<
0404 Policy,
0405 policies::promote_float<false>,
0406 policies::promote_double<false>,
0407 policies::discrete_quantile<>,
0408 policies::assert_undefined<> >::type forwarding_policy;
0409
0410 value_type k = dist.degrees_of_freedom();
0411 value_type l = dist.non_centrality();
0412 value_type r;
0413 if(!detail::check_df(
0414 function,
0415 k, &r, Policy())
0416 ||
0417 !detail::check_non_centrality(
0418 function,
0419 l,
0420 &r,
0421 Policy())
0422 ||
0423 !detail::check_probability(
0424 function,
0425 static_cast<value_type>(p),
0426 &r,
0427 Policy()))
0428 return static_cast<RealType>(r);
0429
0430
0431
0432 if(p == 0)
0433 return comp ? policies::raise_overflow_error<RealType>(function, 0, Policy()) : 0;
0434 if(p == 1)
0435 return comp ? 0 : policies::raise_overflow_error<RealType>(function, 0, Policy());
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445 value_type b = -(l * l) / (k + 3 * l);
0446 value_type c = (k + 3 * l) / (k + 2 * l);
0447 value_type ff = (k + 2 * l) / (c * c);
0448 value_type guess;
0449 if(comp)
0450 {
0451 guess = b + c * quantile(complement(chi_squared_distribution<value_type, forwarding_policy>(ff), p));
0452 }
0453 else
0454 {
0455 guess = b + c * quantile(chi_squared_distribution<value_type, forwarding_policy>(ff), p);
0456 }
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466
0467
0468 if(guess < 0.005)
0469 {
0470 value_type pp = comp ? 1 - p : p;
0471
0472 guess = pow(pow(value_type(2), (k / 2 - 1)) * exp(l / 2) * pp * k * boost::math::tgamma(k / 2, forwarding_policy()), (2 / k));
0473 if(guess == 0)
0474 guess = tools::min_value<value_type>();
0475 }
0476 value_type result = detail::generic_quantile(
0477 non_central_chi_squared_distribution<value_type, forwarding_policy>(k, l),
0478 p,
0479 guess,
0480 comp,
0481 function);
0482
0483 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
0484 result,
0485 function);
0486 }
0487
0488 template <class RealType, class Policy>
0489 BOOST_MATH_GPU_ENABLED RealType nccs_pdf(const non_central_chi_squared_distribution<RealType, Policy>& dist, const RealType& x)
0490 {
0491 BOOST_MATH_STD_USING
0492 constexpr auto function = "pdf(non_central_chi_squared_distribution<%1%>, %1%)";
0493 typedef typename policies::evaluation<RealType, Policy>::type value_type;
0494 typedef typename policies::normalise<
0495 Policy,
0496 policies::promote_float<false>,
0497 policies::promote_double<false>,
0498 policies::discrete_quantile<>,
0499 policies::assert_undefined<> >::type forwarding_policy;
0500
0501 value_type k = dist.degrees_of_freedom();
0502 value_type l = dist.non_centrality();
0503 value_type r;
0504 if(!detail::check_df(
0505 function,
0506 k, &r, Policy())
0507 ||
0508 !detail::check_non_centrality(
0509 function,
0510 l,
0511 &r,
0512 Policy())
0513 ||
0514 !detail::check_positive_x(
0515 function,
0516 (value_type)x,
0517 &r,
0518 Policy()))
0519 return static_cast<RealType>(r);
0520
0521 if(l == 0)
0522 return pdf(boost::math::chi_squared_distribution<RealType, forwarding_policy>(dist.degrees_of_freedom()), x);
0523
0524
0525 if(x == 0)
0526 return 0;
0527 if(l > 50)
0528 {
0529 r = non_central_chi_square_pdf(static_cast<value_type>(x), k, l, forwarding_policy());
0530 }
0531 else
0532 {
0533 r = log(x / l) * (k / 4 - 0.5f) - (x + l) / 2;
0534 if(fabs(r) >= tools::log_max_value<RealType>() / 4)
0535 {
0536 r = non_central_chi_square_pdf(static_cast<value_type>(x), k, l, forwarding_policy());
0537 }
0538 else
0539 {
0540 r = exp(r);
0541 r = 0.5f * r
0542 * boost::math::cyl_bessel_i(k/2 - 1, sqrt(l * x), forwarding_policy());
0543 }
0544 }
0545 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
0546 r,
0547 function);
0548 }
0549
0550 template <class RealType, class Policy>
0551 struct degrees_of_freedom_finder
0552 {
0553 BOOST_MATH_GPU_ENABLED degrees_of_freedom_finder(
0554 RealType lam_, RealType x_, RealType p_, bool c)
0555 : lam(lam_), x(x_), p(p_), comp(c) {}
0556
0557 BOOST_MATH_GPU_ENABLED RealType operator()(const RealType& v)
0558 {
0559 non_central_chi_squared_distribution<RealType, Policy> d(v, lam);
0560 return comp ?
0561 RealType(p - cdf(complement(d, x)))
0562 : RealType(cdf(d, x) - p);
0563 }
0564 private:
0565 RealType lam;
0566 RealType x;
0567 RealType p;
0568 bool comp;
0569 };
0570
0571 template <class RealType, class Policy>
0572 BOOST_MATH_GPU_ENABLED inline RealType find_degrees_of_freedom(
0573 RealType lam, RealType x, RealType p, RealType q, const Policy& pol)
0574 {
0575 constexpr auto function = "non_central_chi_squared<%1%>::find_degrees_of_freedom";
0576 if((p == 0) || (q == 0))
0577 {
0578
0579
0580
0581 return policies::raise_evaluation_error<RealType>(function, "Can't find degrees of freedom when the probability is 0 or 1, only possible answer is %1%",
0582 RealType(boost::math::numeric_limits<RealType>::quiet_NaN()), Policy());
0583 }
0584 degrees_of_freedom_finder<RealType, Policy> f(lam, x, p < q ? p : q, p < q ? false : true);
0585 tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
0586 boost::math::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0587
0588
0589
0590
0591 RealType guess = x - lam;
0592 if(guess < 1)
0593 guess = 1;
0594 boost::math::pair<RealType, RealType> ir = tools::bracket_and_solve_root(
0595 f, guess, RealType(2), false, tol, max_iter, pol);
0596 RealType result = ir.first + (ir.second - ir.first) / 2;
0597 if(max_iter >= policies::get_max_root_iterations<Policy>())
0598 {
0599 return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
0600 " or there is no answer to problem. Current best guess is %1%", result, Policy());
0601 }
0602 return result;
0603 }
0604
0605 template <class RealType, class Policy>
0606 struct non_centrality_finder
0607 {
0608 BOOST_MATH_GPU_ENABLED non_centrality_finder(
0609 RealType v_, RealType x_, RealType p_, bool c)
0610 : v(v_), x(x_), p(p_), comp(c) {}
0611
0612 BOOST_MATH_GPU_ENABLED RealType operator()(const RealType& lam)
0613 {
0614 non_central_chi_squared_distribution<RealType, Policy> d(v, lam);
0615 return comp ?
0616 RealType(p - cdf(complement(d, x)))
0617 : RealType(cdf(d, x) - p);
0618 }
0619 private:
0620 RealType v;
0621 RealType x;
0622 RealType p;
0623 bool comp;
0624 };
0625
0626 template <class RealType, class Policy>
0627 BOOST_MATH_GPU_ENABLED inline RealType find_non_centrality(
0628 RealType v, RealType x, RealType p, RealType q, const Policy& pol)
0629 {
0630 constexpr auto function = "non_central_chi_squared<%1%>::find_non_centrality";
0631 if((p == 0) || (q == 0))
0632 {
0633
0634
0635
0636 return policies::raise_evaluation_error<RealType>(function, "Can't find non centrality parameter when the probability is 0 or 1, only possible answer is %1%",
0637 RealType(boost::math::numeric_limits<RealType>::quiet_NaN()), Policy());
0638 }
0639 non_centrality_finder<RealType, Policy> f(v, x, p < q ? p : q, p < q ? false : true);
0640 tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
0641 boost::math::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0642
0643
0644
0645
0646 RealType guess = x - v;
0647 if(guess < 1)
0648 guess = 1;
0649 boost::math::pair<RealType, RealType> ir = tools::bracket_and_solve_root(
0650 f, guess, RealType(2), false, tol, max_iter, pol);
0651 RealType result = ir.first + (ir.second - ir.first) / 2;
0652 if(max_iter >= policies::get_max_root_iterations<Policy>())
0653 {
0654 return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
0655 " or there is no answer to problem. Current best guess is %1%", result, Policy());
0656 }
0657 return result;
0658 }
0659
0660 }
0661
0662 template <class RealType = double, class Policy = policies::policy<> >
0663 class non_central_chi_squared_distribution
0664 {
0665 public:
0666 typedef RealType value_type;
0667 typedef Policy policy_type;
0668
0669 BOOST_MATH_GPU_ENABLED non_central_chi_squared_distribution(RealType df_, RealType lambda) : df(df_), ncp(lambda)
0670 {
0671 constexpr auto function = "boost::math::non_central_chi_squared_distribution<%1%>::non_central_chi_squared_distribution(%1%,%1%)";
0672 RealType r;
0673 detail::check_df(
0674 function,
0675 df, &r, Policy());
0676 detail::check_non_centrality(
0677 function,
0678 ncp,
0679 &r,
0680 Policy());
0681 }
0682
0683 BOOST_MATH_GPU_ENABLED RealType degrees_of_freedom() const
0684 {
0685 return df;
0686 }
0687 BOOST_MATH_GPU_ENABLED RealType non_centrality() const
0688 {
0689 return ncp;
0690 }
0691 BOOST_MATH_GPU_ENABLED static RealType find_degrees_of_freedom(RealType lam, RealType x, RealType p)
0692 {
0693 constexpr auto function = "non_central_chi_squared<%1%>::find_degrees_of_freedom";
0694 typedef typename policies::evaluation<RealType, Policy>::type eval_type;
0695 typedef typename policies::normalise<
0696 Policy,
0697 policies::promote_float<false>,
0698 policies::promote_double<false>,
0699 policies::discrete_quantile<>,
0700 policies::assert_undefined<> >::type forwarding_policy;
0701 eval_type result = detail::find_degrees_of_freedom(
0702 static_cast<eval_type>(lam),
0703 static_cast<eval_type>(x),
0704 static_cast<eval_type>(p),
0705 static_cast<eval_type>(1-p),
0706 forwarding_policy());
0707 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
0708 result,
0709 function);
0710 }
0711 template <class A, class B, class C>
0712 BOOST_MATH_GPU_ENABLED static RealType find_degrees_of_freedom(const complemented3_type<A,B,C>& c)
0713 {
0714 constexpr auto function = "non_central_chi_squared<%1%>::find_degrees_of_freedom";
0715 typedef typename policies::evaluation<RealType, Policy>::type eval_type;
0716 typedef typename policies::normalise<
0717 Policy,
0718 policies::promote_float<false>,
0719 policies::promote_double<false>,
0720 policies::discrete_quantile<>,
0721 policies::assert_undefined<> >::type forwarding_policy;
0722 eval_type result = detail::find_degrees_of_freedom(
0723 static_cast<eval_type>(c.dist),
0724 static_cast<eval_type>(c.param1),
0725 static_cast<eval_type>(1-c.param2),
0726 static_cast<eval_type>(c.param2),
0727 forwarding_policy());
0728 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
0729 result,
0730 function);
0731 }
0732 BOOST_MATH_GPU_ENABLED static RealType find_non_centrality(RealType v, RealType x, RealType p)
0733 {
0734 constexpr auto function = "non_central_chi_squared<%1%>::find_non_centrality";
0735 typedef typename policies::evaluation<RealType, Policy>::type eval_type;
0736 typedef typename policies::normalise<
0737 Policy,
0738 policies::promote_float<false>,
0739 policies::promote_double<false>,
0740 policies::discrete_quantile<>,
0741 policies::assert_undefined<> >::type forwarding_policy;
0742 eval_type result = detail::find_non_centrality(
0743 static_cast<eval_type>(v),
0744 static_cast<eval_type>(x),
0745 static_cast<eval_type>(p),
0746 static_cast<eval_type>(1-p),
0747 forwarding_policy());
0748 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
0749 result,
0750 function);
0751 }
0752 template <class A, class B, class C>
0753 BOOST_MATH_GPU_ENABLED static RealType find_non_centrality(const complemented3_type<A,B,C>& c)
0754 {
0755 constexpr auto function = "non_central_chi_squared<%1%>::find_non_centrality";
0756 typedef typename policies::evaluation<RealType, Policy>::type eval_type;
0757 typedef typename policies::normalise<
0758 Policy,
0759 policies::promote_float<false>,
0760 policies::promote_double<false>,
0761 policies::discrete_quantile<>,
0762 policies::assert_undefined<> >::type forwarding_policy;
0763 eval_type result = detail::find_non_centrality(
0764 static_cast<eval_type>(c.dist),
0765 static_cast<eval_type>(c.param1),
0766 static_cast<eval_type>(1-c.param2),
0767 static_cast<eval_type>(c.param2),
0768 forwarding_policy());
0769 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
0770 result,
0771 function);
0772 }
0773 private:
0774
0775 RealType df;
0776 RealType ncp;
0777 };
0778
0779 typedef non_central_chi_squared_distribution<double> non_central_chi_squared;
0780
0781 #ifdef __cpp_deduction_guides
0782 template <class RealType>
0783 non_central_chi_squared_distribution(RealType,RealType)->non_central_chi_squared_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0784 #endif
0785
0786
0787
0788 template <class RealType, class Policy>
0789 BOOST_MATH_GPU_ENABLED inline const boost::math::pair<RealType, RealType> range(const non_central_chi_squared_distribution<RealType, Policy>& )
0790 {
0791 using boost::math::tools::max_value;
0792 return boost::math::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
0793 }
0794
0795 template <class RealType, class Policy>
0796 BOOST_MATH_GPU_ENABLED inline const boost::math::pair<RealType, RealType> support(const non_central_chi_squared_distribution<RealType, Policy>& )
0797 {
0798
0799 using boost::math::tools::max_value;
0800 return boost::math::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
0801 }
0802
0803 template <class RealType, class Policy>
0804 BOOST_MATH_GPU_ENABLED inline RealType mean(const non_central_chi_squared_distribution<RealType, Policy>& dist)
0805 {
0806 constexpr auto function = "boost::math::non_central_chi_squared_distribution<%1%>::mean()";
0807 RealType k = dist.degrees_of_freedom();
0808 RealType l = dist.non_centrality();
0809 RealType r;
0810 if(!detail::check_df(
0811 function,
0812 k, &r, Policy())
0813 ||
0814 !detail::check_non_centrality(
0815 function,
0816 l,
0817 &r,
0818 Policy()))
0819 return static_cast<RealType>(r);
0820 return k + l;
0821 }
0822
0823 template <class RealType, class Policy>
0824 BOOST_MATH_GPU_ENABLED inline RealType mode(const non_central_chi_squared_distribution<RealType, Policy>& dist)
0825 {
0826 constexpr auto function = "mode(non_central_chi_squared_distribution<%1%> const&)";
0827
0828 RealType k = dist.degrees_of_freedom();
0829 RealType l = dist.non_centrality();
0830 RealType r;
0831 if(!detail::check_df(
0832 function,
0833 k, &r, Policy())
0834 ||
0835 !detail::check_non_centrality(
0836 function,
0837 l,
0838 &r,
0839 Policy()))
0840 return static_cast<RealType>(r);
0841 bool asymptotic_mode = k < l/4;
0842 RealType starting_point = asymptotic_mode ? k + l - RealType(3) : RealType(1) + k;
0843 return detail::generic_find_mode(dist, starting_point, function);
0844 }
0845
0846 template <class RealType, class Policy>
0847 BOOST_MATH_GPU_ENABLED inline RealType variance(const non_central_chi_squared_distribution<RealType, Policy>& dist)
0848 {
0849 constexpr auto function = "boost::math::non_central_chi_squared_distribution<%1%>::variance()";
0850 RealType k = dist.degrees_of_freedom();
0851 RealType l = dist.non_centrality();
0852 RealType r;
0853 if(!detail::check_df(
0854 function,
0855 k, &r, Policy())
0856 ||
0857 !detail::check_non_centrality(
0858 function,
0859 l,
0860 &r,
0861 Policy()))
0862 return static_cast<RealType>(r);
0863 return 2 * (2 * l + k);
0864 }
0865
0866
0867
0868
0869 template <class RealType, class Policy>
0870 BOOST_MATH_GPU_ENABLED inline RealType skewness(const non_central_chi_squared_distribution<RealType, Policy>& dist)
0871 {
0872 constexpr auto function = "boost::math::non_central_chi_squared_distribution<%1%>::skewness()";
0873 RealType k = dist.degrees_of_freedom();
0874 RealType l = dist.non_centrality();
0875 RealType r;
0876 if(!detail::check_df(
0877 function,
0878 k, &r, Policy())
0879 ||
0880 !detail::check_non_centrality(
0881 function,
0882 l,
0883 &r,
0884 Policy()))
0885 return static_cast<RealType>(r);
0886 BOOST_MATH_STD_USING
0887 return pow(2 / (k + 2 * l), RealType(3)/2) * (k + 3 * l);
0888 }
0889
0890 template <class RealType, class Policy>
0891 BOOST_MATH_GPU_ENABLED inline RealType kurtosis_excess(const non_central_chi_squared_distribution<RealType, Policy>& dist)
0892 {
0893 constexpr auto function = "boost::math::non_central_chi_squared_distribution<%1%>::kurtosis_excess()";
0894 RealType k = dist.degrees_of_freedom();
0895 RealType l = dist.non_centrality();
0896 RealType r;
0897 if(!detail::check_df(
0898 function,
0899 k, &r, Policy())
0900 ||
0901 !detail::check_non_centrality(
0902 function,
0903 l,
0904 &r,
0905 Policy()))
0906 return static_cast<RealType>(r);
0907 return 12 * (k + 4 * l) / ((k + 2 * l) * (k + 2 * l));
0908 }
0909
0910 template <class RealType, class Policy>
0911 BOOST_MATH_GPU_ENABLED inline RealType kurtosis(const non_central_chi_squared_distribution<RealType, Policy>& dist)
0912 {
0913 return kurtosis_excess(dist) + 3;
0914 }
0915
0916 template <class RealType, class Policy>
0917 BOOST_MATH_GPU_ENABLED inline RealType pdf(const non_central_chi_squared_distribution<RealType, Policy>& dist, const RealType& x)
0918 {
0919 return detail::nccs_pdf(dist, x);
0920 }
0921
0922 template <class RealType, class Policy>
0923 BOOST_MATH_GPU_ENABLED RealType cdf(const non_central_chi_squared_distribution<RealType, Policy>& dist, const RealType& x)
0924 {
0925 constexpr auto function = "boost::math::non_central_chi_squared_distribution<%1%>::cdf(%1%)";
0926 RealType k = dist.degrees_of_freedom();
0927 RealType l = dist.non_centrality();
0928 RealType r;
0929 if(!detail::check_df(
0930 function,
0931 k, &r, Policy())
0932 ||
0933 !detail::check_non_centrality(
0934 function,
0935 l,
0936 &r,
0937 Policy())
0938 ||
0939 !detail::check_positive_x(
0940 function,
0941 x,
0942 &r,
0943 Policy()))
0944 return static_cast<RealType>(r);
0945
0946 return detail::non_central_chi_squared_cdf(x, k, l, false, Policy());
0947 }
0948
0949 template <class RealType, class Policy>
0950 BOOST_MATH_GPU_ENABLED RealType cdf(const complemented2_type<non_central_chi_squared_distribution<RealType, Policy>, RealType>& c)
0951 {
0952 constexpr auto function = "boost::math::non_central_chi_squared_distribution<%1%>::cdf(%1%)";
0953 non_central_chi_squared_distribution<RealType, Policy> const& dist = c.dist;
0954 RealType x = c.param;
0955 RealType k = dist.degrees_of_freedom();
0956 RealType l = dist.non_centrality();
0957 RealType r;
0958 if(!detail::check_df(
0959 function,
0960 k, &r, Policy())
0961 ||
0962 !detail::check_non_centrality(
0963 function,
0964 l,
0965 &r,
0966 Policy())
0967 ||
0968 !detail::check_positive_x(
0969 function,
0970 x,
0971 &r,
0972 Policy()))
0973 return static_cast<RealType>(r);
0974
0975 return detail::non_central_chi_squared_cdf(x, k, l, true, Policy());
0976 }
0977
0978 template <class RealType, class Policy>
0979 BOOST_MATH_GPU_ENABLED inline RealType quantile(const non_central_chi_squared_distribution<RealType, Policy>& dist, const RealType& p)
0980 {
0981 return detail::nccs_quantile(dist, p, false);
0982 }
0983
0984 template <class RealType, class Policy>
0985 BOOST_MATH_GPU_ENABLED inline RealType quantile(const complemented2_type<non_central_chi_squared_distribution<RealType, Policy>, RealType>& c)
0986 {
0987 return detail::nccs_quantile(c.dist, c.param, true);
0988 }
0989
0990 }
0991 }
0992
0993
0994
0995
0996 #include <boost/math/distributions/detail/derived_accessors.hpp>
0997
0998 #endif