File indexing completed on 2025-12-16 09:55:38
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_MATH_STATISTICS_UNIVARIATE_STATISTICS_HPP
0008 #define BOOST_MATH_STATISTICS_UNIVARIATE_STATISTICS_HPP
0009
0010 #include <boost/math/statistics/detail/single_pass.hpp>
0011 #include <boost/math/tools/config.hpp>
0012 #include <boost/math/tools/assert.hpp>
0013 #include <algorithm>
0014 #include <iterator>
0015 #include <tuple>
0016 #include <cmath>
0017 #include <vector>
0018 #include <type_traits>
0019 #include <utility>
0020 #include <numeric>
0021 #include <list>
0022
0023 #ifdef BOOST_MATH_EXEC_COMPATIBLE
0024 #include <execution>
0025
0026 namespace boost::math::statistics {
0027
0028 template<class ExecutionPolicy, class ForwardIterator>
0029 inline auto mean(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last)
0030 {
0031 using Real = typename std::iterator_traits<ForwardIterator>::value_type;
0032 BOOST_MATH_ASSERT_MSG(first != last, "At least one sample is required to compute the mean.");
0033
0034 if constexpr (std::is_integral_v<Real>)
0035 {
0036 if constexpr (std::is_same_v<std::remove_reference_t<decltype(exec)>, decltype(std::execution::seq)>)
0037 {
0038 return detail::mean_sequential_impl<double>(first, last);
0039 }
0040 else
0041 {
0042 return std::reduce(exec, first, last, 0.0) / std::distance(first, last);
0043 }
0044 }
0045 else
0046 {
0047 if constexpr (std::is_same_v<std::remove_reference_t<decltype(exec)>, decltype(std::execution::seq)>)
0048 {
0049 return detail::mean_sequential_impl<Real>(first, last);
0050 }
0051 else
0052 {
0053 return std::reduce(exec, first, last, Real(0.0)) / Real(std::distance(first, last));
0054 }
0055 }
0056 }
0057
0058 template<class ExecutionPolicy, class Container>
0059 inline auto mean(ExecutionPolicy&& exec, Container const & v)
0060 {
0061 return mean(exec, std::cbegin(v), std::cend(v));
0062 }
0063
0064 template<class ForwardIterator>
0065 inline auto mean(ForwardIterator first, ForwardIterator last)
0066 {
0067 return mean(std::execution::seq, first, last);
0068 }
0069
0070 template<class Container>
0071 inline auto mean(Container const & v)
0072 {
0073 return mean(std::execution::seq, std::cbegin(v), std::cend(v));
0074 }
0075
0076 template<class ExecutionPolicy, class ForwardIterator>
0077 inline auto variance(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last)
0078 {
0079 using Real = typename std::iterator_traits<ForwardIterator>::value_type;
0080
0081 if constexpr (std::is_integral_v<Real>)
0082 {
0083 if constexpr (std::is_same_v<std::remove_reference_t<decltype(exec)>, decltype(std::execution::seq)>)
0084 {
0085 return std::get<2>(detail::variance_sequential_impl<std::tuple<double, double, double, double>>(first, last));
0086 }
0087 else
0088 {
0089 const auto results = detail::first_four_moments_parallel_impl<std::tuple<double, double, double, double, double>>(first, last);
0090 return std::get<1>(results) / std::get<4>(results);
0091 }
0092 }
0093 else
0094 {
0095 if constexpr (std::is_same_v<std::remove_reference_t<decltype(exec)>, decltype(std::execution::seq)>)
0096 {
0097 return std::get<2>(detail::variance_sequential_impl<std::tuple<Real, Real, Real, Real>>(first, last));
0098 }
0099 else
0100 {
0101 const auto results = detail::first_four_moments_parallel_impl<std::tuple<Real, Real, Real, Real, Real>>(first, last);
0102 return std::get<1>(results) / std::get<4>(results);
0103 }
0104 }
0105 }
0106
0107 template<class ExecutionPolicy, class Container>
0108 inline auto variance(ExecutionPolicy&& exec, Container const & v)
0109 {
0110 return variance(exec, std::cbegin(v), std::cend(v));
0111 }
0112
0113 template<class ForwardIterator>
0114 inline auto variance(ForwardIterator first, ForwardIterator last)
0115 {
0116 return variance(std::execution::seq, first, last);
0117 }
0118
0119 template<class Container>
0120 inline auto variance(Container const & v)
0121 {
0122 return variance(std::execution::seq, std::cbegin(v), std::cend(v));
0123 }
0124
0125 template<class ExecutionPolicy, class ForwardIterator>
0126 inline auto sample_variance(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last)
0127 {
0128 const auto n = std::distance(first, last);
0129 BOOST_MATH_ASSERT_MSG(n > 1, "At least two samples are required to compute the sample variance.");
0130 return n*variance(exec, first, last)/(n-1);
0131 }
0132
0133 template<class ExecutionPolicy, class Container>
0134 inline auto sample_variance(ExecutionPolicy&& exec, Container const & v)
0135 {
0136 return sample_variance(exec, std::cbegin(v), std::cend(v));
0137 }
0138
0139 template<class ForwardIterator>
0140 inline auto sample_variance(ForwardIterator first, ForwardIterator last)
0141 {
0142 return sample_variance(std::execution::seq, first, last);
0143 }
0144
0145 template<class Container>
0146 inline auto sample_variance(Container const & v)
0147 {
0148 return sample_variance(std::execution::seq, std::cbegin(v), std::cend(v));
0149 }
0150
0151 template<class ExecutionPolicy, class ForwardIterator>
0152 inline auto mean_and_sample_variance(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last)
0153 {
0154 using Real = typename std::iterator_traits<ForwardIterator>::value_type;
0155
0156 if constexpr (std::is_integral_v<Real>)
0157 {
0158 if constexpr (std::is_same_v<std::remove_reference_t<decltype(exec)>, decltype(std::execution::seq)>)
0159 {
0160 const auto results = detail::variance_sequential_impl<std::tuple<double, double, double, double>>(first, last);
0161 return std::make_pair(std::get<0>(results), std::get<2>(results)*std::get<3>(results)/(std::get<3>(results)-1.0));
0162 }
0163 else
0164 {
0165 const auto results = detail::first_four_moments_parallel_impl<std::tuple<double, double, double, double, double>>(first, last);
0166 return std::make_pair(std::get<0>(results), std::get<1>(results) / (std::get<4>(results)-1.0));
0167 }
0168 }
0169 else
0170 {
0171 if constexpr (std::is_same_v<std::remove_reference_t<decltype(exec)>, decltype(std::execution::seq)>)
0172 {
0173 const auto results = detail::variance_sequential_impl<std::tuple<Real, Real, Real, Real>>(first, last);
0174 return std::make_pair(std::get<0>(results), std::get<2>(results)*std::get<3>(results)/(std::get<3>(results)-Real(1)));
0175 }
0176 else
0177 {
0178 const auto results = detail::first_four_moments_parallel_impl<std::tuple<Real, Real, Real, Real, Real>>(first, last);
0179 return std::make_pair(std::get<0>(results), std::get<1>(results) / (std::get<4>(results)-Real(1)));
0180 }
0181 }
0182 }
0183
0184 template<class ExecutionPolicy, class Container>
0185 inline auto mean_and_sample_variance(ExecutionPolicy&& exec, Container const & v)
0186 {
0187 return mean_and_sample_variance(exec, std::cbegin(v), std::cend(v));
0188 }
0189
0190 template<class ForwardIterator>
0191 inline auto mean_and_sample_variance(ForwardIterator first, ForwardIterator last)
0192 {
0193 return mean_and_sample_variance(std::execution::seq, first, last);
0194 }
0195
0196 template<class Container>
0197 inline auto mean_and_sample_variance(Container const & v)
0198 {
0199 return mean_and_sample_variance(std::execution::seq, std::cbegin(v), std::cend(v));
0200 }
0201
0202 template<class ExecutionPolicy, class ForwardIterator>
0203 inline auto first_four_moments(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last)
0204 {
0205 using Real = typename std::iterator_traits<ForwardIterator>::value_type;
0206
0207 if constexpr (std::is_integral_v<Real>)
0208 {
0209 if constexpr (std::is_same_v<std::remove_reference_t<decltype(exec)>, decltype(std::execution::seq)>)
0210 {
0211 const auto results = detail::first_four_moments_sequential_impl<std::tuple<double, double, double, double, double>>(first, last);
0212 return std::make_tuple(std::get<0>(results), std::get<1>(results) / std::get<4>(results), std::get<2>(results) / std::get<4>(results),
0213 std::get<3>(results) / std::get<4>(results));
0214 }
0215 else
0216 {
0217 const auto results = detail::first_four_moments_parallel_impl<std::tuple<double, double, double, double, double>>(first, last);
0218 return std::make_tuple(std::get<0>(results), std::get<1>(results) / std::get<4>(results), std::get<2>(results) / std::get<4>(results),
0219 std::get<3>(results) / std::get<4>(results));
0220 }
0221 }
0222 else
0223 {
0224 if constexpr (std::is_same_v<std::remove_reference_t<decltype(exec)>, decltype(std::execution::seq)>)
0225 {
0226 const auto results = detail::first_four_moments_sequential_impl<std::tuple<Real, Real, Real, Real, Real>>(first, last);
0227 return std::make_tuple(std::get<0>(results), std::get<1>(results) / std::get<4>(results), std::get<2>(results) / std::get<4>(results),
0228 std::get<3>(results) / std::get<4>(results));
0229 }
0230 else
0231 {
0232 const auto results = detail::first_four_moments_parallel_impl<std::tuple<Real, Real, Real, Real, Real>>(first, last);
0233 return std::make_tuple(std::get<0>(results), std::get<1>(results) / std::get<4>(results), std::get<2>(results) / std::get<4>(results),
0234 std::get<3>(results) / std::get<4>(results));
0235 }
0236 }
0237 }
0238
0239 template<class ExecutionPolicy, class Container>
0240 inline auto first_four_moments(ExecutionPolicy&& exec, Container const & v)
0241 {
0242 return first_four_moments(exec, std::cbegin(v), std::cend(v));
0243 }
0244
0245 template<class ForwardIterator>
0246 inline auto first_four_moments(ForwardIterator first, ForwardIterator last)
0247 {
0248 return first_four_moments(std::execution::seq, first, last);
0249 }
0250
0251 template<class Container>
0252 inline auto first_four_moments(Container const & v)
0253 {
0254 return first_four_moments(std::execution::seq, std::cbegin(v), std::cend(v));
0255 }
0256
0257
0258 template<class ExecutionPolicy, class ForwardIterator>
0259 inline auto skewness(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last)
0260 {
0261 using Real = typename std::iterator_traits<ForwardIterator>::value_type;
0262 using std::sqrt;
0263
0264 if constexpr (std::is_same_v<std::remove_reference_t<decltype(exec)>, decltype(std::execution::seq)>)
0265 {
0266 if constexpr (std::is_integral_v<Real>)
0267 {
0268 return detail::skewness_sequential_impl<double>(first, last);
0269 }
0270 else
0271 {
0272 return detail::skewness_sequential_impl<Real>(first, last);
0273 }
0274 }
0275 else
0276 {
0277 const auto [M1, M2, M3, M4] = first_four_moments(exec, first, last);
0278 const auto n = std::distance(first, last);
0279 const auto var = M2/(n-1);
0280
0281 if (M2 == 0)
0282 {
0283
0284
0285 if constexpr (std::is_integral_v<Real>)
0286 {
0287 return static_cast<double>(0);
0288 }
0289 else
0290 {
0291 return Real(0);
0292 }
0293 }
0294 else
0295 {
0296 return M3/(M2*sqrt(var)) / Real(2);
0297 }
0298 }
0299 }
0300
0301 template<class ExecutionPolicy, class Container>
0302 inline auto skewness(ExecutionPolicy&& exec, Container & v)
0303 {
0304 return skewness(exec, std::cbegin(v), std::cend(v));
0305 }
0306
0307 template<class ForwardIterator>
0308 inline auto skewness(ForwardIterator first, ForwardIterator last)
0309 {
0310 return skewness(std::execution::seq, first, last);
0311 }
0312
0313 template<class Container>
0314 inline auto skewness(Container const & v)
0315 {
0316 return skewness(std::execution::seq, std::cbegin(v), std::cend(v));
0317 }
0318
0319
0320
0321 template<class ExecutionPolicy, class ForwardIterator>
0322 inline auto kurtosis(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last)
0323 {
0324 const auto [M1, M2, M3, M4] = first_four_moments(exec, first, last);
0325 if (M2 == 0)
0326 {
0327 return M2;
0328 }
0329 return M4/(M2*M2);
0330 }
0331
0332 template<class ExecutionPolicy, class Container>
0333 inline auto kurtosis(ExecutionPolicy&& exec, Container const & v)
0334 {
0335 return kurtosis(exec, std::cbegin(v), std::cend(v));
0336 }
0337
0338 template<class ForwardIterator>
0339 inline auto kurtosis(ForwardIterator first, ForwardIterator last)
0340 {
0341 return kurtosis(std::execution::seq, first, last);
0342 }
0343
0344 template<class Container>
0345 inline auto kurtosis(Container const & v)
0346 {
0347 return kurtosis(std::execution::seq, std::cbegin(v), std::cend(v));
0348 }
0349
0350 template<class ExecutionPolicy, class ForwardIterator>
0351 inline auto excess_kurtosis(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last)
0352 {
0353 return kurtosis(exec, first, last) - 3;
0354 }
0355
0356 template<class ExecutionPolicy, class Container>
0357 inline auto excess_kurtosis(ExecutionPolicy&& exec, Container const & v)
0358 {
0359 return excess_kurtosis(exec, std::cbegin(v), std::cend(v));
0360 }
0361
0362 template<class ForwardIterator>
0363 inline auto excess_kurtosis(ForwardIterator first, ForwardIterator last)
0364 {
0365 return excess_kurtosis(std::execution::seq, first, last);
0366 }
0367
0368 template<class Container>
0369 inline auto excess_kurtosis(Container const & v)
0370 {
0371 return excess_kurtosis(std::execution::seq, std::cbegin(v), std::cend(v));
0372 }
0373
0374
0375 template<class ExecutionPolicy, class RandomAccessIterator>
0376 auto median(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last)
0377 {
0378 const auto num_elems = std::distance(first, last);
0379 BOOST_MATH_ASSERT_MSG(num_elems > 0, "The median of a zero length vector is undefined.");
0380 if (num_elems & 1)
0381 {
0382 auto middle = first + (num_elems - 1)/2;
0383 std::nth_element(exec, first, middle, last);
0384 return *middle;
0385 }
0386 else
0387 {
0388 auto middle = first + num_elems/2 - 1;
0389 std::nth_element(exec, first, middle, last);
0390 std::nth_element(exec, middle, middle+1, last);
0391 return (*middle + *(middle+1))/2;
0392 }
0393 }
0394
0395
0396 template<class ExecutionPolicy, class RandomAccessContainer>
0397 inline auto median(ExecutionPolicy&& exec, RandomAccessContainer & v)
0398 {
0399 return median(exec, std::begin(v), std::end(v));
0400 }
0401
0402 template<class RandomAccessIterator>
0403 inline auto median(RandomAccessIterator first, RandomAccessIterator last)
0404 {
0405 return median(std::execution::seq, first, last);
0406 }
0407
0408 template<class RandomAccessContainer>
0409 inline auto median(RandomAccessContainer & v)
0410 {
0411 return median(std::execution::seq, std::begin(v), std::end(v));
0412 }
0413
0414 #if 0
0415
0416
0417
0418
0419
0420 template<class ExecutionPolicy, class RandomAccessIterator>
0421 inline auto gini_coefficient(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last)
0422 {
0423 using Real = typename std::iterator_traits<RandomAccessIterator>::value_type;
0424
0425 if(!std::is_sorted(exec, first, last))
0426 {
0427 std::sort(exec, first, last);
0428 }
0429
0430 if constexpr (std::is_same_v<std::remove_reference_t<decltype(exec)>, decltype(std::execution::seq)>)
0431 {
0432 if constexpr (std::is_integral_v<Real>)
0433 {
0434 return detail::gini_coefficient_sequential_impl<double>(first, last);
0435 }
0436 else
0437 {
0438 return detail::gini_coefficient_sequential_impl<Real>(first, last);
0439 }
0440 }
0441
0442 else if constexpr (std::is_integral_v<Real>)
0443 {
0444 return detail::gini_coefficient_parallel_impl<double>(exec, first, last);
0445 }
0446
0447 else
0448 {
0449 return detail::gini_coefficient_parallel_impl<Real>(exec, first, last);
0450 }
0451 }
0452 #else
0453 template<class ExecutionPolicy, class RandomAccessIterator>
0454 inline auto gini_coefficient(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last)
0455 {
0456 using Real = typename std::iterator_traits<RandomAccessIterator>::value_type;
0457
0458 if (!std::is_sorted(exec, first, last))
0459 {
0460 std::sort(exec, first, last);
0461 }
0462
0463 if constexpr (std::is_integral_v<Real>)
0464 {
0465 return detail::gini_coefficient_sequential_impl<double>(first, last);
0466 }
0467 else
0468 {
0469 return detail::gini_coefficient_sequential_impl<Real>(first, last);
0470 }
0471 }
0472 #endif
0473
0474 template<class ExecutionPolicy, class RandomAccessContainer>
0475 inline auto gini_coefficient(ExecutionPolicy&& exec, RandomAccessContainer & v)
0476 {
0477 return gini_coefficient(exec, std::begin(v), std::end(v));
0478 }
0479
0480 template<class RandomAccessIterator>
0481 inline auto gini_coefficient(RandomAccessIterator first, RandomAccessIterator last)
0482 {
0483 return gini_coefficient(std::execution::seq, first, last);
0484 }
0485
0486 template<class RandomAccessContainer>
0487 inline auto gini_coefficient(RandomAccessContainer & v)
0488 {
0489 return gini_coefficient(std::execution::seq, std::begin(v), std::end(v));
0490 }
0491
0492 template<class ExecutionPolicy, class RandomAccessIterator>
0493 inline auto sample_gini_coefficient(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last)
0494 {
0495 const auto n = std::distance(first, last);
0496 return n*gini_coefficient(exec, first, last)/(n-1);
0497 }
0498
0499 template<class ExecutionPolicy, class RandomAccessContainer>
0500 inline auto sample_gini_coefficient(ExecutionPolicy&& exec, RandomAccessContainer & v)
0501 {
0502 return sample_gini_coefficient(exec, std::begin(v), std::end(v));
0503 }
0504
0505 template<class RandomAccessIterator>
0506 inline auto sample_gini_coefficient(RandomAccessIterator first, RandomAccessIterator last)
0507 {
0508 return sample_gini_coefficient(std::execution::seq, first, last);
0509 }
0510
0511 template<class RandomAccessContainer>
0512 inline auto sample_gini_coefficient(RandomAccessContainer & v)
0513 {
0514 return sample_gini_coefficient(std::execution::seq, std::begin(v), std::end(v));
0515 }
0516
0517 template<class ExecutionPolicy, class RandomAccessIterator>
0518 auto median_absolute_deviation(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last,
0519 typename std::iterator_traits<RandomAccessIterator>::value_type center=std::numeric_limits<typename std::iterator_traits<RandomAccessIterator>::value_type>::quiet_NaN())
0520 {
0521 using std::abs;
0522 using Real = typename std::iterator_traits<RandomAccessIterator>::value_type;
0523 using std::isnan;
0524 if (isnan(center))
0525 {
0526 center = boost::math::statistics::median(exec, first, last);
0527 }
0528 const auto num_elems = std::distance(first, last);
0529 BOOST_MATH_ASSERT_MSG(num_elems > 0, "The median of a zero-length vector is undefined.");
0530 auto comparator = [¢er](Real a, Real b) { return abs(a-center) < abs(b-center);};
0531 if (num_elems & 1)
0532 {
0533 auto middle = first + (num_elems - 1)/2;
0534 std::nth_element(exec, first, middle, last, comparator);
0535 return abs(*middle-center);
0536 }
0537 else
0538 {
0539 auto middle = first + num_elems/2 - 1;
0540 std::nth_element(exec, first, middle, last, comparator);
0541 std::nth_element(exec, middle, middle+1, last, comparator);
0542 return (abs(*middle-center) + abs(*(middle+1)-center))/abs(static_cast<Real>(2));
0543 }
0544 }
0545
0546 template<class ExecutionPolicy, class RandomAccessContainer>
0547 inline auto median_absolute_deviation(ExecutionPolicy&& exec, RandomAccessContainer & v,
0548 typename RandomAccessContainer::value_type center=std::numeric_limits<typename RandomAccessContainer::value_type>::quiet_NaN())
0549 {
0550 return median_absolute_deviation(exec, std::begin(v), std::end(v), center);
0551 }
0552
0553 template<class RandomAccessIterator>
0554 inline auto median_absolute_deviation(RandomAccessIterator first, RandomAccessIterator last,
0555 typename RandomAccessIterator::value_type center=std::numeric_limits<typename RandomAccessIterator::value_type>::quiet_NaN())
0556 {
0557 return median_absolute_deviation(std::execution::seq, first, last, center);
0558 }
0559
0560 template<class RandomAccessContainer>
0561 inline auto median_absolute_deviation(RandomAccessContainer & v,
0562 typename RandomAccessContainer::value_type center=std::numeric_limits<typename RandomAccessContainer::value_type>::quiet_NaN())
0563 {
0564 return median_absolute_deviation(std::execution::seq, std::begin(v), std::end(v), center);
0565 }
0566
0567 template<class ExecutionPolicy, class ForwardIterator>
0568 auto interquartile_range(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last)
0569 {
0570 using Real = typename std::iterator_traits<ForwardIterator>::value_type;
0571 static_assert(!std::is_integral_v<Real>, "Integer values have not yet been implemented.");
0572 auto m = std::distance(first,last);
0573 BOOST_MATH_ASSERT_MSG(m >= 3, "At least 3 samples are required to compute the interquartile range.");
0574 auto k = m/4;
0575 auto j = m - (4*k);
0576
0577
0578
0579
0580
0581 if (j==2 || j==3)
0582 {
0583 auto q1 = first + k;
0584 auto q3 = first + 3*k + j - 1;
0585 std::nth_element(exec, first, q1, last);
0586 Real Q1 = *q1;
0587 std::nth_element(exec, q1, q3, last);
0588 Real Q3 = *q3;
0589 return Q3 - Q1;
0590 } else {
0591
0592 auto q1 = first + k - 1;
0593 auto q3 = first + 3*k - 1 + j;
0594 std::nth_element(exec, first, q1, last);
0595 Real a = *q1;
0596 std::nth_element(exec, q1, q1 + 1, last);
0597 Real b = *(q1 + 1);
0598 Real Q1 = (a+b)/2;
0599 std::nth_element(exec, q1, q3, last);
0600 a = *q3;
0601 std::nth_element(exec, q3, q3 + 1, last);
0602 b = *(q3 + 1);
0603 Real Q3 = (a+b)/2;
0604 return Q3 - Q1;
0605 }
0606 }
0607
0608 template<class ExecutionPolicy, class RandomAccessContainer>
0609 inline auto interquartile_range(ExecutionPolicy&& exec, RandomAccessContainer & v)
0610 {
0611 return interquartile_range(exec, std::begin(v), std::end(v));
0612 }
0613
0614 template<class RandomAccessIterator>
0615 inline auto interquartile_range(RandomAccessIterator first, RandomAccessIterator last)
0616 {
0617 return interquartile_range(std::execution::seq, first, last);
0618 }
0619
0620 template<class RandomAccessContainer>
0621 inline auto interquartile_range(RandomAccessContainer & v)
0622 {
0623 return interquartile_range(std::execution::seq, std::begin(v), std::end(v));
0624 }
0625
0626 template<class ExecutionPolicy, class ForwardIterator, class OutputIterator>
0627 inline OutputIterator mode(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, OutputIterator output)
0628 {
0629 if(!std::is_sorted(exec, first, last))
0630 {
0631 if constexpr (std::is_same_v<typename std::iterator_traits<ForwardIterator>::iterator_category(), std::random_access_iterator_tag>)
0632 {
0633 std::sort(exec, first, last);
0634 }
0635 else
0636 {
0637 BOOST_MATH_ASSERT("Data must be sorted for sequential mode calculation");
0638 }
0639 }
0640
0641 return detail::mode_impl(first, last, output);
0642 }
0643
0644 template<class ExecutionPolicy, class Container, class OutputIterator>
0645 inline OutputIterator mode(ExecutionPolicy&& exec, Container & v, OutputIterator output)
0646 {
0647 return mode(exec, std::begin(v), std::end(v), output);
0648 }
0649
0650 template<class ForwardIterator, class OutputIterator>
0651 inline OutputIterator mode(ForwardIterator first, ForwardIterator last, OutputIterator output)
0652 {
0653 return mode(std::execution::seq, first, last, output);
0654 }
0655
0656
0657
0658 template<class Container, class OutputIterator, std::enable_if_t<!std::is_convertible_v<std::execution::sequenced_policy, Container> &&
0659 !std::is_convertible_v<std::execution::parallel_unsequenced_policy, Container> &&
0660 !std::is_convertible_v<std::execution::parallel_policy, Container>
0661 #if __cpp_lib_execution > 201900
0662 && !std::is_convertible_v<std::execution::unsequenced_policy, Container>
0663 #endif
0664 , bool> = true>
0665 inline OutputIterator mode(Container & v, OutputIterator output)
0666 {
0667 return mode(std::execution::seq, std::begin(v), std::end(v), output);
0668 }
0669
0670
0671
0672 template<class ExecutionPolicy, class ForwardIterator, class Real = typename std::iterator_traits<ForwardIterator>::value_type>
0673 inline auto mode(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last)
0674 {
0675 std::list<Real> modes;
0676 mode(exec, first, last, std::inserter(modes, modes.begin()));
0677 return modes;
0678 }
0679
0680 template<class ExecutionPolicy, class Container>
0681 inline auto mode(ExecutionPolicy&& exec, Container & v)
0682 {
0683 return mode(exec, std::begin(v), std::end(v));
0684 }
0685
0686 template<class ForwardIterator>
0687 inline auto mode(ForwardIterator first, ForwardIterator last)
0688 {
0689 return mode(std::execution::seq, first, last);
0690 }
0691
0692 template<class Container>
0693 inline auto mode(Container & v)
0694 {
0695 return mode(std::execution::seq, std::begin(v), std::end(v));
0696 }
0697
0698 }
0699
0700 #else
0701
0702 namespace boost { namespace math { namespace statistics {
0703
0704 template<bool B, class T = void>
0705 using enable_if_t = typename std::enable_if<B, T>::type;
0706
0707 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0708 enable_if_t<std::is_integral<Real>::value, bool> = true>
0709 inline double mean(const ForwardIterator first, const ForwardIterator last)
0710 {
0711 BOOST_MATH_ASSERT_MSG(first != last, "At least one sample is required to compute the mean.");
0712 return detail::mean_sequential_impl<double>(first, last);
0713 }
0714
0715 template<class Container, typename Real = typename Container::value_type,
0716 enable_if_t<std::is_integral<Real>::value, bool> = true>
0717 inline double mean(const Container& c)
0718 {
0719 return mean(std::begin(c), std::end(c));
0720 }
0721
0722 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0723 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0724 inline Real mean(const ForwardIterator first, const ForwardIterator last)
0725 {
0726 BOOST_MATH_ASSERT_MSG(first != last, "At least one sample is required to compute the mean.");
0727 return detail::mean_sequential_impl<Real>(first, last);
0728 }
0729
0730 template<class Container, typename Real = typename Container::value_type,
0731 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0732 inline Real mean(const Container& c)
0733 {
0734 return mean(std::begin(c), std::end(c));
0735 }
0736
0737 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0738 enable_if_t<std::is_integral<Real>::value, bool> = true>
0739 inline double variance(const ForwardIterator first, const ForwardIterator last)
0740 {
0741 return std::get<2>(detail::variance_sequential_impl<std::tuple<double, double, double, double>>(first, last));
0742 }
0743
0744 template<class Container, typename Real = typename Container::value_type,
0745 enable_if_t<std::is_integral<Real>::value, bool> = true>
0746 inline double variance(const Container& c)
0747 {
0748 return variance(std::begin(c), std::end(c));
0749 }
0750
0751 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0752 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0753 inline Real variance(const ForwardIterator first, const ForwardIterator last)
0754 {
0755 return std::get<2>(detail::variance_sequential_impl<std::tuple<Real, Real, Real, Real>>(first, last));
0756
0757 }
0758
0759 template<class Container, typename Real = typename Container::value_type,
0760 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0761 inline Real variance(const Container& c)
0762 {
0763 return variance(std::begin(c), std::end(c));
0764 }
0765
0766 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0767 enable_if_t<std::is_integral<Real>::value, bool> = true>
0768 inline double sample_variance(const ForwardIterator first, const ForwardIterator last)
0769 {
0770 const auto n = std::distance(first, last);
0771 BOOST_MATH_ASSERT_MSG(n > 1, "At least two samples are required to compute the sample variance.");
0772 return n*variance(first, last)/(n-1);
0773 }
0774
0775 template<class Container, typename Real = typename Container::value_type,
0776 enable_if_t<std::is_integral<Real>::value, bool> = true>
0777 inline double sample_variance(const Container& c)
0778 {
0779 return sample_variance(std::begin(c), std::end(c));
0780 }
0781
0782 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0783 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0784 inline Real sample_variance(const ForwardIterator first, const ForwardIterator last)
0785 {
0786 const auto n = std::distance(first, last);
0787 BOOST_MATH_ASSERT_MSG(n > 1, "At least two samples are required to compute the sample variance.");
0788 return n*variance(first, last)/(n-1);
0789 }
0790
0791 template<class Container, typename Real = typename Container::value_type,
0792 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0793 inline Real sample_variance(const Container& c)
0794 {
0795 return sample_variance(std::begin(c), std::end(c));
0796 }
0797
0798 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0799 enable_if_t<std::is_integral<Real>::value, bool> = true>
0800 inline std::pair<double, double> mean_and_sample_variance(const ForwardIterator first, const ForwardIterator last)
0801 {
0802 const auto results = detail::variance_sequential_impl<std::tuple<double, double, double, double>>(first, last);
0803 return std::make_pair(std::get<0>(results), std::get<3>(results)*std::get<2>(results)/(std::get<3>(results)-1.0));
0804 }
0805
0806 template<class Container, typename Real = typename Container::value_type,
0807 enable_if_t<std::is_integral<Real>::value, bool> = true>
0808 inline std::pair<double, double> mean_and_sample_variance(const Container& c)
0809 {
0810 return mean_and_sample_variance(std::begin(c), std::end(c));
0811 }
0812
0813 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0814 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0815 inline std::pair<Real, Real> mean_and_sample_variance(const ForwardIterator first, const ForwardIterator last)
0816 {
0817 const auto results = detail::variance_sequential_impl<std::tuple<Real, Real, Real, Real>>(first, last);
0818 return std::make_pair(std::get<0>(results), std::get<3>(results)*std::get<2>(results)/(std::get<3>(results)-Real(1)));
0819 }
0820
0821 template<class Container, typename Real = typename Container::value_type,
0822 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0823 inline std::pair<Real, Real> mean_and_sample_variance(const Container& c)
0824 {
0825 return mean_and_sample_variance(std::begin(c), std::end(c));
0826 }
0827
0828 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0829 enable_if_t<std::is_integral<Real>::value, bool> = true>
0830 inline std::tuple<double, double, double, double> first_four_moments(const ForwardIterator first, const ForwardIterator last)
0831 {
0832 const auto results = detail::first_four_moments_sequential_impl<std::tuple<double, double, double, double, double>>(first, last);
0833 return std::make_tuple(std::get<0>(results), std::get<1>(results) / std::get<4>(results), std::get<2>(results) / std::get<4>(results),
0834 std::get<3>(results) / std::get<4>(results));
0835 }
0836
0837 template<class Container, typename Real = typename Container::value_type,
0838 enable_if_t<std::is_integral<Real>::value, bool> = true>
0839 inline std::tuple<double, double, double, double> first_four_moments(const Container& c)
0840 {
0841 return first_four_moments(std::begin(c), std::end(c));
0842 }
0843
0844 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0845 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0846 inline std::tuple<Real, Real, Real, Real> first_four_moments(const ForwardIterator first, const ForwardIterator last)
0847 {
0848 const auto results = detail::first_four_moments_sequential_impl<std::tuple<Real, Real, Real, Real, Real>>(first, last);
0849 return std::make_tuple(std::get<0>(results), std::get<1>(results) / std::get<4>(results), std::get<2>(results) / std::get<4>(results),
0850 std::get<3>(results) / std::get<4>(results));
0851 }
0852
0853 template<class Container, typename Real = typename Container::value_type,
0854 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0855 inline std::tuple<Real, Real, Real, Real> first_four_moments(const Container& c)
0856 {
0857 return first_four_moments(std::begin(c), std::end(c));
0858 }
0859
0860 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0861 enable_if_t<std::is_integral<Real>::value, bool> = true>
0862 inline double skewness(const ForwardIterator first, const ForwardIterator last)
0863 {
0864 return detail::skewness_sequential_impl<double>(first, last);
0865 }
0866
0867 template<class Container, typename Real = typename Container::value_type,
0868 enable_if_t<std::is_integral<Real>::value, bool> = true>
0869 inline double skewness(const Container& c)
0870 {
0871 return skewness(std::begin(c), std::end(c));
0872 }
0873
0874 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0875 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0876 inline Real skewness(const ForwardIterator first, const ForwardIterator last)
0877 {
0878 return detail::skewness_sequential_impl<Real>(first, last);
0879 }
0880
0881 template<class Container, typename Real = typename Container::value_type,
0882 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0883 inline Real skewness(const Container& c)
0884 {
0885 return skewness(std::begin(c), std::end(c));
0886 }
0887
0888 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0889 enable_if_t<std::is_integral<Real>::value, bool> = true>
0890 inline double kurtosis(const ForwardIterator first, const ForwardIterator last)
0891 {
0892 std::tuple<double, double, double, double> M = first_four_moments(first, last);
0893
0894 if(std::get<1>(M) == 0)
0895 {
0896 return std::get<1>(M);
0897 }
0898 else
0899 {
0900 return std::get<3>(M)/(std::get<1>(M)*std::get<1>(M));
0901 }
0902 }
0903
0904 template<class Container, typename Real = typename Container::value_type,
0905 enable_if_t<std::is_integral<Real>::value, bool> = true>
0906 inline double kurtosis(const Container& c)
0907 {
0908 return kurtosis(std::begin(c), std::end(c));
0909 }
0910
0911 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0912 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0913 inline Real kurtosis(const ForwardIterator first, const ForwardIterator last)
0914 {
0915 std::tuple<Real, Real, Real, Real> M = first_four_moments(first, last);
0916
0917 if(std::get<1>(M) == 0)
0918 {
0919 return std::get<1>(M);
0920 }
0921 else
0922 {
0923 return std::get<3>(M)/(std::get<1>(M)*std::get<1>(M));
0924 }
0925 }
0926
0927 template<class Container, typename Real = typename Container::value_type,
0928 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0929 inline Real kurtosis(const Container& c)
0930 {
0931 return kurtosis(std::begin(c), std::end(c));
0932 }
0933
0934 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0935 enable_if_t<std::is_integral<Real>::value, bool> = true>
0936 inline double excess_kurtosis(const ForwardIterator first, const ForwardIterator last)
0937 {
0938 return kurtosis(first, last) - 3;
0939 }
0940
0941 template<class Container, typename Real = typename Container::value_type,
0942 enable_if_t<std::is_integral<Real>::value, bool> = true>
0943 inline double excess_kurtosis(const Container& c)
0944 {
0945 return excess_kurtosis(std::begin(c), std::end(c));
0946 }
0947
0948 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type,
0949 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0950 inline Real excess_kurtosis(const ForwardIterator first, const ForwardIterator last)
0951 {
0952 return kurtosis(first, last) - 3;
0953 }
0954
0955 template<class Container, typename Real = typename Container::value_type,
0956 enable_if_t<!std::is_integral<Real>::value, bool> = true>
0957 inline Real excess_kurtosis(const Container& c)
0958 {
0959 return excess_kurtosis(std::begin(c), std::end(c));
0960 }
0961
0962 template<class RandomAccessIterator, typename Real = typename std::iterator_traits<RandomAccessIterator>::value_type>
0963 Real median(RandomAccessIterator first, RandomAccessIterator last)
0964 {
0965 const auto num_elems = std::distance(first, last);
0966 BOOST_MATH_ASSERT_MSG(num_elems > 0, "The median of a zero length vector is undefined.");
0967 if (num_elems & 1)
0968 {
0969 auto middle = first + (num_elems - 1)/2;
0970 std::nth_element(first, middle, last);
0971 return *middle;
0972 }
0973 else
0974 {
0975 auto middle = first + num_elems/2 - 1;
0976 std::nth_element(first, middle, last);
0977 std::nth_element(middle, middle+1, last);
0978 return (*middle + *(middle+1))/2;
0979 }
0980 }
0981
0982 template<class RandomAccessContainer, typename Real = typename RandomAccessContainer::value_type>
0983 inline Real median(RandomAccessContainer& c)
0984 {
0985 return median(std::begin(c), std::end(c));
0986 }
0987
0988 template<class RandomAccessIterator, typename Real = typename std::iterator_traits<RandomAccessIterator>::value_type,
0989 enable_if_t<std::is_integral<Real>::value, bool> = true>
0990 inline double gini_coefficient(RandomAccessIterator first, RandomAccessIterator last)
0991 {
0992 if(!std::is_sorted(first, last))
0993 {
0994 std::sort(first, last);
0995 }
0996
0997 return detail::gini_coefficient_sequential_impl<double>(first, last);
0998 }
0999
1000 template<class RandomAccessContainer, typename Real = typename RandomAccessContainer::value_type,
1001 enable_if_t<std::is_integral<Real>::value, bool> = true>
1002 inline double gini_coefficient(RandomAccessContainer& c)
1003 {
1004 return gini_coefficient(std::begin(c), std::end(c));
1005 }
1006
1007 template<class RandomAccessIterator, typename Real = typename std::iterator_traits<RandomAccessIterator>::value_type,
1008 enable_if_t<!std::is_integral<Real>::value, bool> = true>
1009 inline Real gini_coefficient(RandomAccessIterator first, RandomAccessIterator last)
1010 {
1011 if(!std::is_sorted(first, last))
1012 {
1013 std::sort(first, last);
1014 }
1015
1016 return detail::gini_coefficient_sequential_impl<Real>(first, last);
1017 }
1018
1019 template<class RandomAccessContainer, typename Real = typename RandomAccessContainer::value_type,
1020 enable_if_t<!std::is_integral<Real>::value, bool> = true>
1021 inline Real gini_coefficient(RandomAccessContainer& c)
1022 {
1023 return gini_coefficient(std::begin(c), std::end(c));
1024 }
1025
1026 template<class RandomAccessIterator, typename Real = typename std::iterator_traits<RandomAccessIterator>::value_type,
1027 enable_if_t<std::is_integral<Real>::value, bool> = true>
1028 inline double sample_gini_coefficient(RandomAccessIterator first, RandomAccessIterator last)
1029 {
1030 const auto n = std::distance(first, last);
1031 return n*gini_coefficient(first, last)/(n-1);
1032 }
1033
1034 template<class RandomAccessContainer, typename Real = typename RandomAccessContainer::value_type,
1035 enable_if_t<std::is_integral<Real>::value, bool> = true>
1036 inline double sample_gini_coefficient(RandomAccessContainer& c)
1037 {
1038 return sample_gini_coefficient(std::begin(c), std::end(c));
1039 }
1040
1041 template<class RandomAccessIterator, typename Real = typename std::iterator_traits<RandomAccessIterator>::value_type,
1042 enable_if_t<!std::is_integral<Real>::value, bool> = true>
1043 inline Real sample_gini_coefficient(RandomAccessIterator first, RandomAccessIterator last)
1044 {
1045 const auto n = std::distance(first, last);
1046 return n*gini_coefficient(first, last)/(n-1);
1047 }
1048
1049 template<class RandomAccessContainer, typename Real = typename RandomAccessContainer::value_type,
1050 enable_if_t<!std::is_integral<Real>::value, bool> = true>
1051 inline Real sample_gini_coefficient(RandomAccessContainer& c)
1052 {
1053 return sample_gini_coefficient(std::begin(c), std::end(c));
1054 }
1055
1056 template<class RandomAccessIterator, typename Real = typename std::iterator_traits<RandomAccessIterator>::value_type>
1057 Real median_absolute_deviation(RandomAccessIterator first, RandomAccessIterator last,
1058 typename std::iterator_traits<RandomAccessIterator>::value_type center=std::numeric_limits<typename std::iterator_traits<RandomAccessIterator>::value_type>::quiet_NaN())
1059 {
1060 using std::abs;
1061 using std::isnan;
1062 if (isnan(center))
1063 {
1064 center = boost::math::statistics::median(first, last);
1065 }
1066 const auto num_elems = std::distance(first, last);
1067 BOOST_MATH_ASSERT_MSG(num_elems > 0, "The median of a zero-length vector is undefined.");
1068 auto comparator = [¢er](Real a, Real b) { return abs(a-center) < abs(b-center);};
1069 if (num_elems & 1)
1070 {
1071 auto middle = first + (num_elems - 1)/2;
1072 std::nth_element(first, middle, last, comparator);
1073 return abs(*middle-center);
1074 }
1075 else
1076 {
1077 auto middle = first + num_elems/2 - 1;
1078 std::nth_element(first, middle, last, comparator);
1079 std::nth_element(middle, middle+1, last, comparator);
1080 return (abs(*middle-center) + abs(*(middle+1)-center))/abs(static_cast<Real>(2));
1081 }
1082 }
1083
1084 template<class RandomAccessContainer, typename Real = typename RandomAccessContainer::value_type>
1085 inline Real median_absolute_deviation(RandomAccessContainer& c,
1086 typename RandomAccessContainer::value_type center=std::numeric_limits<typename RandomAccessContainer::value_type>::quiet_NaN())
1087 {
1088 return median_absolute_deviation(std::begin(c), std::end(c), center);
1089 }
1090
1091 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type>
1092 Real interquartile_range(ForwardIterator first, ForwardIterator last)
1093 {
1094 static_assert(!std::is_integral<Real>::value, "Integer values have not yet been implemented.");
1095 auto m = std::distance(first,last);
1096 BOOST_MATH_ASSERT_MSG(m >= 3, "At least 3 samples are required to compute the interquartile range.");
1097 auto k = m/4;
1098 auto j = m - (4*k);
1099
1100
1101
1102
1103
1104 if (j==2 || j==3)
1105 {
1106 auto q1 = first + k;
1107 auto q3 = first + 3*k + j - 1;
1108 std::nth_element(first, q1, last);
1109 Real Q1 = *q1;
1110 std::nth_element(q1, q3, last);
1111 Real Q3 = *q3;
1112 return Q3 - Q1;
1113 }
1114 else
1115 {
1116
1117 auto q1 = first + k - 1;
1118 auto q3 = first + 3*k - 1 + j;
1119 std::nth_element(first, q1, last);
1120 Real a = *q1;
1121 std::nth_element(q1, q1 + 1, last);
1122 Real b = *(q1 + 1);
1123 Real Q1 = (a+b)/2;
1124 std::nth_element(q1, q3, last);
1125 a = *q3;
1126 std::nth_element(q3, q3 + 1, last);
1127 b = *(q3 + 1);
1128 Real Q3 = (a+b)/2;
1129 return Q3 - Q1;
1130 }
1131 }
1132
1133 template<class Container, typename Real = typename Container::value_type>
1134 Real interquartile_range(Container& c)
1135 {
1136 return interquartile_range(std::begin(c), std::end(c));
1137 }
1138
1139 template<class ForwardIterator, class OutputIterator,
1140 enable_if_t<std::is_same<typename std::iterator_traits<ForwardIterator>::iterator_category(), std::random_access_iterator_tag>::value, bool> = true>
1141 inline OutputIterator mode(ForwardIterator first, ForwardIterator last, OutputIterator output)
1142 {
1143 if(!std::is_sorted(first, last))
1144 {
1145 std::sort(first, last);
1146 }
1147
1148 return detail::mode_impl(first, last, output);
1149 }
1150
1151 template<class ForwardIterator, class OutputIterator,
1152 enable_if_t<!std::is_same<typename std::iterator_traits<ForwardIterator>::iterator_category(), std::random_access_iterator_tag>::value, bool> = true>
1153 inline OutputIterator mode(ForwardIterator first, ForwardIterator last, OutputIterator output)
1154 {
1155 if(!std::is_sorted(first, last))
1156 {
1157 BOOST_MATH_ASSERT("Data must be sorted for mode calculation");
1158 }
1159
1160 return detail::mode_impl(first, last, output);
1161 }
1162
1163 template<class Container, class OutputIterator>
1164 inline OutputIterator mode(Container& c, OutputIterator output)
1165 {
1166 return mode(std::begin(c), std::end(c), output);
1167 }
1168
1169 template<class ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type>
1170 inline std::list<Real> mode(ForwardIterator first, ForwardIterator last)
1171 {
1172 std::list<Real> modes;
1173 mode(first, last, std::inserter(modes, modes.begin()));
1174 return modes;
1175 }
1176
1177 template<class Container, typename Real = typename Container::value_type>
1178 inline std::list<Real> mode(Container& c)
1179 {
1180 return mode(std::begin(c), std::end(c));
1181 }
1182 }}}
1183 #endif
1184 #endif