1 // Copyright 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 <algorithm>
8 #include <boost/core/lightweight_test.hpp>
9 #include <boost/histogram/axis/integer.hpp>
10 #include <boost/histogram/axis/ostream.hpp>
11 #include <boost/histogram/axis/variable.hpp>
12 #include <boost/histogram/histogram.hpp>
13 #include <boost/histogram/indexed.hpp>
14 #include <boost/histogram/literals.hpp>
15 #include <boost/histogram/ostream.hpp>
16 #include <boost/mp11/algorithm.hpp>
17 #include <boost/mp11/list.hpp>
18 #include <iterator>
19 #include <ostream>
20 #include <type_traits>
21 #include <vector>
22 #include "throw_exception.hpp"
23 #include "utility_histogram.hpp"
24
25 using namespace boost::histogram;
26 using namespace boost::histogram::literals;
27 using namespace boost::mp11;
28
29 template <class Tag, class Coverage>
run_1d_tests(mp_list<Tag,Coverage>)30 void run_1d_tests(mp_list<Tag, Coverage>) {
31 auto h = make(Tag(), axis::integer<>(0, 3));
32 h(-1, weight(1));
33 h(0, weight(2));
34 h(1, weight(3));
35 h(2, weight(4));
36 h(3, weight(5));
37
38 auto ind = indexed(h, Coverage());
39 auto it = ind.begin();
40 BOOST_TEST_EQ(it->indices().size(), 1);
41 BOOST_TEST_EQ(it->indices()[0], Coverage() == coverage::all ? -1 : 0);
42
43 if (Coverage() == coverage::all) {
44 BOOST_TEST_EQ(it->index(0), -1);
45 BOOST_TEST_EQ(**it, 1);
46 BOOST_TEST_EQ(it->bin(0), h.axis().bin(-1));
47 ++it;
48 }
49 BOOST_TEST_EQ(it->index(0), 0);
50 BOOST_TEST_EQ(**it, 2);
51 BOOST_TEST_EQ(it->bin(0), h.axis().bin(0));
52 ++it;
53 BOOST_TEST_EQ(it->index(0), 1);
54 BOOST_TEST_EQ(**it, 3);
55 BOOST_TEST_EQ(it->bin(0), h.axis().bin(1));
56 ++it;
57 // check post-increment
58 auto prev = it++;
59 BOOST_TEST_EQ(prev->index(0), 2);
60 BOOST_TEST_EQ(**prev, 4);
61 BOOST_TEST_EQ(prev->bin(0), h.axis().bin(2));
62 if (Coverage() == coverage::all) {
63 BOOST_TEST_EQ(it->index(0), 3);
64 BOOST_TEST_EQ(**it, 5);
65 BOOST_TEST_EQ(it->bin(0), h.axis().bin(3));
66 ++it;
67 }
68 BOOST_TEST(it == ind.end());
69
70 for (auto&& x : indexed(h, Coverage())) *x = 0;
71
72 for (auto&& x : indexed(static_cast<const decltype(h)&>(h), Coverage()))
73 BOOST_TEST_EQ(*x, 0);
74 }
75
76 template <class Tag, class Coverage>
run_3d_tests(mp_list<Tag,Coverage>)77 void run_3d_tests(mp_list<Tag, Coverage>) {
78 auto h = make_s(Tag(), std::vector<int>(), axis::integer<>(0, 2),
79 axis::integer<int, axis::null_type, axis::option::none_t>(0, 3),
80 axis::integer<int, axis::null_type, axis::option::overflow_t>(0, 4));
81
82 for (int i = -1; i < 3; ++i)
83 for (int j = -1; j < 4; ++j)
84 for (int k = -1; k < 5; ++k) h(i, j, k, weight(i * 100 + j * 10 + k));
85
86 auto ind = indexed(h, Coverage());
87 auto it = ind.begin();
88 BOOST_TEST_EQ(it->indices().size(), 3);
89
90 const int d = Coverage() == coverage::all;
91
92 // imitate iteration order of indexed loop
93 for (int k = 0; k < 4 + d; ++k)
94 for (int j = 0; j < 3; ++j)
95 for (int i = -d; i < 2 + d; ++i) {
96 BOOST_TEST_EQ(it->index(0), i);
97 BOOST_TEST_EQ(it->index(1), j);
98 BOOST_TEST_EQ(it->index(2), k);
99 BOOST_TEST_EQ(it->bin(0_c), h.axis(0_c).bin(i));
100 BOOST_TEST_EQ(it->bin(1_c), h.axis(1_c).bin(j));
101 BOOST_TEST_EQ(it->bin(2_c), h.axis(2_c).bin(k));
102 BOOST_TEST_EQ(**it, i * 100 + j * 10 + k);
103 ++it;
104 }
105 BOOST_TEST(it == ind.end());
106 }
107
108 template <class Tag, class Coverage>
run_density_tests(mp_list<Tag,Coverage>)109 void run_density_tests(mp_list<Tag, Coverage>) {
110 auto ax = axis::variable<>({0.0, 0.1, 0.3, 0.6});
111 auto ay = axis::integer<int>(0, 2);
112 auto az = ax;
113 auto h = make_s(Tag(), std::vector<int>(), ax, ay, az);
114
115 // fill uniformly
116 for (auto&& x : h) x = 1;
117
118 for (auto&& x : indexed(h, Coverage())) {
119 BOOST_TEST_EQ(x.density(), *x / (x.bin(0).width() * x.bin(2).width()));
120 }
121 }
122
123 template <class Tag, class Coverage>
run_stdlib_tests(mp_list<Tag,Coverage>)124 void run_stdlib_tests(mp_list<Tag, Coverage>) {
125 auto ax = axis::regular<>(3, 0, 1);
126 auto ay = axis::integer<>(0, 2);
127 auto h = make_s(Tag(), std::array<int, 20>(), ax, ay);
128
129 struct generator {
130 int i = 0;
131 int operator()() { return ++i; }
132 };
133
134 auto ind = indexed(h, Coverage());
135 std::generate(ind.begin(), ind.end(), generator{});
136
137 {
138 int i = 0;
139 for (auto&& x : ind) BOOST_TEST_EQ(*x, ++i);
140 }
141
142 {
143 auto it = std::min_element(ind.begin(), ind.end());
144 BOOST_TEST(it == ind.begin());
145 BOOST_TEST(it != ind.end());
146 }
147
148 {
149 auto it = std::max_element(ind.begin(), ind.end());
150 // get last before end()
151 auto it2 = ind.begin();
152 auto it3 = it2;
153 while (it2 != ind.end()) it3 = it2++;
154 BOOST_TEST(it == it3);
155 BOOST_TEST(it != ind.begin());
156 }
157 }
158
main()159 int main() {
160 mp_for_each<mp_product<mp_list, mp_list<static_tag, dynamic_tag>,
161 mp_list<std::integral_constant<coverage, coverage::inner>,
162 std::integral_constant<coverage, coverage::all>>>>(
163 [](auto&& x) {
164 run_1d_tests(x);
165 run_3d_tests(x);
166 run_density_tests(x);
167 run_stdlib_tests(x);
168 });
169 return boost::report_errors();
170 }
171