mirror of
https://github.com/boostorg/histogram.git
synced 2025-05-12 05:31:51 +00:00
127 lines
3.7 KiB
C++
127 lines
3.7 KiB
C++
// 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 <algorithm>
|
|
#include <boost/histogram/detail/axes.hpp>
|
|
#include <boost/histogram/detail/index_mapper.hpp>
|
|
#include <boost/histogram/histogram_fwd.hpp>
|
|
#include <boost/histogram/unsafe_access.hpp>
|
|
#include <boost/mp11.hpp>
|
|
#include <stdexcept>
|
|
|
|
namespace boost {
|
|
namespace histogram {
|
|
namespace algorithm {
|
|
|
|
/**
|
|
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 <typename A, typename S, std::size_t I, typename... Ns>
|
|
auto project(const histogram<A, S>& h, mp11::mp_size_t<I> n, Ns... ns) {
|
|
using LN = mp11::mp_list<mp11::mp_size_t<I>, 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));
|
|
|
|
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;
|
|
}
|
|
|
|
/**
|
|
Returns a lower-dimensional histogram, summing over removed axes.
|
|
|
|
This version accepts an iterable range that represents the indices which are kept.
|
|
*/
|
|
template <typename A, typename S, typename C, typename = detail::requires_axis_vector<A>,
|
|
typename = detail::requires_iterable<C>>
|
|
auto project(const histogram<A, S>& h, C c) {
|
|
using H = histogram<A, S>;
|
|
|
|
auto begin = std::begin(c);
|
|
auto end = std::end(c);
|
|
|
|
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);
|
|
r_axes.reserve(std::distance(begin, end));
|
|
|
|
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 it = begin; it != end; ++it) {
|
|
r_axes.emplace_back(axes[*it]);
|
|
auto& stride_ref = im[*it].stride[1];
|
|
if (stride_ref)
|
|
throw std::invalid_argument("indices must be unique");
|
|
else
|
|
stride_ref = stride;
|
|
stride *= axis::traits::extend(axes[*it]);
|
|
}
|
|
|
|
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));
|
|
|
|
im(unsafe_access::storage(r_h), unsafe_access::storage(h));
|
|
return r_h;
|
|
}
|
|
|
|
} // namespace algorithm
|
|
} // namespace histogram
|
|
} // namespace boost
|
|
|
|
#endif
|