From fd31f06729ccd6217f0df94d2ec35235267bf76b Mon Sep 17 00:00:00 2001 From: Hans Dembinski Date: Sun, 11 Nov 2018 21:48:35 +0100 Subject: [PATCH] moved reduce_to to project, closes issue 77 --- CMakeLists.txt | 7 +- examples/guide_histogram_reduction.cpp | 18 +-- include/boost/histogram.hpp | 1 + include/boost/histogram/algorithm/project.hpp | 114 ++++++++++++++ include/boost/histogram/detail/axes.hpp | 70 +-------- .../boost/histogram/detail/index_mapper.hpp | 54 ++----- include/boost/histogram/detail/meta.hpp | 18 --- include/boost/histogram/histogram.hpp | 56 +------ include/boost/histogram/storage_adaptor.hpp | 3 +- include/boost/histogram/unsafe_access.hpp | 2 - test/algorithm_project_test.cpp | 146 ++++++++++++++++++ test/detail_test.cpp | 41 ++--- ...togram_dynamic_reduce_wrong_order_fail.cpp | 2 +- test/histogram_dynamic_test.cpp | 29 ---- test/histogram_test.cpp | 95 ------------ test/index_mapper_test.cpp | 28 +++- test/meta_test.cpp | 9 -- test/utility_meta.hpp | 9 ++ 18 files changed, 347 insertions(+), 355 deletions(-) create mode 100644 include/boost/histogram/algorithm/project.hpp create mode 100644 test/algorithm_project_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a2be937..7cdf22e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,7 @@ function(compiled_test SRC) endfunction() compiled_test(test/adaptive_storage_test.cpp) -compiled_test(test/storage_adaptor_test.cpp) +compiled_test(test/algorithm_project_test.cpp) compiled_test(test/axis_regular_test.cpp) compiled_test(test/axis_circular_test.cpp) compiled_test(test/axis_variable_test.cpp) @@ -89,9 +89,10 @@ compiled_test(test/histogram_dynamic_test.cpp) compiled_test(test/histogram_mixed_test.cpp) compiled_test(test/histogram_test.cpp) compiled_test(test/index_mapper_test.cpp) -compiled_test(test/meta_test.cpp) -compiled_test(test/utility_test.cpp) compiled_test(test/internal_accumulators_test.cpp) +compiled_test(test/meta_test.cpp) +compiled_test(test/storage_adaptor_test.cpp) +compiled_test(test/utility_test.cpp) compiled_test(examples/getting_started_listing_01.cpp) compiled_test(examples/getting_started_listing_02.cpp) diff --git a/examples/guide_histogram_reduction.cpp b/examples/guide_histogram_reduction.cpp index 97f2cc59..39440fe0 100644 --- a/examples/guide_histogram_reduction.cpp +++ b/examples/guide_histogram_reduction.cpp @@ -1,8 +1,8 @@ //[ guide_histogram_reduction #include -#include #include +#include namespace bh = boost::histogram; @@ -18,15 +18,14 @@ int main() { using namespace bh::literals; // enables _c suffix // make a 2d histogram - auto h = bh::make_histogram(bh::axis::regular<>(3, -1, 1), - bh::axis::integer<>(0, 4)); + auto h = bh::make_histogram(bh::axis::regular<>(3, -1, 1), bh::axis::integer<>(0, 4)); h(-0.9, 0); h(0.9, 3); h(0.1, 2); - auto hr0 = h.reduce_to(0_c); // keep only first axis - auto hr1 = h.reduce_to(1_c); // keep only second axis + auto hr0 = bh::algorithm::project(h, 0_c); // keep only first axis + auto hr1 = bh::algorithm::project(h, 1_c); // keep only second axis /* reduce does not remove counts; returned histograms are summed over @@ -39,11 +38,10 @@ int main() { for (auto xi : h.axis(0_c)) { os1 << h.at(xi, yi) << " "; } os1 << "\n"; } - assert(os1.str() == - "1 0 0 \n" - "0 0 0 \n" - "0 1 0 \n" - "0 0 1 \n"); + assert(os1.str() == "1 0 0 \n" + "0 0 0 \n" + "0 1 0 \n" + "0 0 1 \n"); std::ostringstream os2; for (auto xi : hr0.axis()) os2 << hr0.at(xi) << " "; diff --git a/include/boost/histogram.hpp b/include/boost/histogram.hpp index a3833cda..2d393970 100644 --- a/include/boost/histogram.hpp +++ b/include/boost/histogram.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/histogram/algorithm/project.hpp b/include/boost/histogram/algorithm/project.hpp new file mode 100644 index 00000000..db792550 --- /dev/null +++ b/include/boost/histogram/algorithm/project.hpp @@ -0,0 +1,114 @@ +// Copyright 2015-2018 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_ALGORITHM_PROJECT_HPP +#define BOOST_HISTOGRAM_ALGORITHM_PROJECT_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace histogram { +namespace algorithm { + +/// Returns a lower-dimensional histogram +// precondition: argument sequence must be strictly ascending axis indices +template +auto project(const histogram& h, mp11::mp_size_t n, Ns... ns) { + using LN = mp11::mp_list, Ns...>; + + const auto& axes = unsafe_access::axes(h); + auto r_axes = detail::make_sub_axes(axes, n, ns...); + auto r_h = histogram( + std::move(r_axes), + detail::static_if>( + [&h](auto) { return S(unsafe_access::storage(h).get_allocator()); }, + [](auto) { return S(); }, 0)); + + detail::index_mapper im(h.rank()); + auto iter = im.begin(); + std::size_t s = 1; + h.for_each_axis([&](const auto& a) { + const auto n = axis::traits::extend(a); + im.ntotal *= n; + iter->first = s; + s *= n; + iter->second = 0; + ++iter; + }); + + s = 1; + mp11::mp_for_each([&](auto J) { + im[J].second = s; + s *= axis::traits::extend(detail::axis_get(axes)); + }); + + do { + const auto x = unsafe_access::storage(h)[im.first]; + unsafe_access::storage(r_h).add(im.second, x); + } while (im.next()); + return r_h; +} + +/// Returns a lower-dimensional histogram +// precondition: sequence must be strictly ascending axis indices +template , + typename = detail::requires_iterator> +auto project(const histogram& h, Iterator begin, Iterator end) { + using H = histogram; + + BOOST_ASSERT_MSG(std::is_sorted(begin, end, std::less_equal()), + "integer sequence must be strictly ascending"); + + const auto& axes = unsafe_access::axes(h); + auto r_axes = typename H::axes_type(axes.get_allocator()); + r_axes.reserve(std::distance(begin, end)); + + detail::index_mapper im(h.rank()); + auto iter = im.begin(); + std::size_t s = 1; + h.for_each_axis([&](const auto& a) { + const auto n = axis::traits::extend(a); + im.ntotal *= n; + iter->first = s; + s *= n; + iter->second = 0; + ++iter; + }); + + s = 1; + for (auto it = begin; it != end; ++it) { + r_axes.emplace_back(axes[*it]); + im[*it].second = s; + s *= axis::traits::extend(axes[*it]); + } + + auto r_h = H(std::move(r_axes), + detail::static_if>( + [&h](auto) { return S(unsafe_access::storage(h).get_allocator()); }, + [](auto) { return S(); }, 0)); + + do { + const auto x = unsafe_access::storage(h)[im.first]; + unsafe_access::storage(r_h).add(im.second, x); + } while (im.next()); + return r_h; +} + +} // namespace algorithm +} // namespace histogram +} // namespace boost + +#endif diff --git a/include/boost/histogram/detail/axes.hpp b/include/boost/histogram/detail/axes.hpp index df043e2c..41a8254c 100644 --- a/include/boost/histogram/detail/axes.hpp +++ b/include/boost/histogram/detail/axes.hpp @@ -8,6 +8,7 @@ #define BOOST_HISTOGRAM_DETAIL_AXES_HPP #include +#include #include #include #include @@ -138,7 +139,7 @@ static std::size_t axes_size(const T& axes) noexcept { } template -void range_check(const T& axes, const unsigned N) { +void rank_check(const T& axes, const unsigned N) { BOOST_ASSERT_MSG(N < axes_size(axes), "index out of range"); } @@ -159,69 +160,14 @@ std::size_t bincount(const T& axes) { return n; } -struct shape_collector { - std::vector::iterator iter; - shape_collector(std::vector::iterator i) : iter(i) {} - template - void operator()(const T& t) { - *iter++ = axis::traits::extend(t); - } -}; - -template -struct sub_axes_impl {}; - -template -struct sub_axes_impl> { - static_assert(mp11::mp_is_set::value, - "integer arguments must be strictly ascending"); - static_assert(mp_last::value < sizeof...(Ts), "index out of range"); - template - using at = mp11::mp_at, I>; - using L = mp11::mp_rename; - using type = mp11::mp_transform; -}; - -template -struct sub_axes_impl> { - static_assert(mp11::mp_is_set::value, - "integer arguments must be strictly ascending"); - using type = std::vector; -}; - -template -using sub_axes = typename sub_axes_impl, T>::type; - -template -struct sub_static_assign_impl { - const Src& src; - Dst& dst; - template - void operator()(std::pair) const { - std::get(dst) = std::get(src); - } -}; - -template -sub_axes, Ns...> make_sub_axes(const std::tuple& t, Ns...) { - using T = std::tuple; - using U = sub_axes, Ns...>; - U u; - using N1 = mp11::mp_list; - using N2 = mp11::mp_iota>; - using N3 = mp11::mp_transform; - mp11::mp_for_each(sub_static_assign_impl{t, u}); - return u; +template +auto make_sub_axes(const std::tuple& t, Ns... ns) { + return std::make_tuple(std::get(t)...); } -template -sub_axes, Ns...> make_sub_axes(const std::vector& t, Ns...) { - using T = std::vector; - T u(t.get_allocator()); - u.reserve(sizeof...(Ns)); - using N = mp11::mp_list; - mp11::mp_for_each([&](auto I) { u.emplace_back(t[I]); }); - return u; +template +auto make_sub_axes(const std::vector& t, Ns... ns) { + return std::vector({t[ns]...}, t.get_allocator()); } /// Index with an invalid state diff --git a/include/boost/histogram/detail/index_mapper.hpp b/include/boost/histogram/detail/index_mapper.hpp index ebc9a17b..21e02914 100644 --- a/include/boost/histogram/detail/index_mapper.hpp +++ b/include/boost/histogram/detail/index_mapper.hpp @@ -7,58 +7,38 @@ #ifndef BOOST_HISTOGRAM_DETAIL_INDEX_MAPPER_HPP #define BOOST_HISTOGRAM_DETAIL_INDEX_MAPPER_HPP -#include +#include #include -#include namespace boost { namespace histogram { namespace detail { -struct index_mapper { - std::size_t first = 0, second = 0; +class index_mapper : public std::array, 32> { +public: + std::size_t first = 0, second = 0, ntotal = 1; - index_mapper(const std::vector& nvec, - const std::vector& bvec) { - dims.reserve(nvec.size()); - std::size_t s1 = 1, s2 = 1; - auto bi = bvec.begin(); - for (const auto& ni : nvec) { - if (*bi) { - dims.push_back({s1, s2}); - s2 *= ni; - } else { - dims.push_back({s1, 0}); - } - s1 *= ni; - ++bi; - } - std::sort(dims.begin(), dims.end(), [](const dim& a, const dim& b) { - return a.stride1 > b.stride1; - }); - nfirst = s1; - } + index_mapper(std::size_t n) : dims_end(begin() + n) {} bool next() { ++first; second = 0; auto f = first; - for (const auto& d : dims) { - auto i = f / d.stride1; - f -= i * d.stride1; - second += i * d.stride2; + for (auto it = end(); it != begin(); --it) { + const auto& d = *(it - 1); + auto i = f / d.first; + f -= i * d.first; + second += i * d.second; } - return first < nfirst; + return first < ntotal; } + iterator end() { return dims_end; } + private: - std::size_t nfirst; - struct dim { - std::size_t stride1, stride2; - }; - std::vector dims; + iterator dims_end; }; -} -} -} +} // namespace detail +} // namespace histogram +} // namespace boost #endif diff --git a/include/boost/histogram/detail/meta.hpp b/include/boost/histogram/detail/meta.hpp index fedb389e..125fb3f2 100644 --- a/include/boost/histogram/detail/meta.hpp +++ b/include/boost/histogram/detail/meta.hpp @@ -223,24 +223,6 @@ struct is_sample_impl> : std::true_type {}; template using is_sample = is_sample_impl>; -namespace { -struct bool_mask_impl { - std::vector& b; - bool v; - template - void operator()(Int) const { - b[Int::value] = v; - } -}; -} // namespace - -template -std::vector bool_mask(unsigned n, bool v) { - std::vector b(n, !v); - mp11::mp_for_each>(bool_mask_impl{b, v}); - return b; -} - // poor-mans concept checks template (), ++std::declval())> struct requires_iterator {}; diff --git a/include/boost/histogram/histogram.hpp b/include/boost/histogram/histogram.hpp index c6468d25..ff0ee819 100644 --- a/include/boost/histogram/histogram.hpp +++ b/include/boost/histogram/histogram.hpp @@ -103,14 +103,14 @@ public: /// Get N-th axis (const version) template decltype(auto) axis(mp11::mp_size_t) const { - detail::range_check(axes_, N); + detail::rank_check(axes_, N); return detail::axis_get(axes_); } /// Get N-th axis template decltype(auto) axis(mp11::mp_size_t) { - detail::range_check(axes_, N); + detail::rank_check(axes_, N); return detail::axis_get(axes_); } @@ -122,13 +122,13 @@ public: /// Get N-th axis with runtime index (const version) decltype(auto) axis(std::size_t i) const { - detail::range_check(axes_, i); + detail::rank_check(axes_, i); return detail::axis_get(axes_, i); } /// Get N-th axis with runtime index decltype(auto) axis(std::size_t i) { - detail::range_check(axes_, i); + detail::rank_check(axes_, i); return detail::axis_get(axes_, i); } @@ -172,54 +172,6 @@ public: return at(t); } - /// Returns a lower-dimensional histogram - // precondition: argument sequence must be strictly ascending axis indices - template - auto reduce_to(mp11::mp_size_t, Ns...) const - -> histogram, Ns...>, storage_type> { - using N = mp11::mp_size_t; - using LN = mp11::mp_list; - detail::range_check(axes_, detail::mp_last::value); - using sub_axes_type = detail::sub_axes; - using HR = histogram; - auto sub_axes = detail::make_sub_axes(axes_, N(), Ns()...); - auto hr = HR(std::move(sub_axes), - detail::static_if>( - [this](auto) { return storage_type(storage_.get_allocator()); }, - [](auto) { return storage_type(); }, 0)); - const auto b = detail::bool_mask(rank(), true); - std::vector shape(rank()); - for_each_axis(detail::shape_collector(shape.begin())); - detail::index_mapper m(shape, b); - do { hr.storage_.add(m.second, storage_[m.first]); } while (m.next()); - return hr; - } - - /// Returns a lower-dimensional histogram - // precondition: sequence must be strictly ascending axis indices - template , - typename = detail::requires_iterator> - histogram reduce_to(Iterator begin, Iterator end) const { - BOOST_ASSERT_MSG(std::is_sorted(begin, end, std::less_equal()), - "integer sequence must be strictly ascending"); - BOOST_ASSERT_MSG(begin == end || static_cast(*(end - 1)) < rank(), - "index out of range"); - auto sub_axes = histogram::axes_type(axes_.get_allocator()); - sub_axes.reserve(std::distance(begin, end)); - auto b = std::vector(rank(), false); - for (auto it = begin; it != end; ++it) { - sub_axes.push_back(axes_[*it]); - b[*it] = true; - } - auto hr = histogram(std::move(sub_axes), storage_type(storage_.get_allocator())); - std::vector shape(rank()); - for_each_axis(detail::shape_collector(shape.begin())); - detail::index_mapper m(shape, b); - do { hr.storage_.add(m.second, storage_[m.first]); } while (m.next()); - return hr; - } - auto begin() const noexcept { return const_iterator(*this, 0); } auto end() const noexcept { return const_iterator(*this, size()); } diff --git a/include/boost/histogram/storage_adaptor.hpp b/include/boost/histogram/storage_adaptor.hpp index 4c49c78e..1b4b3de3 100644 --- a/include/boost/histogram/storage_adaptor.hpp +++ b/include/boost/histogram/storage_adaptor.hpp @@ -234,15 +234,14 @@ struct storage_adaptor : detail::storage_augmentation { using element_adaptor = detail::element_adaptor; using const_reference = const value_type&; - using base_type::base_type; storage_adaptor() = default; storage_adaptor(const storage_adaptor&) = default; storage_adaptor& operator=(const storage_adaptor&) = default; storage_adaptor(storage_adaptor&&) = default; storage_adaptor& operator=(storage_adaptor&&) = default; - storage_adaptor(const T& t) : base_type(t) {} storage_adaptor(T&& t) : base_type(std::move(t)) {} + storage_adaptor(const T& t) : base_type(t) {} template > storage_adaptor(const U& rhs) { diff --git a/include/boost/histogram/unsafe_access.hpp b/include/boost/histogram/unsafe_access.hpp index a5b2dfff..4ebf3082 100644 --- a/include/boost/histogram/unsafe_access.hpp +++ b/include/boost/histogram/unsafe_access.hpp @@ -7,8 +7,6 @@ #ifndef BOOST_HISTOGRAM_UNSAFE_ACCESS_HPP #define BOOST_HISTOGRAM_UNSAFE_ACCESS_HPP -#include - namespace boost { namespace histogram { diff --git a/test/algorithm_project_test.cpp b/test/algorithm_project_test.cpp new file mode 100644 index 00000000..520f44e3 --- /dev/null +++ b/test/algorithm_project_test.cpp @@ -0,0 +1,146 @@ +// Copyright 2015-2018 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) + +#include +#include +#include +#include +#include +#include "utility_histogram.hpp" + +using namespace boost::histogram; +using namespace boost::histogram::literals; // to get _c suffix +using boost::histogram::algorithm::project; + +template +void run_tests() { + auto h1 = make(Tag(), axis::integer<>(0, 2), axis::integer<>(0, 3)); + h1(0, 0); + h1(0, 1); + h1(1, 0); + h1(1, 1); + h1(1, 2); + + /* + matrix layout: + + 0 -> + 1 1 1 0 0 + | 1 1 0 0 + v 0 1 0 0 + 0 0 0 0 + 0 0 0 0 + */ + + auto h1_0 = project(h1, 0_c); + BOOST_TEST_EQ(h1_0.rank(), 1); + BOOST_TEST_EQ(sum(h1_0), 5); + BOOST_TEST_EQ(h1_0.at(0), 2); + BOOST_TEST_EQ(h1_0.at(1), 3); + BOOST_TEST(h1_0.axis() == h1.axis(0_c)); + + auto h1_1 = project(h1, 1_c); + BOOST_TEST_EQ(h1_1.rank(), 1); + BOOST_TEST_EQ(sum(h1_1), 5); + BOOST_TEST_EQ(h1_1.at(0), 2); + BOOST_TEST_EQ(h1_1.at(1), 2); + BOOST_TEST_EQ(h1_1.at(2), 1); + BOOST_TEST(h1_1.axis() == h1.axis(1_c)); + + auto h2 = + make(Tag(), axis::integer<>(0, 2), axis::integer<>(0, 3), axis::integer<>(0, 4)); + h2(0, 0, 0); + h2(0, 1, 0); + h2(0, 1, 1); + h2(0, 0, 2); + h2(1, 0, 2); + + auto h2_0 = project(h2, 0_c); + BOOST_TEST_EQ(h2_0.rank(), 1); + BOOST_TEST_EQ(sum(h2_0), 5); + BOOST_TEST_EQ(h2_0.at(0), 4); + BOOST_TEST_EQ(h2_0.at(1), 1); + BOOST_TEST(h2_0.axis() == axis::integer<>(0, 2)); + + auto h2_1 = project(h2, 1_c); + BOOST_TEST_EQ(h2_1.rank(), 1); + BOOST_TEST_EQ(sum(h2_1), 5); + BOOST_TEST_EQ(h2_1.at(0), 3); + BOOST_TEST_EQ(h2_1.at(1), 2); + BOOST_TEST(h2_1.axis() == axis::integer<>(0, 3)); + + auto h2_2 = project(h2, 2_c); + BOOST_TEST_EQ(h2_2.rank(), 1); + BOOST_TEST_EQ(sum(h2_2), 5); + BOOST_TEST_EQ(h2_2.at(0), 2); + BOOST_TEST_EQ(h2_2.at(1), 1); + BOOST_TEST_EQ(h2_2.at(2), 2); + BOOST_TEST(h2_2.axis() == axis::integer<>(0, 4)); + + auto h2_01 = project(h2, 0_c, 1_c); + BOOST_TEST_EQ(h2_01.rank(), 2); + BOOST_TEST_EQ(sum(h2_01), 5); + BOOST_TEST_EQ(h2_01.at(0, 0), 2); + BOOST_TEST_EQ(h2_01.at(0, 1), 2); + BOOST_TEST_EQ(h2_01.at(1, 0), 1); + BOOST_TEST(h2_01.axis(0_c) == axis::integer<>(0, 2)); + BOOST_TEST(h2_01.axis(1_c) == axis::integer<>(0, 3)); + + auto h2_02 = project(h2, 0_c, 2_c); + BOOST_TEST_EQ(h2_02.rank(), 2); + BOOST_TEST_EQ(sum(h2_02), 5); + BOOST_TEST_EQ(h2_02.at(0, 0), 2); + BOOST_TEST_EQ(h2_02.at(0, 1), 1); + BOOST_TEST_EQ(h2_02.at(0, 2), 1); + BOOST_TEST_EQ(h2_02.at(1, 2), 1); + BOOST_TEST(h2_02.axis(0_c) == axis::integer<>(0, 2)); + BOOST_TEST(h2_02.axis(1_c) == axis::integer<>(0, 4)); + + auto h2_12 = project(h2, 1_c, 2_c); + BOOST_TEST_EQ(h2_12.rank(), 2); + BOOST_TEST_EQ(sum(h2_12), 5); + BOOST_TEST_EQ(h2_12.at(0, 0), 1); + BOOST_TEST_EQ(h2_12.at(1, 0), 1); + BOOST_TEST_EQ(h2_12.at(1, 1), 1); + BOOST_TEST_EQ(h2_12.at(0, 2), 2); + BOOST_TEST(h2_12.axis(0_c) == axis::integer<>(0, 3)); + BOOST_TEST(h2_12.axis(1_c) == axis::integer<>(0, 4)); +} + +int main() { + run_tests(); + run_tests(); + + { + auto h1 = make(dynamic_tag(), axis::integer<>(0, 2), axis::integer<>(0, 3)); + h1(0, 0); + h1(0, 1); + h1(1, 0); + h1(1, 1); + h1(1, 2); + + std::vector x; + + x = {0}; + auto h1_0 = project(h1, x.begin(), x.end()); + BOOST_TEST_EQ(h1_0.rank(), 1); + BOOST_TEST_EQ(sum(h1_0), 5); + BOOST_TEST_EQ(h1_0.at(0), 2); + BOOST_TEST_EQ(h1_0.at(1), 3); + BOOST_TEST(h1_0.axis() == h1.axis(0_c)); + + x = {1}; + auto h1_1 = project(h1, x.begin(), x.end()); + BOOST_TEST_EQ(h1_1.rank(), 1); + BOOST_TEST_EQ(sum(h1_1), 5); + BOOST_TEST_EQ(h1_1.at(0), 2); + BOOST_TEST_EQ(h1_1.at(1), 2); + BOOST_TEST_EQ(h1_1.at(2), 1); + BOOST_TEST(h1_1.axis() == h1.axis(1_c)); + } + + return boost::report_errors(); +} diff --git a/test/detail_test.cpp b/test/detail_test.cpp index 6f45ed3a..c554fec1 100644 --- a/test/detail_test.cpp +++ b/test/detail_test.cpp @@ -93,36 +93,19 @@ int main() { BOOST_TEST(detail::axes_equal(tuple2, tuple1)); } - // sub_axes + // make_sub_axes { - using ra = axis::regular<>; - using ia = axis::integer<>; - using ca = axis::category<>; - using T = std::tuple; - BOOST_TEST_TRAIT_TRUE((std::is_same, std::tuple>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, std::tuple>)); - BOOST_TEST_TRAIT_TRUE((std::is_same, std::tuple>)); - BOOST_TEST_TRAIT_TRUE( - (std::is_same, std::tuple>)); - BOOST_TEST_TRAIT_TRUE( - (std::is_same, std::tuple>)); - BOOST_TEST_TRAIT_TRUE( - (std::is_same, std::tuple>)); - BOOST_TEST_TRAIT_TRUE( - (std::is_same, std::tuple>)); - } - - // make_sub_tuple - { - using ia = axis::integer<>; - using T = std::tuple; - auto axes = T(ia(0, 1), ia(1, 2), ia(2, 3)); - BOOST_TEST_EQ(detail::make_sub_axes(axes, i1(), i2()), - (std::tuple(ia(1, 2), ia(2, 3)))); - BOOST_TEST_EQ(detail::make_sub_axes(axes, i0(), i1()), - (std::tuple(ia(0, 1), ia(1, 2)))); - BOOST_TEST_EQ(detail::make_sub_axes(axes, i1()), (std::tuple(ia(1, 2)))); - BOOST_TEST_EQ(detail::make_sub_axes(axes, i0(), i1(), i2()), axes); + using boost::mp11::mp_list; + axis::integer<> a0(0, 1), a1(1, 2), a2(2, 3); + auto axes = std::make_tuple(a0, a1, a2); + BOOST_TEST_EQ(detail::make_sub_axes(axes, i0()), std::make_tuple(a0)); + BOOST_TEST_EQ(detail::make_sub_axes(axes, i1()), std::make_tuple(a1)); + BOOST_TEST_EQ(detail::make_sub_axes(axes, i2()), std::make_tuple(a2)); + BOOST_TEST_EQ(detail::make_sub_axes(axes, i0(), i1()), std::make_tuple(a0, a1)); + BOOST_TEST_EQ(detail::make_sub_axes(axes, i0(), i2()), std::make_tuple(a0, a2)); + BOOST_TEST_EQ(detail::make_sub_axes(axes, i1(), i2()), std::make_tuple(a1, a2)); + BOOST_TEST_EQ(detail::make_sub_axes(axes, i0(), i1(), i2()), + std::make_tuple(a0, a1, a2)); } return boost::report_errors(); diff --git a/test/histogram_dynamic_reduce_wrong_order_fail.cpp b/test/histogram_dynamic_reduce_wrong_order_fail.cpp index 1a180cea..85ea83c6 100644 --- a/test/histogram_dynamic_reduce_wrong_order_fail.cpp +++ b/test/histogram_dynamic_reduce_wrong_order_fail.cpp @@ -14,5 +14,5 @@ int main() { a.push_back(axis::integer<>(1, 2)); auto h = make_histogram(a); auto v = {0, 0}; - h.reduce_to(v.begin(), v.end()); + algorithm::project(h, v.begin(), v.end()); } diff --git a/test/histogram_dynamic_test.cpp b/test/histogram_dynamic_test.cpp index f383f817..9000c2b2 100644 --- a/test/histogram_dynamic_test.cpp +++ b/test/histogram_dynamic_test.cpp @@ -62,35 +62,6 @@ int main() { BOOST_TEST_THROWS(c.axis().value(0), std::runtime_error); } - // reduce - { - auto h1 = make(dynamic_tag(), axis::integer<>(0, 2), axis::integer<>(0, 3)); - h1(0, 0); - h1(0, 1); - h1(1, 0); - h1(1, 1); - h1(1, 2); - - std::vector x; - - x = {0}; - auto h1_0 = h1.reduce_to(x.begin(), x.end()); - BOOST_TEST_EQ(h1_0.rank(), 1); - BOOST_TEST_EQ(sum(h1_0), 5); - BOOST_TEST_EQ(h1_0.at(0), 2); - BOOST_TEST_EQ(h1_0.at(1), 3); - BOOST_TEST(h1_0.axis() == h1.axis(0_c)); - - x = {1}; - auto h1_1 = h1.reduce_to(x.begin(), x.end()); - BOOST_TEST_EQ(h1_1.rank(), 1); - BOOST_TEST_EQ(sum(h1_1), 5); - BOOST_TEST_EQ(h1_1.at(0), 2); - BOOST_TEST_EQ(h1_1.at(1), 2); - BOOST_TEST_EQ(h1_1.at(2), 1); - BOOST_TEST(h1_1.axis() == h1.axis(1_c)); - } - // wrong dimension { auto h1 = make(dynamic_tag(), axis::integer<>(0, 2)); diff --git a/test/histogram_test.cpp b/test/histogram_test.cpp index 2474e395..84fe615c 100644 --- a/test/histogram_test.cpp +++ b/test/histogram_test.cpp @@ -569,101 +569,6 @@ void run_tests() { BOOST_TEST_EQ(sum(h), 0); } - // reduce - { - auto h1 = make(Tag(), axis::integer<>(0, 2), axis::integer<>(0, 3)); - h1(0, 0); - h1(0, 1); - h1(1, 0); - h1(1, 1); - h1(1, 2); - - /* - matrix layout: - - 0 -> - 1 1 1 0 0 - | 1 1 0 0 - v 0 1 0 0 - 0 0 0 0 - 0 0 0 0 - */ - - auto h1_0 = h1.reduce_to(0_c); - BOOST_TEST_EQ(h1_0.rank(), 1); - BOOST_TEST_EQ(sum(h1_0), 5); - BOOST_TEST_EQ(h1_0.at(0), 2); - BOOST_TEST_EQ(h1_0.at(1), 3); - BOOST_TEST(h1_0.axis() == h1.axis(0_c)); - - auto h1_1 = h1.reduce_to(1_c); - BOOST_TEST_EQ(h1_1.rank(), 1); - BOOST_TEST_EQ(sum(h1_1), 5); - BOOST_TEST_EQ(h1_1.at(0), 2); - BOOST_TEST_EQ(h1_1.at(1), 2); - BOOST_TEST_EQ(h1_1.at(2), 1); - BOOST_TEST(h1_1.axis() == h1.axis(1_c)); - - auto h2 = - make(Tag(), axis::integer<>(0, 2), axis::integer<>(0, 3), axis::integer<>(0, 4)); - h2(0, 0, 0); - h2(0, 1, 0); - h2(0, 1, 1); - h2(0, 0, 2); - h2(1, 0, 2); - - auto h2_0 = h2.reduce_to(0_c); - BOOST_TEST_EQ(h2_0.rank(), 1); - BOOST_TEST_EQ(sum(h2_0), 5); - BOOST_TEST_EQ(h2_0.at(0), 4); - BOOST_TEST_EQ(h2_0.at(1), 1); - BOOST_TEST(h2_0.axis() == axis::integer<>(0, 2)); - - auto h2_1 = h2.reduce_to(1_c); - BOOST_TEST_EQ(h2_1.rank(), 1); - BOOST_TEST_EQ(sum(h2_1), 5); - BOOST_TEST_EQ(h2_1.at(0), 3); - BOOST_TEST_EQ(h2_1.at(1), 2); - BOOST_TEST(h2_1.axis() == axis::integer<>(0, 3)); - - auto h2_2 = h2.reduce_to(2_c); - BOOST_TEST_EQ(h2_2.rank(), 1); - BOOST_TEST_EQ(sum(h2_2), 5); - BOOST_TEST_EQ(h2_2.at(0), 2); - BOOST_TEST_EQ(h2_2.at(1), 1); - BOOST_TEST_EQ(h2_2.at(2), 2); - BOOST_TEST(h2_2.axis() == axis::integer<>(0, 4)); - - auto h2_01 = h2.reduce_to(0_c, 1_c); - BOOST_TEST_EQ(h2_01.rank(), 2); - BOOST_TEST_EQ(sum(h2_01), 5); - BOOST_TEST_EQ(h2_01.at(0, 0), 2); - BOOST_TEST_EQ(h2_01.at(0, 1), 2); - BOOST_TEST_EQ(h2_01.at(1, 0), 1); - BOOST_TEST(h2_01.axis(0_c) == axis::integer<>(0, 2)); - BOOST_TEST(h2_01.axis(1_c) == axis::integer<>(0, 3)); - - auto h2_02 = h2.reduce_to(0_c, 2_c); - BOOST_TEST_EQ(h2_02.rank(), 2); - BOOST_TEST_EQ(sum(h2_02), 5); - BOOST_TEST_EQ(h2_02.at(0, 0), 2); - BOOST_TEST_EQ(h2_02.at(0, 1), 1); - BOOST_TEST_EQ(h2_02.at(0, 2), 1); - BOOST_TEST_EQ(h2_02.at(1, 2), 1); - BOOST_TEST(h2_02.axis(0_c) == axis::integer<>(0, 2)); - BOOST_TEST(h2_02.axis(1_c) == axis::integer<>(0, 4)); - - auto h2_12 = h2.reduce_to(1_c, 2_c); - BOOST_TEST_EQ(h2_12.rank(), 2); - BOOST_TEST_EQ(sum(h2_12), 5); - BOOST_TEST_EQ(h2_12.at(0, 0), 1); - BOOST_TEST_EQ(h2_12.at(1, 0), 1); - BOOST_TEST_EQ(h2_12.at(1, 1), 1); - BOOST_TEST_EQ(h2_12.at(0, 2), 2); - BOOST_TEST(h2_12.axis(0_c) == axis::integer<>(0, 3)); - BOOST_TEST(h2_12.axis(1_c) == axis::integer<>(0, 4)); - } - // custom axes { struct modified_axis : public axis::integer<> { diff --git a/test/index_mapper_test.cpp b/test/index_mapper_test.cpp index 333ab8b2..bc591602 100644 --- a/test/index_mapper_test.cpp +++ b/test/index_mapper_test.cpp @@ -14,9 +14,11 @@ using namespace boost::histogram::detail; int main() { // index_mapper 1 { - std::vector n{{2, 2}}; - std::vector b{{true, false}}; - index_mapper m(std::move(n), std::move(b)); + // shape: 2, 3; 2, 0 + index_mapper m(2); + m[0] = std::make_pair(1, 1); + m[1] = std::make_pair(2, 0); + m.ntotal = 6; BOOST_TEST_EQ(m.first, 0); BOOST_TEST_EQ(m.second, 0); BOOST_TEST_EQ(m.next(), true); @@ -28,14 +30,22 @@ int main() { BOOST_TEST_EQ(m.next(), true); BOOST_TEST_EQ(m.first, 3); BOOST_TEST_EQ(m.second, 1); + BOOST_TEST_EQ(m.next(), true); + BOOST_TEST_EQ(m.first, 4); + BOOST_TEST_EQ(m.second, 0); + BOOST_TEST_EQ(m.next(), true); + BOOST_TEST_EQ(m.first, 5); + BOOST_TEST_EQ(m.second, 1); BOOST_TEST_EQ(m.next(), false); } // index_mapper 2 { - std::vector n{{2, 2}}; - std::vector b{{false, true}}; - index_mapper m(std::move(n), std::move(b)); + // shape: 2, 3; 0, 3 + index_mapper m(2); + m[0] = std::make_pair(1, 0); + m[1] = std::make_pair(2, 1); + m.ntotal = 6; BOOST_TEST_EQ(m.first, 0); BOOST_TEST_EQ(m.second, 0); BOOST_TEST_EQ(m.next(), true); @@ -47,6 +57,12 @@ int main() { BOOST_TEST_EQ(m.next(), true); BOOST_TEST_EQ(m.first, 3); BOOST_TEST_EQ(m.second, 1); + BOOST_TEST_EQ(m.next(), true); + BOOST_TEST_EQ(m.first, 4); + BOOST_TEST_EQ(m.second, 2); + BOOST_TEST_EQ(m.next(), true); + BOOST_TEST_EQ(m.first, 5); + BOOST_TEST_EQ(m.second, 2); BOOST_TEST_EQ(m.next(), false); } diff --git a/test/meta_test.cpp b/test/meta_test.cpp index 18f1ba38..8a498633 100644 --- a/test/meta_test.cpp +++ b/test/meta_test.cpp @@ -274,15 +274,6 @@ int main() { BOOST_TEST_TRAIT_TRUE((is_axis_variant>>)); } - // bool mask - { - auto v1 = bool_mask(4, false); - BOOST_TEST_EQ(v1, std::vector({true, false, false, true})); - - auto v2 = bool_mask(4, true); - BOOST_TEST_EQ(v2, std::vector({false, true, false, true})); - } - // unqual { using T1 = int; diff --git a/test/utility_meta.hpp b/test/utility_meta.hpp index 713f7123..ced84b69 100644 --- a/test/utility_meta.hpp +++ b/test/utility_meta.hpp @@ -7,6 +7,7 @@ #ifndef BOOST_HISTOGRAM_TEST_UTILITY_META_HPP #define BOOST_HISTOGRAM_TEST_UTILITY_META_HPP +#include #include #include #include @@ -37,6 +38,14 @@ ostream& operator<<(ostream& os, const tuple& t) { os << "]"; return os; } + +template +ostream& operator<<(ostream& os, const array& v) { + os << "[ "; + for (const auto& x : v) os << x << " "; + os << "]"; + return os; +} } // namespace std namespace boost {