]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/histogram/test/histogram_test.cpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / histogram / test / histogram_test.cpp
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/ignore_unused.hpp>
8 #include <boost/core/lightweight_test.hpp>
9 #include <boost/histogram/accumulators.hpp>
10 #include <boost/histogram/accumulators/ostream.hpp>
11 #include <boost/histogram/algorithm/sum.hpp>
12 #include <boost/histogram/axis.hpp>
13 #include <boost/histogram/axis/ostream.hpp>
14 #include <boost/histogram/histogram.hpp>
15 #include <boost/histogram/literals.hpp>
16 #include <boost/histogram/make_histogram.hpp>
17 #include <boost/histogram/ostream.hpp>
18 #include <sstream>
19 #include <stdexcept>
20 #include <tuple>
21 #include <utility>
22 #include <vector>
23 #include "is_close.hpp"
24 #include "std_ostream.hpp"
25 #include "throw_exception.hpp"
26 #include "utility_allocator.hpp"
27 #include "utility_axis.hpp"
28 #include "utility_histogram.hpp"
29
30 using namespace boost::histogram;
31 using namespace boost::histogram::literals; // to get _c suffix
32
33 template <class A, class S>
34 void pass_histogram(boost::histogram::histogram<A, S>& h) {
35 BOOST_TEST_EQ(h.at(0), 0);
36 BOOST_TEST_EQ(h.at(1), 1);
37 BOOST_TEST_EQ(h.at(2), 0);
38 BOOST_TEST_EQ(h.axis(0_c), axis::integer<>(0, 3));
39 }
40
41 template <class Tag>
42 void run_tests() {
43 // init_1
44 {
45 auto h = make(Tag(), axis::regular<>{3, -1, 1});
46 BOOST_TEST_EQ(h.rank(), 1);
47 BOOST_TEST_EQ(h.size(), 5);
48 BOOST_TEST_EQ(h.axis(0_c).size(), 3);
49 BOOST_TEST_EQ(h.axis().size(), 3);
50 auto h2 = make_s(Tag(), std::vector<unsigned>(), axis::regular<>{3, -1, 1});
51 BOOST_TEST_EQ(h2, h);
52 }
53
54 // init_2
55 {
56 auto h = make(Tag(), axis::regular<>{3, -1, 1}, axis::integer<>{-1, 2},
57 axis::circular<>{2, 0, 360}, axis::variable<>{-1, 0, 1},
58 axis::category<>{{3, 1, 2}});
59 BOOST_TEST_EQ(h.rank(), 5);
60 BOOST_TEST_EQ(h.size(), 5 * 5 * 3 * 4 * 4);
61 auto h2 = make_s(Tag(), std::vector<unsigned>(), axis::regular<>{3, -1, 1},
62 axis::integer<>{-1, 2}, axis::circular<>{2, 0, 360},
63 axis::variable<>{-1, 0, 1}, axis::category<>{{3, 1, 2}});
64 BOOST_TEST_EQ(h2, h);
65 }
66
67 // copy_ctor
68 {
69 auto h = make(Tag(), axis::integer<>{0, 2}, axis::integer<>{0, 3});
70 h(0, 0);
71 auto h2 = decltype(h)(h);
72 BOOST_TEST_EQ(h2, h);
73 auto h3 =
74 histogram<std::tuple<axis::integer<>, axis::integer<>>, dense_storage<double>>(h);
75 BOOST_TEST_EQ(h3, h);
76 }
77
78 // copy_assign
79 {
80 auto h = make(Tag(), axis::integer<>(0, 1), axis::integer<>(0, 2));
81 h(0, 0);
82 auto h2 = decltype(h)();
83 BOOST_TEST_NE(h, h2);
84 h2 = h;
85 BOOST_TEST_EQ(h, h2);
86 auto h3 =
87 histogram<std::tuple<axis::integer<>, axis::integer<>>, dense_storage<double>>();
88 h3 = h;
89 BOOST_TEST_EQ(h, h3);
90 }
91
92 // move
93 {
94 auto h = make(Tag(), axis::integer<>(0, 1), axis::integer<>(0, 2));
95 h(0, 0);
96 const auto href = h;
97 decltype(h) h2(std::move(h));
98 BOOST_TEST_EQ(algorithm::sum(h), 0);
99 BOOST_TEST_EQ(h.size(), 0);
100 BOOST_TEST_EQ(h2, href);
101 decltype(h) h3;
102 h3 = std::move(h2);
103 BOOST_TEST_EQ(algorithm::sum(h2), 0);
104 BOOST_TEST_EQ(h2.size(), 0);
105 BOOST_TEST_EQ(h3, href);
106 }
107
108 // axis methods
109 {
110 auto a = make(Tag(), axis::integer<double>(1, 2, "foo"));
111 BOOST_TEST_EQ(a.axis().size(), 1);
112 BOOST_TEST_EQ(a.axis().bin(0).lower(), 1);
113 BOOST_TEST_EQ(a.axis().bin(0).upper(), 2);
114 BOOST_TEST_EQ(a.axis().metadata(), "foo");
115 unsafe_access::axis(a, 0).metadata() = "bar";
116 BOOST_TEST_EQ(a.axis().metadata(), "bar");
117
118 auto b = make(Tag(), axis::integer<double>(1, 2, "foo"), axis::integer<>(1, 3));
119
120 // check static access
121 BOOST_TEST_EQ(b.axis(0_c).size(), 1);
122 BOOST_TEST_EQ(b.axis(0_c).bin(0).lower(), 1);
123 BOOST_TEST_EQ(b.axis(0_c).bin(0).upper(), 2);
124 BOOST_TEST_EQ(b.axis(1_c).size(), 2);
125 BOOST_TEST_EQ(b.axis(1_c).bin(0), 1);
126 BOOST_TEST_EQ(b.axis(1_c).bin(1), 2);
127 unsafe_access::axis(b, 1_c).metadata() = "bar";
128 BOOST_TEST_EQ(b.axis(0_c).metadata(), "foo");
129 BOOST_TEST_EQ(b.axis(1_c).metadata(), "bar");
130
131 // check dynamic access
132 BOOST_TEST_EQ(b.axis(0).size(), 1);
133 BOOST_TEST_EQ(b.axis(0).bin(0).lower(), 1);
134 BOOST_TEST_EQ(b.axis(0).bin(0).upper(), 2);
135 BOOST_TEST_EQ(b.axis(1).size(), 2);
136 BOOST_TEST_EQ(b.axis(1).bin(0), 1);
137 BOOST_TEST_EQ(b.axis(1).bin(1), 2);
138 BOOST_TEST_EQ(b.axis(0).metadata(), "foo");
139 BOOST_TEST_EQ(b.axis(1).metadata(), "bar");
140 unsafe_access::axis(b, 0).metadata() = "baz";
141 BOOST_TEST_EQ(b.axis(0).metadata(), "baz");
142
143 auto c = make(Tag(), axis::category<>({1, 2}));
144 BOOST_TEST_EQ(c.axis().size(), 2);
145 unsafe_access::axis(c, 0).metadata() = "foo";
146 BOOST_TEST_EQ(c.axis().metadata(), "foo");
147 // need to cast here for this to work with Tag == dynamic_tag, too
148 const auto& ca = axis::get<axis::category<>>(c.axis());
149 BOOST_TEST_EQ(ca.bin(0), 1);
150 const auto& ca2 = axis::get<axis::category<>>(c.axis(0));
151 BOOST_TEST_EQ(&ca2, &ca);
152 }
153
154 // equal_compare
155 {
156 auto a = make(Tag(), axis::integer<>(0, 2));
157 auto b = make(Tag(), axis::integer<>(0, 2), axis::integer<>(0, 3));
158 BOOST_TEST(a != b);
159 BOOST_TEST(b != a);
160 auto c = make(Tag(), axis::integer<>(0, 2));
161 BOOST_TEST(b != c);
162 BOOST_TEST(c != b);
163 BOOST_TEST(a == c);
164 BOOST_TEST(c == a);
165 auto d = make(Tag(), axis::regular<>(2, 0, 1));
166 BOOST_TEST(c != d);
167 BOOST_TEST(d != c);
168 c(0);
169 BOOST_TEST(a != c);
170 BOOST_TEST(c != a);
171 a(0);
172 BOOST_TEST(a == c);
173 BOOST_TEST(c == a);
174 a(0);
175 BOOST_TEST(a != c);
176 BOOST_TEST(c != a);
177 }
178
179 // 1D
180 {
181 auto h = make(Tag(), axis::integer<int, axis::null_type>{0, 2});
182 h(0);
183 auto i = h(0);
184 BOOST_TEST(i == h.begin() + 1); // +1 because of underflow
185 i = h(-1);
186 BOOST_TEST(i == h.begin()); // underflow
187 i = h(10);
188 BOOST_TEST(i == h.end() - 1); // overflow
189
190 BOOST_TEST_EQ(h.rank(), 1);
191 BOOST_TEST_EQ(h.axis().size(), 2);
192 BOOST_TEST_EQ(algorithm::sum(h), 4);
193
194 BOOST_TEST_EQ(h.at(-1), 1);
195 BOOST_TEST_EQ(h.at(0), 2);
196 BOOST_TEST_EQ(h.at(1), 0);
197 BOOST_TEST_EQ(h.at(2), 1);
198 }
199
200 // 1D no *flow
201 {
202 auto h = make(Tag(), axis::integer<int, axis::null_type, axis::option::none_t>(0, 2));
203 h(0);
204 auto i = h(-0);
205 BOOST_TEST(i == h.begin());
206 i = h(-1);
207 BOOST_TEST(i == h.end());
208 i = h(10);
209 BOOST_TEST(i == h.end());
210
211 BOOST_TEST_EQ(h.rank(), 1);
212 BOOST_TEST_EQ(h.axis().size(), 2);
213 BOOST_TEST_EQ(algorithm::sum(h), 2);
214
215 BOOST_TEST_EQ(h.at(0), 2);
216 BOOST_TEST_EQ(h.at(1), 0);
217 }
218
219 // 1D category axis
220 {
221 auto h = make(Tag(), axis::category<>({1, 2}));
222 h(1);
223 h(2);
224 h(4);
225 h(5);
226
227 BOOST_TEST_EQ(h.rank(), 1);
228 BOOST_TEST_EQ(h.axis().size(), 2);
229 BOOST_TEST_EQ(algorithm::sum(h), 4);
230
231 BOOST_TEST_EQ(h.at(0), 1);
232 BOOST_TEST_EQ(h.at(1), 1);
233 BOOST_TEST_EQ(h.at(2), 2); // overflow bin
234 }
235
236 // 1D weight
237 {
238 auto h = make_s(Tag(), weight_storage(), axis::integer<>(0, 2));
239 h(-1);
240 h(0);
241 h(weight(0.5), 0);
242 h(1);
243 h(weight(2), 2);
244
245 BOOST_TEST_EQ(algorithm::sum(h).value(), 5.5);
246 BOOST_TEST_EQ(algorithm::sum(h).variance(), 7.25);
247
248 BOOST_TEST_EQ(h[-1].value(), 1);
249 BOOST_TEST_EQ(h[-1].variance(), 1);
250 BOOST_TEST_EQ(h[0].value(), 1.5);
251 BOOST_TEST_EQ(h[0].variance(), 1.25);
252 BOOST_TEST_EQ(h[1].value(), 1);
253 BOOST_TEST_EQ(h[1].variance(), 1);
254 BOOST_TEST_EQ(h[2].value(), 2);
255 BOOST_TEST_EQ(h[2].variance(), 4);
256 }
257
258 // 1D profile
259 {
260 auto h = make_s(Tag(), profile_storage(), axis::integer<>(0, 2));
261
262 h(0, sample(1));
263 h(0, sample(2));
264 h(0, sample(3));
265 h(sample(4), 1);
266 h(sample(5), 1);
267 h(sample(6), 1);
268
269 BOOST_TEST_EQ(h[0].count(), 3);
270 BOOST_TEST_EQ(h[0].value(), 2);
271 BOOST_TEST_EQ(h[0].variance(), 1);
272 BOOST_TEST_EQ(h[1].count(), 3);
273 BOOST_TEST_EQ(h[1].value(), 5);
274 BOOST_TEST_EQ(h[1].variance(), 1);
275 }
276
277 // 1D weighted profile
278 {
279 auto h = make_s(Tag(), weighted_profile_storage(), axis::integer<>(0, 2));
280
281 h(0, sample(1));
282 h(sample(1), 0);
283
284 h(0, weight(2), sample(3));
285 h(0, sample(5), weight(2));
286
287 h(weight(2), 1, sample(1));
288 h(sample(2), 1, weight(2));
289
290 h(weight(2), sample(3), 1);
291 h(sample(4), weight(2), 1);
292
293 BOOST_TEST_EQ(h[0].sum_of_weights(), 6);
294 BOOST_TEST_EQ(h[0].value(), 3);
295 BOOST_TEST_EQ(h[1].sum_of_weights(), 8);
296 BOOST_TEST_EQ(h[1].value(), 2.5);
297 }
298
299 // 2D
300 {
301 auto h = make(Tag(), axis::integer<>(-1, 1),
302 axis::integer<int, axis::null_type, axis::option::none_t>(-1, 2));
303 h(-1, -1);
304 h(-1, 0);
305 h(-1, -10);
306 h(-10, 0);
307
308 BOOST_TEST_EQ(h.rank(), 2);
309 BOOST_TEST_EQ(h.axis(0_c).size(), 2);
310 BOOST_TEST_EQ(h.axis(1_c).size(), 3);
311 BOOST_TEST_EQ(algorithm::sum(h), 3);
312
313 BOOST_TEST_EQ(h.at(-1, 0), 0);
314 BOOST_TEST_EQ(h.at(-1, 1), 1);
315 BOOST_TEST_EQ(h.at(-1, 2), 0);
316
317 BOOST_TEST_EQ(h.at(0, 0), 1);
318 BOOST_TEST_EQ(h.at(0, 1), 1);
319 BOOST_TEST_EQ(h.at(0, 2), 0);
320
321 BOOST_TEST_EQ(h.at(1, 0), 0);
322 BOOST_TEST_EQ(h.at(1, 1), 0);
323 BOOST_TEST_EQ(h.at(1, 2), 0);
324
325 BOOST_TEST_EQ(h.at(2, 0), 0);
326 BOOST_TEST_EQ(h.at(2, 1), 0);
327 BOOST_TEST_EQ(h.at(2, 2), 0);
328 }
329
330 // 2D weight
331 {
332 auto h = make_s(Tag(), weight_storage(), axis::integer<>(-1, 1),
333 axis::integer<int, axis::null_type, axis::option::none_t>(-1, 2));
334 h(-1, 0); // -> 0, 1
335 h(weight(10), -1, -1); // -> 0, 0
336 h(weight(5), -1, -10); // is ignored
337 h(weight(7), -10, 0); // -> -1, 1
338
339 BOOST_TEST_EQ(algorithm::sum(h).value(), 18);
340 BOOST_TEST_EQ(algorithm::sum(h).variance(), 150);
341
342 BOOST_TEST_EQ(h.at(-1, 0).value(), 0);
343 BOOST_TEST_EQ(h.at(-1, 1).value(), 7);
344 BOOST_TEST_EQ(h.at(-1, 2).value(), 0);
345
346 BOOST_TEST_EQ(h.at(0, 0).value(), 10);
347 BOOST_TEST_EQ(h.at(0, 1).value(), 1);
348 BOOST_TEST_EQ(h.at(0, 2).value(), 0);
349
350 BOOST_TEST_EQ(h.at(1, 0).value(), 0);
351 BOOST_TEST_EQ(h.at(1, 1).value(), 0);
352 BOOST_TEST_EQ(h.at(1, 2).value(), 0);
353
354 BOOST_TEST_EQ(h.at(2, 0).value(), 0);
355 BOOST_TEST_EQ(h.at(2, 1).value(), 0);
356 BOOST_TEST_EQ(h.at(2, 2).value(), 0);
357
358 BOOST_TEST_EQ(h.at(-1, 0).variance(), 0);
359 BOOST_TEST_EQ(h.at(-1, 1).variance(), 49);
360 BOOST_TEST_EQ(h.at(-1, 2).variance(), 0);
361
362 BOOST_TEST_EQ(h.at(0, 0).variance(), 100);
363 BOOST_TEST_EQ(h.at(0, 1).variance(), 1);
364 BOOST_TEST_EQ(h.at(0, 2).variance(), 0);
365
366 BOOST_TEST_EQ(h.at(1, 0).variance(), 0);
367 BOOST_TEST_EQ(h.at(1, 1).variance(), 0);
368 BOOST_TEST_EQ(h.at(1, 2).variance(), 0);
369
370 BOOST_TEST_EQ(h.at(2, 0).variance(), 0);
371 BOOST_TEST_EQ(h.at(2, 1).variance(), 0);
372 BOOST_TEST_EQ(h.at(2, 2).variance(), 0);
373 }
374
375 // 3D weight
376 {
377 auto h = make_s(Tag(), weight_storage(), axis::integer<>(0, 3), axis::integer<>(0, 4),
378 axis::integer<>(0, 5));
379 for (auto i = 0; i < h.axis(0_c).size(); ++i)
380 for (auto j = 0; j < h.axis(1_c).size(); ++j)
381 for (auto k = 0; k < h.axis(2_c).size(); ++k) h(i, j, k, weight(i + j + k));
382
383 for (auto i = 0; i < h.axis(0_c).size(); ++i) {
384 for (auto j = 0; j < h.axis(1_c).size(); ++j) {
385 for (auto k = 0; k < h.axis(2_c).size(); ++k) {
386 BOOST_TEST_EQ(h.at(i, j, k).value(), i + j + k);
387 BOOST_TEST_EQ(h.at(i, j, k).variance(), (i + j + k) * (i + j + k));
388 }
389 }
390 }
391 }
392
393 // STL support
394 {
395 auto v = std::vector<int>{0, 1, 2};
396 auto h = std::for_each(v.begin(), v.end(), make(Tag(), axis::integer<>(0, 3)));
397 BOOST_TEST_EQ(h.at(0), 1);
398 BOOST_TEST_EQ(h.at(1), 1);
399 BOOST_TEST_EQ(h.at(2), 1);
400 BOOST_TEST_EQ(algorithm::sum(h), 3);
401
402 auto a = std::vector<double>();
403 // walks over all bins, including underflow and overflow
404 std::partial_sum(h.begin(), h.end(), std::back_inserter(a));
405 BOOST_TEST_EQ(a.size(), 5);
406 BOOST_TEST_EQ(a[0], 0);
407 BOOST_TEST_EQ(a[1], 1);
408 BOOST_TEST_EQ(a[2], 2);
409 BOOST_TEST_EQ(a[3], 3);
410 BOOST_TEST_EQ(a[4], 3);
411 }
412
413 // histogram reset
414 {
415 auto h = make(Tag(), axis::integer<int, axis::null_type, axis::option::none_t>(0, 2));
416 h(0);
417 h(1);
418 BOOST_TEST_EQ(h.at(0), 1);
419 BOOST_TEST_EQ(h.at(1), 1);
420 BOOST_TEST_EQ(algorithm::sum(h), 2);
421 h.reset();
422 BOOST_TEST_EQ(h.at(0), 0);
423 BOOST_TEST_EQ(h.at(1), 0);
424 BOOST_TEST_EQ(algorithm::sum(h), 0);
425 }
426
427 // using containers for input and output
428 {
429 auto h = make(Tag(), axis::integer<>(0, 2), axis::integer<double>(2, 4));
430 // tuple in
431 h(std::make_tuple(0, 2.0));
432 h(std::make_tuple(1, 3.0));
433
434 auto i00 = std::make_tuple(0, 0);
435 auto i11 = std::make_tuple(1, 1);
436
437 // tuple out
438 BOOST_TEST_EQ(h.at(i00), 1);
439 BOOST_TEST_EQ(h[i00], 1);
440 BOOST_TEST_EQ(h[i11], 1);
441
442 // iterable out
443 int j11[] = {1, 1};
444 BOOST_TEST_EQ(h.at(j11), 1);
445 BOOST_TEST_EQ(h[j11], 1);
446 int j111[] = {1, 1, 1};
447 (void)j111;
448 BOOST_TEST_THROWS((void)h.at(j111), std::invalid_argument);
449 int j13[] = {1, 3};
450 (void)j13;
451 BOOST_TEST_THROWS((void)h.at(j13), std::out_of_range);
452
453 // tuple with weight
454 h(std::make_tuple(weight(2), 0, 2.0));
455 h(std::make_tuple(1, 3.0, weight(2)));
456
457 BOOST_TEST_EQ(h.at(i00), 3);
458 BOOST_TEST_EQ(h[i00], 3);
459
460 // test special case of 1-dimensional histogram, which should unpack
461 // 1-dimensional tuple normally, but forward larger tuples to the axis
462 auto h1 = make(Tag(), axis::integer<>(0, 2));
463 h1(std::make_tuple(0)); // as if one had passed 0 directly
464 BOOST_TEST_EQ(h1.at(std::make_tuple(0)), 1); // as if one had passed 0 directly
465 }
466
467 // bad bin access
468 {
469 auto h = make(Tag(), axis::integer<>(0, 1), axis::integer<>(0, 1));
470 BOOST_TEST_THROWS(h.at(0, 2), std::out_of_range);
471 BOOST_TEST_THROWS(h.at(std::make_tuple(2, 0)), std::out_of_range);
472 }
473
474 // pass histogram to function
475 {
476 auto h = make(Tag(), axis::integer<>(0, 3));
477 h(1);
478 pass_histogram(h);
479 }
480
481 // allocator support
482 {
483 tracing_allocator_db db;
484 {
485 tracing_allocator<char> a(db);
486 auto h = make_s(Tag(), std::vector<int, tracing_allocator<int>>(a),
487 axis::integer<>(0, 1000));
488 h(0);
489 }
490
491 // int allocation for std::vector
492 BOOST_TEST_EQ(db.at<int>().first, 0);
493 BOOST_TEST_EQ(db.at<int>().second, 1002);
494
495 if (Tag()) { // axis::variant allocation, only for dynamic histogram
496 using T = axis::variant<axis::integer<>>;
497 BOOST_TEST_EQ(db.at<T>().first, 0);
498 // may be zero if vector uses small-vector-optimisation
499 BOOST_TEST_LE(db.at<T>().second, 1);
500 }
501 }
502 }
503
504 int main() {
505 run_tests<static_tag>();
506 run_tests<dynamic_tag>();
507
508 return boost::report_errors();
509 }