Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / histogram / test / histogram_custom_axis_test.cpp
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
30   auto index(const char* s) const { return integer::index(std::atoi(s)); }
31 };
32
33 struct minimal {
34   auto index(int x) const { return static_cast<axis::index_type>(x % 2); }
35   auto size() const { return axis::index_type{2}; }
36 };
37
38 struct axis2d {
39   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   }
42   auto size() const { return axis::index_type{2}; }
43 };
44
45 class axis2d_growing {
46 public:
47   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
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
64   axis::index_type size() const { return size_; }
65
66 private:
67   axis::index_type size_ = 0;
68 };
69
70 template <class Tag>
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
128 int main() {
129   run_tests<static_tag>();
130   run_tests<dynamic_tag>();
131   return boost::report_errors();
132 }