diff --git a/histogram.sublime-project b/histogram.sublime-project index 764eccd4..d07b9a25 100644 --- a/histogram.sublime-project +++ b/histogram.sublime-project @@ -10,10 +10,10 @@ { "ClangFormat": { - "style": "File", + "style": "File", "format_on_save": true }, - "trim_trailing_white_space_on_save": false, + "trim_trailing_white_space_on_save": true, "ensure_newline_at_eof_on_save": false, }, "build_systems": diff --git a/include/boost/histogram/algorithm/project.hpp b/include/boost/histogram/algorithm/project.hpp index db436d2d..532392b8 100644 --- a/include/boost/histogram/algorithm/project.hpp +++ b/include/boost/histogram/algorithm/project.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -22,11 +23,19 @@ namespace boost { namespace histogram { namespace algorithm { -/// Returns a lower-dimensional histogram +// TODO: make generic reduce, which can sum over axes, shrink, rebin + +/** + Returns a lower-dimensional histogram, summing over removed axes. + + Arguments are the source histogram and compile-time numbers, representing the indices of + axes that are kept. Returns a new histogram which only contains the subset of axes. + The source histogram is summed over the removed axes. +*/ 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...>; + static_assert(mp11::mp_is_set::value, "indices must be unique"); const auto& axes = unsafe_access::axes(h); auto r_axes = detail::make_sub_axes(axes, n, ns...); @@ -61,12 +70,16 @@ auto project(const histogram& h, mp11::mp_size_t n, Ns... ns) { return r_h; } -/// Returns a lower-dimensional histogram +/** + Returns a lower-dimensional histogram, summing over removed axes. + + This version accepts an iterator range that represents the indices which are kept. +*/ template , typename = detail::requires_iterator> auto project(const histogram& h, Iterator begin, Iterator end) { - // TODO: check that n's are unique + BOOST_ASSERT_MSG(detail::is_set(begin, end), "indices must be unique"); using H = histogram; const auto& axes = unsafe_access::axes(h); diff --git a/include/boost/histogram/detail/index_mapper.hpp b/include/boost/histogram/detail/index_mapper.hpp index a3fcb179..05752cc5 100644 --- a/include/boost/histogram/detail/index_mapper.hpp +++ b/include/boost/histogram/detail/index_mapper.hpp @@ -7,17 +7,20 @@ #ifndef BOOST_HISTOGRAM_DETAIL_INDEX_MAPPER_HPP #define BOOST_HISTOGRAM_DETAIL_INDEX_MAPPER_HPP -#include +#include +#include #include namespace boost { namespace histogram { namespace detail { -class index_mapper : public std::array, 32> { +class index_mapper + : public boost::container::static_vector, + axis::limit> { public: std::size_t first = 0, second = 0, ntotal = 1; - index_mapper(std::size_t n) : dims_end(begin() + n) {} + using static_vector, axis::limit>::static_vector; bool next() { ++first; @@ -31,11 +34,6 @@ public: } return first < ntotal; } - - iterator end() { return dims_end; } - -private: - iterator dims_end; }; } // namespace detail } // namespace histogram diff --git a/include/boost/histogram/detail/is_set.hpp b/include/boost/histogram/detail/is_set.hpp new file mode 100644 index 00000000..182b8b15 --- /dev/null +++ b/include/boost/histogram/detail/is_set.hpp @@ -0,0 +1,30 @@ +// 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) + +#ifndef BOOST_HISTOGRAM_DETAIL_IS_SET_HPP +#define BOOST_HISTOGRAM_DETAIL_IS_SET_HPP + +#include +#include +#include +#include + +namespace boost { +namespace histogram { +namespace detail { +template +bool is_set(Iterator begin, Iterator end) { + using T = iterator_value_type; + boost::container::static_vector v(begin, end); + std::sort(v.begin(), v.end()); + auto end2 = std::unique(v.begin(), v.end()); + return static_cast(std::distance(v.begin(), end2)) == v.size(); +} +} // namespace detail +} // namespace histogram +} // namespace boost + +#endif diff --git a/include/boost/histogram/histogram_fwd.hpp b/include/boost/histogram/histogram_fwd.hpp index e2f969ca..2c0cb72c 100644 --- a/include/boost/histogram/histogram_fwd.hpp +++ b/include/boost/histogram/histogram_fwd.hpp @@ -7,12 +7,23 @@ #ifndef BOOST_HISTOGRAM_HISTOGRAM_FWD_HPP #define BOOST_HISTOGRAM_HISTOGRAM_FWD_HPP +#include #include namespace boost { namespace histogram { namespace axis { +/* Most of the histogram code is generic and works for any number of axes. Buffers with a + * fixed maximum capacity are used in some places, which have a size equal to the rank of + * a histogram. The buffers are statically allocated to improve performance, which means + * that they need a preset maximum capacity. 48 seems like a safe upper limit for the rank + * (you can nevertheless increase it here if necessary): the simplest non-trivial axis has + * 2 bins; even if counters are used which need only a byte of storage per bin, this still + * corresponds to 256 TB of storage. + */ +BOOST_ATTRIBUTE_UNUSED static constexpr unsigned limit = 48; + struct null_type {}; /// empty meta data type enum class option_type { diff --git a/include/boost/histogram/storage_adaptor.hpp b/include/boost/histogram/storage_adaptor.hpp index 983aa032..86768cf3 100644 --- a/include/boost/histogram/storage_adaptor.hpp +++ b/include/boost/histogram/storage_adaptor.hpp @@ -282,7 +282,7 @@ struct storage_adaptor : detail::storage_augmentation { storage_adaptor& operator/=(const double x) { return operator*=(1.0 / x); } - template > + template bool operator==(const U& u) const { const auto n = this->size(); if (n != u.size()) return false;