diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 980e6f2c..953b3417 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,7 @@ * range-based for-loops in C++ and Python loops now excludes over-/underflow bins * Regular axis in C++: Allowing transforms with state * Regular axis in Python: Support for all C++ transforms +* Getting rid of utility functions, use interface augmented boost::variant instead [heading 2.0 (not in boost)] diff --git a/doc/guide.qbk b/doc/guide.qbk index 916e177b..1179fe39 100644 --- a/doc/guide.qbk +++ b/doc/guide.qbk @@ -82,7 +82,7 @@ int main() { using hist_type = bh::histogram; auto v = std::vector(); v.push_back(bh::axis::regular<>(100, -1, 1)); - v.push_back(bh::axis::integer<>(1, 6)); + v.push_back(bh::axis::integer<>(1, 7)); auto h = hist_type(v.begin(), v.end()); // do something with h } @@ -141,7 +141,9 @@ namespace bh = boost::histogram; int main() { auto h = bh::make_static_histogram(bh::axis::integer<>(0, 9)); std::vector v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - std::for_each(v.begin(), v.end(), [&h](int x) { h.fill(x, bh::weight(2.0)); }); + std::for_each(v.begin(), v.end(), + [&h](int x) { h.fill(x, bh::weight(2.0)); } + ); // h is now filled } `` diff --git a/examples/guide_listing_4.cpp b/examples/guide_listing_4.cpp index 02d9333b..f6683a90 100644 --- a/examples/guide_listing_4.cpp +++ b/examples/guide_listing_4.cpp @@ -8,7 +8,7 @@ int main() { using hist_type = bh::histogram; auto v = std::vector(); v.push_back(bh::axis::regular<>(100, -1, 1)); - v.push_back(bh::axis::integer<>(1, 6)); + v.push_back(bh::axis::integer<>(1, 7)); auto h = hist_type(v.begin(), v.end()); // do something with h } diff --git a/examples/guide_listing_6.cpp b/examples/guide_listing_6.cpp index 719804da..2de36880 100644 --- a/examples/guide_listing_6.cpp +++ b/examples/guide_listing_6.cpp @@ -8,6 +8,8 @@ namespace bh = boost::histogram; int main() { auto h = bh::make_static_histogram(bh::axis::integer<>(0, 9)); std::vector v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - std::for_each(v.begin(), v.end(), [&h](int x) { h.fill(x, bh::weight(2.0)); }); + std::for_each(v.begin(), v.end(), + [&h](int x) { h.fill(x, bh::weight(2.0)); } + ); // h is now filled } diff --git a/include/boost/histogram.hpp b/include/boost/histogram.hpp index d1409d64..9a33c6b2 100644 --- a/include/boost/histogram.hpp +++ b/include/boost/histogram.hpp @@ -12,7 +12,6 @@ #include #include #include -#include /** * \file boost/histogram.hpp diff --git a/include/boost/histogram/axis.hpp b/include/boost/histogram/axis.hpp index 40200452..42db5ebb 100644 --- a/include/boost/histogram/axis.hpp +++ b/include/boost/histogram/axis.hpp @@ -627,7 +627,8 @@ using builtin_axes = axis::regular, axis::regular, axis::regular, axis::circular<>, - axis::variable<>, axis::integer<>, axis::category<>>; + axis::variable<>, axis::integer<>, + axis::category<>, axis::category>; } // namespace histogram } // namespace boost diff --git a/include/boost/histogram/detail/axis_visitor.hpp b/include/boost/histogram/detail/axis_visitor.hpp index c2879dff..47178c8d 100644 --- a/include/boost/histogram/detail/axis_visitor.hpp +++ b/include/boost/histogram/detail/axis_visitor.hpp @@ -37,10 +37,18 @@ struct uoflow : public static_visitor { template bool operator()(const A &a) const { return a.uoflow(); } }; -template struct index : public static_visitor { - const V &v; - explicit index(const V &x) : v(x) {} - template int operator()(const A &a) const { return a.index(v); } +template struct index : public static_visitor { + const T &t; + explicit index(const T &arg) : t(arg) {} + template int operator()(const Axis &a) const { + return impl(std::is_convertible(), a); + } + template int impl(std::true_type, const Axis& a) const { + return a.index(t); + } + template int impl(std::false_type, const Axis&) const { + throw std::runtime_error("index argument not convertible to axis value type"); + } }; struct bin : public static_visitor> { @@ -135,7 +143,7 @@ inline bool axes_equal_impl(mpl::false_, mpl::false_, const A &a, const B &b) { if (a.size() != n) { return false; } - for (decltype(n) i = 0; i < n; ++i) { + for (auto i = 0; i < n; ++i) { if (!apply_visitor(cmp_axis(a[i]), b[i])) { return false; } diff --git a/include/boost/histogram/detail/utility.hpp b/include/boost/histogram/detail/utility.hpp index a3f2f254..438bd2c2 100644 --- a/include/boost/histogram/detail/utility.hpp +++ b/include/boost/histogram/detail/utility.hpp @@ -28,8 +28,8 @@ inline void escape(std::ostream &os, const string_view s) { os << '\''; } -template -inline void lin(std::size_t &out, std::size_t &stride, const A &a, +template +inline void lin(std::size_t &out, std::size_t &stride, const Axis &a, int j) noexcept { // the following is highly optimized code that runs in a hot loop; // please measure the performance impact of changes @@ -43,12 +43,12 @@ inline void lin(std::size_t &out, std::size_t &stride, const A &a, stride *= a.shape(); } -template -inline void xlin(std::size_t &out, std::size_t &stride, const A &a, - X &&x) noexcept { +template +inline void xlin(std::size_t &out, std::size_t &stride, const Axis &a, + const typename Axis::value_type &x) noexcept { // the following is highly optimized code that runs in a hot loop; // please measure the performance impact of changes - int j = a.index(std::forward(x)); + int j = a.index(x); // j is guaranteed to be in range [-1, bins] j += (j < 0) * (a.size() + 2); // wrap around if j < 0 out += j * stride; diff --git a/include/boost/histogram/histogram.hpp b/include/boost/histogram/histogram.hpp index b7ced2c2..3b95aad7 100644 --- a/include/boost/histogram/histogram.hpp +++ b/include/boost/histogram/histogram.hpp @@ -9,5 +9,6 @@ #include #include +#include #endif diff --git a/include/boost/histogram/histogram_arithmetic_operators.hpp b/include/boost/histogram/histogram_arithmetic_operators.hpp new file mode 100644 index 00000000..f98273b7 --- /dev/null +++ b/include/boost/histogram/histogram_arithmetic_operators.hpp @@ -0,0 +1,81 @@ +// Copyright 2015-2016 Hans Dembinski +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef _BOOST_HISTOGRAM_HISTOGRAM_ARITHMETIC_OPERATORS_HPP_ +#define _BOOST_HISTOGRAM_HISTOGRAM_ARITHMETIC_OPERATORS_HPP_ + +#include + +namespace boost { +namespace histogram { + +template +histogram && +operator+(histogram &&a, + const histogram &b) { + a += b; + return std::move(a); +} + +template +histogram && +operator+(histogram &&a, + histogram &&b) { + a += b; + return std::move(a); +} + +template +histogram && +operator+(const histogram &a, + histogram &&b) { + b += a; + return std::move(b); +} + +template +histogram +operator+(const histogram &a, + const histogram &b) { + histogram r(a); + r += b; + return r; +} + +template +histogram && +operator*(histogram &&a, const double x) { + a *= x; + return std::move(a); +} + +template +histogram && +operator*(const double x, histogram &&b) { + b *= x; + return std::move(b); +} + +template +histogram +operator*(const histogram &a, const double x) { + histogram r(a); + r *= x; + return r; +} + +template +histogram +operator*(const double x, const histogram &b) { + histogram r(b); + r *= x; + return r; +} + +} // namespace histogram +} // namespace boost + +#endif diff --git a/include/boost/histogram/histogram_fwd.hpp b/include/boost/histogram/histogram_fwd.hpp index a6a6d70f..71f36038 100644 --- a/include/boost/histogram/histogram_fwd.hpp +++ b/include/boost/histogram/histogram_fwd.hpp @@ -10,9 +10,7 @@ #include #include #include -#include #include -#include namespace boost { namespace histogram { @@ -65,70 +63,6 @@ inline detail::keep_dynamic keep(unsigned i, Rest... rest) { return s; } -// fast operators (boost::operators does not use rvalue references yet) -template -histogram && -operator+(histogram &&a, - const histogram &b) { - a += b; - return std::move(a); -} - -template -histogram && -operator+(histogram &&a, - histogram &&b) { - a += b; - return std::move(a); -} - -template -histogram && -operator+(const histogram &a, - histogram &&b) { - b += a; - return std::move(b); -} - -template -histogram -operator+(const histogram &a, - const histogram &b) { - histogram r(a); - r += b; - return r; -} - -template -histogram && -operator*(histogram &&a, const double x) { - a *= x; - return std::move(a); -} - -template -histogram && -operator*(const double x, histogram &&b) { - b *= x; - return std::move(b); -} - -template -histogram -operator*(const histogram &a, const double x) { - histogram r(a); - r *= x; - return r; -} - -template -histogram -operator*(const double x, const histogram &b) { - histogram r(b); - r *= x; - return r; -} - } // namespace histogram } // namespace boost diff --git a/include/boost/histogram/histogram_impl_dynamic.hpp b/include/boost/histogram/histogram_impl_dynamic.hpp index 52a862f4..2630bf94 100644 --- a/include/boost/histogram/histogram_impl_dynamic.hpp +++ b/include/boost/histogram/histogram_impl_dynamic.hpp @@ -47,9 +47,43 @@ namespace histogram { template class histogram { static_assert(!mpl::empty::value, "at least one axis required"); + using any_axis = typename make_variant_over::type; public: - using axis_type = typename make_variant_over::type; + class axis_type : public any_axis { + public: + using any_axis::any_axis; + + int size() const { + return apply_visitor(detail::size(), *this); + } + + int shape() const { + return apply_visitor(detail::shape(), *this); + } + + bool uoflow() const { + return apply_visitor(detail::uoflow(), *this); + } + + // note: this only works for axes with compatible value type + int index(const double x) const { + return apply_visitor(detail::index(x), *this); + } + + // note: this only works for axes with compatible bin type + axis::interval operator[](const int i) const { + return apply_visitor(detail::bin(i), *this); + } + + bool operator==(const axis_type& rhs) const { + return any_axis::operator==(static_cast(rhs)); + } + + private: + template void serialize(Archive&, unsigned /* version */); + friend boost::serialization::access; + }; using value_type = typename Storage::value_type; private: @@ -64,14 +98,14 @@ public: template explicit histogram(const Axes1 &... axes) : axes_({axis_type(axes)...}) { - storage_ = Storage(field_count()); + storage_ = Storage(bincount_from_axes()); } template > histogram(Iterator axes_begin, Iterator axes_end) : axes_(std::distance(axes_begin, axes_end)) { std::copy(axes_begin, axes_end, axes_.begin()); - storage_ = Storage(field_count()); + storage_ = Storage(bincount_from_axes()); } template @@ -221,19 +255,20 @@ public: unsigned dim() const noexcept { return axes_.size(); } /// Total number of bins in the histogram (including underflow/overflow) - std::size_t size() const noexcept { return storage_.size(); } + std::size_t bincount() const noexcept { return storage_.size(); } /// Sum of all counts in the histogram double sum() const noexcept { double result = 0.0; - for (std::size_t i = 0, n = size(); i < n; ++i) { + // don't use bincount() here, so sum() still works in a moved-from object + for (std::size_t i = 0, n = storage_.size(); i < n; ++i) { result += storage_.value(i); } return result; } /// Reset bin counters to zero - void reset() { storage_ = std::move(Storage(storage_.size())); } + void reset() { storage_ = Storage(bincount_from_axes()); } /// Return axis \a i const axis_type &axis(unsigned i = 0) const { @@ -252,7 +287,7 @@ private: axes_type axes_; Storage storage_; - std::size_t field_count() const { + std::size_t bincount_from_axes() const noexcept { detail::field_count fc; for_each_axis(fc); return fc.value; @@ -304,9 +339,19 @@ private: const Value &val; xlin_visitor(std::size_t &i, std::size_t &s, const Value &v) : idx(i), stride(s), val(v) {} - template void operator()(const A &a) const { + template void operator()(const Axis &a) const { + impl(std::is_convertible(), a); + } + + template + void impl(std::true_type, const Axis& a) const { detail::xlin(idx, stride, a, val); } + + template + void impl(std::false_type, const Axis&) const { + throw std::runtime_error("fill argument not convertible to axis value type"); + } }; template inline void lin(std::size_t &, std::size_t &) const {} diff --git a/include/boost/histogram/histogram_impl_static.hpp b/include/boost/histogram/histogram_impl_static.hpp index ab580920..91317719 100644 --- a/include/boost/histogram/histogram_impl_static.hpp +++ b/include/boost/histogram/histogram_impl_static.hpp @@ -58,11 +58,11 @@ public: template explicit histogram(const Axis &... axis) : axes_(axis...) { - storage_ = Storage(field_count()); + storage_ = Storage(bincount_from_axes()); } explicit histogram(axes_type &&axes) : axes_(std::move(axes)) { - storage_ = Storage(field_count()); + storage_ = Storage(bincount_from_axes()); } template @@ -142,19 +142,20 @@ public: constexpr unsigned dim() const { return axes_size::value; } /// Total number of bins in the histogram (including underflow/overflow) - std::size_t size() const { return storage_.size(); } + std::size_t bincount() const { return storage_.size(); } /// Sum of all counts in the histogram double sum() const { double result = 0.0; - for (std::size_t i = 0, n = size(); i < n; ++i) { + // don't use bincount() here, so sum() still works in a moved-from object + for (std::size_t i = 0, n = storage_.size(); i < n; ++i) { result += storage_.value(i); } return result; } /// Reset bin counters to zero - void reset() { storage_ = Storage(storage_.size()); } + void reset() { storage_ = Storage(bincount_from_axes()); } /// Get N-th axis template @@ -181,7 +182,7 @@ private: axes_type axes_; Storage storage_; - std::size_t field_count() const { + std::size_t bincount_from_axes() const noexcept { detail::field_count fc; fusion::for_each(axes_, fc); return fc.value; diff --git a/include/boost/histogram/serialization.hpp b/include/boost/histogram/serialization.hpp index 8231dc0a..69b770c0 100644 --- a/include/boost/histogram/serialization.hpp +++ b/include/boost/histogram/serialization.hpp @@ -199,6 +199,12 @@ void histogram::serialize(Archive &ar, unsigned /* version */) { ar &storage_; } +template +template +void histogram::axis_type::serialize(Archive &ar, unsigned /* version */) { + ar &boost::serialization::base_object::any_axis>(*this); +} + } // namespace histogram } // namespace boost diff --git a/include/boost/histogram/utility.hpp b/include/boost/histogram/utility.hpp deleted file mode 100644 index 1fd3f560..00000000 --- a/include/boost/histogram/utility.hpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2015-2016 Hans Dembinski -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt -// or copy at http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_HISTOGRAM_UTILITY_HPP_ -#define BOOST_HISTOGRAM_UTILITY_HPP_ - -#include -#include - -namespace boost { -namespace histogram { - -template inline int size(const A &a) { return a.size(); } - -template inline int size(const boost::variant &a) { - return apply_visitor(detail::size(), a); -} - -template inline int shape(const A &a) { return a.shape(); } - -template inline int shape(const boost::variant &a) { - return apply_visitor(detail::shape(), a); -} - -template inline int index(const A &a, const V v) { - return a.index(v); -} - -template -inline int index(const boost::variant &a, const V v) { - return apply_visitor(detail::index(v), a); -} - -template inline typename A::bin_type bin(const A &a, const int i) { - return a[i]; -} - -template -inline axis::interval bin(const boost::variant &a, - const int i) { - return apply_visitor(detail::bin(i), a); -} - -} // namespace histogram -} // namespace boost - -#endif diff --git a/src/python/histogram.cpp b/src/python/histogram.cpp index ef4f42ae..a2f73aa0 100644 --- a/src/python/histogram.cpp +++ b/src/python/histogram.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -100,7 +99,7 @@ public: d["typestr"] = apply_visitor(dtype_visitor(shapes, strides), b); for (auto i = 0u; i < self.dim(); ++i) { if (i) strides.append(strides[-1] * shapes[-1]); - shapes.append(histogram::shape(self.axis(i))); + shapes.append(self.axis(i).shape()); } if (self.dim() == 0) shapes.append(0); @@ -366,7 +365,7 @@ void register_histogram() { "\nIf Numpy support is enabled, 1d-arrays can be passed instead of" "\nvalues, which must be equal in lenght. Arrays and values can" "\nbe mixed in the same call.") - .add_property("size", &dynamic_histogram::size, + .add_property("bincount", &dynamic_histogram::bincount, "Returns total number of bins, including under- and overflow.") .add_property("sum", &dynamic_histogram::sum, "Returns sum of all entries, including under- and overflow bins.") diff --git a/test/axis_test.cpp b/test/axis_test.cpp index 3eaa7c7f..87e9cdd4 100644 --- a/test/axis_test.cpp +++ b/test/axis_test.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/test/histogram_test.cpp b/test/histogram_test.cpp index b860fae1..12645f4f 100644 --- a/test/histogram_test.cpp +++ b/test/histogram_test.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -42,7 +41,7 @@ bool axis_equal(Static, const T &t, const U &u) { template bool axis_equal(Dynamic, const T &t, const U &u) { - return t == T(u); + return t == T(u); // need to convert rhs to boost::variant } template void run_tests() { @@ -52,7 +51,7 @@ template void run_tests() { auto h = histogram>, adaptive_storage>(); BOOST_TEST_EQ(h.dim(), 1); - BOOST_TEST_EQ(h.size(), 0); + BOOST_TEST_EQ(h.bincount(), 0); auto h2 = histogram>, array_storage>(); BOOST_TEST(h2 == h); @@ -66,9 +65,9 @@ template void run_tests() { auto h = make_histogram(Type(), axis::regular<>{3, -1, 1}); BOOST_TEST_EQ(h.dim(), 1); - BOOST_TEST_EQ(h.size(), 5); - BOOST_TEST_EQ(shape(h.axis(0_c)), 5); - BOOST_TEST_EQ(shape(h.axis()), 5); + BOOST_TEST_EQ(h.bincount(), 5); + BOOST_TEST_EQ(h.axis(0_c).shape(), 5); + BOOST_TEST_EQ(h.axis().shape(), 5); auto h2 = make_histogram>( Type(), axis::regular<>{3, -1, 1}); BOOST_TEST(h2 == h); @@ -79,9 +78,9 @@ template void run_tests() { auto h = make_histogram(Type(), axis::regular<>{3, -1, 1}, axis::integer<>{-1, 2}); BOOST_TEST_EQ(h.dim(), 2); - BOOST_TEST_EQ(h.size(), 25); - BOOST_TEST_EQ(shape(h.axis(0_c)), 5); - BOOST_TEST_EQ(shape(h.axis(1_c)), 5); + BOOST_TEST_EQ(h.bincount(), 25); + BOOST_TEST_EQ(h.axis(0_c).shape(), 5); + BOOST_TEST_EQ(h.axis(1_c).shape(), 5); auto h2 = make_histogram>( Type(), axis::regular<>{3, -1, 1}, axis::integer<>{-1, 2}); BOOST_TEST(h2 == h); @@ -93,7 +92,7 @@ template void run_tests() { axis::integer<>{-1, 2}, axis::circular<>{3}); BOOST_TEST_EQ(h.dim(), 3); - BOOST_TEST_EQ(h.size(), 75); + BOOST_TEST_EQ(h.bincount(), 75); auto h2 = make_histogram>( Type(), axis::regular<>{3, -1, 1}, axis::integer<>{-1, 2}, axis::circular<>{3}); @@ -106,7 +105,7 @@ template void run_tests() { Type(), axis::regular<>{3, -1, 1}, axis::integer<>{-1, 2}, axis::circular<>{3}, axis::variable<>{-1, 0, 1}); BOOST_TEST_EQ(h.dim(), 4); - BOOST_TEST_EQ(h.size(), 300); + BOOST_TEST_EQ(h.bincount(), 300); auto h2 = make_histogram>( Type(), axis::regular<>{3, -1, 1}, axis::integer<>{-1, 2}, axis::circular<>{3}, axis::variable<>{-1, 0, 1}); @@ -121,7 +120,7 @@ template void run_tests() { axis::circular<>{3}, axis::variable<>{-1, 0, 1}, axis::category<>{{A, B, C}}); BOOST_TEST_EQ(h.dim(), 5); - BOOST_TEST_EQ(h.size(), 900); + BOOST_TEST_EQ(h.bincount(), 900); auto h2 = make_histogram>( Type(), axis::regular<>{3, -1, 1}, axis::integer<>{-1, 2}, axis::circular<>{3}, axis::variable<>{-1, 0, 1}, @@ -169,32 +168,40 @@ template void run_tests() { BOOST_TEST_EQ(h.dim(), Type() == 0 ? 2 : 0); // static axes cannot shrink to zero BOOST_TEST_EQ(h.sum(), 0); - BOOST_TEST_EQ(h.size(), 0); + BOOST_TEST_EQ(h.bincount(), 0); BOOST_TEST(h2 == href); decltype(h) h3; h3 = std::move(h2); BOOST_TEST_EQ(h2.dim(), Type() == 0 ? 2 : 0); // static axes cannot shrink to zero BOOST_TEST_EQ(h2.sum(), 0); - BOOST_TEST_EQ(h2.size(), 0); + BOOST_TEST_EQ(h2.bincount(), 0); BOOST_TEST(h3 == href); } - // utility + // axis methods { + enum { A=3, B=5 }; auto a = make_histogram(Type(), axis::regular<>(1, 1, 2)); - BOOST_TEST_EQ(size(a.axis()), 1); - BOOST_TEST_EQ(shape(a.axis()), 3); - BOOST_TEST_EQ(index(a.axis(), 1.0), 0); - BOOST_TEST_EQ(bin(a.axis(), 0).lower(), 1.0); - BOOST_TEST_EQ(bin(a.axis(), 0).upper(), 2.0); + BOOST_TEST_EQ(a.axis().size(), 1); + BOOST_TEST_EQ(a.axis().shape(), 3); + BOOST_TEST_EQ(a.axis().index(1.0), 0); + BOOST_TEST_EQ(a.axis()[0].lower(), 1.0); + BOOST_TEST_EQ(a.axis()[0].upper(), 2.0); auto b = make_histogram(Type(), axis::integer<>(1, 2)); - BOOST_TEST_EQ(size(a.axis()), 1); - BOOST_TEST_EQ(shape(a.axis()), 3); - BOOST_TEST_EQ(index(a.axis(), 1.0), 0); - BOOST_TEST_EQ(bin(b.axis(), 0).lower(), 1.0); - BOOST_TEST_EQ(bin(b.axis(), 0).upper(), 2.0); + BOOST_TEST_EQ(b.axis().size(), 1); + BOOST_TEST_EQ(b.axis().shape(), 3); + BOOST_TEST_EQ(b.axis().index(1), 0); + BOOST_TEST_EQ(b.axis()[0].lower(), 1); + BOOST_TEST_EQ(b.axis()[0].upper(), 2); + + auto c = make_histogram(Type(), axis::category<>({A, B})); + BOOST_TEST_EQ(c.axis().size(), 2); + BOOST_TEST_EQ(c.axis().shape(), 2); + BOOST_TEST_EQ(c.axis().index(A), 0); + BOOST_TEST_EQ(c.axis().index(B), 1); + // c.axis()[0] is tested separately for Static and Dynamic below } // equal_compare @@ -232,22 +239,22 @@ template void run_tests() { h.fill(10, count(10)); BOOST_TEST_EQ(h.dim(), 1); - BOOST_TEST_EQ(size(h.axis(0_c)), 2); - BOOST_TEST_EQ(shape(h.axis(0_c)), 4); + BOOST_TEST_EQ(h.axis(0_c).size(), 2); + BOOST_TEST_EQ(h.axis(0_c).shape(), 4); BOOST_TEST_EQ(h.sum(), 13); BOOST_TEST_THROWS(h.value(-2), std::out_of_range); - BOOST_TEST_EQ(h.value(-1), 1.0); - BOOST_TEST_EQ(h.value(0), 2.0); - BOOST_TEST_EQ(h.value(1), 0.0); - BOOST_TEST_EQ(h.value(2), 10.0); + BOOST_TEST_EQ(h.value(-1), 1); + BOOST_TEST_EQ(h.value(0), 2); + BOOST_TEST_EQ(h.value(1), 0); + BOOST_TEST_EQ(h.value(2), 10); BOOST_TEST_THROWS(h.value(3), std::out_of_range); BOOST_TEST_THROWS(h.variance(-2), std::out_of_range); - BOOST_TEST_EQ(h.variance(-1), 1.0); - BOOST_TEST_EQ(h.variance(0), 2.0); - BOOST_TEST_EQ(h.variance(1), 0.0); - BOOST_TEST_EQ(h.variance(2), 10.0); + BOOST_TEST_EQ(h.variance(-1), 1); + BOOST_TEST_EQ(h.variance(0), 2); + BOOST_TEST_EQ(h.variance(1), 0); + BOOST_TEST_EQ(h.variance(2), 10); BOOST_TEST_THROWS(h.variance(3), std::out_of_range); } @@ -261,18 +268,43 @@ template void run_tests() { h.fill(10, count(10)); BOOST_TEST_EQ(h.dim(), 1); - BOOST_TEST_EQ(size(h.axis(0_c)), 2); - BOOST_TEST_EQ(shape(h.axis(0_c)), 2); + BOOST_TEST_EQ(h.axis(0_c).size(), 2); + BOOST_TEST_EQ(h.axis(0_c).shape(), 2); BOOST_TEST_EQ(h.sum(), 2); BOOST_TEST_THROWS(h.value(-1), std::out_of_range); - BOOST_TEST_EQ(h.value(0), 2.0); - BOOST_TEST_EQ(h.value(1), 0.0); + BOOST_TEST_EQ(h.value(0), 2); + BOOST_TEST_EQ(h.value(1), 0); BOOST_TEST_THROWS(h.value(2), std::out_of_range); BOOST_TEST_THROWS(h.variance(-1), std::out_of_range); - BOOST_TEST_EQ(h.variance(0), 2.0); - BOOST_TEST_EQ(h.variance(1), 0.0); + BOOST_TEST_EQ(h.variance(0), 2); + BOOST_TEST_EQ(h.variance(1), 0); + BOOST_TEST_THROWS(h.variance(2), std::out_of_range); + } + + // d1_3 + { + auto h = make_histogram( + Type(), axis::category({"A", "B"})); + h.fill("A"); + h.fill("B"); + h.fill("D"); + h.fill("E", count(10)); + + BOOST_TEST_EQ(h.dim(), 1); + BOOST_TEST_EQ(h.axis(0_c).size(), 2); + BOOST_TEST_EQ(h.axis(0_c).shape(), 2); + BOOST_TEST_EQ(h.sum(), 2); + + BOOST_TEST_THROWS(h.value(-1), std::out_of_range); + BOOST_TEST_EQ(h.value(0), 1); + BOOST_TEST_EQ(h.value(1), 1); + BOOST_TEST_THROWS(h.value(2), std::out_of_range); + + BOOST_TEST_THROWS(h.variance(-1), std::out_of_range); + BOOST_TEST_EQ(h.variance(0), 1); + BOOST_TEST_EQ(h.variance(1), 1); BOOST_TEST_THROWS(h.variance(2), std::out_of_range); } @@ -328,10 +360,10 @@ template void run_tests() { h.fill(-10, 0); BOOST_TEST_EQ(h.dim(), 2); - BOOST_TEST_EQ(size(h.axis(0_c)), 2); - BOOST_TEST_EQ(shape(h.axis(0_c)), 4); - BOOST_TEST_EQ(size(h.axis(1_c)), 3); - BOOST_TEST_EQ(shape(h.axis(1_c)), 3); + BOOST_TEST_EQ(h.axis(0_c).size(), 2); + BOOST_TEST_EQ(h.axis(0_c).shape(), 4); + BOOST_TEST_EQ(h.axis(1_c).size(), 3); + BOOST_TEST_EQ(h.axis(1_c).shape(), 3); BOOST_TEST_EQ(h.sum(), 3); BOOST_TEST_EQ(h.value(-1, 0), 0.0); @@ -417,17 +449,17 @@ template void run_tests() { auto h = make_histogram(Type(), axis::integer<>(0, 3), axis::integer<>(0, 4), axis::integer<>(0, 5)); - for (auto i = 0; i < size(h.axis(0_c)); ++i) { - for (auto j = 0; j < size(h.axis(1_c)); ++j) { - for (auto k = 0; k < size(h.axis(2_c)); ++k) { + for (auto i = 0; i < h.axis(0_c).size(); ++i) { + for (auto j = 0; j < h.axis(1_c).size(); ++j) { + for (auto k = 0; k < h.axis(2_c).size(); ++k) { h.fill(weight(i + j + k), i, j, k); } } } - for (auto i = 0; i < size(h.axis(0_c)); ++i) { - for (auto j = 0; j < size(h.axis(1_c)); ++j) { - for (auto k = 0; k < size(h.axis(2_c)); ++k) { + for (auto i = 0; i < h.axis(0_c).size(); ++i) { + for (auto j = 0; j < h.axis(1_c).size(); ++j) { + for (auto k = 0; k < h.axis(2_c).size(); ++k) { BOOST_TEST_EQ(h.value(i, j, k), i + j + k); } } @@ -623,8 +655,8 @@ template void run_tests() { BOOST_TEST_EQ(h1_0.sum(), 5); BOOST_TEST_EQ(h1_0.value(0), 2); BOOST_TEST_EQ(h1_0.value(1), 3); - BOOST_TEST_EQ(bin(h1_0.axis(), 0).lower(), 0.0); - BOOST_TEST_EQ(bin(h1_0.axis(), 1).lower(), 1.0); + BOOST_TEST_EQ(h1_0.axis()[0].lower(), 0.0); + BOOST_TEST_EQ(h1_0.axis()[1].lower(), 1.0); BOOST_TEST(axis_equal(Type(), h1_0.axis(), h1.axis(0_c))); auto h1_1 = reduce(h1, keep(1_c)); @@ -733,6 +765,9 @@ int main() { run_tests(); run_tests(); + // special stuff that only works with Static + + // special stuff that only works with Dynamic // init @@ -747,12 +782,12 @@ int main() { BOOST_TEST_EQ(h.axis(1), v[1]); } - // utility + // axis methods { enum { A, B }; auto c = make_dynamic_histogram(axis::category<>({A, B})); - BOOST_TEST_THROWS(bin(c.axis(), 0).lower(), std::runtime_error); - BOOST_TEST_THROWS(bin(c.axis(), 0).upper(), std::runtime_error); + BOOST_TEST_THROWS(c.axis()[0].lower(), std::runtime_error); + BOOST_TEST_THROWS(c.axis()[0].upper(), std::runtime_error); } // reduce