mirror of
https://github.com/boostorg/histogram.git
synced 2026-01-29 07:32:23 +00:00
first working accumulator support
This commit is contained in:
@@ -15,7 +15,6 @@
|
||||
#include <boost/histogram/detail/buffer.hpp>
|
||||
#include <boost/histogram/detail/meta.hpp>
|
||||
#include <boost/histogram/histogram_fwd.hpp>
|
||||
#include <boost/histogram/weight.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
#if defined BOOST_CLANG
|
||||
#pragma clang diagnostic push
|
||||
|
||||
@@ -34,8 +34,7 @@ struct get_polymorphic_bin_data
|
||||
|
||||
template <typename A>
|
||||
std::tuple<double, double, double> operator()(const A& a) const {
|
||||
return detail::static_if<
|
||||
detail::has_value_method_with_return_type_convertible_to_x<A, double>>(
|
||||
return detail::static_if<detail::has_method_value<A, double>>(
|
||||
[this](const auto& a) {
|
||||
using Arg = detail::unqual<detail::arg_type<detail::unqual<decltype(a)>>>;
|
||||
const auto x = a.value(idx);
|
||||
@@ -193,8 +192,7 @@ public:
|
||||
return visit(
|
||||
[idx](const auto& a) -> double {
|
||||
using A = detail::unqual<decltype(a)>;
|
||||
return detail::static_if<
|
||||
detail::has_value_method_with_return_type_convertible_to_x<A, double>>(
|
||||
return detail::static_if<detail::has_method_value<A, double>>(
|
||||
[idx](const auto& a) -> double {
|
||||
return static_cast<double>(a.value(idx));
|
||||
},
|
||||
|
||||
@@ -319,13 +319,38 @@ optional_index args_to_index(const T& axes, const U& args) {
|
||||
return idx;
|
||||
}
|
||||
|
||||
template <typename... Us>
|
||||
constexpr int weight_index() {
|
||||
const int n = sizeof...(Us) - 1;
|
||||
using L = mp11::mp_list<Us...>;
|
||||
if (is_weight<mp11::mp_at_c<L, 0>>::value) return 0;
|
||||
if (is_weight<mp11::mp_at_c<L, n>>::value) return n;
|
||||
return -1;
|
||||
template <typename U>
|
||||
constexpr std::pair<int, int> weight_sample_indices() {
|
||||
if (is_weight<U>::value) return std::make_pair(0, -1);
|
||||
if (is_sample<U>::value) return std::make_pair(-1, 0);
|
||||
return std::make_pair(-1, -1);
|
||||
}
|
||||
|
||||
template <typename U0, typename U1, typename... Us>
|
||||
constexpr std::pair<int, int> weight_sample_indices() {
|
||||
using L = mp11::mp_list<U0, U1, Us...>;
|
||||
const int n = sizeof...(Us) + 1;
|
||||
if (is_weight<mp11::mp_at_c<L, 0>>::value) {
|
||||
if (is_sample<mp11::mp_at_c<L, 1>>::value) return std::make_pair(0, 1);
|
||||
if (is_sample<mp11::mp_at_c<L, n>>::value) return std::make_pair(0, n);
|
||||
return std::make_pair(0, -1);
|
||||
}
|
||||
if (is_sample<mp11::mp_at_c<L, 0>>::value) {
|
||||
if (is_weight<mp11::mp_at_c<L, 1>>::value) return std::make_pair(1, 0);
|
||||
if (is_weight<mp11::mp_at_c<L, n>>::value) return std::make_pair(n, 0);
|
||||
return std::make_pair(-1, 0);
|
||||
}
|
||||
if (is_weight<mp11::mp_at_c<L, n>>::value) {
|
||||
// 0, n already covered
|
||||
if (is_sample<mp11::mp_at_c<L, (n - 1)>>::value) return std::make_pair(n, n - 1);
|
||||
return std::make_pair(n, -1);
|
||||
}
|
||||
if (is_sample<mp11::mp_at_c<L, n>>::value) {
|
||||
// n, 0 already covered
|
||||
if (is_weight<mp11::mp_at_c<L, (n - 1)>>::value) return std::make_pair(n - 1, n);
|
||||
return std::make_pair(-1, n);
|
||||
}
|
||||
return std::make_pair(-1, -1);
|
||||
}
|
||||
|
||||
template <typename S, typename T>
|
||||
@@ -343,22 +368,28 @@ void fill_storage_impl(mp11::mp_int<Iw>, mp11::mp_int<-1>, S& storage, std::size
|
||||
template <int Is, typename S, typename T>
|
||||
void fill_storage_impl(mp11::mp_int<-1>, mp11::mp_int<Is>, S& storage, std::size_t i,
|
||||
const T& args) {
|
||||
storage(i, std::get<Is>(args).value);
|
||||
mp11::tuple_apply([&](auto&&... sargs) { storage(i, sargs...); },
|
||||
std::get<Is>(args).value);
|
||||
}
|
||||
|
||||
template <int Iw, int Is, typename S, typename T>
|
||||
void fill_storage_impl(mp11::mp_int<Iw>, mp11::mp_int<Is>, S& storage, std::size_t i,
|
||||
void fill_storage_impl(mp11::mp_int<Iw>, mp11::mp_int<Is>, S&, std::size_t i,
|
||||
const T& args) {
|
||||
storage(i, std::get<Iw>(args), std::get<Is>(args).value);
|
||||
mp11::tuple_apply([&](auto&&... sargs) { storage(i, std::get<Iw>(args), sargs...); },
|
||||
std::get<Is>(args).value);
|
||||
}
|
||||
|
||||
template <typename S, typename T, typename... Us>
|
||||
void fill_impl(S& storage, const T& axes, const std::tuple<Us...>& args) {
|
||||
constexpr int Iw = weight_index<Us...>();
|
||||
constexpr unsigned N = Iw >= 0 ? sizeof...(Us) - 1 : sizeof...(Us);
|
||||
optional_index idx = args_to_index<(Iw == 0 ? 1 : 0), N>(axes, args);
|
||||
constexpr std::pair<int, int> iws = weight_sample_indices<Us...>();
|
||||
constexpr unsigned n = sizeof...(Us) - (iws.first > -1) - (iws.second > -1);
|
||||
constexpr unsigned offset = (iws.first == 0 || iws.second == 0)
|
||||
? (iws.first == 1 || iws.second == 1 ? 2 : 1)
|
||||
: 0;
|
||||
optional_index idx = args_to_index<offset, n>(axes, args);
|
||||
if (idx) {
|
||||
fill_storage_impl(mp11::mp_int<Iw>(), mp11::mp_int<-1>(), storage, *idx, args);
|
||||
fill_storage_impl(mp11::mp_int<iws.first>(), mp11::mp_int<iws.second>(), storage,
|
||||
*idx, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,14 +121,6 @@ decltype(auto) sub_tuple(const T& t) {
|
||||
template <typename T> \
|
||||
using name = typename name##_impl<T>::type
|
||||
|
||||
BOOST_HISTOGRAM_MAKE_SFINAE(has_variance_support,
|
||||
(std::declval<T&>().value(), std::declval<T&>().variance()));
|
||||
|
||||
BOOST_HISTOGRAM_MAKE_SFINAE(has_method_value, (std::declval<T&>().value(0)));
|
||||
|
||||
// TODO try casting to more specific pmf with correct return type
|
||||
BOOST_HISTOGRAM_MAKE_SFINAE(has_method_options, (std::declval<T&>().options()));
|
||||
|
||||
BOOST_HISTOGRAM_MAKE_SFINAE(has_method_metadata, (std::declval<T&>().metadata()));
|
||||
|
||||
// resize has two overloads, trying to get pmf in this case always fails
|
||||
@@ -138,6 +130,28 @@ BOOST_HISTOGRAM_MAKE_SFINAE(has_method_size, &T::size);
|
||||
|
||||
BOOST_HISTOGRAM_MAKE_SFINAE(has_method_clear, &T::clear);
|
||||
|
||||
template <typename T, typename X>
|
||||
struct has_method_value_impl {
|
||||
template <typename U, typename V = decltype(std::declval<U&>().value(0))>
|
||||
static typename std::is_convertible<V, X>::type Test(void*);
|
||||
template <typename U>
|
||||
static std::false_type Test(...);
|
||||
using type = decltype(Test<T>(nullptr));
|
||||
};
|
||||
template <typename T, typename X>
|
||||
using has_method_value = typename has_method_value_impl<T, X>::type;
|
||||
|
||||
template <typename T>
|
||||
struct has_method_options_impl {
|
||||
template <typename U, typename V = decltype(std::declval<const U&>().options())>
|
||||
static typename std::is_same<V, axis::option_type>::type Test(void*);
|
||||
template <typename U>
|
||||
static std::false_type Test(...);
|
||||
using type = decltype(Test<T>(nullptr));
|
||||
};
|
||||
template <typename T>
|
||||
using has_method_options = typename has_method_options_impl<T>::type;
|
||||
|
||||
BOOST_HISTOGRAM_MAKE_SFINAE(has_allocator, &T::get_allocator);
|
||||
|
||||
BOOST_HISTOGRAM_MAKE_SFINAE(is_indexable, (std::declval<T&>()[0]));
|
||||
@@ -209,18 +223,6 @@ struct is_sample_impl<sample_type<T>> : std::true_type {};
|
||||
template <typename T>
|
||||
using is_sample = is_sample_impl<unqual<T>>;
|
||||
|
||||
template <typename T, typename X>
|
||||
struct has_value_method_with_return_type_convertible_to_x_impl {
|
||||
template <typename U, typename V = decltype(std::declval<U&>().value(0))>
|
||||
static typename std::is_convertible<V, X>::type Test(void*);
|
||||
template <typename U>
|
||||
static std::false_type Test(...);
|
||||
using type = decltype(Test<T>(nullptr));
|
||||
};
|
||||
template <typename T, typename X>
|
||||
using has_value_method_with_return_type_convertible_to_x =
|
||||
typename has_value_method_with_return_type_convertible_to_x_impl<T, X>::type;
|
||||
|
||||
namespace {
|
||||
struct bool_mask_impl {
|
||||
std::vector<bool>& b;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#ifndef BOOST_HISTOGRAM_SAMPLE_HPP
|
||||
#define BOOST_HISTOGRAM_SAMPLE_HPP
|
||||
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
@@ -18,10 +19,10 @@ struct sample_type {
|
||||
T value;
|
||||
};
|
||||
|
||||
/// Helper function to mark argument as sample
|
||||
template <typename T>
|
||||
sample_type<T> sample(T&& t) {
|
||||
return {std::forward<T>(t)};
|
||||
/// Helper function to mark arguments as sample
|
||||
template <typename... Ts>
|
||||
sample_type<std::tuple<Ts...>> sample(Ts&&... ts) {
|
||||
return {std::make_tuple(std::forward<Ts>(ts)...)};
|
||||
}
|
||||
|
||||
} // namespace histogram
|
||||
|
||||
@@ -20,8 +20,8 @@ struct weight_type {
|
||||
|
||||
/// Helper function to mark argument as weight
|
||||
template <typename T>
|
||||
weight_type<T> weight(T&& t) {
|
||||
return {std::forward<T>(t)};
|
||||
auto weight(T&& t) {
|
||||
return weight_type<T>{std::forward<T>(t)};
|
||||
}
|
||||
|
||||
} // namespace histogram
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
#include <boost/histogram/histogram.hpp>
|
||||
#include <boost/histogram/literals.hpp>
|
||||
#include <boost/histogram/ostream_operators.hpp>
|
||||
#include <boost/histogram/sample.hpp>
|
||||
#include <boost/histogram/storage_adaptor.hpp>
|
||||
#include <boost/histogram/weight.hpp>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
@@ -288,19 +290,16 @@ void run_tests() {
|
||||
// d1 mean
|
||||
{
|
||||
auto h = make_s(Tag(), std::vector<accumulators::mean<>>(), axis::integer<>(0, 2));
|
||||
// TODO
|
||||
// h(0, 1);
|
||||
// h(0, 2);
|
||||
// h(0, 3);
|
||||
// h(1, 2);
|
||||
// h(1, 3);
|
||||
h(0, sample(1));
|
||||
h(0, sample(2));
|
||||
h(0, sample(3));
|
||||
h(sample(2), 1);
|
||||
h(sample(3), 1);
|
||||
|
||||
// BOOST_TEST_EQ(h[0].sum(), 3);
|
||||
// BOOST_TEST_EQ(h[0].value(), 2);
|
||||
// BOOST_TEST_IS_CLOSE(h[0].variance(), 0.666, 1e-2);
|
||||
// BOOST_TEST_EQ(h[1].sum(), 2);
|
||||
// BOOST_TEST_EQ(h[1].value(), 2.5);
|
||||
// BOOST_TEST_IS_CLOSE(h[1].variance(), 0.25, 1e-2);
|
||||
BOOST_TEST_EQ(h[0].sum(), 3);
|
||||
BOOST_TEST_EQ(h[0].value(), 2);
|
||||
BOOST_TEST_EQ(h[1].sum(), 2);
|
||||
BOOST_TEST_EQ(h[1].value(), 2.5);
|
||||
}
|
||||
|
||||
// d2
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <boost/histogram/axis/variant.hpp>
|
||||
#include <boost/histogram/detail/meta.hpp>
|
||||
#include <boost/histogram/literals.hpp>
|
||||
#include <boost/histogram/sample.hpp>
|
||||
#include <boost/histogram/weight.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
#include <deque>
|
||||
#include <iterator>
|
||||
@@ -47,51 +49,36 @@ int main() {
|
||||
BOOST_TEST_EQ(decltype(j213)::value, 213);
|
||||
}
|
||||
|
||||
// has_variance_support
|
||||
{
|
||||
struct A {};
|
||||
|
||||
struct B {
|
||||
void value() {}
|
||||
};
|
||||
|
||||
struct C {
|
||||
void variance() {}
|
||||
};
|
||||
|
||||
struct D {
|
||||
void value() {}
|
||||
void variance() {}
|
||||
};
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE((has_variance_support<A>));
|
||||
BOOST_TEST_TRAIT_FALSE((has_variance_support<B>));
|
||||
BOOST_TEST_TRAIT_FALSE((has_variance_support<C>));
|
||||
BOOST_TEST_TRAIT_TRUE((has_variance_support<D>));
|
||||
}
|
||||
|
||||
// has_method_value
|
||||
{
|
||||
struct A {};
|
||||
struct B {
|
||||
void value(int) {}
|
||||
A value(int) const { return {}; }
|
||||
};
|
||||
struct C {
|
||||
char value(int) const { return 0; }
|
||||
};
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE((has_method_value<A>));
|
||||
BOOST_TEST_TRAIT_TRUE((has_method_value<B>));
|
||||
BOOST_TEST_TRAIT_FALSE((has_method_value<A, double>));
|
||||
BOOST_TEST_TRAIT_TRUE((has_method_value<B, A>));
|
||||
BOOST_TEST_TRAIT_FALSE((has_method_value<B, char>));
|
||||
BOOST_TEST_TRAIT_TRUE((has_method_value<C, char>));
|
||||
BOOST_TEST_TRAIT_FALSE((has_method_value<C, A>));
|
||||
}
|
||||
|
||||
// has_method_options
|
||||
{
|
||||
struct A {};
|
||||
struct B {
|
||||
bh::axis::option_type options() { return bh::axis::option_type(); }
|
||||
void options() {}
|
||||
};
|
||||
struct C {
|
||||
bh::axis::option_type options() const { return {}; }
|
||||
};
|
||||
|
||||
auto foo = static_cast<std::function<bh::axis::option_type(B&)>>(&B::options);
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE((has_method_options<A>));
|
||||
BOOST_TEST_TRAIT_TRUE((has_method_options<B>));
|
||||
BOOST_TEST_TRAIT_FALSE((has_method_options<B>));
|
||||
BOOST_TEST_TRAIT_TRUE((has_method_options<C>));
|
||||
}
|
||||
|
||||
// has_method_metadata
|
||||
@@ -436,5 +423,27 @@ int main() {
|
||||
BOOST_TEST_TRAIT_TRUE((is_axis_vector<decltype(std::move(v))>));
|
||||
}
|
||||
|
||||
// is_weight
|
||||
{
|
||||
struct A {};
|
||||
using B = int;
|
||||
using C = decltype(bh::weight(1));
|
||||
BOOST_TEST_TRAIT_FALSE((is_weight<A>));
|
||||
BOOST_TEST_TRAIT_FALSE((is_weight<B>));
|
||||
BOOST_TEST_TRAIT_TRUE((is_weight<C>));
|
||||
}
|
||||
|
||||
// is_sample
|
||||
{
|
||||
struct A {};
|
||||
using B = int;
|
||||
using C = decltype(bh::sample(1));
|
||||
using D = decltype(bh::sample(1, 2.0));
|
||||
BOOST_TEST_TRAIT_FALSE((is_sample<A>));
|
||||
BOOST_TEST_TRAIT_FALSE((is_sample<B>));
|
||||
BOOST_TEST_TRAIT_TRUE((is_sample<C>));
|
||||
BOOST_TEST_TRAIT_TRUE((is_sample<D>));
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user