1 // Copyright (C) 2021 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #pragma once
16
17 #include <ditto/logger.h>
18 #include <ditto/sampler.h>
19
20 #include <cmath>
21 #include <ctime>
22
23 #include <algorithm>
24 #include <memory>
25 #include <numeric>
26 #include <string>
27 #include <vector>
28
29 namespace dittosuite {
30
31 template <class T>
StatisticsGetMin(const std::vector<T> & samples)32 T StatisticsGetMin(const std::vector<T>& samples) {
33 if (samples.empty()) LOGF("Cannot compute the min on an empty vector");
34
35 return *std::min_element(samples.begin(), samples.end());
36 }
37
38 template <class T>
StatisticsGetMax(const std::vector<T> & samples)39 T StatisticsGetMax(const std::vector<T>& samples) {
40 if (samples.empty()) LOGF("Cannot compute the max on an empty vector");
41
42 return *std::max_element(samples.begin(), samples.end());
43 }
44
45 template <class T>
StatisticsGetMean(const std::vector<T> & samples)46 T StatisticsGetMean(const std::vector<T>& samples) {
47 if (samples.empty()) LOGF("Cannot compute the mean on an empty vector");
48
49 T result = std::accumulate(samples.begin(), samples.end(), T{});
50 return result / samples.size();
51 }
52
53 template <class T>
StatisticsGetMedian(const std::vector<T> & samples)54 T StatisticsGetMedian(const std::vector<T>& samples) {
55 if (samples.empty()) LOGF("Cannot compute the median on an empty vector");
56
57 auto my_vector_copy = samples;
58 auto n = samples.size();
59
60 if (n % 2) {
61 // odd number of elements, the median is the element in the middle
62 std::nth_element(my_vector_copy.begin(), my_vector_copy.begin() + n / 2, my_vector_copy.end());
63 return my_vector_copy[n / 2];
64 } else {
65 // even number of elements, the median is the average between the two middle elements
66 std::nth_element(my_vector_copy.begin(), my_vector_copy.begin() + n / 2, my_vector_copy.end());
67 std::nth_element(my_vector_copy.begin(), my_vector_copy.begin() + (n - 1) / 2,
68 my_vector_copy.end());
69 T result = my_vector_copy[n / 2] + my_vector_copy[(n - 1) / 2];
70 return result / 2;
71 }
72 }
73
74 // The standard deviation sd of a population of N samples, where x_i is the
75 // i-th sample and x is the average among all the samples is computed as:
76 //
77 // sd = sqrt( sum( (x_i - x)^2 ) / N )
78 template <class T>
StatisticsGetSd(const std::vector<T> & samples)79 double StatisticsGetSd(const std::vector<T>& samples) {
80 if (samples.empty()) LOGF("Cannot compute the sd on an empty vector");
81
82 T mean = StatisticsGetMean(samples);
83 double variance;
84
85 variance = 0.0;
86 for (const auto& s : samples) {
87 double deviation = s - mean;
88 double deviation_square = std::pow(deviation, 2);
89 variance += deviation_square; // TODO(lucialup): add overflow error handling
90 }
91 variance /= samples.size();
92
93 return std::sqrt(variance);
94 }
95
96 } // namespace dittosuite