From 7e23f3da7bc140809e59d4dc1132c50a21dc7a46 Mon Sep 17 00:00:00 2001 From: Hans Dembinski Date: Mon, 12 Nov 2018 21:56:58 +0100 Subject: [PATCH] lifted condition that indices must be rising --- CMakeLists.txt | 1 - include/boost/histogram/algorithm/project.hpp | 8 +- .../boost/histogram/detail/index_mapper.hpp | 6 +- test/algorithm_project_test.cpp | 234 ++++++++++-------- ...togram_dynamic_reduce_wrong_order_fail.cpp | 18 -- 5 files changed, 141 insertions(+), 126 deletions(-) delete mode 100644 test/histogram_dynamic_reduce_wrong_order_fail.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7cdf22e0..42189a03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,7 +84,6 @@ compiled_test(test/axis_integer_test.cpp) compiled_test(test/axis_category_test.cpp) compiled_test(test/axis_variant_test.cpp) compiled_test(test/detail_test.cpp) -compiled_test(test/histogram_dynamic_reduce_wrong_order_fail.cpp) compiled_test(test/histogram_dynamic_test.cpp) compiled_test(test/histogram_mixed_test.cpp) compiled_test(test/histogram_test.cpp) diff --git a/include/boost/histogram/algorithm/project.hpp b/include/boost/histogram/algorithm/project.hpp index db792550..14b0461b 100644 --- a/include/boost/histogram/algorithm/project.hpp +++ b/include/boost/histogram/algorithm/project.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -23,9 +24,9 @@ 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) { + // TODO: check that n's are unique using LN = mp11::mp_list, Ns...>; const auto& axes = unsafe_access::axes(h); @@ -62,16 +63,13 @@ auto project(const histogram& h, mp11::mp_size_t n, Ns... ns) { } /// 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) { + // TODO: check that n's are unique 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)); diff --git a/include/boost/histogram/detail/index_mapper.hpp b/include/boost/histogram/detail/index_mapper.hpp index 21e02914..a3fcb179 100644 --- a/include/boost/histogram/detail/index_mapper.hpp +++ b/include/boost/histogram/detail/index_mapper.hpp @@ -25,9 +25,9 @@ public: auto f = first; 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; + // compiler usually optimizes div & mod into one div + second += f / d.first * d.second; + f %= d.first; } return first < ntotal; } diff --git a/test/algorithm_project_test.cpp b/test/algorithm_project_test.cpp index 520f44e3..2547ffa2 100644 --- a/test/algorithm_project_test.cpp +++ b/test/algorithm_project_test.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include "utility_histogram.hpp" @@ -17,97 +18,119 @@ 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); + { + auto h = make(Tag(), axis::integer<>(0, 2), axis::integer<>(0, 3)); + h(0, 0); + h(0, 1); + h(1, 0); + h(1, 1); + h(1, 2); + h(1, 2); - /* - matrix layout: + /* + 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 - */ + x -> + y 1 1 + | 1 1 + v 0 2 + */ - 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 hx = project(h, 0_c); + BOOST_TEST_EQ(hx.rank(), 1); + BOOST_TEST_EQ(sum(hx), 6); + BOOST_TEST_EQ(hx.axis(), h.axis(0_c)); + BOOST_TEST_EQ(hx.at(0), 2); + BOOST_TEST_EQ(hx.at(1), 4); - 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 hy = project(h, 1_c); + BOOST_TEST_EQ(hy.rank(), 1); + BOOST_TEST_EQ(sum(hy), 6); + BOOST_TEST_EQ(hy.axis(), h.axis(1_c)); + BOOST_TEST_EQ(hy.at(0), 2); + BOOST_TEST_EQ(hy.at(1), 2); + BOOST_TEST_EQ(hy.at(2), 2); - 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 hyx = project(h, 1_c, 0_c); + BOOST_TEST_EQ(hyx.rank(), 2); + BOOST_TEST_EQ(sum(hyx), 6); + BOOST_TEST_EQ(hyx.axis(0_c), h.axis(1_c)); + BOOST_TEST_EQ(hyx.axis(1_c), h.axis(0_c)); + BOOST_TEST_EQ(hyx.at(0, 0), 1); + BOOST_TEST_EQ(hyx.at(1, 0), 1); + BOOST_TEST_EQ(hyx.at(2, 0), 0); + BOOST_TEST_EQ(hyx.at(0, 1), 1); + BOOST_TEST_EQ(hyx.at(1, 1), 1); + BOOST_TEST_EQ(hyx.at(2, 1), 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 h = + make(Tag(), axis::integer<>(0, 2), axis::integer<>(0, 3), axis::integer<>(0, 4)); + h(0, 0, 0); + h(0, 1, 0); + h(0, 1, 1); + h(0, 0, 2); + h(1, 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 h_0 = project(h, 0_c); + BOOST_TEST_EQ(h_0.rank(), 1); + BOOST_TEST_EQ(sum(h_0), 5); + BOOST_TEST_EQ(h_0.at(0), 4); + BOOST_TEST_EQ(h_0.at(1), 1); + BOOST_TEST_EQ(h_0.axis(), axis::integer<>(0, 2)); - 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 h_1 = project(h, 1_c); + BOOST_TEST_EQ(h_1.rank(), 1); + BOOST_TEST_EQ(sum(h_1), 5); + BOOST_TEST_EQ(h_1.at(0), 3); + BOOST_TEST_EQ(h_1.at(1), 2); + BOOST_TEST_EQ(h_1.axis(), axis::integer<>(0, 3)); - 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 h_2 = project(h, 2_c); + BOOST_TEST_EQ(h_2.rank(), 1); + BOOST_TEST_EQ(sum(h_2), 5); + BOOST_TEST_EQ(h_2.at(0), 2); + BOOST_TEST_EQ(h_2.at(1), 1); + BOOST_TEST_EQ(h_2.at(2), 2); + BOOST_TEST_EQ(h_2.axis(), axis::integer<>(0, 4)); - 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 h_01 = project(h, 0_c, 1_c); + BOOST_TEST_EQ(h_01.rank(), 2); + BOOST_TEST_EQ(sum(h_01), 5); + BOOST_TEST_EQ(h_01.at(0, 0), 2); + BOOST_TEST_EQ(h_01.at(0, 1), 2); + BOOST_TEST_EQ(h_01.at(1, 0), 1); + BOOST_TEST_EQ(h_01.axis(0_c), axis::integer<>(0, 2)); + BOOST_TEST_EQ(h_01.axis(1_c), axis::integer<>(0, 3)); - 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)); + auto h_02 = project(h, 0_c, 2_c); + BOOST_TEST_EQ(h_02.rank(), 2); + BOOST_TEST_EQ(sum(h_02), 5); + BOOST_TEST_EQ(h_02.at(0, 0), 2); + BOOST_TEST_EQ(h_02.at(0, 1), 1); + BOOST_TEST_EQ(h_02.at(0, 2), 1); + BOOST_TEST_EQ(h_02.at(1, 2), 1); + BOOST_TEST_EQ(h_02.axis(0_c), axis::integer<>(0, 2)); + BOOST_TEST_EQ(h_02.axis(1_c), axis::integer<>(0, 4)); + + auto h_12 = project(h, 1_c, 2_c); + BOOST_TEST_EQ(h_12.rank(), 2); + BOOST_TEST_EQ(sum(h_12), 5); + BOOST_TEST_EQ(h_12.at(0, 0), 1); + BOOST_TEST_EQ(h_12.at(1, 0), 1); + BOOST_TEST_EQ(h_12.at(1, 1), 1); + BOOST_TEST_EQ(h_12.at(0, 2), 2); + BOOST_TEST_EQ(h_12.axis(0_c), axis::integer<>(0, 3)); + BOOST_TEST_EQ(h_12.axis(1_c), axis::integer<>(0, 4)); + + auto h_210 = project(h, 2_c, 1_c, 0_c); + BOOST_TEST_EQ(h_210.at(0, 0, 0), 1); + BOOST_TEST_EQ(h_210.at(0, 1, 0), 1); + BOOST_TEST_EQ(h_210.at(1, 1, 0), 1); + BOOST_TEST_EQ(h_210.at(2, 0, 0), 1); + BOOST_TEST_EQ(h_210.at(2, 0, 1), 1); + } } int main() { @@ -115,31 +138,44 @@ int main() { 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); + auto h = make(dynamic_tag(), axis::integer<>(0, 2), axis::integer<>(0, 3)); + h(0, 0); + h(0, 1); + h(1, 0); + h(1, 1); + h(1, 2); + h(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)); + auto hx = project(h, x.begin(), x.end()); + BOOST_TEST_EQ(hx.rank(), 1); + BOOST_TEST_EQ(sum(hx), 6); + BOOST_TEST_EQ(hx.at(0), 2); + BOOST_TEST_EQ(hx.at(1), 4); + BOOST_TEST(hx.axis() == h.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)); + auto hy = project(h, x.begin(), x.end()); + BOOST_TEST_EQ(hy.rank(), 1); + BOOST_TEST_EQ(sum(hy), 6); + BOOST_TEST_EQ(hy.at(0), 2); + BOOST_TEST_EQ(hy.at(1), 2); + BOOST_TEST_EQ(hy.at(2), 2); + BOOST_TEST(hy.axis() == h.axis(1_c)); + + x = {1, 0}; + auto hyx = project(h, x.begin(), x.end()); + BOOST_TEST_EQ(hyx.rank(), 2); + BOOST_TEST_EQ(hyx.axis(0_c), h.axis(1_c)); + BOOST_TEST_EQ(hyx.axis(1_c), h.axis(0_c)); + BOOST_TEST_EQ(sum(hyx), 6); + BOOST_TEST_EQ(hyx.at(0, 0), 1); + BOOST_TEST_EQ(hyx.at(1, 0), 1); + BOOST_TEST_EQ(hyx.at(0, 1), 1); + BOOST_TEST_EQ(hyx.at(1, 1), 1); + BOOST_TEST_EQ(hyx.at(2, 1), 2); } return boost::report_errors(); diff --git a/test/histogram_dynamic_reduce_wrong_order_fail.cpp b/test/histogram_dynamic_reduce_wrong_order_fail.cpp deleted file mode 100644 index 85ea83c6..00000000 --- a/test/histogram_dynamic_reduce_wrong_order_fail.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 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 - -using namespace boost::histogram; -int main() { - auto a = std::vector>>(); - a.push_back(axis::integer<>(0, 1)); - a.push_back(axis::integer<>(1, 2)); - auto h = make_histogram(a); - auto v = {0, 0}; - algorithm::project(h, v.begin(), v.end()); -}