blob: 590bf8c7850cf9d59a73d1071b17341227503df0 [file] [log] [blame]
Artem Titove4ed6ea2019-01-11 11:02:19 +01001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "rtc_base/numerics/samples_stats_counter.h"
12
Artem Titove6f6a0c2019-02-07 12:14:35 +010013#include <math.h>
Artem Titovd2a63782019-03-21 10:37:37 +010014#include <random>
Artem Titove4ed6ea2019-01-11 11:02:19 +010015#include <vector>
16
Steve Anton2acd1632019-03-25 13:48:30 -070017#include "absl/algorithm/container.h"
Artem Titove4ed6ea2019-01-11 11:02:19 +010018#include "test/gtest.h"
19
20namespace webrtc {
21namespace {
Artem Titove6f6a0c2019-02-07 12:14:35 +010022
Artem Titove4ed6ea2019-01-11 11:02:19 +010023SamplesStatsCounter CreateStatsFilledWithIntsFrom1ToN(int n) {
24 std::vector<double> data;
25 for (int i = 1; i <= n; i++) {
26 data.push_back(i);
27 }
Steve Anton2acd1632019-03-25 13:48:30 -070028 absl::c_shuffle(data, std::mt19937(std::random_device()()));
Artem Titove4ed6ea2019-01-11 11:02:19 +010029
30 SamplesStatsCounter stats;
31 for (double v : data) {
32 stats.AddSample(v);
33 }
34 return stats;
35}
Artem Titove6f6a0c2019-02-07 12:14:35 +010036
Yves Gerey890f62b2019-04-10 17:18:48 +020037// Add n samples drawn from uniform distribution in [a;b].
38SamplesStatsCounter CreateStatsFromUniformDistribution(int n,
39 double a,
40 double b) {
41 std::mt19937 gen{std::random_device()()};
42 std::uniform_real_distribution<> dis(a, b);
43
44 SamplesStatsCounter stats;
45 for (int i = 1; i <= n; i++) {
46 stats.AddSample(dis(gen));
47 }
48 return stats;
49}
50
51class SamplesStatsCounterTest : public ::testing::TestWithParam<int> {};
52
53constexpr int SIZE_FOR_MERGE = 10;
54
Artem Titove4ed6ea2019-01-11 11:02:19 +010055} // namespace
56
57TEST(SamplesStatsCounter, FullSimpleTest) {
58 SamplesStatsCounter stats = CreateStatsFilledWithIntsFrom1ToN(100);
59
Artem Titove6f6a0c2019-02-07 12:14:35 +010060 EXPECT_TRUE(!stats.IsEmpty());
61 EXPECT_DOUBLE_EQ(stats.GetMin(), 1.0);
62 EXPECT_DOUBLE_EQ(stats.GetMax(), 100.0);
63 EXPECT_DOUBLE_EQ(stats.GetAverage(), 50.5);
Artem Titove4ed6ea2019-01-11 11:02:19 +010064 for (int i = 1; i <= 100; i++) {
65 double p = i / 100.0;
Artem Titove6f6a0c2019-02-07 12:14:35 +010066 EXPECT_GE(stats.GetPercentile(p), i);
67 EXPECT_LT(stats.GetPercentile(p), i + 1);
Artem Titove4ed6ea2019-01-11 11:02:19 +010068 }
69}
70
Artem Titove6f6a0c2019-02-07 12:14:35 +010071TEST(SamplesStatsCounter, VarianceAndDeviation) {
72 SamplesStatsCounter stats;
73 stats.AddSample(2);
74 stats.AddSample(2);
75 stats.AddSample(-1);
76 stats.AddSample(5);
77
78 EXPECT_DOUBLE_EQ(stats.GetAverage(), 2.0);
79 EXPECT_DOUBLE_EQ(stats.GetVariance(), 4.5);
80 EXPECT_DOUBLE_EQ(stats.GetStandardDeviation(), sqrt(4.5));
81}
82
Artem Titove4ed6ea2019-01-11 11:02:19 +010083TEST(SamplesStatsCounter, FractionPercentile) {
84 SamplesStatsCounter stats = CreateStatsFilledWithIntsFrom1ToN(5);
85
Artem Titove6f6a0c2019-02-07 12:14:35 +010086 EXPECT_DOUBLE_EQ(stats.GetPercentile(0.5), 3);
Artem Titove4ed6ea2019-01-11 11:02:19 +010087}
88
89TEST(SamplesStatsCounter, TestBorderValues) {
90 SamplesStatsCounter stats = CreateStatsFilledWithIntsFrom1ToN(5);
91
Artem Titove6f6a0c2019-02-07 12:14:35 +010092 EXPECT_GE(stats.GetPercentile(0.01), 1);
93 EXPECT_LT(stats.GetPercentile(0.01), 2);
94 EXPECT_DOUBLE_EQ(stats.GetPercentile(1.0), 5);
Artem Titove4ed6ea2019-01-11 11:02:19 +010095}
96
Yves Gerey890f62b2019-04-10 17:18:48 +020097TEST(SamplesStatsCounter, VarianceFromUniformDistribution) {
98 // Check variance converge to 1/12 for [0;1) uniform distribution.
99 // Acts as a sanity check for NumericStabilityForVariance test.
100 SamplesStatsCounter stats = CreateStatsFromUniformDistribution(1e6, 0, 1);
101
102 EXPECT_NEAR(stats.GetVariance(), 1. / 12, 1e-3);
103}
104
105TEST(SamplesStatsCounter, NumericStabilityForVariance) {
106 // Same test as VarianceFromUniformDistribution,
107 // except the range is shifted to [1e9;1e9+1).
108 // Variance should also converge to 1/12.
109 // NB: Although we lose precision for the samples themselves, the fractional
110 // part still enjoys 22 bits of mantissa and errors should even out,
111 // so that couldn't explain a mismatch.
112 SamplesStatsCounter stats =
113 CreateStatsFromUniformDistribution(1e6, 1e9, 1e9 + 1);
114
115 EXPECT_NEAR(stats.GetVariance(), 1. / 12, 1e-3);
116}
117
118TEST_P(SamplesStatsCounterTest, AddSamples) {
119 int data[SIZE_FOR_MERGE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
120 // Split the data in different partitions.
121 // We have 11 distinct tests:
122 // * Empty merged with full sequence.
123 // * 1 sample merged with 9 last.
124 // * 2 samples merged with 8 last.
125 // [...]
126 // * Full merged with empty sequence.
127 // All must lead to the same result.
128 SamplesStatsCounter stats0, stats1;
129 for (int i = 0; i < GetParam(); ++i) {
130 stats0.AddSample(data[i]);
131 }
132 for (int i = GetParam(); i < SIZE_FOR_MERGE; ++i) {
133 stats1.AddSample(data[i]);
134 }
135 stats0.AddSamples(stats1);
136
137 EXPECT_EQ(stats0.GetMin(), 0);
138 EXPECT_EQ(stats0.GetMax(), 9);
139 EXPECT_DOUBLE_EQ(stats0.GetAverage(), 4.5);
140 EXPECT_DOUBLE_EQ(stats0.GetVariance(), 8.25);
141 EXPECT_DOUBLE_EQ(stats0.GetStandardDeviation(), sqrt(8.25));
142 EXPECT_DOUBLE_EQ(stats0.GetPercentile(0.1), 0.9);
143 EXPECT_DOUBLE_EQ(stats0.GetPercentile(0.5), 4.5);
144 EXPECT_DOUBLE_EQ(stats0.GetPercentile(0.9), 8.1);
145}
146
147INSTANTIATE_TEST_SUITE_P(SamplesStatsCounterTests,
148 SamplesStatsCounterTest,
149 ::testing::Range(0, SIZE_FOR_MERGE + 1));
150
Artem Titove4ed6ea2019-01-11 11:02:19 +0100151} // namespace webrtc