fixed reduce function

This commit is contained in:
Hans Dembinski 2017-10-13 16:26:41 +02:00
parent 7e8b2bb403
commit c07162e7a8
10 changed files with 182 additions and 85 deletions

View File

@ -91,9 +91,10 @@ private:
friend class boost::iterator_core_access;
};
/// Common base class for axes.
/// Common base class for all axes.
template <bool UOFlow> class axis_base;
/// Specialization with overflow/underflow bins.
template <> class axis_base<true> {
public:
/// Returns the number of bins, excluding overflow/underflow.
@ -149,6 +150,7 @@ private:
template <class Archive> void serialize(Archive &, unsigned);
};
/// Specialization without overflow/underflow bins.
template <> class axis_base<false> {
public:
/// Returns the number of bins, excluding overflow/underflow.

View File

@ -21,7 +21,7 @@ inline std::ostream &operator<<(std::ostream &os, const regular<RealType> &a) {
os << "regular(" << a.bins() << ", " << a[0] << ", " << a[a.bins()];
if (!a.label().empty()) {
os << ", label=";
detail::escape(os, a.label());
::boost::histogram::detail::escape(os, a.label());
}
if (!a.uoflow()) {
os << ", uoflow=False";
@ -41,7 +41,7 @@ inline std::ostream &operator<<(std::ostream &os, const circular<RealType> &a) {
}
if (!a.label().empty()) {
os << ", label=";
detail::escape(os, a.label());
::boost::histogram::detail::escape(os, a.label());
}
os << ")";
return os;
@ -55,7 +55,7 @@ inline std::ostream &operator<<(std::ostream &os, const variable<RealType> &a) {
}
if (!a.label().empty()) {
os << ", label=";
detail::escape(os, a.label());
::boost::histogram::detail::escape(os, a.label());
}
if (!a.uoflow()) {
os << ", uoflow=False";
@ -68,7 +68,7 @@ inline std::ostream &operator<<(std::ostream &os, const integer &a) {
os << "integer(" << a[0] << ", " << a[a.bins() - 1];
if (!a.label().empty()) {
os << ", label=";
detail::escape(os, a.label());
::boost::histogram::detail::escape(os, a.label());
}
if (!a.uoflow()) {
os << ", uoflow=False";
@ -80,12 +80,12 @@ inline std::ostream &operator<<(std::ostream &os, const integer &a) {
inline std::ostream &operator<<(std::ostream &os, const category &a) {
os << "category(";
for (int i = 0; i < a.bins(); ++i) {
detail::escape(os, a[i]);
::boost::histogram::detail::escape(os, a[i]);
os << (i == (a.bins() - 1) ? "" : ", ");
}
if (!a.label().empty()) {
os << ", label=";
detail::escape(os, a.label());
::boost::histogram::detail::escape(os, a.label());
}
os << ")";
return os;

View File

@ -50,23 +50,23 @@ template <typename MainVector, typename AuxVector> struct combine {
mpl::back_inserter<MainVector>>::type;
};
struct bool_mask_helper {
struct bool_mask_op {
std::vector<bool> &b;
bool v;
template <typename N> void operator()(const N &) const { b[N::value] = v; }
};
template <typename Ns> std::vector<bool> bool_mask(std::size_t n, bool v) {
template <typename Ns> std::vector<bool> bool_mask(unsigned n, bool v) {
std::vector<bool> b(n, !v);
mpl::for_each<Ns>(bool_mask_helper{b, v});
mpl::for_each<Ns>(bool_mask_op{b, v});
return b;
}
template <typename Axes, typename Ns> struct axes_assign_subset_helper {
template <typename Axes, typename Ns> struct axes_assign_subset_op {
const Axes &axes_;
template <typename I, typename R>
auto operator()(const I &, R &r) const -> typename mpl::next<I>::type {
using I2 = typename mpl::at_c<Ns, I::value>::type;
template <int N, typename R>
auto operator()(mpl::int_<N>, R &r) const -> mpl::int_<N+1> {
using I2 = typename mpl::at_c<Ns, N>::type;
r = fusion::at_c<I2::value>(axes_);
return {};
}
@ -75,17 +75,17 @@ template <typename Axes, typename Ns> struct axes_assign_subset_helper {
template <typename Ns, typename Axes1, typename Axes>
void axes_assign_subset(Axes1 &axes1, const Axes &axes) {
fusion::fold(axes1, mpl::int_<0>(),
axes_assign_subset_helper<Axes, Ns>{axes});
axes_assign_subset_op<Axes, Ns>{axes});
}
template <typename... Ns> struct unique_sorted {
using type = typename mpl::unique<
typename mpl::sort<typename mpl::vector<Ns...>::type>::type>::type;
};
template <typename Ns>
using unique_sorted =
typename mpl::unique<typename mpl::sort<Ns>::type,
std::is_same<mpl::_1, mpl::_2>>::type;
template <typename Axes, typename Numbers> struct axes_select {
using type = typename mpl::transform<Numbers, mpl::at<Axes, mpl::_1>>::type;
};
template <typename Axes, typename Numbers>
using axes_select =
typename mpl::transform<Numbers, mpl::at<Axes, mpl::_1>>::type;
} // namespace detail
} // namespace histogram

View File

@ -8,6 +8,7 @@
#define _BOOST_HISTOGRAM_HISTOGRAM_FWD_HPP_
#include <boost/histogram/detail/meta.hpp>
#include <boost/mpl/vector.hpp>
#include <set>
#include <type_traits>
@ -41,19 +42,17 @@ private:
unsigned value;
};
namespace detail {
template <typename Ns> struct keep_static { using type = Ns; };
struct keep_dynamic : std::set<unsigned> {};
} // namespace detail
template <typename... Ns>
auto keep(Ns...)
-> detail::keep_static<typename detail::unique_sorted<Ns...>::type> {
inline auto keep(Ns...) -> detail::unique_sorted<mpl::vector<Ns...>> {
return {};
}
namespace detail {
using keep_dynamic = std::set<unsigned>;
} // namespace detail
template <typename Iterator, typename = detail::is_iterator<Iterator>>
detail::keep_dynamic keep(Iterator begin, Iterator end) {
inline detail::keep_dynamic keep(Iterator begin, Iterator end) {
detail::keep_dynamic s;
std::copy(begin, end, s.begin());
return s;

View File

@ -364,9 +364,8 @@ private:
return h;
}
template <typename Ns>
friend histogram reduce(const histogram &h, const detail::keep_static<Ns> &) {
const auto b = detail::bool_mask<Ns>(h.dim(), true);
template <typename Keep> friend histogram reduce(const histogram &h, Keep) {
const auto b = detail::bool_mask<Keep>(h.dim(), true);
return h.reduce_impl(b);
}

View File

@ -156,10 +156,10 @@ public:
void reset() { storage_ = std::move(Storage(storage_.size())); }
/// Get N-th axis
template <unsigned N>
template <int N>
constexpr typename std::add_const<
typename fusion::result_of::value_at_c<axes_type, N>::type>::type &
axis(std::integral_constant<unsigned, N>) const {
axis(mpl::int_<N>) const {
static_assert(N < axes_size::value, "axis index out of range");
return fusion::at_c<N>(axes_);
}
@ -277,16 +277,14 @@ private:
} while (m.next());
}
template <typename Ns>
friend auto reduce(const histogram &h, const detail::keep_static<Ns> &)
-> histogram<Static, typename detail::axes_select<Axes, Ns>::type,
Storage> {
using HR = histogram<Static, typename detail::axes_select<Axes, Ns>::type,
Storage>;
template <typename Keep>
friend auto reduce(const histogram &h, Keep)
-> histogram<Static, detail::axes_select<Axes, Keep>, Storage> {
using HR = histogram<Static, detail::axes_select<Axes, Keep>, Storage>;
typename HR::axes_type axes;
detail::axes_assign_subset<Ns>(axes, h.axes_);
detail::axes_assign_subset<Keep>(axes, h.axes_);
auto hr = HR(std::move(axes));
const auto b = detail::bool_mask<Ns>(h.dim(), true);
const auto b = detail::bool_mask<Keep>(h.dim(), true);
h.reduce_impl(hr, b);
return hr;
}

View File

@ -7,6 +7,7 @@
#ifndef _BOOST_HISTOGRAM_LITERALS_HPP_
#define _BOOST_HISTOGRAM_LITERALS_HPP_
#include <boost/mpl/int.hpp>
#include <type_traits>
namespace boost {
@ -14,28 +15,27 @@ namespace histogram {
namespace literals {
namespace detail {
template <char C> struct char2int;
template <> struct char2int<'0'> { static constexpr unsigned value = 0; };
template <> struct char2int<'1'> { static constexpr unsigned value = 1; };
template <> struct char2int<'2'> { static constexpr unsigned value = 2; };
template <> struct char2int<'3'> { static constexpr unsigned value = 3; };
template <> struct char2int<'4'> { static constexpr unsigned value = 4; };
template <> struct char2int<'5'> { static constexpr unsigned value = 5; };
template <> struct char2int<'6'> { static constexpr unsigned value = 6; };
template <> struct char2int<'7'> { static constexpr unsigned value = 7; };
template <> struct char2int<'8'> { static constexpr unsigned value = 8; };
template <> struct char2int<'9'> { static constexpr unsigned value = 9; };
template <> struct char2int<'0'> { static constexpr int value = 0; };
template <> struct char2int<'1'> { static constexpr int value = 1; };
template <> struct char2int<'2'> { static constexpr int value = 2; };
template <> struct char2int<'3'> { static constexpr int value = 3; };
template <> struct char2int<'4'> { static constexpr int value = 4; };
template <> struct char2int<'5'> { static constexpr int value = 5; };
template <> struct char2int<'6'> { static constexpr int value = 6; };
template <> struct char2int<'7'> { static constexpr int value = 7; };
template <> struct char2int<'8'> { static constexpr int value = 8; };
template <> struct char2int<'9'> { static constexpr int value = 9; };
template <unsigned N> constexpr unsigned parse() { return N; }
template <int N> constexpr int parse() { return N; }
template <unsigned N, char First, char... Rest> constexpr unsigned parse() {
template <int N, char First, char... Rest> constexpr int parse() {
return parse<N * 10 + char2int<First>::value, Rest...>();
}
} // namespace detail
template <char... Digits>
auto operator"" _c() -> decltype(
std::integral_constant<unsigned, detail::parse<0, Digits...>()>()) {
return std::integral_constant<unsigned, detail::parse<0, Digits...>()>();
auto operator"" _c() -> decltype(mpl::int_<detail::parse<0u, Digits...>()>()) {
return mpl::int_<detail::parse<0u, Digits...>()>();
}
} // namespace literals

View File

@ -7,57 +7,57 @@
#ifndef BOOST_HISTOGRAM_UTILITY_HPP_
#define BOOST_HISTOGRAM_UTILITY_HPP_
#include <boost/histogram/detail/axis_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/histogram/detail/axis_visitor.hpp>
namespace boost {
namespace histogram {
template <typename A> int bins(const A &a) { return a.bins(); }
template <typename A> inline int bins(const A &a) { return a.bins(); }
template <typename... Axes> int bins(const boost::variant<Axes...> &a) {
template <typename... Axes> inline int bins(const boost::variant<Axes...> &a) {
return apply_visitor(detail::bins(), a);
}
template <typename A> int shape(const A &a) { return a.shape(); }
template <typename A> inline int shape(const A &a) { return a.shape(); }
template <typename... Axes> int shape(const boost::variant<Axes...> &a) {
template <typename... Axes> inline int shape(const boost::variant<Axes...> &a) {
return apply_visitor(detail::shape(), a);
}
template <typename A, typename V> int index(const A &a, const V v) {
template <typename A, typename V> inline int index(const A &a, const V v) {
return a.index(v);
}
template <typename... Axes, typename V>
int index(const boost::variant<Axes...> &a, const V v) {
inline int index(const boost::variant<Axes...> &a, const V v) {
return apply_visitor(detail::index<V>(v), a);
}
template <typename A> typename A::value_type left(const A &a, const int i) {
template <typename A> inline typename A::value_type left(const A &a, const int i) {
return a[i];
}
template <typename... Axes>
double left(const boost::variant<Axes...> &a, const int i) {
inline double left(const boost::variant<Axes...> &a, const int i) {
return apply_visitor(detail::left(i), a);
}
template <typename A> typename A::value_type right(const A &a, const int i) {
template <typename A> inline typename A::value_type right(const A &a, const int i) {
return left(a, i + 1);
}
template <typename... Axes>
double right(const boost::variant<Axes...> &a, const int i) {
inline double right(const boost::variant<Axes...> &a, const int i) {
return apply_visitor(detail::right(i), a);
}
template <typename A> double center(const A &a, const int i) {
template <typename A> inline double center(const A &a, const int i) {
return 0.5 * (left(a, i) + right(a, i));
}
template <typename... Axes>
double center(const boost::variant<Axes...> &a, const int i) {
inline double center(const boost::variant<Axes...> &a, const int i) {
return apply_visitor(detail::center(i), a);
}

View File

@ -35,6 +35,16 @@ auto make_histogram(Dynamic, Axes &&... axes)
return make_dynamic_histogram_with<S>(std::forward<Axes>(axes)...);
}
template <typename T, typename U>
bool axis_equal(Static, const T& t, const U& u) {
return t == u;
}
template <typename T, typename U>
bool axis_equal(Dynamic, const T& t, const U& u) {
return t == T(u);
}
template <typename Type> void run_tests() {
// init_0
@ -573,21 +583,88 @@ template <typename Type> void run_tests() {
// reduce
{
auto h1 = make_histogram<adaptive_storage<>>(Type(), axis::integer(0, 1),
axis::integer(2, 3));
h1.fill(0, 2);
h1.fill(0, 3);
axis::integer(0, 2));
h1.fill(0, 0);
h1.fill(0, 1);
h1.fill(1, 0);
h1.fill(1, 1);
h1.fill(1, 2);
h1.fill(1, 3);
h1.fill(1, 3);
BOOST_TEST_EQ(h1.dim(), 2);
BOOST_TEST_EQ(h1.sum(), 5);
auto h2 = reduce(h1, keep(1_c));
BOOST_TEST_EQ(h2.dim(), 1);
BOOST_TEST_EQ(h2.sum(), 5);
BOOST_TEST_EQ(h2.value(0), 2);
BOOST_TEST_EQ(h2.value(1), 3);
BOOST_TEST_EQ(left(h2.axis(), 0), 2.0);
BOOST_TEST_EQ(left(h2.axis(), 1), 3.0);
auto h1_0 = reduce(h1, keep(0_c));
BOOST_TEST_EQ(h1_0.dim(), 1);
BOOST_TEST_EQ(h1_0.sum(), 5);
BOOST_TEST_EQ(h1_0.value(0), 2);
BOOST_TEST_EQ(h1_0.value(1), 3);
BOOST_TEST_EQ(left(h1_0.axis(), 0), 0.0);
BOOST_TEST_EQ(left(h1_0.axis(), 1), 1.0);
BOOST_TEST(axis_equal(Type(), h1_0.axis(), axis::integer(0, 1)));
auto h1_1 = reduce(h1, keep(1_c));
BOOST_TEST_EQ(h1_1.dim(), 1);
BOOST_TEST_EQ(h1_1.sum(), 5);
BOOST_TEST_EQ(h1_1.value(0), 2);
BOOST_TEST_EQ(h1_1.value(1), 2);
BOOST_TEST_EQ(h1_1.value(2), 1);
BOOST_TEST(axis_equal(Type(), h1_1.axis(), axis::integer(0, 2)));
auto h2 = make_histogram<adaptive_storage<>>(
Type(), axis::integer(0, 1), axis::integer(0, 2), axis::integer(0, 3));
h2.fill(0, 0, 0);
h2.fill(0, 1, 0);
h2.fill(0, 1, 1);
h2.fill(0, 0, 2);
h2.fill(1, 0, 2);
auto h2_0 = reduce(h2, keep(0_c));
BOOST_TEST_EQ(h2_0.dim(), 1);
BOOST_TEST_EQ(h2_0.sum(), 5);
BOOST_TEST_EQ(h2_0.value(0), 4);
BOOST_TEST_EQ(h2_0.value(1), 1);
BOOST_TEST(axis_equal(Type(), h2_0.axis(), axis::integer(0, 1)));
auto h2_1 = reduce(h2, keep(1_c));
BOOST_TEST_EQ(h2_1.dim(), 1);
BOOST_TEST_EQ(h2_1.sum(), 5);
BOOST_TEST_EQ(h2_1.value(0), 3);
BOOST_TEST_EQ(h2_1.value(1), 2);
BOOST_TEST(axis_equal(Type(), h2_1.axis(), axis::integer(0, 2)));
auto h2_2 = reduce(h2, keep(2_c));
BOOST_TEST_EQ(h2_2.dim(), 1);
BOOST_TEST_EQ(h2_2.sum(), 5);
BOOST_TEST_EQ(h2_2.value(0), 2);
BOOST_TEST_EQ(h2_2.value(1), 1);
BOOST_TEST_EQ(h2_2.value(2), 2);
BOOST_TEST(axis_equal(Type(), h2_2.axis(), axis::integer(0, 3)));
auto h2_01 = reduce(h2, keep(0_c, 1_c));
BOOST_TEST_EQ(h2_01.dim(), 2);
BOOST_TEST_EQ(h2_01.sum(), 5);
BOOST_TEST_EQ(h2_01.value(0, 0), 2);
BOOST_TEST_EQ(h2_01.value(0, 1), 2);
BOOST_TEST_EQ(h2_01.value(1, 0), 1);
BOOST_TEST(axis_equal(Type(), h2_01.axis(0_c), axis::integer(0, 1)));
BOOST_TEST(axis_equal(Type(), h2_01.axis(1_c), axis::integer(0, 2)));
auto h2_02 = reduce(h2, keep(0_c, 2_c));
BOOST_TEST_EQ(h2_02.dim(), 2);
BOOST_TEST_EQ(h2_02.sum(), 5);
BOOST_TEST_EQ(h2_02.value(0, 0), 2);
BOOST_TEST_EQ(h2_02.value(0, 1), 1);
BOOST_TEST_EQ(h2_02.value(0, 2), 1);
BOOST_TEST_EQ(h2_02.value(1, 2), 1);
BOOST_TEST(axis_equal(Type(), h2_02.axis(0_c), axis::integer(0, 1)));
BOOST_TEST(axis_equal(Type(), h2_02.axis(1_c), axis::integer(0, 3)));
auto h2_12 = reduce(h2, keep(1_c, 2_c));
BOOST_TEST_EQ(h2_12.dim(), 2);
BOOST_TEST_EQ(h2_12.sum(), 5);
BOOST_TEST_EQ(h2_12.value(0, 0), 1);
BOOST_TEST_EQ(h2_12.value(1, 0), 1);
BOOST_TEST_EQ(h2_12.value(1, 1), 1);
BOOST_TEST_EQ(h2_12.value(0, 2), 2);
BOOST_TEST(axis_equal(Type(), h2_12.axis(0_c), axis::integer(0, 2)));
BOOST_TEST(axis_equal(Type(), h2_12.axis(1_c), axis::integer(0, 3)));
}
}

22
test/meta_test.cpp Normal file
View File

@ -0,0 +1,22 @@
#include <boost/core/lightweight_test.hpp>
#include <boost/histogram/detail/meta.hpp>
#include <boost/mpl/equal.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/sort.hpp>
#include <boost/mpl/unique.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/type_traits.hpp>
using namespace boost;
using namespace boost::mpl;
namespace bhd = boost::histogram::detail;
int main() {
typedef vector_c<int, 2, 1, 1, 3> numbers;
typedef vector_c<int, 1, 2, 3> expected;
using result = bhd::unique_sorted<numbers>;
BOOST_MPL_ASSERT((equal<result, expected, equal_to<_, _>>));
return boost::report_errors();
}