]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/histogram/test/histogram_fill_test.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / libs / histogram / test / histogram_fill_test.cpp
1 // Copyright 2019 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 <array>
8 #include <boost/config.hpp>
9 #include <boost/core/lightweight_test.hpp>
10 #include <boost/histogram/accumulators/mean.hpp>
11 #include <boost/histogram/accumulators/ostream.hpp>
12 #include <boost/histogram/accumulators/weighted_mean.hpp>
13 #include <boost/histogram/algorithm/sum.hpp>
14 #include <boost/histogram/axis/category.hpp>
15 #include <boost/histogram/axis/integer.hpp>
16 #include <boost/histogram/axis/ostream.hpp>
17 #include <boost/histogram/axis/regular.hpp>
18 #include <boost/histogram/axis/variant.hpp>
19 #include <boost/histogram/histogram.hpp>
20 #include <boost/histogram/literals.hpp>
21 #include <boost/histogram/make_histogram.hpp>
22 #include <boost/histogram/ostream.hpp>
23 #include <boost/histogram/storage_adaptor.hpp>
24 #include <boost/variant2/variant.hpp>
25 #include <random>
26 #include <sstream>
27 #include <stdexcept>
28 #include <tuple>
29 #include <utility>
30 #include <vector>
31 #include "throw_exception.hpp"
32 #include "utility_histogram.hpp"
33
34 using namespace boost::histogram;
35 using namespace boost::histogram::algorithm;
36 using namespace boost::histogram::literals; // to get _c suffix
37 using boost::variant2::variant;
38
39 constexpr auto ndata = 1 << 16; // should be larger than index buffer in fill_n
40
41 using in = axis::integer<int, axis::null_type>;
42 using in0 = axis::integer<int, axis::null_type, axis::option::none_t>;
43 using ing = axis::integer<double, axis::null_type,
44 decltype(axis::option::growth | axis::option::underflow |
45 axis::option::overflow)>;
46 using cs = axis::category<std::string, axis::null_type>;
47 using csg = axis::category<std::string, axis::null_type, axis::option::growth_t>;
48
49 struct axis2d {
50 auto size() const { return axis::index_type{2}; }
51
52 auto index(const std::tuple<double, double>& xy) const {
53 const auto x = std::get<0>(xy);
54 const auto y = std::get<1>(xy);
55 const auto r = std::sqrt(x * x + y * y);
56 return std::min(static_cast<axis::index_type>(r), size());
57 }
58
59 friend std::ostream& operator<<(std::ostream& os, const axis2d&) {
60 os << "axis2d()";
61 return os;
62 }
63 };
64
65 template <class Tag>
66 void run_tests(const std::vector<int>& x, const std::vector<int>& y,
67 const std::vector<double>& w) {
68
69 // 1D simple A
70 {
71 auto h = make(Tag(), in{1, 3});
72 auto h2 = h;
73 for (auto&& xi : x) h(xi);
74 // uses 1D specialization
75 h2.fill(x);
76 BOOST_TEST_EQ(h, h2);
77 }
78
79 // 1D simple B
80 {
81 auto h = make(Tag(), in{1, 3});
82 auto h2 = h;
83 for (auto&& xi : x) h(xi);
84 // uses generic form
85 const auto vx = {x};
86 h2.fill(vx);
87 BOOST_TEST_EQ(h, h2);
88 }
89
90 // 1D simple C
91 {
92 auto h = make(Tag(), in{1, 3});
93 auto h2 = h;
94 h(1);
95 for (auto&& xi : x) h(xi);
96 // uses variant
97 variant<int, std::vector<int>, std::string> v[1];
98 v[0] = 1;
99 h2.fill(v);
100 v[0] = x;
101 h2.fill(v);
102 BOOST_TEST_EQ(h, h2);
103 }
104
105 // 1D bad arguments
106 {
107 auto h = make(Tag(), in{1, 3});
108
109 int bad1[2][4];
110 (void)bad1;
111 BOOST_TEST_THROWS(h.fill(bad1), std::invalid_argument);
112
113 std::vector<std::array<int, 4>> bad2;
114 (void)bad2;
115 BOOST_TEST_THROWS(h.fill(bad2), std::invalid_argument);
116 }
117
118 // 1D with category axis
119 {
120 auto h = make(Tag(), cs{"A", "B"});
121 auto h2 = h;
122
123 const auto s = {"A", "B", "C"};
124 for (auto&& si : s) h(si);
125 h2.fill(s);
126
127 variant<int, std::string, std::vector<std::string>> v[1];
128 h("B");
129 v[0] = "B";
130 h2.fill(v);
131
132 v[0] = std::vector<std::string>(s.begin(), s.end());
133 for (auto&& si : s) h(si);
134 h2.fill(v);
135
136 BOOST_TEST_EQ(h, h2);
137 }
138
139 // 1D weight
140 {
141 auto h = make(Tag(), in{1, 3});
142 auto h2 = h;
143
144 for (auto&& xi : x) h(weight(2), xi);
145 h2.fill(weight(2), x);
146
147 for (unsigned i = 0; i < ndata; ++i) h(weight(w[i]), x[i]);
148 h2.fill(weight(w), x);
149
150 BOOST_TEST_EQ(h, h2);
151
152 auto w2 = {1};
153 (void)w2;
154 BOOST_TEST_THROWS(h2.fill(x, weight(w2)), std::invalid_argument);
155 }
156
157 // 2D simple
158 {
159 auto h = make(Tag(), in{1, 3}, in0{1, 5});
160 auto h2 = h;
161
162 for (int i = 0; i < ndata; ++i) h(x[i], y[i]);
163 const auto xy = {x, y};
164 h2.fill(xy);
165
166 BOOST_TEST_EQ(h, h2);
167
168 // wrong rank
169 BOOST_TEST_THROWS(h.fill(x), std::invalid_argument);
170
171 // not rectangular
172 std::array<std::vector<int>, 2> bad = {{std::vector<int>(1), std::vector<int>(2)}};
173 (void)bad;
174 BOOST_TEST_THROWS(h2.fill(bad), std::invalid_argument);
175 }
176
177 // 2D variant and weight
178 {
179 auto h = make(Tag(), in{1, 3}, in0{1, 5});
180
181 using V = variant<int, std::vector<int>, std::string>;
182 V xy[2];
183
184 {
185 xy[0] = 3;
186 xy[1] = y;
187 auto h1 = h;
188 auto h2 = h;
189 for (auto&& vi : y) h1(3, vi);
190 h2.fill(xy);
191 BOOST_TEST_EQ(h1, h2);
192 }
193
194 {
195 xy[0] = x;
196 xy[1] = 3;
197 auto h1 = h;
198 auto h2 = h;
199 for (auto&& vi : x) h1(vi, 3);
200 h2.fill(xy);
201 BOOST_TEST_EQ(h1, h2);
202 }
203
204 {
205 xy[0] = 3;
206 xy[1] = y;
207 auto h1 = h;
208 auto h2 = h;
209 for (auto&& vi : y) h1(3, vi, weight(2));
210 h2.fill(xy, weight(2));
211 BOOST_TEST_EQ(h1, h2);
212 }
213
214 {
215 xy[0] = 3;
216 xy[1] = y;
217 auto h1 = h;
218 auto h2 = h;
219 for (unsigned i = 0; i < ndata; ++i) h1(3, y[i], weight(w[i]));
220 h2.fill(xy, weight(w));
221 BOOST_TEST_EQ(sum(h1), sum(h2));
222 BOOST_TEST_EQ(h1, h2);
223 }
224 }
225
226 // 1D growing
227 {
228 auto h = make(Tag(), ing());
229 auto h2 = h;
230 for (const auto& xi : x) h(xi);
231 h2.fill(x);
232 BOOST_TEST_EQ(h, h2);
233 }
234
235 // 2D growing A
236 {
237 auto h = make(Tag(), in(1, 3), ing());
238 auto h2 = h;
239 for (unsigned i = 0; i < ndata; ++i) h(x[i], y[i]);
240 const auto xy = {x, y};
241 h2.fill(xy);
242 BOOST_TEST_EQ(h, h2);
243 }
244
245 // 2D growing B
246 {
247 auto h = make(Tag(), ing(), ing());
248 auto h2 = h;
249 for (unsigned i = 0; i < ndata; ++i) h(x[i], y[i]);
250 const auto xy = {x, y};
251 h2.fill(xy);
252 BOOST_TEST_EQ(h, h2);
253 }
254
255 // 2D growing with weights A
256 {
257 auto h = make(Tag(), in(1, 3), ing());
258 auto h2 = h;
259 for (unsigned i = 0; i < ndata; ++i) h(x[i], y[i], weight(w[i]));
260 const auto xy = {x, y};
261 h2.fill(xy, weight(w));
262 BOOST_TEST_EQ(h, h2);
263 }
264
265 // 2D growing with weights B
266 {
267 auto h = make(Tag(), ing(), ing());
268 auto h2 = h;
269 for (unsigned i = 0; i < ndata; ++i) h(x[i], y[i], weight(2));
270 const auto xy = {x, y};
271 h2.fill(xy, weight(2));
272 BOOST_TEST_EQ(h, h2);
273 }
274
275 // 2D growing and variant
276 {
277 auto h = make(Tag(), csg{}, in{1, 2});
278 auto h2 = h;
279
280 h("foo", 1);
281 h("foo", 2);
282
283 using V = variant<std::string, std::vector<std::string>, int, std::vector<int>>;
284 const auto xy = {V("foo"), V(std::vector<int>{1, 2})};
285 h2.fill(xy);
286
287 BOOST_TEST_EQ(h, h2);
288
289 const auto bad = {V(std::vector<std::string>(1, "foo")), V(std::vector<int>{1, 2})};
290 (void)bad;
291 BOOST_TEST_THROWS(h.fill(bad), std::invalid_argument);
292 }
293
294 // 1D profile with samples
295 {
296 auto h = make_s(Tag(), profile_storage(), in(1, 3));
297 auto h2 = h;
298
299 for (unsigned i = 0; i < ndata; ++i) h(x[i], sample(w[i]));
300 for (unsigned i = 0; i < ndata; ++i) h(x[i], sample(w[i]), weight(w[i]));
301 for (unsigned i = 0; i < ndata; ++i) h(x[i], sample(2), weight(w[i]));
302 for (unsigned i = 0; i < ndata; ++i) h(x[i], sample(w[i]), weight(2));
303
304 h2.fill(x, sample(w));
305 h2.fill(x, sample(w), weight(w));
306 h2.fill(x, sample(2), weight(w));
307 h2.fill(x, sample(w), weight(2));
308
309 BOOST_TEST_EQ(h, h2);
310 }
311
312 // 2D weighted profile with samples and weights
313 {
314 auto h = make_s(Tag(), weighted_profile_storage(), in(1, 3), in0(1, 3));
315 auto h2 = h;
316
317 for (unsigned i = 0; i < ndata; ++i) h(x[i], 3, sample(w[i]), weight(w[i]));
318 for (unsigned i = 0; i < ndata; ++i) h(x[i], 3, sample(2), weight(w[i]));
319 for (unsigned i = 0; i < ndata; ++i) h(x[i], 3, sample(w[i]), weight(2));
320
321 using V = variant<int, std::vector<int>>;
322 std::array<V, 2> xy;
323 xy[0] = x;
324 xy[1] = 3;
325 h2.fill(xy, sample(w), weight(w));
326 h2.fill(xy, sample(2), weight(w));
327 h2.fill(xy, sample(w), weight(2));
328
329 BOOST_TEST_EQ(h, h2);
330 }
331
332 // axis2d
333 {
334 auto h = make(Tag(), axis2d{});
335 auto h2 = h;
336
337 std::vector<std::tuple<double, double>> xy;
338 xy.reserve(ndata);
339 for (unsigned i = 0; i < ndata; ++i) xy.emplace_back(x[i], y[i]);
340
341 for (auto&& xyi : xy) h(xyi);
342 h2.fill(xy);
343
344 BOOST_TEST_EQ(h, h2);
345 }
346 }
347
348 int main() {
349 std::mt19937 gen(1);
350 std::normal_distribution<> id(0, 2);
351 std::vector<int> x(ndata), y(ndata);
352 auto generator = [&] { return static_cast<int>(id(gen)); };
353 std::generate(x.begin(), x.end(), generator);
354 std::generate(y.begin(), y.end(), generator);
355 std::vector<double> w(ndata);
356 // must be all positive
357 std::generate(w.begin(), w.end(), [&] { return 0.5 + std::abs(id(gen)); });
358
359 run_tests<static_tag>(x, y, w);
360 run_tests<dynamic_tag>(x, y, w);
361
362 return boost::report_errors();
363 }