File indexing completed on 2025-07-12 08:18:15
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107 #ifndef BOOST_MATH_DISTRIBUTIONS_KOLMOGOROV_SMIRNOV_HPP
0108 #define BOOST_MATH_DISTRIBUTIONS_KOLMOGOROV_SMIRNOV_HPP
0109
0110 #include <boost/math/distributions/fwd.hpp>
0111 #include <boost/math/distributions/complement.hpp>
0112 #include <boost/math/distributions/detail/common_error_handling.hpp>
0113 #include <boost/math/special_functions/jacobi_theta.hpp>
0114 #include <boost/math/tools/tuple.hpp>
0115 #include <boost/math/tools/roots.hpp> // Newton-Raphson
0116 #include <boost/math/tools/minima.hpp> // For the mode
0117
0118 namespace boost { namespace math {
0119
0120 namespace detail {
0121 template <class RealType>
0122 inline RealType kolmogorov_smirnov_quantile_guess(RealType p) {
0123
0124 if (p > 0.9)
0125 return RealType(1.8) - 5 * (1 - p);
0126 if (p < 0.3)
0127 return p + RealType(0.45);
0128 return p + RealType(0.3);
0129 }
0130
0131
0132 template <class RealType, class Policy>
0133 RealType kolmogorov_smirnov_pdf_small_x(RealType x, RealType n, const Policy&) {
0134 BOOST_MATH_STD_USING
0135 RealType value = RealType(0), delta = RealType(0), last_delta = RealType(0);
0136 RealType eps = policies::get_epsilon<RealType, Policy>();
0137 int i = 0;
0138 RealType pi2 = constants::pi_sqr<RealType>();
0139 RealType x2n = x*x*n;
0140 if (x2n*x2n == 0.0) {
0141 return static_cast<RealType>(0);
0142 }
0143 while (true) {
0144 delta = exp(-RealType(i+0.5)*RealType(i+0.5)*pi2/(2*x2n)) * (RealType(i+0.5)*RealType(i+0.5)*pi2 - x2n);
0145
0146 if (delta == 0.0)
0147 break;
0148
0149 if (last_delta != 0.0 && fabs(delta/last_delta) < eps)
0150 break;
0151
0152 value += delta + delta;
0153 last_delta = delta;
0154 i++;
0155 }
0156
0157 return value * sqrt(n) * constants::root_half_pi<RealType>() / (x2n*x2n);
0158 }
0159
0160
0161 template <class RealType, class Policy>
0162 inline RealType kolmogorov_smirnov_pdf_large_x(RealType x, RealType n, const Policy&) {
0163 BOOST_MATH_STD_USING
0164 RealType value = RealType(0), delta = RealType(0), last_delta = RealType(0);
0165 RealType eps = policies::get_epsilon<RealType, Policy>();
0166 int i = 1;
0167 while (true) {
0168 delta = 8*x*i*i*exp(-2*i*i*x*x*n);
0169
0170 if (delta == 0.0)
0171 break;
0172
0173 if (last_delta != 0.0 && fabs(delta / last_delta) < eps)
0174 break;
0175
0176 if (i%2 == 0)
0177 delta = -delta;
0178
0179 value += delta;
0180 last_delta = delta;
0181 i++;
0182 }
0183
0184 return value * n;
0185 }
0186
0187 }
0188
0189 template <class RealType = double, class Policy = policies::policy<> >
0190 class kolmogorov_smirnov_distribution
0191 {
0192 public:
0193 typedef RealType value_type;
0194 typedef Policy policy_type;
0195
0196
0197 kolmogorov_smirnov_distribution( RealType n ) : n_obs_(n)
0198 {
0199 RealType result;
0200 detail::check_df(
0201 "boost::math::kolmogorov_smirnov_distribution<%1%>::kolmogorov_smirnov_distribution", n_obs_, &result, Policy());
0202 }
0203
0204 RealType number_of_observations()const
0205 {
0206 return n_obs_;
0207 }
0208
0209 private:
0210
0211 RealType n_obs_;
0212 };
0213
0214 typedef kolmogorov_smirnov_distribution<double> kolmogorov_k;
0215
0216 #ifdef __cpp_deduction_guides
0217 template <class RealType>
0218 kolmogorov_smirnov_distribution(RealType)->kolmogorov_smirnov_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0219 #endif
0220
0221 namespace detail {
0222 template <class RealType, class Policy>
0223 struct kolmogorov_smirnov_quantile_functor
0224 {
0225 kolmogorov_smirnov_quantile_functor(const boost::math::kolmogorov_smirnov_distribution<RealType, Policy> dist, RealType const& p)
0226 : distribution(dist), prob(p)
0227 {
0228 }
0229
0230 boost::math::tuple<RealType, RealType> operator()(RealType const& x)
0231 {
0232 RealType fx = cdf(distribution, x) - prob;
0233 RealType dx = pdf(distribution, x);
0234
0235 return boost::math::make_tuple(fx, dx);
0236 }
0237 private:
0238 const boost::math::kolmogorov_smirnov_distribution<RealType, Policy> distribution;
0239 RealType prob;
0240 };
0241
0242 template <class RealType, class Policy>
0243 struct kolmogorov_smirnov_complementary_quantile_functor
0244 {
0245 kolmogorov_smirnov_complementary_quantile_functor(const boost::math::kolmogorov_smirnov_distribution<RealType, Policy> dist, RealType const& p)
0246 : distribution(dist), prob(p)
0247 {
0248 }
0249
0250 boost::math::tuple<RealType, RealType> operator()(RealType const& x)
0251 {
0252 RealType fx = cdf(complement(distribution, x)) - prob;
0253 RealType dx = -pdf(distribution, x);
0254
0255 return boost::math::make_tuple(fx, dx);
0256 }
0257 private:
0258 const boost::math::kolmogorov_smirnov_distribution<RealType, Policy> distribution;
0259 RealType prob;
0260 };
0261
0262 template <class RealType, class Policy>
0263 struct kolmogorov_smirnov_negative_pdf_functor
0264 {
0265 RealType operator()(RealType const& x) {
0266 if (2*x*x < constants::pi<RealType>()) {
0267 return -kolmogorov_smirnov_pdf_small_x(x, static_cast<RealType>(1), Policy());
0268 }
0269 return -kolmogorov_smirnov_pdf_large_x(x, static_cast<RealType>(1), Policy());
0270 }
0271 };
0272 }
0273
0274 template <class RealType, class Policy>
0275 inline const std::pair<RealType, RealType> range(const kolmogorov_smirnov_distribution<RealType, Policy>& )
0276 {
0277 using boost::math::tools::max_value;
0278 return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
0279 }
0280
0281 template <class RealType, class Policy>
0282 inline const std::pair<RealType, RealType> support(const kolmogorov_smirnov_distribution<RealType, Policy>& )
0283 {
0284
0285
0286 using boost::math::tools::max_value;
0287 return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
0288 }
0289
0290 template <class RealType, class Policy>
0291 inline RealType pdf(const kolmogorov_smirnov_distribution<RealType, Policy>& dist, const RealType& x)
0292 {
0293 BOOST_FPU_EXCEPTION_GUARD
0294 BOOST_MATH_STD_USING
0295
0296 RealType n = dist.number_of_observations();
0297 RealType error_result;
0298 static const char* function = "boost::math::pdf(const kolmogorov_smirnov_distribution<%1%>&, %1%)";
0299 if(false == detail::check_x_not_NaN(function, x, &error_result, Policy()))
0300 return error_result;
0301
0302 if(false == detail::check_df(function, n, &error_result, Policy()))
0303 return error_result;
0304
0305 if (x < 0 || !(boost::math::isfinite)(x))
0306 {
0307 return policies::raise_domain_error<RealType>(
0308 function, "Kolmogorov-Smirnov parameter was %1%, but must be > 0 !", x, Policy());
0309 }
0310
0311 if (2*x*x*n < constants::pi<RealType>()) {
0312 return detail::kolmogorov_smirnov_pdf_small_x(x, n, Policy());
0313 }
0314
0315 return detail::kolmogorov_smirnov_pdf_large_x(x, n, Policy());
0316 }
0317
0318 template <class RealType, class Policy>
0319 inline RealType cdf(const kolmogorov_smirnov_distribution<RealType, Policy>& dist, const RealType& x)
0320 {
0321 BOOST_MATH_STD_USING
0322 static const char* function = "boost::math::cdf(const kolmogorov_smirnov_distribution<%1%>&, %1%)";
0323 RealType error_result;
0324 RealType n = dist.number_of_observations();
0325 if(false == detail::check_x_not_NaN(function, x, &error_result, Policy()))
0326 return error_result;
0327 if(false == detail::check_df(function, n, &error_result, Policy()))
0328 return error_result;
0329 if((x < 0) || !(boost::math::isfinite)(x)) {
0330 return policies::raise_domain_error<RealType>(
0331 function, "Random variable parameter was %1%, but must be between > 0 !", x, Policy());
0332 }
0333
0334 if (x*x*n == 0)
0335 return 0;
0336
0337 return jacobi_theta4tau(RealType(0), 2*x*x*n/constants::pi<RealType>(), Policy());
0338 }
0339
0340 template <class RealType, class Policy>
0341 inline RealType cdf(const complemented2_type<kolmogorov_smirnov_distribution<RealType, Policy>, RealType>& c) {
0342 BOOST_MATH_STD_USING
0343 RealType x = c.param;
0344 static const char* function = "boost::math::cdf(const complemented2_type<const kolmogorov_smirnov_distribution<%1%>&, %1%>)";
0345 RealType error_result;
0346 kolmogorov_smirnov_distribution<RealType, Policy> const& dist = c.dist;
0347 RealType n = dist.number_of_observations();
0348
0349 if(false == detail::check_x_not_NaN(function, x, &error_result, Policy()))
0350 return error_result;
0351 if(false == detail::check_df(function, n, &error_result, Policy()))
0352 return error_result;
0353
0354 if((x < 0) || !(boost::math::isfinite)(x))
0355 return policies::raise_domain_error<RealType>(
0356 function, "Random variable parameter was %1%, but must be between > 0 !", x, Policy());
0357
0358 if (x*x*n == 0)
0359 return 1;
0360
0361 if (2*x*x*n > constants::pi<RealType>())
0362 return -jacobi_theta4m1tau(RealType(0), 2*x*x*n/constants::pi<RealType>(), Policy());
0363
0364 return RealType(1) - jacobi_theta4tau(RealType(0), 2*x*x*n/constants::pi<RealType>(), Policy());
0365 }
0366
0367 template <class RealType, class Policy>
0368 inline RealType quantile(const kolmogorov_smirnov_distribution<RealType, Policy>& dist, const RealType& p)
0369 {
0370 BOOST_MATH_STD_USING
0371 static const char* function = "boost::math::quantile(const kolmogorov_smirnov_distribution<%1%>&, %1%)";
0372
0373 RealType error_result;
0374 RealType n = dist.number_of_observations();
0375 if(false == detail::check_probability(function, p, &error_result, Policy()))
0376 return error_result;
0377 if(false == detail::check_df(function, n, &error_result, Policy()))
0378 return error_result;
0379
0380 RealType k = detail::kolmogorov_smirnov_quantile_guess(p) / sqrt(n);
0381 const int get_digits = policies::digits<RealType, Policy>();
0382 std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0383
0384 RealType result = tools::newton_raphson_iterate(detail::kolmogorov_smirnov_quantile_functor<RealType, Policy>(dist, p),
0385 k, RealType(0), RealType(1), get_digits, max_iter);
0386 if (max_iter >= policies::get_max_root_iterations<Policy>())
0387 {
0388 return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
0389 " either there is no answer to quantile or the answer is infinite. Current best guess is %1%", result, Policy());
0390 }
0391 return result;
0392 }
0393
0394 template <class RealType, class Policy>
0395 inline RealType quantile(const complemented2_type<kolmogorov_smirnov_distribution<RealType, Policy>, RealType>& c) {
0396 BOOST_MATH_STD_USING
0397 static const char* function = "boost::math::quantile(const kolmogorov_smirnov_distribution<%1%>&, %1%)";
0398 kolmogorov_smirnov_distribution<RealType, Policy> const& dist = c.dist;
0399 RealType n = dist.number_of_observations();
0400
0401 RealType error_result;
0402 RealType p = c.param;
0403
0404 if(false == detail::check_probability(function, p, &error_result, Policy()))
0405 return error_result;
0406 if(false == detail::check_df(function, n, &error_result, Policy()))
0407 return error_result;
0408
0409 RealType k = detail::kolmogorov_smirnov_quantile_guess(RealType(1-p)) / sqrt(n);
0410
0411 const int get_digits = policies::digits<RealType, Policy>();
0412 std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0413
0414 RealType result = tools::newton_raphson_iterate(
0415 detail::kolmogorov_smirnov_complementary_quantile_functor<RealType, Policy>(dist, p),
0416 k, RealType(0), RealType(1), get_digits, max_iter);
0417 if (max_iter >= policies::get_max_root_iterations<Policy>())
0418 {
0419 return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
0420 " either there is no answer to quantile or the answer is infinite. Current best guess is %1%", result, Policy());
0421 }
0422 return result;
0423 }
0424
0425 template <class RealType, class Policy>
0426 inline RealType mode(const kolmogorov_smirnov_distribution<RealType, Policy>& dist)
0427 {
0428 BOOST_MATH_STD_USING
0429 static const char* function = "boost::math::mode(const kolmogorov_smirnov_distribution<%1%>&)";
0430 RealType n = dist.number_of_observations();
0431 RealType error_result;
0432 if(false == detail::check_df(function, n, &error_result, Policy()))
0433 return error_result;
0434
0435 std::pair<RealType, RealType> r = boost::math::tools::brent_find_minima(
0436 detail::kolmogorov_smirnov_negative_pdf_functor<RealType, Policy>(),
0437 static_cast<RealType>(0), static_cast<RealType>(1), policies::digits<RealType, Policy>());
0438 return r.first / sqrt(n);
0439 }
0440
0441
0442
0443 template <class RealType, class Policy>
0444 inline RealType mean(const kolmogorov_smirnov_distribution<RealType, Policy>& dist)
0445 {
0446 BOOST_MATH_STD_USING
0447 static const char* function = "boost::math::mean(const kolmogorov_smirnov_distribution<%1%>&)";
0448 RealType n = dist.number_of_observations();
0449 RealType error_result;
0450 if(false == detail::check_df(function, n, &error_result, Policy()))
0451 return error_result;
0452 return constants::root_half_pi<RealType>() * constants::ln_two<RealType>() / sqrt(n);
0453 }
0454
0455 template <class RealType, class Policy>
0456 inline RealType variance(const kolmogorov_smirnov_distribution<RealType, Policy>& dist)
0457 {
0458 static const char* function = "boost::math::variance(const kolmogorov_smirnov_distribution<%1%>&)";
0459 RealType n = dist.number_of_observations();
0460 RealType error_result;
0461 if(false == detail::check_df(function, n, &error_result, Policy()))
0462 return error_result;
0463 return (constants::pi_sqr_div_six<RealType>()
0464 - constants::pi<RealType>() * constants::ln_two<RealType>() * constants::ln_two<RealType>()) / (2*n);
0465 }
0466
0467
0468
0469 template <class RealType, class Policy>
0470 inline RealType skewness(const kolmogorov_smirnov_distribution<RealType, Policy>& dist)
0471 {
0472 BOOST_MATH_STD_USING
0473 static const char* function = "boost::math::skewness(const kolmogorov_smirnov_distribution<%1%>&)";
0474 RealType n = dist.number_of_observations();
0475 RealType error_result;
0476 if(false == detail::check_df(function, n, &error_result, Policy()))
0477 return error_result;
0478 RealType ex3 = RealType(0.5625) * constants::root_half_pi<RealType>() * constants::zeta_three<RealType>() / n / sqrt(n);
0479 RealType mean = boost::math::mean(dist);
0480 RealType var = boost::math::variance(dist);
0481 return (ex3 - 3 * mean * var - mean * mean * mean) / var / sqrt(var);
0482 }
0483
0484 template <class RealType, class Policy>
0485 inline RealType kurtosis(const kolmogorov_smirnov_distribution<RealType, Policy>& dist)
0486 {
0487 BOOST_MATH_STD_USING
0488 static const char* function = "boost::math::kurtosis(const kolmogorov_smirnov_distribution<%1%>&)";
0489 RealType n = dist.number_of_observations();
0490 RealType error_result;
0491 if(false == detail::check_df(function, n, &error_result, Policy()))
0492 return error_result;
0493 RealType ex4 = 7 * constants::pi_sqr_div_six<RealType>() * constants::pi_sqr_div_six<RealType>() / 20 / n / n;
0494 RealType mean = boost::math::mean(dist);
0495 RealType var = boost::math::variance(dist);
0496 RealType skew = boost::math::skewness(dist);
0497 return (ex4 - 4 * mean * skew * var * sqrt(var) - 6 * mean * mean * var - mean * mean * mean * mean) / var / var;
0498 }
0499
0500 template <class RealType, class Policy>
0501 inline RealType kurtosis_excess(const kolmogorov_smirnov_distribution<RealType, Policy>& dist)
0502 {
0503 static const char* function = "boost::math::kurtosis_excess(const kolmogorov_smirnov_distribution<%1%>&)";
0504 RealType n = dist.number_of_observations();
0505 RealType error_result;
0506 if(false == detail::check_df(function, n, &error_result, Policy()))
0507 return error_result;
0508 return kurtosis(dist) - 3;
0509 }
0510 }}
0511 #endif