Belle II Software development
CalcMeanCov.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8#include <framework/utilities/CalcMeanCov.h>
9#include <TRandom.h>
10#include <TMath.h>
11
12#include <gtest/gtest.h>
13
14using namespace std;
15using namespace Belle2;
16
17namespace {
20 TEST(CalcMeanCov, Normal)
21 {
22 constexpr int N = 10000;
23 std::vector<double> values(N, 0);
24 CalcMeanCov<> meancov;
25
26 for (double gmean : { -5.0, 0.0, 1.0, 3.5, 150.}) {
27 for (double gsigma : {0.1, 1.0, 4.2, 25.}) {
28 double sum1(0), sum2(0), sum3(0);
29 for (int i = 0; i < N; ++i) {
30 const double x = gRandom->Gaus(gmean, gsigma);
31 sum1 += x;
32 values[i] = x;
33 meancov.add(x);
34 }
35 const double mean = sum1 / N;
36 for (auto x : values) {
37 const double d = x - mean;
38 sum2 += d * d;
39 sum3 += d;
40 }
41 const double variance = (sum2 - sum3 * sum3 / N) / N;
42 const double sigma = std::sqrt(variance);
43
44 EXPECT_FLOAT_EQ(N, meancov.getEntries());
45 EXPECT_FLOAT_EQ(mean, meancov.getMean());
46 EXPECT_FLOAT_EQ(sigma, meancov.getStddev());
47 EXPECT_FLOAT_EQ(sum1, meancov.getSum());
48 meancov.clear();
49 }
50 }
51 }
52
57 TEST(CalcMeanCov, ManyUniform)
58 {
59 CalcMeanCov<3> meancov;
60 constexpr int N = 10001;
61 //Let's use a districte, uniform distribution because sum,
62 //mean and variance are very easy to calculate
63 //Result should not depend on the order of entries and a constant offset
64 //should only influence mean and sum, not the variance/standard deviation
65 for (int i = 0; i < N; ++i) {
66 meancov.add(i + 1, i + 13.5, N - i);
67 }
68 const double sum1 = (N * N + N) / 2.;
69 const double sum2 = sum1 + 12.5 * N;
70 const double mean1 = (N + 1.0) / 2;
71 const double mean2 = (13.5 + N + 12.5) / 2;
72 const double varia = (N * N - 1.) / 12;
73 const double sigma = std::sqrt(varia);
74
75 EXPECT_DOUBLE_EQ(N, meancov.getEntries());
76 EXPECT_DOUBLE_EQ(mean1, meancov.getMean<0>());
77 EXPECT_DOUBLE_EQ(mean2, meancov.getMean<1>());
78 EXPECT_DOUBLE_EQ(mean1, meancov.getMean<2>());
79 EXPECT_DOUBLE_EQ(sigma, meancov.getStddev<0>());
80 EXPECT_DOUBLE_EQ(sigma, meancov.getStddev<1>());
81 EXPECT_DOUBLE_EQ(sigma, meancov.getStddev<2>());
82 EXPECT_DOUBLE_EQ(sum1, meancov.getSum<0>());
83 EXPECT_DOUBLE_EQ(sum2, meancov.getSum<1>());
84 EXPECT_DOUBLE_EQ(sum1, meancov.getSum<2>());
85 //Check that correlation is correct
86 EXPECT_DOUBLE_EQ(+1, (meancov.getCorrelation<0, 1>()));
87 EXPECT_DOUBLE_EQ(-1, (meancov.getCorrelation<0, 2>()));
88 EXPECT_DOUBLE_EQ(-1, (meancov.getCorrelation<1, 2>()));
89 //Check that the covariance matrix is symmetric
90 EXPECT_EQ((meancov.getCovariance<1, 0>()), (meancov.getCovariance<0, 1>()));
91 EXPECT_EQ((meancov.getCovariance<2, 0>()), (meancov.getCovariance<0, 2>()));
92 EXPECT_EQ((meancov.getCovariance<2, 1>()), (meancov.getCovariance<1, 2>()));
93 }
94
99 TEST(CalcMeanCov, Binomial)
100 {
101 CalcMeanCov<> meancov;
102 for (double n : {10, 13, 25}) {
103 for (double p : {0.1, 0.5, 0.75}) {
104 for (int k = 0; k <= n; ++k) {
105 const double b = TMath::Binomial(n, k) * std::pow(p, k) * std::pow(1 - p, n - k);
106 meancov.addWeighted(b, k);
107 }
108 EXPECT_DOUBLE_EQ(1.0, meancov.getEntries()) << "n: " << n << ", p: " << p;
109 EXPECT_DOUBLE_EQ(n * p, meancov.getMean()) << "n: " << n << ", p: " << p;
110 EXPECT_DOUBLE_EQ(n * p * (1 - p), meancov.getVariance()) << "n: " << n << ", p: " << p;
111 meancov.clear();
112 }
113 }
114 }
115
117 TEST(CalcMeanCov, TemplateVsArray)
118 {
119 CalcMeanCov<3> templated;
120 CalcMeanCov<3> arrayed;
121 double values[3];
122 for (int i = 0; i < 10000; ++i) {
123 const double weight = gRandom->Uniform(0, 10);
124 values[0] = gRandom->Gaus(0, 1);
125 values[1] = gRandom->Gaus(values[0], 1);
126 values[2] = gRandom->Uniform(-5, 5);
127 templated.addWeighted(weight, values[0], values[1], values[2]);
128 arrayed.addWeightedArray(weight, values);
129
130 ASSERT_EQ(templated.getEntries(), arrayed.getEntries());
131 ASSERT_EQ(templated.getSum<0>(), arrayed.getSum(0));
132 ASSERT_EQ(templated.getSum<1>(), arrayed.getSum(1));
133 ASSERT_EQ(templated.getSum<2>(), arrayed.getSum(2));
134 ASSERT_EQ(templated.getMean<0>(), arrayed.getMean(0));
135 ASSERT_EQ(templated.getMean<1>(), arrayed.getMean(1));
136 ASSERT_EQ(templated.getMean<2>(), arrayed.getMean(2));
137 ASSERT_EQ(templated.getStddev<0>(), arrayed.getStddev(0));
138 ASSERT_EQ(templated.getStddev<1>(), arrayed.getStddev(1));
139 ASSERT_EQ(templated.getStddev<2>(), arrayed.getStddev(2));
140 ASSERT_EQ((templated.getCovariance<0, 1>()), arrayed.getCovariance(0, 1));
141 ASSERT_EQ((templated.getCovariance<0, 2>()), arrayed.getCovariance(0, 2));
142 ASSERT_EQ((templated.getCovariance<1, 2>()), arrayed.getCovariance(1, 2));
143 }
144 }
145
147 TEST(CalcMeanCov, AddingTwoSets)
148 {
149 constexpr int N = 10000;
150 CalcMeanCov<> meancov; //adding one by one
151 CalcMeanCov<> sum;
152 CalcMeanCov<> otherhalf; //added to sum
153
154 for (double gmean : { -5.0, 0.0, 1.0, 3.5, 150.}) {
155 for (double gsigma : {0.1, 1.0, 4.2, 25.}) {
156 for (int i = 0; i < N; ++i) {
157 const double x = gRandom->Gaus(gmean, gsigma);
158 meancov.add(x);
159 if (i % 2 == 0)
160 sum.add(x);
161 else
162 otherhalf.add(x);
163 }
164 sum.add(otherhalf);
165
166 EXPECT_FLOAT_EQ(sum.getEntries(), meancov.getEntries());
167 EXPECT_FLOAT_EQ(sum.getMean(), meancov.getMean());
168 EXPECT_FLOAT_EQ(sum.getStddev(), meancov.getStddev());
169 EXPECT_FLOAT_EQ(sum.getSum(), meancov.getSum());
170 meancov.clear();
171 sum.clear();
172 otherhalf.clear();
173 }
174 }
175 }
176} // namespace
Class to calculate mean and and covariance between a number of parameters on running data without sto...
Definition: CalcMeanCov.h:35
void addWeighted(value_type weight, T... values)
Update mean and covariance by adding a new, weighted entry.
Definition: CalcMeanCov.h:59
value_type getVariance(int i) const
Return the variance for parameter i.
Definition: CalcMeanCov.h:137
value_type getCorrelation(int i, int j) const
Return the correlation coefficient between parameters i and j.
Definition: CalcMeanCov.h:130
value_type getStddev(int i) const
Return the standard deviation for parameter i.
Definition: CalcMeanCov.h:139
value_type getMean(int i) const
Return the mean for parameter i.
Definition: CalcMeanCov.h:122
value_type getCovariance(int i, int j) const
Return the covariance between parameters i and j.
Definition: CalcMeanCov.h:124
void addWeightedArray(value_type weight, value_type *values)
Update mean and covarianced by adding a new weighted entry.
Definition: CalcMeanCov.h:100
value_type getSum(int i) const
Return the weighted sum values for parameter i.
Definition: CalcMeanCov.h:141
void add(T... values)
Update mean and covariance by adding a new entry.
Definition: CalcMeanCov.h:71
void clear()
Clear all values.
Definition: CalcMeanCov.h:45
value_type getEntries() const
Return the number of entries.
Definition: CalcMeanCov.h:120
Abstract base class for different kinds of events.
STL namespace.