123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511 |
- #ifndef BOOST_MATH_DISTRIBUTIONS_KOLMOGOROV_SMIRNOV_HPP
- #define BOOST_MATH_DISTRIBUTIONS_KOLMOGOROV_SMIRNOV_HPP
- #include <boost/math/distributions/fwd.hpp>
- #include <boost/math/distributions/complement.hpp>
- #include <boost/math/distributions/detail/common_error_handling.hpp>
- #include <boost/math/special_functions/jacobi_theta.hpp>
- #include <boost/math/tools/tuple.hpp>
- #include <boost/math/tools/roots.hpp>
- #include <boost/math/tools/minima.hpp>
- namespace boost { namespace math {
- namespace detail {
- template <class RealType>
- inline RealType kolmogorov_smirnov_quantile_guess(RealType p) {
-
- if (p > 0.9)
- return RealType(1.8) - 5 * (1 - p);
- if (p < 0.3)
- return p + RealType(0.45);
- return p + RealType(0.3);
- }
- template <class RealType, class Policy>
- RealType kolmogorov_smirnov_pdf_small_x(RealType x, RealType n, const Policy&) {
- BOOST_MATH_STD_USING
- RealType value = RealType(0), delta = RealType(0), last_delta = RealType(0);
- RealType eps = policies::get_epsilon<RealType, Policy>();
- int i = 0;
- RealType pi2 = constants::pi_sqr<RealType>();
- RealType x2n = x*x*n;
- if (x2n*x2n == 0.0) {
- return static_cast<RealType>(0);
- }
- while (true) {
- delta = exp(-RealType(i+0.5)*RealType(i+0.5)*pi2/(2*x2n)) * (RealType(i+0.5)*RealType(i+0.5)*pi2 - x2n);
- if (delta == 0.0)
- break;
- if (last_delta != 0.0 && fabs(delta/last_delta) < eps)
- break;
- value += delta + delta;
- last_delta = delta;
- i++;
- }
- return value * sqrt(n) * constants::root_half_pi<RealType>() / (x2n*x2n);
- }
- template <class RealType, class Policy>
- inline RealType kolmogorov_smirnov_pdf_large_x(RealType x, RealType n, const Policy&) {
- BOOST_MATH_STD_USING
- RealType value = RealType(0), delta = RealType(0), last_delta = RealType(0);
- RealType eps = policies::get_epsilon<RealType, Policy>();
- int i = 1;
- while (true) {
- delta = 8*x*i*i*exp(-2*i*i*x*x*n);
- if (delta == 0.0)
- break;
- if (last_delta != 0.0 && fabs(delta / last_delta) < eps)
- break;
- if (i%2 == 0)
- delta = -delta;
- value += delta;
- last_delta = delta;
- i++;
- }
- return value * n;
- }
- }
- template <class RealType = double, class Policy = policies::policy<> >
- class kolmogorov_smirnov_distribution
- {
- public:
- typedef RealType value_type;
- typedef Policy policy_type;
-
- kolmogorov_smirnov_distribution( RealType n ) : n_obs_(n)
- {
- RealType result;
- detail::check_df(
- "boost::math::kolmogorov_smirnov_distribution<%1%>::kolmogorov_smirnov_distribution", n_obs_, &result, Policy());
- }
- RealType number_of_observations()const
- {
- return n_obs_;
- }
- private:
- RealType n_obs_;
- };
- typedef kolmogorov_smirnov_distribution<double> kolmogorov_k;
- #ifdef __cpp_deduction_guides
- template <class RealType>
- kolmogorov_smirnov_distribution(RealType)->kolmogorov_smirnov_distribution<typename boost::math::tools::promote_args<RealType>::type>;
- #endif
- namespace detail {
- template <class RealType, class Policy>
- struct kolmogorov_smirnov_quantile_functor
- {
- kolmogorov_smirnov_quantile_functor(const boost::math::kolmogorov_smirnov_distribution<RealType, Policy> dist, RealType const& p)
- : distribution(dist), prob(p)
- {
- }
- boost::math::tuple<RealType, RealType> operator()(RealType const& x)
- {
- RealType fx = cdf(distribution, x) - prob;
- RealType dx = pdf(distribution, x);
-
- return boost::math::make_tuple(fx, dx);
- }
- private:
- const boost::math::kolmogorov_smirnov_distribution<RealType, Policy> distribution;
- RealType prob;
- };
- template <class RealType, class Policy>
- struct kolmogorov_smirnov_complementary_quantile_functor
- {
- kolmogorov_smirnov_complementary_quantile_functor(const boost::math::kolmogorov_smirnov_distribution<RealType, Policy> dist, RealType const& p)
- : distribution(dist), prob(p)
- {
- }
- boost::math::tuple<RealType, RealType> operator()(RealType const& x)
- {
- RealType fx = cdf(complement(distribution, x)) - prob;
- RealType dx = -pdf(distribution, x);
-
- return boost::math::make_tuple(fx, dx);
- }
- private:
- const boost::math::kolmogorov_smirnov_distribution<RealType, Policy> distribution;
- RealType prob;
- };
- template <class RealType, class Policy>
- struct kolmogorov_smirnov_negative_pdf_functor
- {
- RealType operator()(RealType const& x) {
- if (2*x*x < constants::pi<RealType>()) {
- return -kolmogorov_smirnov_pdf_small_x(x, static_cast<RealType>(1), Policy());
- }
- return -kolmogorov_smirnov_pdf_large_x(x, static_cast<RealType>(1), Policy());
- }
- };
- }
- template <class RealType, class Policy>
- inline const std::pair<RealType, RealType> range(const kolmogorov_smirnov_distribution<RealType, Policy>& )
- {
- using boost::math::tools::max_value;
- return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
- }
- template <class RealType, class Policy>
- inline const std::pair<RealType, RealType> support(const kolmogorov_smirnov_distribution<RealType, Policy>& )
- {
-
-
- using boost::math::tools::max_value;
- return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
- }
- template <class RealType, class Policy>
- inline RealType pdf(const kolmogorov_smirnov_distribution<RealType, Policy>& dist, const RealType& x)
- {
- BOOST_FPU_EXCEPTION_GUARD
- BOOST_MATH_STD_USING
- RealType n = dist.number_of_observations();
- RealType error_result;
- static const char* function = "boost::math::pdf(const kolmogorov_smirnov_distribution<%1%>&, %1%)";
- if(false == detail::check_x_not_NaN(function, x, &error_result, Policy()))
- return error_result;
- if(false == detail::check_df(function, n, &error_result, Policy()))
- return error_result;
- if (x < 0 || !(boost::math::isfinite)(x))
- {
- return policies::raise_domain_error<RealType>(
- function, "Kolmogorov-Smirnov parameter was %1%, but must be > 0 !", x, Policy());
- }
- if (2*x*x*n < constants::pi<RealType>()) {
- return detail::kolmogorov_smirnov_pdf_small_x(x, n, Policy());
- }
- return detail::kolmogorov_smirnov_pdf_large_x(x, n, Policy());
- }
- template <class RealType, class Policy>
- inline RealType cdf(const kolmogorov_smirnov_distribution<RealType, Policy>& dist, const RealType& x)
- {
- BOOST_MATH_STD_USING
- static const char* function = "boost::math::cdf(const kolmogorov_smirnov_distribution<%1%>&, %1%)";
- RealType error_result;
- RealType n = dist.number_of_observations();
- if(false == detail::check_x_not_NaN(function, x, &error_result, Policy()))
- return error_result;
- if(false == detail::check_df(function, n, &error_result, Policy()))
- return error_result;
- if((x < 0) || !(boost::math::isfinite)(x)) {
- return policies::raise_domain_error<RealType>(
- function, "Random variable parameter was %1%, but must be between > 0 !", x, Policy());
- }
- if (x*x*n == 0)
- return 0;
- return jacobi_theta4tau(RealType(0), 2*x*x*n/constants::pi<RealType>(), Policy());
- }
- template <class RealType, class Policy>
- inline RealType cdf(const complemented2_type<kolmogorov_smirnov_distribution<RealType, Policy>, RealType>& c) {
- BOOST_MATH_STD_USING
- RealType x = c.param;
- static const char* function = "boost::math::cdf(const complemented2_type<const kolmogorov_smirnov_distribution<%1%>&, %1%>)";
- RealType error_result;
- kolmogorov_smirnov_distribution<RealType, Policy> const& dist = c.dist;
- RealType n = dist.number_of_observations();
- if(false == detail::check_x_not_NaN(function, x, &error_result, Policy()))
- return error_result;
- if(false == detail::check_df(function, n, &error_result, Policy()))
- return error_result;
- if((x < 0) || !(boost::math::isfinite)(x))
- return policies::raise_domain_error<RealType>(
- function, "Random variable parameter was %1%, but must be between > 0 !", x, Policy());
- if (x*x*n == 0)
- return 1;
- if (2*x*x*n > constants::pi<RealType>())
- return -jacobi_theta4m1tau(RealType(0), 2*x*x*n/constants::pi<RealType>(), Policy());
- return RealType(1) - jacobi_theta4tau(RealType(0), 2*x*x*n/constants::pi<RealType>(), Policy());
- }
- template <class RealType, class Policy>
- inline RealType quantile(const kolmogorov_smirnov_distribution<RealType, Policy>& dist, const RealType& p)
- {
- BOOST_MATH_STD_USING
- static const char* function = "boost::math::quantile(const kolmogorov_smirnov_distribution<%1%>&, %1%)";
-
- RealType error_result;
- RealType n = dist.number_of_observations();
- if(false == detail::check_probability(function, p, &error_result, Policy()))
- return error_result;
- if(false == detail::check_df(function, n, &error_result, Policy()))
- return error_result;
- RealType k = detail::kolmogorov_smirnov_quantile_guess(p) / sqrt(n);
- const int get_digits = policies::digits<RealType, Policy>();
- std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
- RealType result = tools::newton_raphson_iterate(detail::kolmogorov_smirnov_quantile_functor<RealType, Policy>(dist, p),
- k, RealType(0), RealType(1), get_digits, max_iter);
- if (max_iter >= policies::get_max_root_iterations<Policy>())
- {
- return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
- " either there is no answer to quantile or the answer is infinite. Current best guess is %1%", result, Policy());
- }
- return result;
- }
- template <class RealType, class Policy>
- inline RealType quantile(const complemented2_type<kolmogorov_smirnov_distribution<RealType, Policy>, RealType>& c) {
- BOOST_MATH_STD_USING
- static const char* function = "boost::math::quantile(const kolmogorov_smirnov_distribution<%1%>&, %1%)";
- kolmogorov_smirnov_distribution<RealType, Policy> const& dist = c.dist;
- RealType n = dist.number_of_observations();
-
- RealType error_result;
- RealType p = c.param;
- if(false == detail::check_probability(function, p, &error_result, Policy()))
- return error_result;
- if(false == detail::check_df(function, n, &error_result, Policy()))
- return error_result;
- RealType k = detail::kolmogorov_smirnov_quantile_guess(RealType(1-p)) / sqrt(n);
- const int get_digits = policies::digits<RealType, Policy>();
- std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
- RealType result = tools::newton_raphson_iterate(
- detail::kolmogorov_smirnov_complementary_quantile_functor<RealType, Policy>(dist, p),
- k, RealType(0), RealType(1), get_digits, max_iter);
- if (max_iter >= policies::get_max_root_iterations<Policy>())
- {
- return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
- " either there is no answer to quantile or the answer is infinite. Current best guess is %1%", result, Policy());
- }
- return result;
- }
- template <class RealType, class Policy>
- inline RealType mode(const kolmogorov_smirnov_distribution<RealType, Policy>& dist)
- {
- BOOST_MATH_STD_USING
- static const char* function = "boost::math::mode(const kolmogorov_smirnov_distribution<%1%>&)";
- RealType n = dist.number_of_observations();
- RealType error_result;
- if(false == detail::check_df(function, n, &error_result, Policy()))
- return error_result;
- std::pair<RealType, RealType> r = boost::math::tools::brent_find_minima(
- detail::kolmogorov_smirnov_negative_pdf_functor<RealType, Policy>(),
- static_cast<RealType>(0), static_cast<RealType>(1), policies::digits<RealType, Policy>());
- return r.first / sqrt(n);
- }
- template <class RealType, class Policy>
- inline RealType mean(const kolmogorov_smirnov_distribution<RealType, Policy>& dist)
- {
- BOOST_MATH_STD_USING
- static const char* function = "boost::math::mean(const kolmogorov_smirnov_distribution<%1%>&)";
- RealType n = dist.number_of_observations();
- RealType error_result;
- if(false == detail::check_df(function, n, &error_result, Policy()))
- return error_result;
- return constants::root_half_pi<RealType>() * constants::ln_two<RealType>() / sqrt(n);
- }
- template <class RealType, class Policy>
- inline RealType variance(const kolmogorov_smirnov_distribution<RealType, Policy>& dist)
- {
- static const char* function = "boost::math::variance(const kolmogorov_smirnov_distribution<%1%>&)";
- RealType n = dist.number_of_observations();
- RealType error_result;
- if(false == detail::check_df(function, n, &error_result, Policy()))
- return error_result;
- return (constants::pi_sqr_div_six<RealType>()
- - constants::pi<RealType>() * constants::ln_two<RealType>() * constants::ln_two<RealType>()) / (2*n);
- }
- template <class RealType, class Policy>
- inline RealType skewness(const kolmogorov_smirnov_distribution<RealType, Policy>& dist)
- {
- BOOST_MATH_STD_USING
- static const char* function = "boost::math::skewness(const kolmogorov_smirnov_distribution<%1%>&)";
- RealType n = dist.number_of_observations();
- RealType error_result;
- if(false == detail::check_df(function, n, &error_result, Policy()))
- return error_result;
- RealType ex3 = RealType(0.5625) * constants::root_half_pi<RealType>() * constants::zeta_three<RealType>() / n / sqrt(n);
- RealType mean = boost::math::mean(dist);
- RealType var = boost::math::variance(dist);
- return (ex3 - 3 * mean * var - mean * mean * mean) / var / sqrt(var);
- }
- template <class RealType, class Policy>
- inline RealType kurtosis(const kolmogorov_smirnov_distribution<RealType, Policy>& dist)
- {
- BOOST_MATH_STD_USING
- static const char* function = "boost::math::kurtosis(const kolmogorov_smirnov_distribution<%1%>&)";
- RealType n = dist.number_of_observations();
- RealType error_result;
- if(false == detail::check_df(function, n, &error_result, Policy()))
- return error_result;
- RealType ex4 = 7 * constants::pi_sqr_div_six<RealType>() * constants::pi_sqr_div_six<RealType>() / 20 / n / n;
- RealType mean = boost::math::mean(dist);
- RealType var = boost::math::variance(dist);
- RealType skew = boost::math::skewness(dist);
- return (ex4 - 4 * mean * skew * var * sqrt(var) - 6 * mean * mean * var - mean * mean * mean * mean) / var / var;
- }
- template <class RealType, class Policy>
- inline RealType kurtosis_excess(const kolmogorov_smirnov_distribution<RealType, Policy>& dist)
- {
- static const char* function = "boost::math::kurtosis_excess(const kolmogorov_smirnov_distribution<%1%>&)";
- RealType n = dist.number_of_observations();
- RealType error_result;
- if(false == detail::check_df(function, n, &error_result, Policy()))
- return error_result;
- return kurtosis(dist) - 3;
- }
- }}
- #endif
|