xref: /aosp_15_r20/system/media/audio_utils/tests/statistics_tests.cpp (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
1*b9df5ad1SAndroid Build Coastguard Worker /*
2*b9df5ad1SAndroid Build Coastguard Worker  * Copyright 2018 The Android Open Source Project
3*b9df5ad1SAndroid Build Coastguard Worker  *
4*b9df5ad1SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*b9df5ad1SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*b9df5ad1SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*b9df5ad1SAndroid Build Coastguard Worker  *
8*b9df5ad1SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*b9df5ad1SAndroid Build Coastguard Worker  *
10*b9df5ad1SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*b9df5ad1SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*b9df5ad1SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b9df5ad1SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*b9df5ad1SAndroid Build Coastguard Worker  * limitations under the License.
15*b9df5ad1SAndroid Build Coastguard Worker  */
16*b9df5ad1SAndroid Build Coastguard Worker 
17*b9df5ad1SAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*b9df5ad1SAndroid Build Coastguard Worker #define LOG_TAG "audio_utils_statistics_tests"
19*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/Statistics.h>
20*b9df5ad1SAndroid Build Coastguard Worker 
21*b9df5ad1SAndroid Build Coastguard Worker #include <random>
22*b9df5ad1SAndroid Build Coastguard Worker #include <stdio.h>
23*b9df5ad1SAndroid Build Coastguard Worker #include <gtest/gtest.h>
24*b9df5ad1SAndroid Build Coastguard Worker 
25*b9df5ad1SAndroid Build Coastguard Worker // create uniform distribution
26*b9df5ad1SAndroid Build Coastguard Worker template <typename T, typename V>
initUniform(V & data,T rangeMin,T rangeMax)27*b9df5ad1SAndroid Build Coastguard Worker static void initUniform(V& data, T rangeMin, T rangeMax) {
28*b9df5ad1SAndroid Build Coastguard Worker     const size_t count = data.capacity();
29*b9df5ad1SAndroid Build Coastguard Worker     std::minstd_rand gen(count);
30*b9df5ad1SAndroid Build Coastguard Worker     std::uniform_real_distribution<T> dis(rangeMin, rangeMax);
31*b9df5ad1SAndroid Build Coastguard Worker 
32*b9df5ad1SAndroid Build Coastguard Worker     // for_each works for scalars
33*b9df5ad1SAndroid Build Coastguard Worker     for (auto& datum : data) {
34*b9df5ad1SAndroid Build Coastguard Worker         android::audio_utils::for_each(datum, [&](T &value) { return value = dis(gen);});
35*b9df5ad1SAndroid Build Coastguard Worker     }
36*b9df5ad1SAndroid Build Coastguard Worker }
37*b9df5ad1SAndroid Build Coastguard Worker 
38*b9df5ad1SAndroid Build Coastguard Worker // create gaussian distribution
39*b9df5ad1SAndroid Build Coastguard Worker template <typename T, typename V>
initNormal(V & data,T mean,T stddev)40*b9df5ad1SAndroid Build Coastguard Worker static void initNormal(V& data, T mean, T stddev) {
41*b9df5ad1SAndroid Build Coastguard Worker     const size_t count = data.capacity();
42*b9df5ad1SAndroid Build Coastguard Worker     std::minstd_rand gen(count);
43*b9df5ad1SAndroid Build Coastguard Worker 
44*b9df5ad1SAndroid Build Coastguard Worker     // values near the mean are the most likely
45*b9df5ad1SAndroid Build Coastguard Worker     // standard deviation affects the dispersion of generated values from the mean
46*b9df5ad1SAndroid Build Coastguard Worker     std::normal_distribution<> dis{mean, stddev};
47*b9df5ad1SAndroid Build Coastguard Worker 
48*b9df5ad1SAndroid Build Coastguard Worker     // for_each works for scalars
49*b9df5ad1SAndroid Build Coastguard Worker     for (auto& datum : data) {
50*b9df5ad1SAndroid Build Coastguard Worker         android::audio_utils::for_each(datum, [&](T &value) { return value = dis(gen);});
51*b9df5ad1SAndroid Build Coastguard Worker     }
52*b9df5ad1SAndroid Build Coastguard Worker }
53*b9df5ad1SAndroid Build Coastguard Worker 
54*b9df5ad1SAndroid Build Coastguard Worker // Used to create compile-time reference constants for variance testing.
55*b9df5ad1SAndroid Build Coastguard Worker template <typename T>
56*b9df5ad1SAndroid Build Coastguard Worker class ConstexprStatistics {
57*b9df5ad1SAndroid Build Coastguard Worker public:
58*b9df5ad1SAndroid Build Coastguard Worker     template <size_t N>
ConstexprStatistics(const T (& a)[N])59*b9df5ad1SAndroid Build Coastguard Worker     explicit constexpr ConstexprStatistics(const T (&a)[N])
60*b9df5ad1SAndroid Build Coastguard Worker         : mN{N}
61*b9df5ad1SAndroid Build Coastguard Worker         , mMax{android::audio_utils::max(a)}
62*b9df5ad1SAndroid Build Coastguard Worker         , mMin{android::audio_utils::min(a)}
63*b9df5ad1SAndroid Build Coastguard Worker         , mMean{android::audio_utils::sum(a) / mN}
64*b9df5ad1SAndroid Build Coastguard Worker         , mM2{android::audio_utils::sumSqDiff(a, mMean)}
65*b9df5ad1SAndroid Build Coastguard Worker         , mPopVariance{mM2 / mN}
66*b9df5ad1SAndroid Build Coastguard Worker         , mPopStdDev{android::audio_utils::sqrt_constexpr(mPopVariance)}
67*b9df5ad1SAndroid Build Coastguard Worker         , mVariance{mM2 / (mN - 1)}
68*b9df5ad1SAndroid Build Coastguard Worker         , mStdDev{android::audio_utils::sqrt_constexpr(mVariance)}
69*b9df5ad1SAndroid Build Coastguard Worker     { }
70*b9df5ad1SAndroid Build Coastguard Worker 
getN() const71*b9df5ad1SAndroid Build Coastguard Worker     constexpr int64_t getN() const { return mN; }
getMin() const72*b9df5ad1SAndroid Build Coastguard Worker     constexpr T getMin() const { return mMin; }
getMax() const73*b9df5ad1SAndroid Build Coastguard Worker     constexpr T getMax() const { return mMax; }
getWeight() const74*b9df5ad1SAndroid Build Coastguard Worker     constexpr double getWeight() const { return (double)mN; }
getMean() const75*b9df5ad1SAndroid Build Coastguard Worker     constexpr double getMean() const { return mMean; }
getVariance() const76*b9df5ad1SAndroid Build Coastguard Worker     constexpr double getVariance() const { return mVariance; }
getStdDev() const77*b9df5ad1SAndroid Build Coastguard Worker     constexpr double getStdDev() const { return mStdDev; }
getPopVariance() const78*b9df5ad1SAndroid Build Coastguard Worker     constexpr double getPopVariance() const { return mPopVariance; }
getPopStdDev() const79*b9df5ad1SAndroid Build Coastguard Worker     constexpr double getPopStdDev() const { return mPopStdDev; }
80*b9df5ad1SAndroid Build Coastguard Worker 
81*b9df5ad1SAndroid Build Coastguard Worker private:
82*b9df5ad1SAndroid Build Coastguard Worker     const size_t mN;
83*b9df5ad1SAndroid Build Coastguard Worker     const T mMax;
84*b9df5ad1SAndroid Build Coastguard Worker     const T mMin;
85*b9df5ad1SAndroid Build Coastguard Worker     const double mMean;
86*b9df5ad1SAndroid Build Coastguard Worker     const double mM2;
87*b9df5ad1SAndroid Build Coastguard Worker     const double mPopVariance;
88*b9df5ad1SAndroid Build Coastguard Worker     const double mPopStdDev;
89*b9df5ad1SAndroid Build Coastguard Worker     const double mVariance;
90*b9df5ad1SAndroid Build Coastguard Worker     const double mStdDev;
91*b9df5ad1SAndroid Build Coastguard Worker };
92*b9df5ad1SAndroid Build Coastguard Worker 
93*b9df5ad1SAndroid Build Coastguard Worker class StatisticsTest : public testing::TestWithParam<const char *>
94*b9df5ad1SAndroid Build Coastguard Worker {
95*b9df5ad1SAndroid Build Coastguard Worker };
96*b9df5ad1SAndroid Build Coastguard Worker 
97*b9df5ad1SAndroid Build Coastguard Worker // find power of 2 that is small enough that it doesn't add to 1. due to finite mantissa.
98*b9df5ad1SAndroid Build Coastguard Worker template <typename T>
smallp2()99*b9df5ad1SAndroid Build Coastguard Worker constexpr T smallp2() {
100*b9df5ad1SAndroid Build Coastguard Worker     T smallOne{};
101*b9df5ad1SAndroid Build Coastguard Worker     for (smallOne = T{1.}; smallOne + T{1.} > T{1.}; smallOne *= T(0.5));
102*b9df5ad1SAndroid Build Coastguard Worker     return smallOne;
103*b9df5ad1SAndroid Build Coastguard Worker }
104*b9df5ad1SAndroid Build Coastguard Worker 
105*b9df5ad1SAndroid Build Coastguard Worker // Our near expectation is 16x the bit that doesn't fit the mantissa.
106*b9df5ad1SAndroid Build Coastguard Worker // this works so long as we add values close in exponent with each other
107*b9df5ad1SAndroid Build Coastguard Worker // realizing that errors accumulate as the sqrt of N (random walk, lln, etc).
108*b9df5ad1SAndroid Build Coastguard Worker #define TEST_EXPECT_NEAR(e, v) \
109*b9df5ad1SAndroid Build Coastguard Worker     EXPECT_NEAR((e), (v), abs((e) * std::numeric_limits<decltype(e)>::epsilon() * 8))
110*b9df5ad1SAndroid Build Coastguard Worker 
111*b9df5ad1SAndroid Build Coastguard Worker #define PRINT_AND_EXPECT_EQ(expected, expr) { \
112*b9df5ad1SAndroid Build Coastguard Worker     auto value = (expr); \
113*b9df5ad1SAndroid Build Coastguard Worker     printf("(%s): %s\n", #expr, std::to_string(value).c_str()); \
114*b9df5ad1SAndroid Build Coastguard Worker     if ((expected) == (expected)) { EXPECT_EQ((expected), (value)); } \
115*b9df5ad1SAndroid Build Coastguard Worker     EXPECT_EQ((expected) != (expected), (value) != (value)); /* nan check */\
116*b9df5ad1SAndroid Build Coastguard Worker }
117*b9df5ad1SAndroid Build Coastguard Worker 
118*b9df5ad1SAndroid Build Coastguard Worker #define PRINT_AND_EXPECT_NEAR(expected, expr) { \
119*b9df5ad1SAndroid Build Coastguard Worker     auto ref = (expected); \
120*b9df5ad1SAndroid Build Coastguard Worker     auto value = (expr); \
121*b9df5ad1SAndroid Build Coastguard Worker     printf("(%s): %s\n", #expr, std::to_string(value).c_str()); \
122*b9df5ad1SAndroid Build Coastguard Worker     TEST_EXPECT_NEAR(ref, value); \
123*b9df5ad1SAndroid Build Coastguard Worker }
124*b9df5ad1SAndroid Build Coastguard Worker 
125*b9df5ad1SAndroid Build Coastguard Worker template <typename T, typename S>
verify(const T & stat,const S & refstat)126*b9df5ad1SAndroid Build Coastguard Worker static void verify(const T &stat, const S &refstat) {
127*b9df5ad1SAndroid Build Coastguard Worker     EXPECT_EQ(refstat.getN(), stat.getN());
128*b9df5ad1SAndroid Build Coastguard Worker     EXPECT_EQ(refstat.getMin(), stat.getMin());
129*b9df5ad1SAndroid Build Coastguard Worker     EXPECT_EQ(refstat.getMax(), stat.getMax());
130*b9df5ad1SAndroid Build Coastguard Worker     TEST_EXPECT_NEAR(refstat.getWeight(), stat.getWeight());
131*b9df5ad1SAndroid Build Coastguard Worker     TEST_EXPECT_NEAR(refstat.getMean(), stat.getMean());
132*b9df5ad1SAndroid Build Coastguard Worker     TEST_EXPECT_NEAR(refstat.getVariance(), stat.getVariance());
133*b9df5ad1SAndroid Build Coastguard Worker     TEST_EXPECT_NEAR(refstat.getStdDev(), stat.getStdDev());
134*b9df5ad1SAndroid Build Coastguard Worker     TEST_EXPECT_NEAR(refstat.getPopVariance(), stat.getPopVariance());
135*b9df5ad1SAndroid Build Coastguard Worker     TEST_EXPECT_NEAR(refstat.getPopStdDev(), stat.getPopStdDev());
136*b9df5ad1SAndroid Build Coastguard Worker }
137*b9df5ad1SAndroid Build Coastguard Worker 
138*b9df5ad1SAndroid Build Coastguard Worker // Test against fixed reference
139*b9df5ad1SAndroid Build Coastguard Worker 
TEST(StatisticsTest,high_precision_sums)140*b9df5ad1SAndroid Build Coastguard Worker TEST(StatisticsTest, high_precision_sums)
141*b9df5ad1SAndroid Build Coastguard Worker {
142*b9df5ad1SAndroid Build Coastguard Worker     static const double simple[] = { 1., 2., 3. };
143*b9df5ad1SAndroid Build Coastguard Worker 
144*b9df5ad1SAndroid Build Coastguard Worker     double rssum = android::audio_utils::sum<double, double>(simple);
145*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(6., rssum);
146*b9df5ad1SAndroid Build Coastguard Worker     double kssum =
147*b9df5ad1SAndroid Build Coastguard Worker         android::audio_utils::sum<double, android::audio_utils::KahanSum<double>>(simple);
148*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(6., kssum);
149*b9df5ad1SAndroid Build Coastguard Worker     double nmsum =
150*b9df5ad1SAndroid Build Coastguard Worker         android::audio_utils::sum<double, android::audio_utils::NeumaierSum<double>>(simple);
151*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(6., nmsum);
152*b9df5ad1SAndroid Build Coastguard Worker 
153*b9df5ad1SAndroid Build Coastguard Worker     double rs{};
154*b9df5ad1SAndroid Build Coastguard Worker     android::audio_utils::KahanSum<double> ks{};
155*b9df5ad1SAndroid Build Coastguard Worker     android::audio_utils::NeumaierSum<double> ns{};
156*b9df5ad1SAndroid Build Coastguard Worker 
157*b9df5ad1SAndroid Build Coastguard Worker     // add 1.
158*b9df5ad1SAndroid Build Coastguard Worker     rs += 1.;
159*b9df5ad1SAndroid Build Coastguard Worker     ks += 1.;
160*b9df5ad1SAndroid Build Coastguard Worker     ns += 1.;
161*b9df5ad1SAndroid Build Coastguard Worker 
162*b9df5ad1SAndroid Build Coastguard Worker     static constexpr double smallOne = std::numeric_limits<double>::epsilon() * 0.5;
163*b9df5ad1SAndroid Build Coastguard Worker     // add lots of small values
164*b9df5ad1SAndroid Build Coastguard Worker     static const int loop = 1000;
165*b9df5ad1SAndroid Build Coastguard Worker     for (int i = 0; i < loop; ++i) {
166*b9df5ad1SAndroid Build Coastguard Worker         rs += smallOne;
167*b9df5ad1SAndroid Build Coastguard Worker         ks += smallOne;
168*b9df5ad1SAndroid Build Coastguard Worker         ns += smallOne;
169*b9df5ad1SAndroid Build Coastguard Worker     }
170*b9df5ad1SAndroid Build Coastguard Worker 
171*b9df5ad1SAndroid Build Coastguard Worker     // remove 1.
172*b9df5ad1SAndroid Build Coastguard Worker     rs += -1.;
173*b9df5ad1SAndroid Build Coastguard Worker     ks += -1.;
174*b9df5ad1SAndroid Build Coastguard Worker     ns += -1.;
175*b9df5ad1SAndroid Build Coastguard Worker 
176*b9df5ad1SAndroid Build Coastguard Worker     const double totalAdded = smallOne * loop;
177*b9df5ad1SAndroid Build Coastguard Worker     printf("totalAdded: %lg\n", totalAdded);
178*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(0., rs);            // normal count fails
179*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(totalAdded, ks);    // kahan succeeds
180*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(totalAdded, ns);    // neumaier succeeds
181*b9df5ad1SAndroid Build Coastguard Worker 
182*b9df5ad1SAndroid Build Coastguard Worker     // test case where kahan fails and neumaier method succeeds.
183*b9df5ad1SAndroid Build Coastguard Worker     static const double tricky[] = { 1e100, 1., -1e100 };
184*b9df5ad1SAndroid Build Coastguard Worker 
185*b9df5ad1SAndroid Build Coastguard Worker     rssum = android::audio_utils::sum<double, double>(tricky);
186*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(0., rssum);
187*b9df5ad1SAndroid Build Coastguard Worker     kssum = android::audio_utils::sum<double, android::audio_utils::KahanSum<double>>(tricky);
188*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(0., kssum);
189*b9df5ad1SAndroid Build Coastguard Worker     nmsum = android::audio_utils::sum<double, android::audio_utils::NeumaierSum<double>>(tricky);
190*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(1., nmsum);
191*b9df5ad1SAndroid Build Coastguard Worker }
192*b9df5ad1SAndroid Build Coastguard Worker 
TEST(StatisticsTest,minmax_bounds)193*b9df5ad1SAndroid Build Coastguard Worker TEST(StatisticsTest, minmax_bounds)
194*b9df5ad1SAndroid Build Coastguard Worker {
195*b9df5ad1SAndroid Build Coastguard Worker     // range based min and max use iterator forms of min and max.
196*b9df5ad1SAndroid Build Coastguard Worker 
197*b9df5ad1SAndroid Build Coastguard Worker     static constexpr double one[] = { 1. };
198*b9df5ad1SAndroid Build Coastguard Worker 
199*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(std::numeric_limits<double>::infinity(),
200*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::min(&one[0], &one[0]));
201*b9df5ad1SAndroid Build Coastguard Worker 
202*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(-std::numeric_limits<double>::infinity(),
203*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::max(&one[0], &one[0]));
204*b9df5ad1SAndroid Build Coastguard Worker 
205*b9df5ad1SAndroid Build Coastguard Worker     static constexpr int un[] = { 1 };
206*b9df5ad1SAndroid Build Coastguard Worker 
207*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(std::numeric_limits<int>::max(),
208*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::min(&un[0], &un[0]));
209*b9df5ad1SAndroid Build Coastguard Worker 
210*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(std::numeric_limits<int>::min(),
211*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::max(&un[0], &un[0]));
212*b9df5ad1SAndroid Build Coastguard Worker 
213*b9df5ad1SAndroid Build Coastguard Worker     double nanarray[] = { nan(""), nan(""), nan("") };
214*b9df5ad1SAndroid Build Coastguard Worker 
215*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(std::numeric_limits<double>::infinity(),
216*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::min(nanarray));
217*b9df5ad1SAndroid Build Coastguard Worker 
218*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(-std::numeric_limits<double>::infinity(),
219*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::max(nanarray));
220*b9df5ad1SAndroid Build Coastguard Worker 
221*b9df5ad1SAndroid Build Coastguard Worker     android::audio_utils::Statistics<double> s(nanarray);
222*b9df5ad1SAndroid Build Coastguard Worker 
223*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(std::numeric_limits<double>::infinity(),
224*b9df5ad1SAndroid Build Coastguard Worker            s.getMin());
225*b9df5ad1SAndroid Build Coastguard Worker 
226*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(-std::numeric_limits<double>::infinity(),
227*b9df5ad1SAndroid Build Coastguard Worker             s.getMax());
228*b9df5ad1SAndroid Build Coastguard Worker }
229*b9df5ad1SAndroid Build Coastguard Worker 
230*b9df5ad1SAndroid Build Coastguard Worker /*
231*b9df5ad1SAndroid Build Coastguard Worker TEST(StatisticsTest, sqrt_convergence)
232*b9df5ad1SAndroid Build Coastguard Worker {
233*b9df5ad1SAndroid Build Coastguard Worker     union {
234*b9df5ad1SAndroid Build Coastguard Worker         int i;
235*b9df5ad1SAndroid Build Coastguard Worker         float f;
236*b9df5ad1SAndroid Build Coastguard Worker     } u;
237*b9df5ad1SAndroid Build Coastguard Worker 
238*b9df5ad1SAndroid Build Coastguard Worker     for (int i = 0; i < INT_MAX; ++i) {
239*b9df5ad1SAndroid Build Coastguard Worker         u.i = i;
240*b9df5ad1SAndroid Build Coastguard Worker         const float f = u.f;
241*b9df5ad1SAndroid Build Coastguard Worker         if (!android::audio_utils::isnan(f)) {
242*b9df5ad1SAndroid Build Coastguard Worker             const float sf = android::audio_utils::sqrt(f);
243*b9df5ad1SAndroid Build Coastguard Worker             if ((i & (1 << 16) - 1) == 0) {
244*b9df5ad1SAndroid Build Coastguard Worker                 printf("i: %d  f:%f  sf:%f\n", i, f, sf);
245*b9df5ad1SAndroid Build Coastguard Worker             }
246*b9df5ad1SAndroid Build Coastguard Worker         }
247*b9df5ad1SAndroid Build Coastguard Worker     }
248*b9df5ad1SAndroid Build Coastguard Worker }
249*b9df5ad1SAndroid Build Coastguard Worker */
250*b9df5ad1SAndroid Build Coastguard Worker 
TEST(StatisticsTest,minmax_simple_array)251*b9df5ad1SAndroid Build Coastguard Worker TEST(StatisticsTest, minmax_simple_array)
252*b9df5ad1SAndroid Build Coastguard Worker {
253*b9df5ad1SAndroid Build Coastguard Worker     static constexpr double ary[] = { -1.5, 1.5, -2.5, 2.5 };
254*b9df5ad1SAndroid Build Coastguard Worker 
255*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(-2.5, android::audio_utils::min(ary));
256*b9df5ad1SAndroid Build Coastguard Worker 
257*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(2.5, android::audio_utils::max(ary));
258*b9df5ad1SAndroid Build Coastguard Worker 
259*b9df5ad1SAndroid Build Coastguard Worker     static constexpr int ray[] = { -1, 1, -2, 2 };
260*b9df5ad1SAndroid Build Coastguard Worker 
261*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(-2, android::audio_utils::min(ray));
262*b9df5ad1SAndroid Build Coastguard Worker 
263*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(2, android::audio_utils::max(ray));
264*b9df5ad1SAndroid Build Coastguard Worker }
265*b9df5ad1SAndroid Build Coastguard Worker 
TEST(StatisticsTest,sqrt)266*b9df5ad1SAndroid Build Coastguard Worker TEST(StatisticsTest, sqrt)
267*b9df5ad1SAndroid Build Coastguard Worker {
268*b9df5ad1SAndroid Build Coastguard Worker     // check doubles
269*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(std::numeric_limits<double>::infinity(),
270*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::sqrt(std::numeric_limits<double>::infinity()));
271*b9df5ad1SAndroid Build Coastguard Worker 
272*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(std::nan(""),
273*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::sqrt(-std::numeric_limits<double>::infinity()));
274*b9df5ad1SAndroid Build Coastguard Worker 
275*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_NEAR(sqrt(std::numeric_limits<double>::epsilon()),
276*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::sqrt(std::numeric_limits<double>::epsilon()));
277*b9df5ad1SAndroid Build Coastguard Worker 
278*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(3.,
279*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::sqrt(9.));
280*b9df5ad1SAndroid Build Coastguard Worker 
281*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(0.,
282*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::sqrt(0.));
283*b9df5ad1SAndroid Build Coastguard Worker 
284*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(std::nan(""),
285*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::sqrt(-1.));
286*b9df5ad1SAndroid Build Coastguard Worker 
287*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(std::nan(""),
288*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::sqrt(std::nan("")));
289*b9df5ad1SAndroid Build Coastguard Worker 
290*b9df5ad1SAndroid Build Coastguard Worker     // check floats
291*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(std::numeric_limits<float>::infinity(),
292*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::sqrt(std::numeric_limits<float>::infinity()));
293*b9df5ad1SAndroid Build Coastguard Worker 
294*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(std::nanf(""),
295*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::sqrt(-std::numeric_limits<float>::infinity()));
296*b9df5ad1SAndroid Build Coastguard Worker 
297*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_NEAR(sqrtf(std::numeric_limits<float>::epsilon()),
298*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::sqrt(std::numeric_limits<float>::epsilon()));
299*b9df5ad1SAndroid Build Coastguard Worker 
300*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(2.f,
301*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::sqrt(4.f));
302*b9df5ad1SAndroid Build Coastguard Worker 
303*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(0.f,
304*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::sqrt(0.f));
305*b9df5ad1SAndroid Build Coastguard Worker 
306*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(std::nanf(""),
307*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::sqrt(-1.f));
308*b9df5ad1SAndroid Build Coastguard Worker 
309*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(std::nanf(""),
310*b9df5ad1SAndroid Build Coastguard Worker             android::audio_utils::sqrt(std::nanf("")));
311*b9df5ad1SAndroid Build Coastguard Worker }
312*b9df5ad1SAndroid Build Coastguard Worker 
TEST(StatisticsTest,stat_reference)313*b9df5ad1SAndroid Build Coastguard Worker TEST(StatisticsTest, stat_reference)
314*b9df5ad1SAndroid Build Coastguard Worker {
315*b9df5ad1SAndroid Build Coastguard Worker     // fixed reference compile time constants.
316*b9df5ad1SAndroid Build Coastguard Worker     static constexpr double data[] = {0.1, -0.1, 0.2, -0.3};
317*b9df5ad1SAndroid Build Coastguard Worker     static constexpr ConstexprStatistics<double> rstat(data); // use alpha = 1.
318*b9df5ad1SAndroid Build Coastguard Worker     static constexpr android::audio_utils::Statistics<double> stat{data};
319*b9df5ad1SAndroid Build Coastguard Worker 
320*b9df5ad1SAndroid Build Coastguard Worker     verify(stat, rstat);
321*b9df5ad1SAndroid Build Coastguard Worker }
322*b9df5ad1SAndroid Build Coastguard Worker 
TEST(StatisticsTest,stat_variable_alpha)323*b9df5ad1SAndroid Build Coastguard Worker TEST(StatisticsTest, stat_variable_alpha)
324*b9df5ad1SAndroid Build Coastguard Worker {
325*b9df5ad1SAndroid Build Coastguard Worker     constexpr size_t TEST_SIZE = 1 << 20;
326*b9df5ad1SAndroid Build Coastguard Worker     std::vector<double> data(TEST_SIZE);
327*b9df5ad1SAndroid Build Coastguard Worker     std::vector<double> alpha(TEST_SIZE);
328*b9df5ad1SAndroid Build Coastguard Worker 
329*b9df5ad1SAndroid Build Coastguard Worker     initUniform(data, -1., 1.);
330*b9df5ad1SAndroid Build Coastguard Worker     initUniform(alpha, .95, .99);
331*b9df5ad1SAndroid Build Coastguard Worker 
332*b9df5ad1SAndroid Build Coastguard Worker     android::audio_utils::ReferenceStatistics<double> rstat;
333*b9df5ad1SAndroid Build Coastguard Worker     android::audio_utils::Statistics<double> stat;
334*b9df5ad1SAndroid Build Coastguard Worker 
335*b9df5ad1SAndroid Build Coastguard Worker     static_assert(std::is_trivially_copyable<decltype(stat)>::value,
336*b9df5ad1SAndroid Build Coastguard Worker         "basic statistics must be trivially copyable");
337*b9df5ad1SAndroid Build Coastguard Worker 
338*b9df5ad1SAndroid Build Coastguard Worker     for (size_t i = 0; i < TEST_SIZE; ++i) {
339*b9df5ad1SAndroid Build Coastguard Worker         rstat.setAlpha(alpha[i]);
340*b9df5ad1SAndroid Build Coastguard Worker         rstat.add(data[i]);
341*b9df5ad1SAndroid Build Coastguard Worker 
342*b9df5ad1SAndroid Build Coastguard Worker         stat.setAlpha(alpha[i]);
343*b9df5ad1SAndroid Build Coastguard Worker         stat.add(data[i]);
344*b9df5ad1SAndroid Build Coastguard Worker     }
345*b9df5ad1SAndroid Build Coastguard Worker 
346*b9df5ad1SAndroid Build Coastguard Worker     printf("statistics: %s\n", stat.toString().c_str());
347*b9df5ad1SAndroid Build Coastguard Worker     printf("ref statistics: %s\n", rstat.toString().c_str());
348*b9df5ad1SAndroid Build Coastguard Worker     verify(stat, rstat);
349*b9df5ad1SAndroid Build Coastguard Worker }
350*b9df5ad1SAndroid Build Coastguard Worker 
TEST(StatisticsTest,stat_vector)351*b9df5ad1SAndroid Build Coastguard Worker TEST(StatisticsTest, stat_vector)
352*b9df5ad1SAndroid Build Coastguard Worker {
353*b9df5ad1SAndroid Build Coastguard Worker     // for operator overloading...
354*b9df5ad1SAndroid Build Coastguard Worker     using namespace android::audio_utils;
355*b9df5ad1SAndroid Build Coastguard Worker 
356*b9df5ad1SAndroid Build Coastguard Worker     using data_t = std::tuple<double, double>;
357*b9df5ad1SAndroid Build Coastguard Worker     using covariance_t = std::tuple<double, double, double, double>;
358*b9df5ad1SAndroid Build Coastguard Worker     using covariance_ut_t = std::tuple<double, double, double>;
359*b9df5ad1SAndroid Build Coastguard Worker 
360*b9df5ad1SAndroid Build Coastguard Worker     constexpr size_t TEST_SIZE = 1 << 20;
361*b9df5ad1SAndroid Build Coastguard Worker     std::vector<data_t> data(TEST_SIZE);
362*b9df5ad1SAndroid Build Coastguard Worker     // std::vector<double> alpha(TEST_SIZE);
363*b9df5ad1SAndroid Build Coastguard Worker 
364*b9df5ad1SAndroid Build Coastguard Worker     initUniform(data, -1., 1.);
365*b9df5ad1SAndroid Build Coastguard Worker 
366*b9df5ad1SAndroid Build Coastguard Worker     std::cout << "sample data[0]: " << data[0] << "\n";
367*b9df5ad1SAndroid Build Coastguard Worker 
368*b9df5ad1SAndroid Build Coastguard Worker     Statistics<data_t, data_t, data_t, double, double, innerProduct_scalar<data_t>> stat;
369*b9df5ad1SAndroid Build Coastguard Worker     Statistics<data_t, data_t, data_t, double,
370*b9df5ad1SAndroid Build Coastguard Worker             covariance_t, outerProduct_tuple<data_t>> stat_outer;
371*b9df5ad1SAndroid Build Coastguard Worker     Statistics<data_t, data_t, data_t, double,
372*b9df5ad1SAndroid Build Coastguard Worker             covariance_ut_t, outerProduct_UT_tuple<data_t>> stat_outer_ut;
373*b9df5ad1SAndroid Build Coastguard Worker 
374*b9df5ad1SAndroid Build Coastguard Worker     using pair_t = std::pair<double, double>;
375*b9df5ad1SAndroid Build Coastguard Worker     std::vector<pair_t> pairs(TEST_SIZE);
376*b9df5ad1SAndroid Build Coastguard Worker     initUniform(pairs, -1., 1.);
377*b9df5ad1SAndroid Build Coastguard Worker     Statistics<pair_t, pair_t, pair_t, double, double, innerProduct_scalar<pair_t>> stat_pair;
378*b9df5ad1SAndroid Build Coastguard Worker 
379*b9df5ad1SAndroid Build Coastguard Worker     using array_t = std::array<double, 2>;
380*b9df5ad1SAndroid Build Coastguard Worker     using array_covariance_ut_t = std::array<double, 3>;
381*b9df5ad1SAndroid Build Coastguard Worker     std::vector<array_t> arrays(TEST_SIZE);
382*b9df5ad1SAndroid Build Coastguard Worker     initUniform(arrays, -1., 1.);
383*b9df5ad1SAndroid Build Coastguard Worker     Statistics<array_t, array_t, array_t, double,
384*b9df5ad1SAndroid Build Coastguard Worker                double, innerProduct_scalar<array_t>> stat_array;
385*b9df5ad1SAndroid Build Coastguard Worker     Statistics<array_t, array_t, array_t, double,
386*b9df5ad1SAndroid Build Coastguard Worker                array_covariance_ut_t, outerProduct_UT_array<array_t>> stat_array_ut;
387*b9df5ad1SAndroid Build Coastguard Worker 
388*b9df5ad1SAndroid Build Coastguard Worker     for (size_t i = 0; i < TEST_SIZE; ++i) {
389*b9df5ad1SAndroid Build Coastguard Worker         stat.add(data[i]);
390*b9df5ad1SAndroid Build Coastguard Worker         stat_outer.add(data[i]);
391*b9df5ad1SAndroid Build Coastguard Worker         stat_outer_ut.add(data[i]);
392*b9df5ad1SAndroid Build Coastguard Worker         stat_pair.add(pairs[i]);
393*b9df5ad1SAndroid Build Coastguard Worker         stat_array.add(arrays[i]);
394*b9df5ad1SAndroid Build Coastguard Worker         stat_array_ut.add(arrays[i]);
395*b9df5ad1SAndroid Build Coastguard Worker     }
396*b9df5ad1SAndroid Build Coastguard Worker 
397*b9df5ad1SAndroid Build Coastguard Worker #if 0
398*b9df5ad1SAndroid Build Coastguard Worker     // these aren't trivially copyable
399*b9df5ad1SAndroid Build Coastguard Worker     static_assert(std::is_trivially_copyable<decltype(stat)>::value,
400*b9df5ad1SAndroid Build Coastguard Worker         "tuple based inner product not trivially copyable");
401*b9df5ad1SAndroid Build Coastguard Worker     static_assert(std::is_trivially_copyable<decltype(stat_outer)>::value,
402*b9df5ad1SAndroid Build Coastguard Worker         "tuple based outer product not trivially copyable");
403*b9df5ad1SAndroid Build Coastguard Worker     static_assert(std::is_trivially_copyable<decltype(stat_outer_ut)>::value,
404*b9df5ad1SAndroid Build Coastguard Worker         "tuple based outer product not trivially copyable");
405*b9df5ad1SAndroid Build Coastguard Worker #endif
406*b9df5ad1SAndroid Build Coastguard Worker     static_assert(std::is_trivially_copyable<decltype(stat_array)>::value,
407*b9df5ad1SAndroid Build Coastguard Worker         "array based inner product not trivially copyable");
408*b9df5ad1SAndroid Build Coastguard Worker     static_assert(std::is_trivially_copyable<decltype(stat_array_ut)>::value,
409*b9df5ad1SAndroid Build Coastguard Worker         "array based inner product not trivially copyable");
410*b9df5ad1SAndroid Build Coastguard Worker 
411*b9df5ad1SAndroid Build Coastguard Worker     // inner product variance should be same as outer product diagonal sum
412*b9df5ad1SAndroid Build Coastguard Worker     const double variance = stat.getPopVariance();
413*b9df5ad1SAndroid Build Coastguard Worker     EXPECT_NEAR(variance,
414*b9df5ad1SAndroid Build Coastguard Worker         std::get<0>(stat_outer.getPopVariance()) +
415*b9df5ad1SAndroid Build Coastguard Worker         std::get<3>(stat_outer.getPopVariance()),
416*b9df5ad1SAndroid Build Coastguard Worker         variance * std::numeric_limits<double>::epsilon() * 128);
417*b9df5ad1SAndroid Build Coastguard Worker 
418*b9df5ad1SAndroid Build Coastguard Worker     // outer product covariance should be identical
419*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_NEAR(std::get<1>(stat_outer.getPopVariance()),
420*b9df5ad1SAndroid Build Coastguard Worker         std::get<2>(stat_outer.getPopVariance()));
421*b9df5ad1SAndroid Build Coastguard Worker 
422*b9df5ad1SAndroid Build Coastguard Worker     // upper triangular computation should be identical to outer product
423*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_NEAR(std::get<0>(stat_outer.getPopVariance()),
424*b9df5ad1SAndroid Build Coastguard Worker         std::get<0>(stat_outer_ut.getPopVariance()));
425*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_NEAR(std::get<1>(stat_outer.getPopVariance()),
426*b9df5ad1SAndroid Build Coastguard Worker         std::get<1>(stat_outer_ut.getPopVariance()));
427*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_NEAR(std::get<3>(stat_outer.getPopVariance()),
428*b9df5ad1SAndroid Build Coastguard Worker         std::get<2>(stat_outer_ut.getPopVariance()));
429*b9df5ad1SAndroid Build Coastguard Worker 
430*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(variance, stat_pair.getPopVariance());
431*b9df5ad1SAndroid Build Coastguard Worker 
432*b9df5ad1SAndroid Build Coastguard Worker     EXPECT_TRUE(equivalent(stat_array_ut.getPopVariance(), stat_outer_ut.getPopVariance()));
433*b9df5ad1SAndroid Build Coastguard Worker 
434*b9df5ad1SAndroid Build Coastguard Worker     printf("statistics_inner: %s\n", stat.toString().c_str());
435*b9df5ad1SAndroid Build Coastguard Worker     printf("statistics_outer: %s\n", stat_outer.toString().c_str());
436*b9df5ad1SAndroid Build Coastguard Worker     printf("statistics_outer_ut: %s\n", stat_outer_ut.toString().c_str());
437*b9df5ad1SAndroid Build Coastguard Worker }
438*b9df5ad1SAndroid Build Coastguard Worker 
TEST(StatisticsTest,stat_linearfit)439*b9df5ad1SAndroid Build Coastguard Worker TEST(StatisticsTest, stat_linearfit)
440*b9df5ad1SAndroid Build Coastguard Worker {
441*b9df5ad1SAndroid Build Coastguard Worker     using namespace android::audio_utils; // for operator overload
442*b9df5ad1SAndroid Build Coastguard Worker     LinearLeastSquaresFit<double> fit;
443*b9df5ad1SAndroid Build Coastguard Worker 
444*b9df5ad1SAndroid Build Coastguard Worker     static_assert(std::is_trivially_copyable<decltype(fit)>::value,
445*b9df5ad1SAndroid Build Coastguard Worker         "LinearLeastSquaresFit must be trivially copyable");
446*b9df5ad1SAndroid Build Coastguard Worker 
447*b9df5ad1SAndroid Build Coastguard Worker     using array_t = std::array<double, 2>;
448*b9df5ad1SAndroid Build Coastguard Worker     array_t data{0.0, 1.5};
449*b9df5ad1SAndroid Build Coastguard Worker 
450*b9df5ad1SAndroid Build Coastguard Worker     for (size_t i = 0; i < 10; ++i) {
451*b9df5ad1SAndroid Build Coastguard Worker         fit.add(data);
452*b9df5ad1SAndroid Build Coastguard Worker         data = data + array_t{0.1, 0.2};
453*b9df5ad1SAndroid Build Coastguard Worker     }
454*b9df5ad1SAndroid Build Coastguard Worker 
455*b9df5ad1SAndroid Build Coastguard Worker     // check the y line equation
456*b9df5ad1SAndroid Build Coastguard Worker     {
457*b9df5ad1SAndroid Build Coastguard Worker         double a, b, r2;
458*b9df5ad1SAndroid Build Coastguard Worker         fit.computeYLine(a, b, r2);
459*b9df5ad1SAndroid Build Coastguard Worker         printf("y line - a:%lf  b:%lf  r2:%lf\n", a, b, r2);
460*b9df5ad1SAndroid Build Coastguard Worker         PRINT_AND_EXPECT_NEAR(1.5, a); // y intercept
461*b9df5ad1SAndroid Build Coastguard Worker         PRINT_AND_EXPECT_NEAR(2.0, b); // y slope
462*b9df5ad1SAndroid Build Coastguard Worker         PRINT_AND_EXPECT_NEAR(1.0, r2); // correlation coefficient.
463*b9df5ad1SAndroid Build Coastguard Worker 
464*b9df5ad1SAndroid Build Coastguard Worker         // check same as static variant
465*b9df5ad1SAndroid Build Coastguard Worker         double ac, bc, r2c;
466*b9df5ad1SAndroid Build Coastguard Worker         computeYLineFromStatistics(ac, bc, r2c,
467*b9df5ad1SAndroid Build Coastguard Worker             std::get<0>(fit.getMean()), /* mean_x */
468*b9df5ad1SAndroid Build Coastguard Worker             std::get<1>(fit.getMean()), /* mean_y */
469*b9df5ad1SAndroid Build Coastguard Worker             std::get<0>(fit.getPopVariance()), /* var_x */
470*b9df5ad1SAndroid Build Coastguard Worker             std::get<1>(fit.getPopVariance()), /* cov_xy */
471*b9df5ad1SAndroid Build Coastguard Worker             std::get<2>(fit.getPopVariance())); /* var_y */
472*b9df5ad1SAndroid Build Coastguard Worker 
473*b9df5ad1SAndroid Build Coastguard Worker         EXPECT_EQ(a, ac);
474*b9df5ad1SAndroid Build Coastguard Worker         EXPECT_EQ(b, bc);
475*b9df5ad1SAndroid Build Coastguard Worker         EXPECT_EQ(r2, r2c);
476*b9df5ad1SAndroid Build Coastguard Worker 
477*b9df5ad1SAndroid Build Coastguard Worker         TEST_EXPECT_NEAR(1.9, fit.getYFromX(0.2));
478*b9df5ad1SAndroid Build Coastguard Worker         TEST_EXPECT_NEAR(0.2, fit.getXFromY(1.9));
479*b9df5ad1SAndroid Build Coastguard Worker         TEST_EXPECT_NEAR(1.0, fit.getR2());
480*b9df5ad1SAndroid Build Coastguard Worker     }
481*b9df5ad1SAndroid Build Coastguard Worker 
482*b9df5ad1SAndroid Build Coastguard Worker     // check the x line equation
483*b9df5ad1SAndroid Build Coastguard Worker     {
484*b9df5ad1SAndroid Build Coastguard Worker         double a, b, r2;
485*b9df5ad1SAndroid Build Coastguard Worker         fit.computeXLine(a, b, r2);
486*b9df5ad1SAndroid Build Coastguard Worker         printf("x line - a:%lf  b:%lf  r2:%lf\n", a, b, r2);
487*b9df5ad1SAndroid Build Coastguard Worker         PRINT_AND_EXPECT_NEAR(-0.75, a); // x intercept
488*b9df5ad1SAndroid Build Coastguard Worker         PRINT_AND_EXPECT_NEAR(0.5, b); // x slope
489*b9df5ad1SAndroid Build Coastguard Worker         PRINT_AND_EXPECT_NEAR(1.0, r2); // correlation coefficient.
490*b9df5ad1SAndroid Build Coastguard Worker     }
491*b9df5ad1SAndroid Build Coastguard Worker }
492*b9df5ad1SAndroid Build Coastguard Worker 
TEST(StatisticsTest,stat_linearfit_noise)493*b9df5ad1SAndroid Build Coastguard Worker TEST(StatisticsTest, stat_linearfit_noise)
494*b9df5ad1SAndroid Build Coastguard Worker {
495*b9df5ad1SAndroid Build Coastguard Worker     using namespace android::audio_utils; // for operator overload
496*b9df5ad1SAndroid Build Coastguard Worker     using array_t = std::array<double, 2>;
497*b9df5ad1SAndroid Build Coastguard Worker     LinearLeastSquaresFit<double> fit;
498*b9df5ad1SAndroid Build Coastguard Worker 
499*b9df5ad1SAndroid Build Coastguard Worker     // We use 1000 steps for a linear line going from (0, 0) to (1, 1) as true data for
500*b9df5ad1SAndroid Build Coastguard Worker     // our linear fit.
501*b9df5ad1SAndroid Build Coastguard Worker     constexpr size_t ELEMENTS = 1000;
502*b9df5ad1SAndroid Build Coastguard Worker     array_t incr{1. / ELEMENTS, 1. / ELEMENTS};
503*b9df5ad1SAndroid Build Coastguard Worker 
504*b9df5ad1SAndroid Build Coastguard Worker     // To simulate additive noise, we use a Gaussian with stddev of 1, and then scale
505*b9df5ad1SAndroid Build Coastguard Worker     // achieve the desired stddev. We precompute our noise here (1000 of them).
506*b9df5ad1SAndroid Build Coastguard Worker     std::vector<array_t> noise(ELEMENTS);
507*b9df5ad1SAndroid Build Coastguard Worker     initNormal(noise, 0. /* mean */, 1. /* stddev */);
508*b9df5ad1SAndroid Build Coastguard Worker 
509*b9df5ad1SAndroid Build Coastguard Worker     for (int i = 0; i < 30; ++i) {
510*b9df5ad1SAndroid Build Coastguard Worker         // We run through 30 trials, with noise stddev ranging from 0 to 1.
511*b9df5ad1SAndroid Build Coastguard Worker         // The steps increment linearly from 0.001 to 0.01, linearly from 0.01 to 0.1, and
512*b9df5ad1SAndroid Build Coastguard Worker         // linearly again from 0.1 to 1.0.
513*b9df5ad1SAndroid Build Coastguard Worker         // 0.001, 0.002, ... 0.009, 0.01, 0.02, ....0.09, 0.1, 0.2, .... 1.0
514*b9df5ad1SAndroid Build Coastguard Worker         const double stddev = (i <= 10) ? i / 1000. : (i <= 20) ? (i - 9) / 100. : (i - 19) / 10.;
515*b9df5ad1SAndroid Build Coastguard Worker         fit.reset();
516*b9df5ad1SAndroid Build Coastguard Worker 
517*b9df5ad1SAndroid Build Coastguard Worker         for (size_t j = 0; j < ELEMENTS; ++j) {
518*b9df5ad1SAndroid Build Coastguard Worker             array_t data = j * incr + noise[j] * stddev;
519*b9df5ad1SAndroid Build Coastguard Worker             fit.add(data);
520*b9df5ad1SAndroid Build Coastguard Worker         }
521*b9df5ad1SAndroid Build Coastguard Worker 
522*b9df5ad1SAndroid Build Coastguard Worker         double a, b, r2;
523*b9df5ad1SAndroid Build Coastguard Worker         fit.computeYLine(a, b, r2);
524*b9df5ad1SAndroid Build Coastguard Worker         printf("stddev: %lf y line - N:%lld a:%lf  b:%lf  r2:%lf\n",
525*b9df5ad1SAndroid Build Coastguard Worker                 stddev, (long long) fit.getN(), a, b, r2);
526*b9df5ad1SAndroid Build Coastguard Worker     }
527*b9df5ad1SAndroid Build Coastguard Worker }
528*b9df5ad1SAndroid Build Coastguard Worker 
529*b9df5ad1SAndroid Build Coastguard Worker 
TEST_P(StatisticsTest,stat_simple_char)530*b9df5ad1SAndroid Build Coastguard Worker TEST_P(StatisticsTest, stat_simple_char)
531*b9df5ad1SAndroid Build Coastguard Worker {
532*b9df5ad1SAndroid Build Coastguard Worker     const char *param = GetParam();
533*b9df5ad1SAndroid Build Coastguard Worker 
534*b9df5ad1SAndroid Build Coastguard Worker     android::audio_utils::Statistics<char> stat(0.9);
535*b9df5ad1SAndroid Build Coastguard Worker     android::audio_utils::ReferenceStatistics<char> rstat(0.9);
536*b9df5ad1SAndroid Build Coastguard Worker 
537*b9df5ad1SAndroid Build Coastguard Worker     // feed the string character by character to the statistics collectors.
538*b9df5ad1SAndroid Build Coastguard Worker     for (size_t i = 0; param[i] != '\0'; ++i) {
539*b9df5ad1SAndroid Build Coastguard Worker         stat.add(param[i]);
540*b9df5ad1SAndroid Build Coastguard Worker         rstat.add(param[i]);
541*b9df5ad1SAndroid Build Coastguard Worker     }
542*b9df5ad1SAndroid Build Coastguard Worker 
543*b9df5ad1SAndroid Build Coastguard Worker     printf("statistics for %s: %s\n", param, stat.toString().c_str());
544*b9df5ad1SAndroid Build Coastguard Worker     printf("ref statistics for %s: %s\n", param, rstat.toString().c_str());
545*b9df5ad1SAndroid Build Coastguard Worker     // verify that the statistics are the same
546*b9df5ad1SAndroid Build Coastguard Worker     verify(stat, rstat);
547*b9df5ad1SAndroid Build Coastguard Worker }
548*b9df5ad1SAndroid Build Coastguard Worker 
549*b9df5ad1SAndroid Build Coastguard Worker // find the variance of pet names as signed characters.
550*b9df5ad1SAndroid Build Coastguard Worker const char *pets[] = {"cat", "dog", "elephant", "mountain lion"};
551*b9df5ad1SAndroid Build Coastguard Worker INSTANTIATE_TEST_CASE_P(PetNameStatistics, StatisticsTest,
552*b9df5ad1SAndroid Build Coastguard Worker                         ::testing::ValuesIn(pets));
553*b9df5ad1SAndroid Build Coastguard Worker 
TEST(StatisticsTest,simple_stats)554*b9df5ad1SAndroid Build Coastguard Worker TEST(StatisticsTest, simple_stats)
555*b9df5ad1SAndroid Build Coastguard Worker {
556*b9df5ad1SAndroid Build Coastguard Worker     simple_stats_t ss{};
557*b9df5ad1SAndroid Build Coastguard Worker 
558*b9df5ad1SAndroid Build Coastguard Worker     for (const double value : { -1., 1., 3.}) {
559*b9df5ad1SAndroid Build Coastguard Worker         simple_stats_log(&ss, value);
560*b9df5ad1SAndroid Build Coastguard Worker     }
561*b9df5ad1SAndroid Build Coastguard Worker 
562*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(3., ss.last);
563*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(1., ss.mean);
564*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(-1., ss.min);
565*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(3., ss.max);
566*b9df5ad1SAndroid Build Coastguard Worker     PRINT_AND_EXPECT_EQ(3, ss.n);
567*b9df5ad1SAndroid Build Coastguard Worker 
568*b9df5ad1SAndroid Build Coastguard Worker     char buffer[256];
569*b9df5ad1SAndroid Build Coastguard Worker     simple_stats_to_string(&ss, buffer, sizeof(buffer));
570*b9df5ad1SAndroid Build Coastguard Worker     printf("simple_stats: %s", buffer);
571*b9df5ad1SAndroid Build Coastguard Worker }
572