prepare/change interface for point-wise adding

This commit is contained in:
Hans Dembinski 2017-05-05 00:13:44 +02:00
parent cc45928cc8
commit 9606c38a64
8 changed files with 148 additions and 108 deletions

View File

@ -45,13 +45,13 @@ A `storage_type` is required to:
* have the following methods:
* `std::size_t size() const`
* `void increase(std::size_t index)`
* `void increase(std::size_t index, value_type n)`
* `value_type value(std::size_t index) const`
* `storage_type& operator+=(const storage_type& rhs)`
To support weighted fills, two additional methods are required:
* `value_type variance(std::size_t index) const`
* `void increase(std::size_t index, value_type weight)`
* `void weighted_increase(std::size_t index, value_type weight)`
[classref boost::histogram::container_storage] is a simple example of a storage type which does not support weighted fills.

View File

@ -23,11 +23,18 @@ class weight {
public:
explicit weight(double v) : value(v) {}
explicit operator double() const { return value; }
private:
double value;
};
class count {
public:
explicit count(unsigned v) : value(v) {}
explicit operator unsigned() const { return value; }
private:
unsigned value;
};
} // namespace histogram
} // namespace boost

View File

@ -15,7 +15,7 @@
#include <boost/histogram/detail/meta.hpp>
#include <boost/histogram/detail/utility.hpp>
#include <boost/histogram/histogram_fwd.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/count.hpp>
#include <boost/mpl/empty.hpp>
#include <boost/mpl/vector.hpp>
@ -121,17 +121,19 @@ public:
if (!detail::axes_equal(axes_, rhs.axes_)) {
throw std::logic_error("axes of histograms differ");
}
storage_ += rhs.storage_;
for (std::size_t i = 0, n = storage_.size(); i < n; ++i)
storage_.increase(i, rhs.storage_.value(i));
return *this;
}
template <typename... Args> void fill(Args... args) noexcept {
using n_count = typename mpl::count<mpl::vector<Args...>, count>;
using n_weight = typename mpl::count<mpl::vector<Args...>, weight>;
static_assert(n_weight::value <= 1,
"arguments may contain at most one instance of type weight");
BOOST_ASSERT_MSG(sizeof...(args) == dim() + n_weight::value,
static_assert((n_count::value + n_weight::value) <= 1,
"arguments may contain at most one instance of type count or weight");
BOOST_ASSERT_MSG(sizeof...(args) == (dim() + n_count::value + n_weight::value),
"number of arguments does not match histogram dimension");
fill_impl(mpl::bool_<(n_weight::value > 0)>(), args...);
fill_impl(mpl::int_<(n_count::value + 2 * n_weight::value)>(), args...);
}
template <typename Iterator, typename = detail::is_iterator<Iterator>>
@ -152,7 +154,7 @@ public:
std::size_t idx = 0, stride = 1;
apply_lin_iter<detail::xlin>(idx, stride, begin);
if (stride) {
storage_.increase(idx, static_cast<double>(w));
storage_.weighted_increase(idx, static_cast<double>(w));
}
}
@ -250,17 +252,7 @@ private:
}
template <typename... Args>
inline void fill_impl(mpl::true_, const Args &... args) {
std::size_t idx = 0, stride = 1;
double w = 0.0;
apply_lin_w<detail::xlin, 0, Args...>(idx, stride, w, args...);
if (stride) {
storage_.increase(idx, w);
}
}
template <typename... Args>
inline void fill_impl(mpl::false_, const Args &... args) {
inline void fill_impl(mpl::int_<0>, const Args &... args) {
std::size_t idx = 0, stride = 1;
apply_lin<detail::xlin, 0, Args...>(idx, stride, args...);
if (stride) {
@ -268,6 +260,26 @@ private:
}
}
template <typename... Args>
inline void fill_impl(mpl::int_<1>, const Args &... args) {
std::size_t idx = 0, stride = 1;
unsigned n = 0;
apply_lin_x<detail::xlin, 0, unsigned, Args...>(idx, stride, n, args...);
if (stride) {
storage_.increase(idx, n);
}
}
template <typename... Args>
inline void fill_impl(mpl::int_<2>, const Args &... args) {
std::size_t idx = 0, stride = 1;
double w = 0.0;
apply_lin_x<detail::xlin, 0, double, Args...>(idx, stride, w, args...);
if (stride) {
storage_.weighted_increase(idx, w);
}
}
template <template <class, class> class Lin, typename Value>
struct lin_visitor : public static_visitor<void> {
std::size_t &idx;
@ -280,6 +292,9 @@ private:
}
};
template <template <class, class> class Lin, unsigned D>
inline void apply_lin(std::size_t &, std::size_t &) const {}
template <template <class, class> class Lin, unsigned D, typename First,
typename... Rest>
inline void apply_lin(std::size_t &idx, std::size_t &stride, const First &x,
@ -288,29 +303,33 @@ private:
return apply_lin<Lin, D + 1, Rest...>(idx, stride, rest...);
}
template <template <class, class> class Lin, unsigned D>
inline void apply_lin(std::size_t &idx, std::size_t &stride) const {}
template <template <class, class> class Lin, unsigned D, typename X>
inline void apply_lin_x(std::size_t &, std::size_t &, X &) const {}
template <template <class, class> class Lin, unsigned D, typename First,
template <template <class, class> class Lin, unsigned D, typename X, typename First,
typename... Rest>
inline typename std::enable_if<!(std::is_same<First, weight>::value)>::type
apply_lin_w(std::size_t &idx, std::size_t &stride, double &w, const First &x,
inline typename std::enable_if<!(std::is_same<First, weight>::value || std::is_same<First, count>::value)>::type
apply_lin_x(std::size_t &idx, std::size_t &stride, X &x, const First &first,
const Rest &... rest) const {
apply_visitor(lin_visitor<Lin, First>(idx, stride, x), axes_[D]);
return apply_lin_w<Lin, D + 1, Rest...>(idx, stride, w, rest...);
apply_visitor(lin_visitor<Lin, First>(idx, stride, first), axes_[D]);
return apply_lin_x<Lin, D + 1, X, Rest...>(idx, stride, x, rest...);
}
template <template <class, class> class Lin, unsigned D, typename,
template <template <class, class> class Lin, unsigned D, typename X, typename,
typename... Rest>
inline void apply_lin_w(std::size_t &idx, std::size_t &stride, double &w,
const weight &x, const Rest &... rest) const {
w = static_cast<double>(x);
return apply_lin_w<Lin, D, Rest...>(idx, stride, w, rest...);
inline void apply_lin_x(std::size_t &idx, std::size_t &stride, X &x,
const weight &first, const Rest &... rest) const {
x = static_cast<X>(first);
return apply_lin_x<Lin, D, X, Rest...>(idx, stride, x, rest...);
}
template <template <class, class> class Lin, unsigned D>
inline void apply_lin_w(std::size_t &idx, std::size_t &stride,
double &w) const {}
template <template <class, class> class Lin, unsigned D, typename X, typename,
typename... Rest>
inline void apply_lin_x(std::size_t &idx, std::size_t &stride, X &x,
const count &first, const Rest &... rest) const {
x = static_cast<X>(first);
return apply_lin_x<Lin, D, X, Rest...>(idx, stride, x, rest...);
}
template <template <class, class> class Lin, typename Iterator>
void apply_lin_iter(std::size_t &idx, std::size_t &stride,
@ -322,7 +341,8 @@ private:
}
template <typename D, typename A, typename S> friend class histogram;
template <typename K>
friend histogram reduce(const histogram&, const K&);
friend class ::boost::python::access;
friend class ::boost::serialization::access;
template <typename Archive> void serialize(Archive &, unsigned);

View File

@ -26,7 +26,7 @@
#include <boost/histogram/detail/meta.hpp>
#include <boost/histogram/detail/utility.hpp>
#include <boost/histogram/histogram_fwd.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/count.hpp>
#include <boost/mpl/empty.hpp>
#include <boost/mpl/vector.hpp>
@ -98,17 +98,19 @@ public:
if (!detail::axes_equal(axes_, rhs.axes_)) {
throw std::logic_error("axes of histograms differ");
}
storage_ += rhs.storage_;
for (std::size_t i = 0, n = storage_.size(); i < n; ++i)
storage_.increase(i, rhs.storage_.value(i));
return *this;
}
template <typename... Args> void fill(const Args &... args) {
using n_count = typename mpl::count<mpl::vector<Args...>, count>;
using n_weight = typename mpl::count<mpl::vector<Args...>, weight>;
static_assert(n_weight::value <= 1,
"arguments may contain at most one instance of type weight");
static_assert(sizeof...(args) == axes_size::value + n_weight::value,
static_assert((n_count::value + n_weight::value) <= 1,
"arguments may contain at most one instance of type count or weight");
static_assert(sizeof...(args) == (axes_size::value + n_count::value + n_weight::value),
"number of arguments does not match histogram dimension");
fill_impl(mpl::bool_<(n_weight::value > 0)>(), args...);
fill_impl(mpl::int_<(n_count::value + 2 * n_weight::value)>(), args...);
}
template <typename... Indices>
@ -187,7 +189,7 @@ private:
}
template <typename... Args>
inline void fill_impl(mpl::false_, const Args &... args) {
inline void fill_impl(mpl::int_<0>, const Args &... args) {
std::size_t idx = 0, stride = 1;
apply_lin<detail::xlin, 0, Args...>(idx, stride, args...);
if (stride) {
@ -196,15 +198,28 @@ private:
}
template <typename... Args>
inline void fill_impl(mpl::true_, const Args &... args) {
inline void fill_impl(mpl::int_<1>, const Args &... args) {
std::size_t idx = 0, stride = 1;
double w = 0.0;
apply_lin_w<detail::xlin, 0, Args...>(idx, stride, w, args...);
unsigned n = 0;
apply_lin_x<detail::xlin, 0, unsigned, Args...>(idx, stride, n, args...);
if (stride) {
storage_.increase(idx, w);
storage_.increase(idx, n);
}
}
template <typename... Args>
inline void fill_impl(mpl::int_<2>, const Args &... args) {
std::size_t idx = 0, stride = 1;
double w = 0.0;
apply_lin_x<detail::xlin, 0, double, Args...>(idx, stride, w, args...);
if (stride) {
storage_.weighted_increase(idx, w);
}
}
template <template <class, class> class Lin, unsigned D>
inline void apply_lin(std::size_t &, std::size_t &) const {}
template <template <class, class> class Lin, unsigned D, typename First,
typename... Rest>
inline void apply_lin(std::size_t &idx, std::size_t &stride, const First &x,
@ -214,30 +229,34 @@ private:
return apply_lin<Lin, D + 1, Rest...>(idx, stride, rest...);
}
template <template <class, class> class Lin, unsigned D>
inline void apply_lin(std::size_t &idx, std::size_t &stride) const {}
template <template <class, class> class Lin, unsigned D, typename X>
inline void apply_lin_x(std::size_t &, std::size_t &, X &) const {}
template <template <class, class> class Lin, unsigned D, typename First,
typename... Rest>
inline typename std::enable_if<!(std::is_same<First, weight>::value)>::type
apply_lin_w(std::size_t &idx, std::size_t &stride, double &w, const First &x,
template <template <class, class> class Lin, unsigned D, typename X,
typename First, typename... Rest>
inline typename std::enable_if<!(std::is_same<First, weight>::value || std::is_same<First, count>::value)>::type
apply_lin_x(std::size_t &idx, std::size_t &stride, X &x, const First &first,
const Rest &... rest) const {
Lin<typename fusion::result_of::value_at_c<axes_type, D>::type,
First>::apply(idx, stride, fusion::at_c<D>(axes_), x);
return apply_lin_w<Lin, D + 1, Rest...>(idx, stride, w, rest...);
First>::apply(idx, stride, fusion::at_c<D>(axes_), first);
return apply_lin_x<Lin, D + 1, X, Rest...>(idx, stride, x, rest...);
}
template <template <class, class> class Lin, unsigned D, typename,
template <template <class, class> class Lin, unsigned D, typename X, typename,
typename... Rest>
inline void apply_lin_w(std::size_t &idx, std::size_t &stride, double &w,
const weight &x, const Rest &... rest) const {
w = static_cast<double>(x);
return apply_lin_w<Lin, D, Rest...>(idx, stride, w, rest...);
inline void apply_lin_x(std::size_t &idx, std::size_t &stride, X &x,
const weight &first, const Rest &... rest) const {
x = static_cast<X>(first);
return apply_lin_x<Lin, D, X, Rest...>(idx, stride, x, rest...);
}
template <template <class, class> class Lin, unsigned D>
inline void apply_lin_w(std::size_t &idx, std::size_t &stride,
double &w) const {}
template <template <class, class> class Lin, unsigned D, typename X, typename,
typename... Rest>
inline void apply_lin_x(std::size_t &idx, std::size_t &stride, X &x,
const count &first, const Rest &... rest) const {
x = static_cast<X>(first);
return apply_lin_x<Lin, D, X, Rest...>(idx, stride, x, rest...);
}
template <typename D, typename A, typename S> friend class histogram;

View File

@ -188,8 +188,15 @@ public:
apply_visitor(increase_visitor(i, buffer_), buffer_);
}
void increase(std::size_t i, value_type w) {
apply_visitor(wincrease_visitor(i, w, buffer_), buffer_);
template <typename Value>
void increase(std::size_t i, const Value& n) {
apply_visitor(
add_visitor<Value>(i, n, buffer_),
buffer_);
}
void weighted_increase(std::size_t i, value_type weight) {
apply_visitor(wincrease_visitor(i, weight, buffer_), buffer_);
}
value_type value(std::size_t i) const {
@ -200,14 +207,6 @@ public:
return apply_visitor(variance_visitor(i), buffer_);
}
template <typename S> adaptive_storage &operator+=(const S &rhs) {
for (std::size_t i = 0, n = rhs.size(); i < n; ++i)
apply_visitor(
add_visitor<typename S::value_type>(i, rhs.value(i), buffer_),
buffer_);
return *this;
}
bool operator==(const adaptive_storage &rhs) const {
return apply_visitor(bicmp_visitor(), buffer_, rhs.buffer_);
}
@ -359,7 +358,7 @@ private:
void operator()(array<void> &b) const {
if (value > 0) {
buffer = array<uint8_t>(b.size);
(*this)(get<array<uint8_t>>(buffer));
operator()(get<array<uint8_t>>(buffer));
}
}

View File

@ -49,16 +49,16 @@ public:
container_storage(container_storage &&) = default;
container_storage &operator=(container_storage &&) = default;
template <typename OtherStorage, typename = detail::is_storage<OtherStorage>>
explicit container_storage(const OtherStorage &other) {
template <typename S, typename = detail::is_storage<S>>
explicit container_storage(const S &other) {
detail::init(container_, other.size());
for (std::size_t i = 0; i < container_.size(); ++i) {
container_[i] = other.value(i);
}
}
template <typename OtherStorage>
container_storage &operator=(const OtherStorage &other) {
template <typename S>
container_storage &operator=(const S &other) {
detail::init(container_, other.size());
for (std::size_t i = 0; i < container_.size(); ++i) {
container_[i] = other.value(i);
@ -68,15 +68,10 @@ public:
std::size_t size() const { return container_.size(); }
void increase(std::size_t i) { ++(container_[i]); }
void increase(std::size_t i, value_type w) { container_[i] += w; }
template <typename Value>
void increase(std::size_t i, const Value& n) { container_[i] += n; }
value_type value(std::size_t i) const { return container_[i]; }
template <typename OtherStorage> void operator+=(const OtherStorage &other) {
for (std::size_t i = 0; i < container_.size(); ++i) {
container_[i] += other.value(i);
}
}
template <typename C> bool operator==(const container_storage<C> &rhs) {
return container_.size() == rhs.container_.size() &&
std::equal(container_.begin(), container_.end(),

View File

@ -22,7 +22,7 @@ template <typename T> adaptive_storage<> prepare(unsigned n = 1) {
s.increase(0);
const auto tmax = std::numeric_limits<T>::max();
while (s.value(0) < 0.1 * tmax) {
s += s;
s.increase(0, s.value(0));
}
return s;
}
@ -34,7 +34,7 @@ template <> adaptive_storage<> prepare<void>(unsigned n) {
template <> adaptive_storage<> prepare<detail::weight>(unsigned n) {
adaptive_storage<> s(n);
s.increase(0, 1.0);
s.weighted_increase(0, 1.0);
return s;
}
@ -44,7 +44,7 @@ template <> adaptive_storage<> prepare<detail::mp_int>(unsigned n) {
auto tmax = static_cast<double>(std::numeric_limits<uint64_t>::max());
tmax *= 2.0;
while (s.value(0) < tmax) {
s += s;
s.increase(0, s.value(0));
}
return s;
}
@ -170,8 +170,8 @@ template <typename T> void increase_and_grow_impl() {
adaptive_storage<> x(2);
x.increase(0);
n2 += x;
n2 += x;
n2.increase(0, x.value(0));
n2.increase(0, x.value(0));
double v = tmax;
++v;
@ -207,7 +207,7 @@ template <typename T> void convert_container_storage_impl() {
BOOST_TEST(!(b == s));
auto c = aref;
c += s;
c.increase(0, s.value(0));
BOOST_TEST_EQ(c.value(0), 1.0);
BOOST_TEST(c == s);
BOOST_TEST(s == c);
@ -215,7 +215,7 @@ template <typename T> void convert_container_storage_impl() {
container_storage<std::vector<float>> t(1);
t.increase(0);
while (t.value(0) < 1e20)
t += t;
t.increase(0, t.value(0));
auto d = aref;
d = t;
BOOST_TEST(d == t);
@ -234,7 +234,7 @@ template <typename T> void convert_container_storage_impl() {
BOOST_TEST(!(f == s));
auto g = aref;
g += s;
g.increase(0, s.value(0));
BOOST_TEST_EQ(g.value(0), 1.0);
BOOST_TEST(g == s);
BOOST_TEST(s == g);
@ -261,7 +261,7 @@ template <> void convert_container_storage_impl<void>() {
BOOST_TEST(!(a == s));
auto c = aref;
c += s;
c.increase(0, s.value(0));
BOOST_TEST_EQ(c.value(0), 1.0);
BOOST_TEST(c == s);
BOOST_TEST(s == c);
@ -330,23 +330,23 @@ int main() {
double x = 1.0;
adaptive_storage<> y(1);
BOOST_TEST_EQ(y.value(0), 0.0);
a += y;
a.increase(0, y.value(0));
BOOST_TEST_EQ(a.value(0), x);
for (unsigned i = 0; i < 80; ++i) {
a += a;
a.increase(0, a.value(0));
x += x;
adaptive_storage<> b(1);
b += a;
b.increase(0, a.value(0));
BOOST_TEST_EQ(a.value(0), x);
BOOST_TEST_EQ(a.variance(0), x);
BOOST_TEST_EQ(b.value(0), x);
BOOST_TEST_EQ(b.variance(0), x);
b.increase(0, 0.0);
b.weighted_increase(0, 0.0);
BOOST_TEST_EQ(b.value(0), x);
BOOST_TEST_EQ(b.variance(0), x);
adaptive_storage<> c(1);
c.increase(0, 0.0);
c += a;
c.weighted_increase(0, 0.0);
c.increase(0, a.value(0));
BOOST_TEST_EQ(c.value(0), x);
BOOST_TEST_EQ(c.variance(0), x);
}

View File

@ -201,25 +201,25 @@ template <typename Type> void run_tests() {
h.fill(0);
h.fill(0);
h.fill(-1);
h.fill(10);
h.fill(10, count(10));
BOOST_TEST_EQ(h.dim(), 1);
BOOST_TEST_EQ(bins(h.axis(0_c)), 2);
BOOST_TEST_EQ(shape(h.axis(0_c)), 4);
BOOST_TEST_EQ(h.sum(), 4);
BOOST_TEST_EQ(h.sum(), 13);
BOOST_TEST_THROWS(h.value(-2), std::out_of_range);
BOOST_TEST_EQ(h.value(-1), 1.0);
BOOST_TEST_EQ(h.value(0), 2.0);
BOOST_TEST_EQ(h.value(1), 0.0);
BOOST_TEST_EQ(h.value(2), 1.0);
BOOST_TEST_EQ(h.value(2), 10.0);
BOOST_TEST_THROWS(h.value(3), std::out_of_range);
BOOST_TEST_THROWS(h.variance(-2), std::out_of_range);
BOOST_TEST_EQ(h.variance(-1), 1.0);
BOOST_TEST_EQ(h.variance(0), 2.0);
BOOST_TEST_EQ(h.variance(1), 0.0);
BOOST_TEST_EQ(h.variance(2), 1.0);
BOOST_TEST_EQ(h.variance(2), 10.0);
BOOST_TEST_THROWS(h.variance(3), std::out_of_range);
}
@ -230,7 +230,7 @@ template <typename Type> void run_tests() {
h.fill(0);
h.fill(-0);
h.fill(-1);
h.fill(10);
h.fill(10, count(10));
BOOST_TEST_EQ(h.dim(), 1);
BOOST_TEST_EQ(bins(h.axis(0_c)), 2);
@ -276,10 +276,10 @@ template <typename Type> void run_tests() {
auto h = make_histogram<container_storage<std::vector<float>>>(
Type(), regular_axis<>(2, -1, 1));
h.fill(0);
h.fill(weight(2.0), -1.0);
h.fill(count(2.0), -1.0);
h.fill(-1.0);
h.fill(-2.0);
h.fill(weight(5.0), 10.0);
h.fill(count(5.0), 10.0);
BOOST_TEST_EQ(h.sum(), 10);