mirror of
https://github.com/boostorg/histogram.git
synced 2025-05-11 13:14:06 +00:00
added density method to indexed proxy, hide details of axes_buffer
This commit is contained in:
parent
31c762b359
commit
a4fe842b4a
@ -39,7 +39,7 @@ auto project(const histogram<A, S>& h, mp11::mp_size_t<I> n, Ns... ns) {
|
||||
[&h](auto) { return S(unsafe_access::storage(h).get_allocator()); },
|
||||
[](auto) { return S(); }, 0));
|
||||
|
||||
detail::index_mapper im(h.rank());
|
||||
detail::index_mapper<A> im(h.rank());
|
||||
auto iter = im.begin();
|
||||
std::size_t s = 1;
|
||||
h.for_each_axis([&](const auto& a) {
|
||||
@ -87,7 +87,7 @@ auto project(const histogram<A, S>& h, C c) {
|
||||
axes);
|
||||
r_axes.reserve(std::distance(begin, end));
|
||||
|
||||
detail::index_mapper im(h.rank());
|
||||
detail::index_mapper<A> im(h.rank());
|
||||
auto iter = im.begin();
|
||||
std::size_t stride = 1;
|
||||
h.for_each_axis([&](const auto& a) {
|
||||
|
@ -8,7 +8,6 @@
|
||||
#define BOOST_HISTOGRAM_ALGORITHM_REDUCE_HPP
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
#include <boost/histogram/detail/axes.hpp>
|
||||
#include <boost/histogram/detail/index_mapper.hpp>
|
||||
#include <boost/histogram/detail/meta.hpp>
|
||||
@ -66,8 +65,7 @@ reduce_option_type rebin(unsigned merge) { return rebin(0, merge); }
|
||||
|
||||
template <typename A, typename S, typename C, typename = detail::requires_iterable<C>>
|
||||
histogram<A, S> reduce(const histogram<A, S>& h, const C& c) {
|
||||
auto options =
|
||||
boost::container::static_vector<reduce_option_type, axis::limit>(h.rank());
|
||||
auto options = detail::axes_buffer<A, reduce_option_type>(h.rank());
|
||||
for (const auto& o : c) {
|
||||
auto& opt_ref = options[o.iaxis];
|
||||
if (opt_ref) throw std::invalid_argument("indices must be unique");
|
||||
@ -78,7 +76,7 @@ histogram<A, S> reduce(const histogram<A, S>& h, const C& c) {
|
||||
|
||||
auto r_axes = detail::make_empty_axes(unsafe_access::axes(h));
|
||||
|
||||
detail::index_mapper_reduce im(h.rank());
|
||||
detail::index_mapper_reduce<A> im(h.rank());
|
||||
auto im_iter = im.begin();
|
||||
std::size_t stride[2] = {1, 1};
|
||||
unsigned iaxis = 0;
|
||||
|
@ -61,6 +61,19 @@ unsigned extend(const T& t) noexcept {
|
||||
return t.size() + (opt & option_type::underflow) + (opt & option_type::overflow);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
double width(const T& t, unsigned idx) {
|
||||
return detail::static_if<detail::has_method_value<detail::unqual<T>, double>>(
|
||||
[&](const auto& a) {
|
||||
using Arg = detail::unqual<detail::arg_type<detail::unqual<decltype(a)>>>;
|
||||
return detail::static_if<std::is_integral<Arg>>(
|
||||
[&](const auto&) -> double { return 1; },
|
||||
[&](const auto& a) -> double { return a.value(idx + 1) - a.value(idx); }, a);
|
||||
},
|
||||
[](const auto&) -> double { throw std::runtime_error("axis has no value method"); },
|
||||
t);
|
||||
}
|
||||
|
||||
} // namespace traits
|
||||
} // namespace axis
|
||||
} // namespace histogram
|
||||
|
@ -20,6 +20,18 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
/* 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. 32 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 4 GB of storage.
|
||||
*/
|
||||
#ifndef BOOST_HISTOGRAM_DETAIL_AXES_LIMIT
|
||||
#define BOOST_HISTOGRAM_DETAIL_AXES_LIMIT 32
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
@ -151,10 +163,11 @@ void for_each_axis(const T& axes, F&& f) {
|
||||
for (const auto& x : axes) { axis::visit(std::forward<F>(f), x); }
|
||||
}
|
||||
|
||||
template <typename T, typename A>
|
||||
using make_axes_buffer = boost::container::static_vector<
|
||||
T, mp11::mp_eval_if_c<!(has_fixed_size<A>::value), mp11::mp_size_t<axis::limit>,
|
||||
std::tuple_size, A>::value>;
|
||||
template <typename Axes, typename T>
|
||||
using axes_buffer = boost::container::static_vector<
|
||||
T, mp11::mp_eval_if_c<!(has_fixed_size<Axes>::value),
|
||||
mp11::mp_size_t<BOOST_HISTOGRAM_DETAIL_AXES_LIMIT>,
|
||||
std::tuple_size, Axes>::value>;
|
||||
|
||||
template <typename T>
|
||||
auto make_empty_axes(const T& t) {
|
||||
|
@ -16,16 +16,14 @@ namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
struct index_mapper_item {
|
||||
std::size_t stride[2];
|
||||
};
|
||||
template <typename A>
|
||||
struct index_mapper {
|
||||
struct item {
|
||||
std::size_t stride[2];
|
||||
};
|
||||
using buffer_type = axes_buffer<A, item>;
|
||||
|
||||
class index_mapper
|
||||
: public boost::container::static_vector<index_mapper_item, axis::limit> {
|
||||
public:
|
||||
std::size_t total = 1;
|
||||
|
||||
index_mapper(unsigned dim) : static_vector(dim) {}
|
||||
index_mapper(unsigned dim) : buffer(dim) {}
|
||||
|
||||
template <typename T, typename U>
|
||||
void operator()(T& dst, const U& src) {
|
||||
@ -42,19 +40,26 @@ public:
|
||||
dst.add(j, src[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct index_mapper_reduce_item {
|
||||
std::size_t stride[2];
|
||||
int underflow[2], overflow[2], begin, end, merge;
|
||||
};
|
||||
decltype(auto) begin() { return buffer.begin(); }
|
||||
decltype(auto) end() { return buffer.end(); }
|
||||
|
||||
class index_mapper_reduce
|
||||
: public boost::container::static_vector<index_mapper_reduce_item, axis::limit> {
|
||||
public:
|
||||
decltype(auto) operator[](unsigned i) { return buffer[i]; }
|
||||
|
||||
buffer_type buffer;
|
||||
std::size_t total = 1;
|
||||
};
|
||||
|
||||
index_mapper_reduce(unsigned dim) : static_vector(dim) {}
|
||||
template <typename A>
|
||||
class index_mapper_reduce {
|
||||
public:
|
||||
struct item {
|
||||
std::size_t stride[2];
|
||||
int underflow[2], overflow[2], begin, end, merge;
|
||||
};
|
||||
using buffer_type = axes_buffer<A, item>;
|
||||
|
||||
index_mapper_reduce(unsigned dim) : buffer(dim) {}
|
||||
|
||||
template <typename T, typename U>
|
||||
void operator()(T& dst, const U& src) {
|
||||
@ -80,6 +85,14 @@ public:
|
||||
if (!drop) dst.add(j, src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
decltype(auto) begin() { return buffer.begin(); }
|
||||
decltype(auto) end() { return buffer.end(); }
|
||||
|
||||
decltype(auto) operator[](unsigned i) { return buffer[i]; }
|
||||
|
||||
buffer_type buffer;
|
||||
std::size_t total = 1;
|
||||
};
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
#include <boost/histogram/detail/meta.hpp>
|
||||
#include <boost/histogram/histogram_fwd.hpp> // for axis::limit
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
@ -18,7 +17,7 @@ namespace detail {
|
||||
template <class Iterator>
|
||||
bool is_set(Iterator begin, Iterator end) {
|
||||
using T = iterator_value_type<Iterator>;
|
||||
using C = boost::container::static_vector<T, axis::limit>;
|
||||
using C = boost::container::static_vector<T, BOOST_HISTOGRAM_DETAIL_AXES_LIMIT>;
|
||||
boost::container::flat_set<T, std::less<T>, C> s(begin, end);
|
||||
return static_cast<std::size_t>(std::distance(begin, end)) == s.size();
|
||||
}
|
||||
|
@ -30,8 +30,9 @@ public:
|
||||
using axes_type = Axes;
|
||||
using storage_type = Storage;
|
||||
using value_type = typename storage_type::value_type;
|
||||
using iterator = typename storage_type::const_iterator; // for boost::range_iterator
|
||||
using const_iterator = typename storage_type::const_iterator;
|
||||
// typedefs for boost::range_iterator
|
||||
using iterator = decltype(std::declval<storage_type&>().begin());
|
||||
using const_iterator = decltype(std::declval<const storage_type&>().begin());
|
||||
|
||||
histogram() = default;
|
||||
histogram(const histogram& rhs) = default;
|
||||
|
@ -18,21 +18,6 @@ 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. 32 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 4 GB of storage.
|
||||
*/
|
||||
BOOST_ATTRIBUTE_UNUSED static constexpr unsigned limit =
|
||||
#ifdef BOOST_HISTOGRAM_AXES_LIMIT
|
||||
BOOST_HISTOGRAM_AXES_LIMIT;
|
||||
#else
|
||||
32;
|
||||
#endif
|
||||
|
||||
/// empty metadata type
|
||||
struct null_type {};
|
||||
|
||||
|
@ -7,13 +7,13 @@
|
||||
#ifndef BOOST_HISTOGRAM_INDEXED_HPP
|
||||
#define BOOST_HISTOGRAM_INDEXED_HPP
|
||||
|
||||
#include <boost/container/static_vector.hpp>
|
||||
#include <boost/histogram/axis/traits.hpp>
|
||||
#include <boost/histogram/detail/axes.hpp>
|
||||
#include <boost/histogram/detail/meta.hpp>
|
||||
#include <boost/histogram/histogram_fwd.hpp>
|
||||
#include <boost/histogram/unsafe_access.hpp>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
@ -29,8 +29,8 @@ class indexed_range {
|
||||
std::size_t stride;
|
||||
int underflow;
|
||||
};
|
||||
using strides_type = detail::make_axes_buffer<stride_t, axes_type>;
|
||||
using index_type = detail::make_axes_buffer<int, axes_type>;
|
||||
using strides_type = detail::axes_buffer<axes_type, stride_t>;
|
||||
using index_type = detail::axes_buffer<axes_type, int>;
|
||||
using value_type = decltype(std::declval<storage_type&>()[0]);
|
||||
|
||||
public:
|
||||
@ -42,11 +42,20 @@ public:
|
||||
decltype(auto) bin(mp11::mp_size_t<N>) const {
|
||||
return detail::axis_get<N>(axes_)[(*this)[N]];
|
||||
}
|
||||
|
||||
decltype(auto) bin(unsigned d) const {
|
||||
return detail::axis_get(axes_, d)[(*this)[d]];
|
||||
}
|
||||
|
||||
value_type value;
|
||||
double density() const {
|
||||
double x = 1;
|
||||
auto it = this->begin();
|
||||
detail::for_each_axis(axes_,
|
||||
[&](const auto& a) { x *= axis::traits::width(a, *it++); });
|
||||
return value / x;
|
||||
}
|
||||
|
||||
const value_type value;
|
||||
|
||||
protected:
|
||||
index_value(const axes_type& a, value_type v)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/histogram/axis/integer.hpp>
|
||||
#include <boost/histogram/axis/ostream_operators.hpp>
|
||||
#include <boost/histogram/axis/variable.hpp>
|
||||
#include <boost/histogram/histogram.hpp>
|
||||
#include <boost/histogram/indexed.hpp>
|
||||
#include <boost/histogram/literals.hpp>
|
||||
@ -105,6 +106,22 @@ void run_tests() {
|
||||
++it;
|
||||
BOOST_TEST(it == ind.end());
|
||||
}
|
||||
|
||||
{
|
||||
auto ax = axis::variable<>({0.0, 0.1, 0.3, 0.6});
|
||||
auto ay = axis::integer<int>(0, 2);
|
||||
auto az = ax;
|
||||
auto h = make_s(Tag(), std::vector<int>(), ax, ay, az);
|
||||
|
||||
// fill uniformly
|
||||
for (auto x : indexed(h)) {
|
||||
h(x.bin(0).center(), x.bin(1).value(), x.bin(2).center());
|
||||
}
|
||||
|
||||
for (auto x : indexed(h)) {
|
||||
BOOST_TEST_EQ(x.density(), x.value / (x.bin(0).width() * x.bin(2).width()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user