File indexing completed on 2025-01-30 10:02:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef CATCH_STATS_HPP_INCLUDED
0011 #define CATCH_STATS_HPP_INCLUDED
0012
0013 #include <catch2/benchmark/catch_estimate.hpp>
0014 #include <catch2/benchmark/catch_outlier_classification.hpp>
0015
0016 #include <algorithm>
0017 #include <vector>
0018 #include <cmath>
0019
0020 namespace Catch {
0021 namespace Benchmark {
0022 namespace Detail {
0023 using sample = std::vector<double>;
0024
0025
0026
0027 bool directCompare( double lhs, double rhs );
0028
0029 double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last);
0030
0031 OutlierClassification
0032 classify_outliers( std::vector<double>::const_iterator first,
0033 std::vector<double>::const_iterator last );
0034
0035 double mean( std::vector<double>::const_iterator first,
0036 std::vector<double>::const_iterator last );
0037
0038 template <typename Estimator>
0039 sample jackknife(Estimator&& estimator,
0040 std::vector<double>::iterator first,
0041 std::vector<double>::iterator last) {
0042 auto n = static_cast<size_t>(last - first);
0043 auto second = first;
0044 ++second;
0045 sample results;
0046 results.reserve(n);
0047
0048 for (auto it = first; it != last; ++it) {
0049 std::iter_swap(it, first);
0050 results.push_back(estimator(second, last));
0051 }
0052
0053 return results;
0054 }
0055
0056 inline double normal_cdf(double x) {
0057 return std::erfc(-x / std::sqrt(2.0)) / 2.0;
0058 }
0059
0060 double erfc_inv(double x);
0061
0062 double normal_quantile(double p);
0063
0064 template <typename Estimator>
0065 Estimate<double> bootstrap( double confidence_level,
0066 std::vector<double>::iterator first,
0067 std::vector<double>::iterator last,
0068 sample const& resample,
0069 Estimator&& estimator ) {
0070 auto n_samples = last - first;
0071
0072 double point = estimator(first, last);
0073
0074 if (n_samples == 1) return { point, point, point, confidence_level };
0075
0076 sample jack = jackknife(estimator, first, last);
0077 double jack_mean = mean(jack.begin(), jack.end());
0078 double sum_squares = 0, sum_cubes = 0;
0079 for (double x : jack) {
0080 auto difference = jack_mean - x;
0081 auto square = difference * difference;
0082 auto cube = square * difference;
0083 sum_squares += square; sum_cubes += cube;
0084 }
0085
0086 double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5));
0087 long n = static_cast<long>(resample.size());
0088 double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / static_cast<double>(n);
0089
0090 if ( directCompare( prob_n, 0. ) ) {
0091 return { point, point, point, confidence_level };
0092 }
0093
0094 double bias = normal_quantile(prob_n);
0095 double z1 = normal_quantile((1. - confidence_level) / 2.);
0096
0097 auto cumn = [n]( double x ) -> long {
0098 return std::lround( normal_cdf( x ) * static_cast<double>(n) );
0099 };
0100 auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); };
0101 double b1 = bias + z1;
0102 double b2 = bias - z1;
0103 double a1 = a(b1);
0104 double a2 = a(b2);
0105 auto lo = static_cast<size_t>((std::max)(cumn(a1), 0l));
0106 auto hi = static_cast<size_t>((std::min)(cumn(a2), n - 1));
0107
0108 return { point, resample[lo], resample[hi], confidence_level };
0109 }
0110
0111 struct bootstrap_analysis {
0112 Estimate<double> mean;
0113 Estimate<double> standard_deviation;
0114 double outlier_variance;
0115 };
0116
0117 bootstrap_analysis analyse_samples(double confidence_level,
0118 unsigned int n_resamples,
0119 std::vector<double>::iterator first,
0120 std::vector<double>::iterator last);
0121 }
0122 }
0123 }
0124
0125 #endif