]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/histogram/test/algorithm_reduce_test.cpp
1 // Copyright 2018 Hans Dembinski
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)
7 #include <boost/core/lightweight_test.hpp>
8 #include <boost/histogram/algorithm/reduce.hpp>
9 #include <boost/histogram/algorithm/sum.hpp>
10 #include <boost/histogram/axis/category.hpp>
11 #include <boost/histogram/axis/integer.hpp>
12 #include <boost/histogram/axis/ostream.hpp>
13 #include <boost/histogram/axis/regular.hpp>
14 #include <boost/histogram/axis/variable.hpp>
15 #include <boost/histogram/ostream.hpp>
16 #include <boost/histogram/unsafe_access.hpp>
18 #include "throw_exception.hpp"
19 #include "utility_histogram.hpp"
21 using namespace boost::histogram
;
22 using namespace boost::histogram::algorithm
;
24 template <typename Tag
>
27 // - does not work with arguments not convertible to double
28 // - does not work with category axis, which is not ordered
30 using R
= axis::regular
<double, axis::transform::id
, axis::null_type
>;
31 using ID
= axis::integer
<double, axis::null_type
>;
32 using V
= axis::variable
<double, axis::empty_type
>;
33 using CI
= axis::category
<int, axis::empty_type
>;
37 auto h
= make(Tag(), R(4, 1, 5), R(3, -1, 2));
39 // not allowed: invalid axis index
40 BOOST_TEST_THROWS((void)reduce(h
, slice(10, 2, 3)), std::invalid_argument
);
41 // not allowed: repeated indices
42 BOOST_TEST_THROWS((void)reduce(h
, slice(1, 0, 2), slice(1, 1, 3)),
43 std::invalid_argument
);
44 BOOST_TEST_THROWS((void)reduce(h
, rebin(0, 2), rebin(0, 2)), std::invalid_argument
);
45 BOOST_TEST_THROWS((void)reduce(h
, shrink(1, 0, 2), shrink(1, 0, 2)),
46 std::invalid_argument
);
47 // not allowed: slice with begin >= end
48 BOOST_TEST_THROWS((void)reduce(h
, slice(0, 1, 1)), std::invalid_argument
);
49 BOOST_TEST_THROWS((void)reduce(h
, slice(0, 2, 1)), std::invalid_argument
);
50 // not allowed: shrink with lower == upper
51 BOOST_TEST_THROWS((void)reduce(h
, shrink(0, 0, 0)), std::invalid_argument
);
52 // not allowed: shrink axis to zero size
53 BOOST_TEST_THROWS((void)reduce(h
, shrink(0, 10, 11)), std::invalid_argument
);
54 // not allowed: rebin with zero merge
55 BOOST_TEST_THROWS((void)reduce(h
, rebin(0, 0)), std::invalid_argument
);
58 // shrink behavior when value on edge and not on edge is inclusive:
59 // - lower edge of shrink: pick bin which contains edge, lower <= x < upper
60 // - upper edge of shrink: pick bin which contains edge + 1, lower < x <= upper
62 auto h
= make(Tag(), ID(0, 3));
63 const auto& ax
= h
.axis();
64 BOOST_TEST_EQ(ax
.value(0), 0);
65 BOOST_TEST_EQ(ax
.value(1), 1);
66 BOOST_TEST_EQ(ax
.value(2), 2);
67 BOOST_TEST_EQ(ax
.value(3), 3);
68 BOOST_TEST_EQ(ax
.index(-1), -1);
69 BOOST_TEST_EQ(ax
.index(0), 0);
70 BOOST_TEST_EQ(ax
.index(1), 1);
71 BOOST_TEST_EQ(ax
.index(2), 2);
72 BOOST_TEST_EQ(ax
.index(3), 3);
74 BOOST_TEST_EQ(reduce(h
, shrink(-1, 5)).axis(), ID(0, 3));
75 BOOST_TEST_EQ(reduce(h
, shrink(0, 3)).axis(), ID(0, 3));
76 BOOST_TEST_EQ(reduce(h
, shrink(1, 3)).axis(), ID(1, 3));
77 BOOST_TEST_EQ(reduce(h
, shrink(1.001, 3)).axis(), ID(1, 3));
78 BOOST_TEST_EQ(reduce(h
, shrink(1.999, 3)).axis(), ID(1, 3));
79 BOOST_TEST_EQ(reduce(h
, shrink(2, 3)).axis(), ID(2, 3));
80 BOOST_TEST_EQ(reduce(h
, shrink(0, 2.999)).axis(), ID(0, 3));
81 BOOST_TEST_EQ(reduce(h
, shrink(0, 2.001)).axis(), ID(0, 3));
82 BOOST_TEST_EQ(reduce(h
, shrink(0, 2)).axis(), ID(0, 2));
83 BOOST_TEST_EQ(reduce(h
, shrink(0, 1.999)).axis(), ID(0, 2));
87 auto h
= make_s(Tag(), std::vector
<int>(), R(4, 1, 5), R(3, -1, 2));
104 // should do nothing, index order does not matter
105 auto hr
= reduce(h
, shrink(1, -1, 2), rebin(0, 1));
106 BOOST_TEST_EQ(hr
.rank(), 2);
107 BOOST_TEST_EQ(sum(hr
), 10);
108 BOOST_TEST_EQ(hr
.axis(0), R(4, 1, 5));
109 BOOST_TEST_EQ(hr
.axis(1), R(3, -1, 2));
110 BOOST_TEST_EQ(hr
, h
);
112 hr
= reduce(h
, slice(1, 0, 4), slice(0, 0, 4));
113 BOOST_TEST_EQ(hr
, h
);
115 hr
= reduce(h
, shrink(0, 2, 4));
116 BOOST_TEST_EQ(hr
.rank(), 2);
117 BOOST_TEST_EQ(sum(hr
), 10);
118 BOOST_TEST_EQ(hr
.axis(0), R(2, 2, 4));
119 BOOST_TEST_EQ(hr
.axis(1), R(3, -1, 2));
120 BOOST_TEST_EQ(hr
.at(-1, 0), 1); // underflow
121 BOOST_TEST_EQ(hr
.at(0, 0), 0);
122 BOOST_TEST_EQ(hr
.at(1, 0), 1);
123 BOOST_TEST_EQ(hr
.at(2, 0), 0); // overflow
124 BOOST_TEST_EQ(hr
.at(-1, 1), 1);
125 BOOST_TEST_EQ(hr
.at(0, 1), 1);
126 BOOST_TEST_EQ(hr
.at(1, 1), 0);
127 BOOST_TEST_EQ(hr
.at(2, 1), 0);
128 BOOST_TEST_EQ(hr
.at(-1, 2), 0);
129 BOOST_TEST_EQ(hr
.at(0, 2), 2);
130 BOOST_TEST_EQ(hr
.at(1, 2), 1);
131 BOOST_TEST_EQ(hr
.at(2, 2), 3);
141 hr
= reduce(h
, shrink_and_rebin(0, 2, 5, 2), rebin(1, 3));
142 BOOST_TEST_EQ(hr
.rank(), 2);
143 BOOST_TEST_EQ(sum(hr
), 10);
144 BOOST_TEST_EQ(hr
.axis(0).size(), 1);
145 BOOST_TEST_EQ(hr
.axis(1).size(), 1);
146 BOOST_TEST_EQ(hr
.axis(0).bin(0).lower(), 2);
147 BOOST_TEST_EQ(hr
.axis(0).bin(0).upper(), 4);
148 BOOST_TEST_EQ(hr
.axis(1).bin(0).lower(), -1);
149 BOOST_TEST_EQ(hr
.axis(1).bin(0).upper(), 2);
150 BOOST_TEST_EQ(hr
.at(-1, 0), 2); // underflow
151 BOOST_TEST_EQ(hr
.at(0, 0), 5);
152 BOOST_TEST_EQ(hr
.at(1, 0), 3); // overflow
154 // test overload that accepts iterable and test option fusion
155 std::vector
<reduce_option
> opts
{{shrink(0, 2, 5), rebin(0, 2), rebin(1, 3)}};
156 auto hr2
= reduce(h
, opts
);
157 BOOST_TEST_EQ(hr2
, hr
);
158 opts
= {rebin(0, 2), slice(0, 1, 4), rebin(1, 3)};
159 auto hr3
= reduce(h
, opts
);
160 BOOST_TEST_EQ(hr3
, hr
);
168 auto h
= make(Tag(), r
, v
, c
);
169 auto hr
= algorithm::reduce(h
, shrink(0, 0.2, 0.7));
170 BOOST_TEST_EQ(hr
.axis(0).size(), 3);
171 BOOST_TEST_EQ(hr
.axis(0).bin(0).lower(), 0.2);
172 BOOST_TEST_EQ(hr
.axis(0).bin(2).upper(), 0.8);
173 BOOST_TEST_EQ(hr
.axis(1).size(), 2);
174 BOOST_TEST_EQ(hr
.axis(1).bin(0).lower(), 1);
175 BOOST_TEST_EQ(hr
.axis(1).bin(1).upper(), 3);
176 BOOST_TEST_THROWS((void)algorithm::reduce(h
, rebin(2, 2)), std::invalid_argument
);
179 // reduce on integer axis, rebin must fail
181 auto h
= make(Tag(), axis::integer
<>(1, 4));
182 BOOST_TEST_THROWS((void)reduce(h
, rebin(2)), std::invalid_argument
);
183 auto hr
= reduce(h
, shrink(2, 3));
184 BOOST_TEST_EQ(hr
.axis().size(), 1);
185 BOOST_TEST_EQ(hr
.axis().bin(0), 2);
186 BOOST_TEST_EQ(hr
.axis().bin(1), 3);
189 // reduce on circular axis, shrink must fail, also rebin with remainder
191 auto h
= make(Tag(), axis::circular
<>(4, 1, 4));
192 BOOST_TEST_THROWS((void)reduce(h
, shrink(0, 2)), std::invalid_argument
);
193 BOOST_TEST_THROWS((void)reduce(h
, rebin(3)), std::invalid_argument
);
194 auto hr
= reduce(h
, rebin(2));
195 BOOST_TEST_EQ(hr
.axis().size(), 2);
196 BOOST_TEST_EQ(hr
.axis().bin(0).lower(), 1);
197 BOOST_TEST_EQ(hr
.axis().bin(1).upper(), 4);
200 // reduce on variable axis
202 auto h
= make(Tag(), V({0, 1, 2, 3, 4, 5, 6}));
203 auto hr
= reduce(h
, shrink_and_rebin(1, 5, 2));
204 BOOST_TEST_EQ(hr
.axis().size(), 2);
205 BOOST_TEST_EQ(hr
.axis().value(0), 1);
206 BOOST_TEST_EQ(hr
.axis().value(1), 3);
207 BOOST_TEST_EQ(hr
.axis().value(2), 5);
210 // reduce on axis with inverted range
212 auto h
= make(Tag(), R(4, 2, -2));
213 const auto& ax
= h
.axis();
214 BOOST_TEST_EQ(ax
.index(-0.999), 2);
215 BOOST_TEST_EQ(ax
.index(-1.0), 3);
216 BOOST_TEST_EQ(ax
.index(-1.5), 3);
218 BOOST_TEST_EQ(reduce(h
, shrink(3, -3)).axis(), R(4, 2, -2));
219 BOOST_TEST_EQ(reduce(h
, shrink(2, -2)).axis(), R(4, 2, -2));
220 BOOST_TEST_EQ(reduce(h
, shrink(1.999, -2)).axis(), R(4, 2, -2));
221 BOOST_TEST_EQ(reduce(h
, shrink(1.001, -2)).axis(), R(4, 2, -2));
222 BOOST_TEST_EQ(reduce(h
, shrink(1, -2)).axis(), R(3, 1, -2));
223 BOOST_TEST_EQ(reduce(h
, shrink(2, -1.999)).axis(), R(4, 2, -2));
224 BOOST_TEST_EQ(reduce(h
, shrink(2, -1.001)).axis(), R(4, 2, -2));
225 BOOST_TEST_EQ(reduce(h
, shrink(2, -1)).axis(), R(3, 2, -1));
230 run_tests
<static_tag
>();
231 run_tests
<dynamic_tag
>();
233 return boost::report_errors();