1 // Copyright 2018-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 <boost/core/lightweight_test.hpp>
8 #include <boost/histogram/accumulators/mean.hpp>
9 #include <boost/histogram/accumulators/weighted_mean.hpp>
10 #include <boost/histogram/axis.hpp>
11 #include <boost/histogram/axis/ostream.hpp>
12 #include <boost/histogram/histogram.hpp>
13 #include <boost/histogram/literals.hpp>
14 #include <boost/histogram/make_histogram.hpp>
15 #include <boost/histogram/ostream.hpp>
16 #include <boost/histogram/storage_adaptor.hpp>
17 #include <sstream>
18 #include <stdexcept>
19 #include <tuple>
20 #include <utility>
21 #include <vector>
22 #include "throw_exception.hpp"
23 #include "utility_histogram.hpp"
24
25 using namespace boost::histogram;
26
27 struct modified_axis : public axis::integer<> {
28 using integer::integer; // inherit ctors of base
29 // customization point: convert argument and call base class
indexmodified_axis30 auto index(const char* s) const { return integer::index(std::atoi(s)); }
31 };
32
33 struct minimal {
indexminimal34 auto index(int x) const { return static_cast<axis::index_type>(x % 2); }
sizeminimal35 auto size() const { return axis::index_type{2}; }
36 };
37
38 struct axis2d {
indexaxis2d39 auto index(const std::tuple<double, double>& x) const {
40 return axis::index_type{std::get<0>(x) == 1 && std::get<1>(x) == 2};
41 }
sizeaxis2d42 auto size() const { return axis::index_type{2}; }
43 };
44
45 class axis2d_growing {
46 public:
index(std::tuple<double,double> xy) const47 auto index(std::tuple<double, double> xy) const {
48 const auto x = std::get<0>(xy);
49 const auto y = std::get<1>(xy);
50 const auto r = std::sqrt(x * x + y * y);
51 return std::min(static_cast<axis::index_type>(r), size());
52 }
53
update(std::tuple<double,double> xy)54 auto update(std::tuple<double, double> xy) {
55 const auto x = std::get<0>(xy);
56 const auto y = std::get<1>(xy);
57 const auto r = std::sqrt(x * x + y * y);
58 const auto n = static_cast<int>(r);
59 const auto old = size_;
60 if (n >= size_) size_ = n + 1;
61 return std::make_pair(n, old - size_);
62 }
63
size() const64 axis::index_type size() const { return size_; }
65
66 private:
67 axis::index_type size_ = 0;
68 };
69
70 template <class Tag>
run_tests()71 void run_tests() {
72 // one 2d axis
73 {
74 auto h = make(Tag(), axis2d());
75 h(1, 2); // ok, forwards 2d tuple to axis
76 h(std::make_tuple(1, 2)); // also ok, forwards 2d tuple to axis
77 BOOST_TEST_THROWS(h(1), std::invalid_argument);
78 BOOST_TEST_THROWS(h(1, 2, 3), std::invalid_argument);
79 BOOST_TEST_EQ(h.at(0), 0); // ok, bin access is still 1d
80 BOOST_TEST_EQ(h[std::make_tuple(1)], 2);
81 // also works with weights
82 h(1, 2, weight(2));
83 h(std::make_tuple(weight(3), 1, 2));
84 BOOST_TEST_EQ(h.at(0), 0);
85 BOOST_TEST_EQ(h.at(1), 7);
86
87 auto h2 = make_s(Tag(), profile_storage(), axis2d());
88 h2(1, 2, sample(2));
89 BOOST_TEST_EQ(h2[1].count(), 1);
90 BOOST_TEST_EQ(h2[1].value(), 2);
91
92 auto h3 = make_s(Tag(), weighted_profile_storage(), axis2d());
93 h3(1, 2, weight(3), sample(2));
94 BOOST_TEST_EQ(h3[1].sum_of_weights(), 3);
95 BOOST_TEST_EQ(h3[1].value(), 2);
96 }
97
98 // several axes, one 2d
99 {
100 auto h = make(Tag(), modified_axis(0, 3), minimal(), axis2d());
101 h("0", 1, std::make_tuple(1.0, 2.0));
102 h("1", 2, std::make_tuple(2.0, 1.0));
103
104 BOOST_TEST_EQ(h.rank(), 3);
105 BOOST_TEST_EQ(h.at(0, 0, 0), 0);
106 BOOST_TEST_EQ(h.at(0, 1, 1), 1);
107 BOOST_TEST_EQ(h.at(1, 0, 0), 1);
108 }
109
110 // growing axis
111 {
112 auto h = make_s(Tag{}, std::vector<int>{}, axis2d_growing{});
113 BOOST_TEST_EQ(h.size(), 0);
114 h(0, 0);
115 BOOST_TEST_EQ(h.size(), 1);
116 h(1, 0);
117 h(0, 1);
118 BOOST_TEST_EQ(h.size(), 2);
119 h(10, 0);
120 BOOST_TEST_EQ(h.size(), 11);
121 BOOST_TEST_EQ(h[0], 1);
122 BOOST_TEST_EQ(h[1], 2);
123 BOOST_TEST_EQ(h[10], 1);
124 BOOST_TEST_THROWS(h(0), std::invalid_argument);
125 }
126 }
127
main()128 int main() {
129 run_tests<static_tag>();
130 run_tests<dynamic_tag>();
131 return boost::report_errors();
132 }
133