File indexing completed on 2025-01-18 09:39:39
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef BOOST_MATH_DISTRIBUTIONS_CHI_SQUARED_HPP
0010 #define BOOST_MATH_DISTRIBUTIONS_CHI_SQUARED_HPP
0011
0012 #include <boost/math/distributions/fwd.hpp>
0013 #include <boost/math/special_functions/gamma.hpp> // for incomplete beta.
0014 #include <boost/math/distributions/complement.hpp> // complements
0015 #include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
0016 #include <boost/math/special_functions/fpclassify.hpp>
0017
0018 #include <utility>
0019
0020 namespace boost{ namespace math{
0021
0022 template <class RealType = double, class Policy = policies::policy<> >
0023 class chi_squared_distribution
0024 {
0025 public:
0026 using value_type = RealType;
0027 using policy_type = Policy;
0028
0029 explicit chi_squared_distribution(RealType i) : m_df(i)
0030 {
0031 RealType result;
0032 detail::check_df(
0033 "boost::math::chi_squared_distribution<%1%>::chi_squared_distribution", m_df, &result, Policy());
0034 }
0035
0036 RealType degrees_of_freedom()const
0037 {
0038 return m_df;
0039 }
0040
0041
0042 static RealType find_degrees_of_freedom(
0043 RealType difference_from_variance,
0044 RealType alpha,
0045 RealType beta,
0046 RealType variance,
0047 RealType hint = 100);
0048
0049 private:
0050
0051
0052
0053 RealType m_df;
0054 };
0055
0056 using chi_squared = chi_squared_distribution<double>;
0057
0058 #ifdef __cpp_deduction_guides
0059 template <class RealType>
0060 chi_squared_distribution(RealType)->chi_squared_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0061 #endif
0062
0063 #ifdef _MSC_VER
0064 #pragma warning(push)
0065 #pragma warning(disable:4127)
0066 #endif
0067
0068 template <class RealType, class Policy>
0069 inline std::pair<RealType, RealType> range(const chi_squared_distribution<RealType, Policy>& )
0070 {
0071 if (std::numeric_limits<RealType>::has_infinity)
0072 {
0073 return std::pair<RealType, RealType>(static_cast<RealType>(0), std::numeric_limits<RealType>::infinity());
0074 }
0075 else
0076 {
0077 using boost::math::tools::max_value;
0078 return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
0079 }
0080 }
0081
0082 #ifdef _MSC_VER
0083 #pragma warning(pop)
0084 #endif
0085
0086 template <class RealType, class Policy>
0087 inline std::pair<RealType, RealType> support(const chi_squared_distribution<RealType, Policy>& )
0088 {
0089
0090 return std::pair<RealType, RealType>(static_cast<RealType>(0), tools::max_value<RealType>());
0091 }
0092
0093 template <class RealType, class Policy>
0094 RealType pdf(const chi_squared_distribution<RealType, Policy>& dist, const RealType& chi_square)
0095 {
0096 BOOST_MATH_STD_USING
0097 RealType degrees_of_freedom = dist.degrees_of_freedom();
0098
0099 RealType error_result;
0100
0101 static const char* function = "boost::math::pdf(const chi_squared_distribution<%1%>&, %1%)";
0102
0103 if(false == detail::check_df(
0104 function, degrees_of_freedom, &error_result, Policy()))
0105 return error_result;
0106
0107 if((chi_square < 0) || !(boost::math::isfinite)(chi_square))
0108 {
0109 return policies::raise_domain_error<RealType>(
0110 function, "Chi Square parameter was %1%, but must be > 0 !", chi_square, Policy());
0111 }
0112
0113 if(chi_square == 0)
0114 {
0115
0116 if(degrees_of_freedom < 2)
0117 {
0118 return policies::raise_overflow_error<RealType>(
0119 function, 0, Policy());
0120 }
0121 else if(degrees_of_freedom == 2)
0122 {
0123 return 0.5f;
0124 }
0125 else
0126 {
0127 return 0;
0128 }
0129 }
0130
0131 return gamma_p_derivative(degrees_of_freedom / 2, chi_square / 2, Policy()) / 2;
0132 }
0133
0134 template <class RealType, class Policy>
0135 inline RealType cdf(const chi_squared_distribution<RealType, Policy>& dist, const RealType& chi_square)
0136 {
0137 RealType degrees_of_freedom = dist.degrees_of_freedom();
0138
0139 RealType error_result;
0140 static const char* function = "boost::math::cdf(const chi_squared_distribution<%1%>&, %1%)";
0141
0142 if(false == detail::check_df(
0143 function, degrees_of_freedom, &error_result, Policy()))
0144 return error_result;
0145
0146 if((chi_square < 0) || !(boost::math::isfinite)(chi_square))
0147 {
0148 return policies::raise_domain_error<RealType>(
0149 function, "Chi Square parameter was %1%, but must be > 0 !", chi_square, Policy());
0150 }
0151
0152 return boost::math::gamma_p(degrees_of_freedom / 2, chi_square / 2, Policy());
0153 }
0154
0155 template <class RealType, class Policy>
0156 inline RealType quantile(const chi_squared_distribution<RealType, Policy>& dist, const RealType& p)
0157 {
0158 RealType degrees_of_freedom = dist.degrees_of_freedom();
0159 static const char* function = "boost::math::quantile(const chi_squared_distribution<%1%>&, %1%)";
0160
0161 RealType error_result;
0162 if(false ==
0163 (
0164 detail::check_df(function, degrees_of_freedom, &error_result, Policy())
0165 && detail::check_probability(function, p, &error_result, Policy()))
0166 )
0167 return error_result;
0168
0169 return 2 * boost::math::gamma_p_inv(degrees_of_freedom / 2, p, Policy());
0170 }
0171
0172 template <class RealType, class Policy>
0173 inline RealType cdf(const complemented2_type<chi_squared_distribution<RealType, Policy>, RealType>& c)
0174 {
0175 RealType const& degrees_of_freedom = c.dist.degrees_of_freedom();
0176 RealType const& chi_square = c.param;
0177 static const char* function = "boost::math::cdf(const chi_squared_distribution<%1%>&, %1%)";
0178
0179 RealType error_result;
0180 if(false == detail::check_df(
0181 function, degrees_of_freedom, &error_result, Policy()))
0182 return error_result;
0183
0184 if((chi_square < 0) || !(boost::math::isfinite)(chi_square))
0185 {
0186 return policies::raise_domain_error<RealType>(
0187 function, "Chi Square parameter was %1%, but must be > 0 !", chi_square, Policy());
0188 }
0189
0190 return boost::math::gamma_q(degrees_of_freedom / 2, chi_square / 2, Policy());
0191 }
0192
0193 template <class RealType, class Policy>
0194 inline RealType quantile(const complemented2_type<chi_squared_distribution<RealType, Policy>, RealType>& c)
0195 {
0196 RealType const& degrees_of_freedom = c.dist.degrees_of_freedom();
0197 RealType const& q = c.param;
0198 static const char* function = "boost::math::quantile(const chi_squared_distribution<%1%>&, %1%)";
0199
0200 RealType error_result;
0201 if(false == (
0202 detail::check_df(function, degrees_of_freedom, &error_result, Policy())
0203 && detail::check_probability(function, q, &error_result, Policy()))
0204 )
0205 return error_result;
0206
0207 return 2 * boost::math::gamma_q_inv(degrees_of_freedom / 2, q, Policy());
0208 }
0209
0210 template <class RealType, class Policy>
0211 inline RealType mean(const chi_squared_distribution<RealType, Policy>& dist)
0212 {
0213 return dist.degrees_of_freedom();
0214 }
0215
0216 template <class RealType, class Policy>
0217 inline RealType variance(const chi_squared_distribution<RealType, Policy>& dist)
0218 {
0219 return 2 * dist.degrees_of_freedom();
0220 }
0221
0222 template <class RealType, class Policy>
0223 inline RealType mode(const chi_squared_distribution<RealType, Policy>& dist)
0224 {
0225 RealType df = dist.degrees_of_freedom();
0226 static const char* function = "boost::math::mode(const chi_squared_distribution<%1%>&)";
0227
0228 if(df < 2)
0229 return policies::raise_domain_error<RealType>(
0230 function,
0231 "Chi-Squared distribution only has a mode for degrees of freedom >= 2, but got degrees of freedom = %1%.",
0232 df, Policy());
0233 return df - 2;
0234 }
0235
0236 template <class RealType, class Policy>
0237 inline RealType skewness(const chi_squared_distribution<RealType, Policy>& dist)
0238 {
0239 BOOST_MATH_STD_USING
0240 RealType df = dist.degrees_of_freedom();
0241 return sqrt (8 / df);
0242 }
0243
0244 template <class RealType, class Policy>
0245 inline RealType kurtosis(const chi_squared_distribution<RealType, Policy>& dist)
0246 {
0247 RealType df = dist.degrees_of_freedom();
0248 return 3 + 12 / df;
0249 }
0250
0251 template <class RealType, class Policy>
0252 inline RealType kurtosis_excess(const chi_squared_distribution<RealType, Policy>& dist)
0253 {
0254 RealType df = dist.degrees_of_freedom();
0255 return 12 / df;
0256 }
0257
0258
0259
0260
0261 namespace detail
0262 {
0263
0264 template <class RealType, class Policy>
0265 struct df_estimator
0266 {
0267 df_estimator(RealType a, RealType b, RealType variance, RealType delta)
0268 : alpha(a), beta(b), ratio(delta/variance)
0269 {
0270 }
0271
0272 RealType operator()(const RealType& df)
0273 {
0274 if(df <= tools::min_value<RealType>())
0275 return 1;
0276 chi_squared_distribution<RealType, Policy> cs(df);
0277
0278 RealType result;
0279 if(ratio > 0)
0280 {
0281 RealType r = 1 + ratio;
0282 result = cdf(cs, quantile(complement(cs, alpha)) / r) - beta;
0283 }
0284 else
0285 {
0286 RealType r = 1 + ratio;
0287 result = cdf(complement(cs, quantile(cs, alpha) / r)) - beta;
0288 }
0289 return result;
0290 }
0291 private:
0292 RealType alpha;
0293 RealType beta;
0294 RealType ratio;
0295 };
0296
0297 }
0298
0299 template <class RealType, class Policy>
0300 RealType chi_squared_distribution<RealType, Policy>::find_degrees_of_freedom(
0301 RealType difference_from_variance,
0302 RealType alpha,
0303 RealType beta,
0304 RealType variance,
0305 RealType hint)
0306 {
0307 static const char* function = "boost::math::chi_squared_distribution<%1%>::find_degrees_of_freedom(%1%,%1%,%1%,%1%,%1%)";
0308
0309 RealType error_result;
0310 if(false ==
0311 detail::check_probability(function, alpha, &error_result, Policy())
0312 && detail::check_probability(function, beta, &error_result, Policy()))
0313 {
0314 return error_result;
0315 }
0316
0317 if(hint <= 0)
0318 {
0319 hint = 1;
0320 }
0321
0322 detail::df_estimator<RealType, Policy> f(alpha, beta, variance, difference_from_variance);
0323 tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
0324 std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0325 std::pair<RealType, RealType> r =
0326 tools::bracket_and_solve_root(f, hint, RealType(2), false, tol, max_iter, Policy());
0327 RealType result = r.first + (r.second - r.first) / 2;
0328 if(max_iter >= policies::get_max_root_iterations<Policy>())
0329 {
0330 policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
0331 " either there is no answer to how many degrees of freedom are required"
0332 " or the answer is infinite. Current best guess is %1%", result, Policy());
0333 }
0334 return result;
0335 }
0336
0337 }
0338 }
0339
0340
0341
0342
0343 #include <boost/math/distributions/detail/derived_accessors.hpp>
0344
0345 #endif