mirror of
https://github.com/boostorg/histogram.git
synced 2026-01-29 19:42:12 +00:00
use indexed in reduce and project, making index_mapper obsolete
This commit is contained in:
@@ -9,8 +9,9 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/histogram/detail/axes.hpp>
|
||||
#include <boost/histogram/detail/index_mapper.hpp>
|
||||
#include <boost/histogram/histogram_fwd.hpp>
|
||||
#include <boost/histogram/detail/meta.hpp>
|
||||
#include <boost/histogram/histogram.hpp>
|
||||
#include <boost/histogram/indexed.hpp>
|
||||
#include <boost/histogram/unsafe_access.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
@@ -29,38 +30,22 @@ namespace algorithm {
|
||||
histogram is summed over the removed axes.
|
||||
*/
|
||||
template <typename A, typename S, unsigned N, typename... Ns>
|
||||
auto project(const histogram<A, S>& h, std::integral_constant<unsigned, N> n, Ns... ns) {
|
||||
auto project(const histogram<A, S>& hist, std::integral_constant<unsigned, N> n,
|
||||
Ns... ns) {
|
||||
using LN = mp11::mp_list<decltype(n), Ns...>;
|
||||
static_assert(mp11::mp_is_set<LN>::value, "indices must be unique");
|
||||
|
||||
const auto& axes = unsafe_access::axes(h);
|
||||
auto r_axes = detail::make_sub_axes(axes, n, ns...);
|
||||
auto r_h = histogram<decltype(r_axes), S>(
|
||||
std::move(r_axes),
|
||||
detail::static_if<detail::has_allocator<S>>(
|
||||
[&h](auto) { return S(unsafe_access::storage(h).get_allocator()); },
|
||||
[](auto) { return S(); }, 0));
|
||||
auto axes = detail::make_sub_axes(unsafe_access::axes(hist), n, ns...);
|
||||
auto result = histogram<decltype(axes), S>(
|
||||
std::move(axes), detail::make_default(unsafe_access::storage(hist)));
|
||||
|
||||
detail::index_mapper<A> 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.total *= n;
|
||||
iter->stride[0] = s;
|
||||
s *= n;
|
||||
iter->stride[1] = 0;
|
||||
++iter;
|
||||
});
|
||||
|
||||
s = 1;
|
||||
mp11::mp_for_each<LN>([&](auto J) {
|
||||
im[J].stride[1] = s;
|
||||
s *= axis::traits::extend(detail::axis_get<J>(axes));
|
||||
});
|
||||
|
||||
im(unsafe_access::storage(r_h), unsafe_access::storage(h));
|
||||
return r_h;
|
||||
detail::axes_buffer<typename decltype(result)::axes_type, int> idx(result.rank());
|
||||
for (auto x : indexed(hist, true)) {
|
||||
auto i = idx.begin();
|
||||
mp11::mp_for_each<LN>([&i, &x](auto I) { *i++ = x[I]; });
|
||||
unsafe_access::add_value(result, idx, *x);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,59 +54,32 @@ auto project(const histogram<A, S>& h, std::integral_constant<unsigned, N> n, Ns
|
||||
This version accepts a source histogram and an iterable range containing the remaining
|
||||
indices.
|
||||
*/
|
||||
template <typename A, typename S, typename C, typename = detail::requires_iterable<C>>
|
||||
auto project(const histogram<A, S>& h, const C& c) {
|
||||
template <typename A, typename S, typename Iterable,
|
||||
typename = detail::requires_iterable<Iterable>>
|
||||
auto project(const histogram<A, S>& hist, const Iterable& c) {
|
||||
static_assert(detail::is_axis_vector<A>::value,
|
||||
"dynamic version of project requires a histogram with dynamic axis");
|
||||
|
||||
using H = histogram<A, S>;
|
||||
|
||||
const auto& axes = unsafe_access::axes(h);
|
||||
auto r_axes = detail::static_if<detail::has_allocator<A>>(
|
||||
[](const auto& axes) {
|
||||
using T = detail::unqual<decltype(axes)>;
|
||||
return T(axes.get_allocator());
|
||||
},
|
||||
[](const auto& axes) {
|
||||
using T = detail::unqual<decltype(axes)>;
|
||||
return T();
|
||||
},
|
||||
axes);
|
||||
|
||||
using std::begin;
|
||||
using std::end;
|
||||
r_axes.reserve(std::distance(begin(c), end(c)));
|
||||
|
||||
detail::index_mapper<A> im(h.rank());
|
||||
auto iter = im.begin();
|
||||
std::size_t stride = 1;
|
||||
h.for_each_axis([&](const auto& a) {
|
||||
const auto n = axis::traits::extend(a);
|
||||
im.total *= n;
|
||||
iter->stride[0] = stride;
|
||||
stride *= n;
|
||||
iter->stride[1] = 0;
|
||||
++iter;
|
||||
});
|
||||
|
||||
stride = 1;
|
||||
for (auto idx : c) {
|
||||
r_axes.emplace_back(axes[idx]);
|
||||
auto& stride_ref = im[idx].stride[1];
|
||||
if (stride_ref)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("indices must be unique"));
|
||||
else
|
||||
stride_ref = stride;
|
||||
stride *= axis::traits::extend(axes[idx]);
|
||||
const auto& hist_axes = unsafe_access::axes(hist);
|
||||
auto axes = detail::make_default(hist_axes);
|
||||
axes.reserve(c.size());
|
||||
detail::axes_buffer<A, bool> seen(hist_axes.size(), false);
|
||||
for (auto d : c) {
|
||||
if (seen[d]) BOOST_THROW_EXCEPTION(std::invalid_argument("indices must be unique"));
|
||||
seen[d] = true;
|
||||
axes.emplace_back(hist_axes[d]);
|
||||
}
|
||||
|
||||
auto r_h = H(std::move(r_axes),
|
||||
detail::static_if<detail::has_allocator<S>>(
|
||||
[&h](auto) { return S(unsafe_access::storage(h).get_allocator()); },
|
||||
[](auto) { return S(); }, 0));
|
||||
auto result = histogram<A, S>(std::move(axes),
|
||||
detail::make_default(unsafe_access::storage(hist)));
|
||||
|
||||
im(unsafe_access::storage(r_h), unsafe_access::storage(h));
|
||||
return r_h;
|
||||
detail::axes_buffer<A, int> idx(result.rank());
|
||||
for (auto x : indexed(hist, true)) {
|
||||
auto i = idx.begin();
|
||||
for (auto d : c) *i++ = x[d];
|
||||
unsafe_access::add_value(result, idx, *x);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace algorithm
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/histogram/detail/axes.hpp>
|
||||
#include <boost/histogram/detail/index_mapper.hpp>
|
||||
#include <boost/histogram/detail/meta.hpp>
|
||||
#include <boost/histogram/histogram_fwd.hpp>
|
||||
#include <boost/histogram/indexed.hpp>
|
||||
@@ -112,12 +111,8 @@ histogram<A, S> reduce(const histogram<A, S>& hist, const C& options) {
|
||||
++iaxis;
|
||||
});
|
||||
|
||||
const auto& storage = unsafe_access::storage(hist);
|
||||
using storage_type = detail::unqual<decltype(storage)>;
|
||||
auto result = histogram<A, S>(
|
||||
std::move(axes), detail::static_if<detail::has_allocator<storage_type>>(
|
||||
[](auto& x) { return storage_type(x.get_allocator()); },
|
||||
[](auto&) { return storage_type(); }, storage));
|
||||
auto result = histogram<A, S>(std::move(axes),
|
||||
detail::make_default(unsafe_access::storage(hist)));
|
||||
|
||||
detail::axes_buffer<A, int> idx(hist.rank());
|
||||
for (auto x : indexed(hist, true)) {
|
||||
|
||||
@@ -172,9 +172,9 @@ using axes_buffer = boost::container::static_vector<
|
||||
std::tuple_size, Axes>::value>;
|
||||
|
||||
template <typename T>
|
||||
auto make_empty_axes(const T& t) {
|
||||
auto r = T();
|
||||
static_if<is_vector_like<T>>([&](auto) { r.reserve(t.size()); }, [](auto) {}, 0);
|
||||
auto make_empty_axes(const std::vector<T>& t) {
|
||||
auto r = std::vector<T>(t.get_allocator());
|
||||
r.reserve(t.size());
|
||||
for_each_axis(t, [&r](const auto& a) {
|
||||
using U = unqual<decltype(a)>;
|
||||
r.emplace_back(U());
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
// Copyright 2015-2017 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_INDEX_MAPPER_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_INDEX_MAPPER_HPP
|
||||
|
||||
#include <boost/container/static_vector.hpp>
|
||||
#include <boost/histogram/histogram_fwd.hpp>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
template <typename A>
|
||||
struct index_mapper {
|
||||
struct item {
|
||||
std::size_t stride[2];
|
||||
};
|
||||
using buffer_type = axes_buffer<A, item>;
|
||||
|
||||
index_mapper(unsigned dim) : buffer(dim) {}
|
||||
|
||||
template <typename T, typename U>
|
||||
void operator()(T& dst, const U& src) {
|
||||
for (std::size_t i = 0; i < total; ++i) {
|
||||
std::size_t j = 0;
|
||||
auto imod = i;
|
||||
for (auto it = end(); it != begin(); --it) {
|
||||
const auto& d = *(it - 1);
|
||||
// compiler usually optimizes div & mod into one div
|
||||
const auto k = imod / d.stride[0];
|
||||
imod %= d.stride[0];
|
||||
j += k * d.stride[1];
|
||||
}
|
||||
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;
|
||||
};
|
||||
|
||||
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) {
|
||||
for (std::size_t i = 0; i < total; ++i) {
|
||||
std::size_t j = 0;
|
||||
auto imod = i;
|
||||
bool drop = false;
|
||||
for (auto it = end(); it != begin(); --it) {
|
||||
const auto& d = *(it - 1);
|
||||
// compiler usually optimizes div & mod into one div
|
||||
int k = imod / d.stride[0];
|
||||
imod %= d.stride[0];
|
||||
if (k < d.begin || k == d.underflow[0]) {
|
||||
k = d.underflow[1];
|
||||
} else if (k >= d.end || k == d.overflow[0]) {
|
||||
k = d.overflow[1];
|
||||
} else {
|
||||
k = (k - d.begin) / d.merge;
|
||||
}
|
||||
drop |= k < 0;
|
||||
j += k * d.stride[1];
|
||||
}
|
||||
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
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -284,6 +284,13 @@ struct requires_axis_or_axis_variant {};
|
||||
template <typename T, typename = mp11::mp_if<is_axis_vector<unqual<T>>, void>>
|
||||
struct requires_axis_vector {};
|
||||
|
||||
template <typename T>
|
||||
T make_default(const T& t) {
|
||||
using U = unqual<T>;
|
||||
return static_if<has_allocator<U>>([](const auto& t) { return U(t.get_allocator()); },
|
||||
[](const auto&) { return U(); }, t);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
@@ -117,14 +117,14 @@ public:
|
||||
, cache_(hist_.rank()) {
|
||||
auto c = cache_.begin();
|
||||
std::size_t stride = 1;
|
||||
const auto extra = include_extra_bins_;
|
||||
h.for_each_axis([&](const auto& a) {
|
||||
h.for_each_axis([&, this](const auto& a) {
|
||||
const auto opt = axis::traits::options(a);
|
||||
const auto shift = opt & axis::option_type::underflow;
|
||||
|
||||
c->extend = axis::traits::extend(a);
|
||||
c->begin = extra ? -shift : 0;
|
||||
c->end = c->extend - shift - (extra ? 0 : (opt & axis::option_type::overflow));
|
||||
c->begin = include_extra_bins_ ? -shift : 0;
|
||||
c->end = c->extend - shift -
|
||||
(include_extra_bins_ ? 0 : (opt & axis::option_type::overflow));
|
||||
c->idx = c->begin;
|
||||
|
||||
begin_ += (c->begin + shift) * stride;
|
||||
|
||||
@@ -27,7 +27,6 @@ alias run-tests :
|
||||
[ run histogram_mixed_test.cpp ]
|
||||
[ run histogram_serialization_test.cpp /boost/serialization//boost_serialization/<link>static ]
|
||||
[ run histogram_test.cpp ]
|
||||
[ run index_mapper_test.cpp ]
|
||||
[ run meta_test.cpp ]
|
||||
[ run storage_adaptor_test.cpp ]
|
||||
[ run storage_adaptor_serialization_test.cpp /boost/serialization//boost_serialization/<link>static ]
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "utility_allocator.hpp"
|
||||
#include "utility_meta.hpp"
|
||||
|
||||
namespace bh = boost::histogram;
|
||||
@@ -435,5 +436,17 @@ int main() {
|
||||
BOOST_TEST(has_fixed_size<D>::value);
|
||||
}
|
||||
|
||||
// make_default
|
||||
{
|
||||
struct A {};
|
||||
auto a = make_default(A());
|
||||
BOOST_TEST_TRAIT_TRUE((std::is_same<decltype(a), A>));
|
||||
bh::tracing_allocator_db db;
|
||||
using B = std::vector<int, bh::tracing_allocator<int>>;
|
||||
B b = make_default(B(bh::tracing_allocator<int>(db)));
|
||||
b.resize(100);
|
||||
BOOST_TEST_EQ(db[&BOOST_CORE_TYPEID(int)].first, 100);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user