1 // Copyright 2015-2018 Hans Dembinski
2 //
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt
5 // or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7 #include <boost/core/lightweight_test.hpp>
8 #include <boost/histogram/accumulators/mean.hpp>
9 #include <boost/histogram/accumulators/ostream.hpp>
10 #include <boost/histogram/accumulators/sum.hpp>
11 #include <boost/histogram/accumulators/thread_safe.hpp>
12 #include <boost/histogram/accumulators/weighted_mean.hpp>
13 #include <boost/histogram/accumulators/weighted_sum.hpp>
14 #include <boost/histogram/weight.hpp>
15 #include <sstream>
16 #include "is_close.hpp"
17 #include "throw_exception.hpp"
18
19 using namespace boost::histogram;
20 using namespace std::literals;
21
22 template <class T>
str(const T & t,int w=0,bool left=true)23 auto str(const T& t, int w = 0, bool left = true) {
24 std::ostringstream os;
25 os.width(w);
26 if (left)
27 os << std::left;
28 else
29 os << std::right;
30 os << t;
31 return os.str();
32 }
33
main()34 int main() {
35 {
36 using w_t = accumulators::weighted_sum<double>;
37 w_t w;
38 BOOST_TEST_EQ(str(w), "weighted_sum(0, 0)"s);
39 BOOST_TEST_EQ(str(w, 20, false), " weighted_sum(0, 0)"s);
40 BOOST_TEST_EQ(str(w, 20, true), "weighted_sum(0, 0) "s);
41 BOOST_TEST_EQ(w, w_t{});
42
43 BOOST_TEST_EQ(w, w_t(0));
44 BOOST_TEST_NE(w, w_t(1));
45 w = w_t(1);
46 BOOST_TEST_EQ(w.value(), 1);
47 BOOST_TEST_EQ(w.variance(), 1);
48 BOOST_TEST_EQ(w, 1);
49 BOOST_TEST_NE(w, 2);
50
51 w += 2;
52 BOOST_TEST_EQ(w.value(), 3);
53 BOOST_TEST_EQ(w.variance(), 5);
54 BOOST_TEST_EQ(w, w_t(3, 5));
55 BOOST_TEST_NE(w, w_t(3));
56
57 w += w_t(1, 2);
58 BOOST_TEST_EQ(w.value(), 4);
59 BOOST_TEST_EQ(w.variance(), 7);
60
61 // consistency: a weighted counter increased by weight 1 multiplied
62 // by 2 must be the same as a weighted counter increased by weight 2
63 w_t u(0);
64 ++u;
65 u *= 2;
66 BOOST_TEST_EQ(u, w_t(2, 4));
67
68 w_t v(0);
69 v += 2;
70 BOOST_TEST_EQ(u, v);
71
72 // conversion to RealType
73 w_t y(1, 2);
74 BOOST_TEST_NE(y, 1);
75 BOOST_TEST_EQ(static_cast<double>(y), 1);
76
77 BOOST_TEST_EQ(w_t() += w_t(), w_t());
78 }
79
80 {
81 using m_t = accumulators::mean<double>;
82 m_t a;
83 BOOST_TEST_EQ(a.count(), 0);
84 BOOST_TEST_EQ(a, m_t{});
85
86 a(4);
87 a(7);
88 a(13);
89 a(16);
90
91 BOOST_TEST_EQ(a.count(), 4);
92 BOOST_TEST_EQ(a.value(), 10);
93 BOOST_TEST_EQ(a.variance(), 30);
94
95 BOOST_TEST_EQ(str(a), "mean(4, 10, 30)"s);
96 BOOST_TEST_EQ(str(a, 20, false), " mean(4, 10, 30)"s);
97 BOOST_TEST_EQ(str(a, 20, true), "mean(4, 10, 30) "s);
98
99 m_t b;
100 b(1e8 + 4);
101 b(1e8 + 7);
102 b(1e8 + 13);
103 b(1e8 + 16);
104
105 BOOST_TEST_EQ(b.count(), 4);
106 BOOST_TEST_EQ(b.value(), 1e8 + 10);
107 BOOST_TEST_EQ(b.variance(), 30);
108
109 auto c = a;
110 c += a; // same as feeding all samples twice
111
112 BOOST_TEST_EQ(c.count(), 8);
113 BOOST_TEST_EQ(c.value(), 10);
114 BOOST_TEST_IS_CLOSE(c.variance(), 25.714, 1e-3);
115
116 // also same as feeding all samples twice
117 m_t d;
118 d(weight(2), 4);
119 d(weight(2), 7);
120 d(weight(2), 13);
121 d(weight(2), 16);
122
123 BOOST_TEST_EQ(d, c);
124
125 BOOST_TEST_EQ(m_t() += m_t(), m_t());
126 BOOST_TEST_EQ(m_t(1, 2, 3) += m_t(), m_t(1, 2, 3));
127 BOOST_TEST_EQ(m_t() += m_t(1, 2, 3), m_t(1, 2, 3));
128 }
129
130 {
131 using m_t = accumulators::weighted_mean<double>;
132 m_t a;
133 BOOST_TEST_EQ(a.sum_of_weights(), 0);
134 BOOST_TEST_EQ(a, m_t{});
135
136 a(weight(0.5), 1);
137 a(weight(1.0), 2);
138 a(weight(0.5), 3);
139
140 BOOST_TEST_EQ(a.sum_of_weights(), 2);
141 BOOST_TEST_EQ(a.sum_of_weights_squared(), 1.5);
142 BOOST_TEST_EQ(a.value(), 2);
143 BOOST_TEST_IS_CLOSE(a.variance(), 0.8, 1e-3);
144
145 BOOST_TEST_EQ(str(a), "weighted_mean(2, 2, 0.8)"s);
146 BOOST_TEST_EQ(str(a, 25, false), " weighted_mean(2, 2, 0.8)"s);
147 BOOST_TEST_EQ(str(a, 25, true), "weighted_mean(2, 2, 0.8) "s);
148
149 auto b = a;
150 b += a; // same as feeding all samples twice
151
152 BOOST_TEST_EQ(b.sum_of_weights(), 4);
153 BOOST_TEST_EQ(b.value(), 2);
154 BOOST_TEST_IS_CLOSE(b.variance(), 0.615, 1e-3);
155
156 BOOST_TEST_EQ(m_t() += m_t(), m_t());
157 BOOST_TEST_EQ(m_t(1, 2, 3, 4) += m_t(), m_t(1, 2, 3, 4));
158 BOOST_TEST_EQ(m_t() += m_t(1, 2, 3, 4), m_t(1, 2, 3, 4));
159 }
160
161 {
162 double bad_sum = 0;
163 bad_sum += 1;
164 bad_sum += 1e100;
165 bad_sum += 1;
166 bad_sum += -1e100;
167 BOOST_TEST_EQ(bad_sum, 0); // instead of 2
168
169 using s_t = accumulators::sum<double>;
170 s_t sum;
171 ++sum;
172 BOOST_TEST_EQ(sum.large(), 1);
173 BOOST_TEST_EQ(sum.small(), 0);
174 BOOST_TEST_EQ(str(sum), "sum(1 + 0)"s);
175 BOOST_TEST_EQ(str(sum, 15, false), " sum(1 + 0)"s);
176 BOOST_TEST_EQ(str(sum, 15, true), "sum(1 + 0) "s);
177
178 sum += 1e100;
179 BOOST_TEST_EQ(str(sum), "sum(1e+100 + 1)"s);
180 ++sum;
181 BOOST_TEST_EQ(str(sum), "sum(1e+100 + 2)"s);
182 sum += -1e100;
183 BOOST_TEST_EQ(str(sum), "sum(0 + 2)"s);
184 BOOST_TEST_EQ(sum, 2); // correct answer
185 BOOST_TEST_EQ(sum.large(), 0);
186 BOOST_TEST_EQ(sum.small(), 2);
187
188 accumulators::sum<double> a(3), b(2), c(3);
189 BOOST_TEST_LT(b, c);
190 BOOST_TEST_LE(b, c);
191 BOOST_TEST_LE(a, c);
192 BOOST_TEST_GT(a, b);
193 BOOST_TEST_GE(a, b);
194 BOOST_TEST_GE(a, c);
195
196 BOOST_TEST_EQ(s_t() += s_t(), s_t());
197 }
198
199 {
200 using s_t = accumulators::weighted_sum<accumulators::sum<double>>;
201 s_t w;
202
203 ++w;
204 w += 1e100;
205 ++w;
206 w += -1e100;
207
208 BOOST_TEST_EQ(w.value(), 2);
209 BOOST_TEST_EQ(w.variance(), 2e200);
210
211 BOOST_TEST_EQ(s_t() += s_t(), s_t());
212 }
213
214 {
215 using ts_t = accumulators::thread_safe<int>;
216 ts_t i;
217 ++i;
218 i += 1000;
219
220 BOOST_TEST_EQ(i, 1001);
221 BOOST_TEST_EQ(str(i), "1001"s);
222
223 BOOST_TEST_EQ(ts_t() += ts_t(), ts_t());
224 }
225
226 return boost::report_errors();
227 }
228