Merge branch 'master' into reduce

This commit is contained in:
Hans Dembinski 2017-05-30 19:03:23 +02:00
commit b94d21a46f
10 changed files with 69 additions and 77 deletions

View File

@ -17,20 +17,24 @@ Check out the [full documentation](https://htmlpreview.github.io/?https://raw.gi
## Features
* Multi-dimensional histogram
* Simple and convenient interface
* Value semantics with efficient move operations
* Support for various binning schemes (e.g. regular steps in log-scale), user-extensible
* Optional underflow/overflow bins for each dimension
* Counts cannot overflow or be capped (+)
* Simple and convenient interface in C++11 and Python
* Static and dynamic implementation in C++ with unified interface
* Counters cannot overflow or be capped (+)
* Higher performance than other libraries (see benchmarks for details)
* Efficient move operations
* Efficient conversion between static and dynamic implementation
* Efficient use of memory (counter size dynamically grows as needed)
* Support for many binning schemes (user-extensible)
* Support for weighted input
* Statistical variance can be queried for each bin
* High performance (see benchmarks)
* Efficient use of memory for counters (dynamically grows as needed)
* Serialization support using `boost.serialization`
* Language support: C++11, Python 2.x and 3.x
* Numpy support
* Support for underflow/overflow bins for each dimension (can be disabled)
* Support for statistical variance queries with zero overhead (++)
* Support for addition of histograms
* Support for serialization using `boost.serialization`
* Support for Python 2.x and 3.x
* Support for Numpy in Python
(+) In the standard configuration and if you don't use weighted input.
(++) Overhead only occurs if you use weighted input.
## Dependencies

View File

@ -46,11 +46,12 @@ A `storage_type` is required to:
* `std::size_t size() const`
* `void increase(std::size_t index)`
* `void increase(std::size_t index, value_type n)`
* `void add(std::size_t index, const value_type& val, const value_type& var)`
* `value_type value(std::size_t index) const`
* `value_type variance(std::size_t index) const`
To support weighted fills, two additional methods are required:
To support weighted fills, an additional method is required:
* `value_type variance(std::size_t index) const`
* `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

@ -19,11 +19,11 @@ namespace boost {
namespace histogram {
namespace detail {
template <typename T> struct has_variance {
template <typename T> struct supports_weights {
template <typename> static std::false_type test(...);
template <typename C>
static decltype(std::declval<C &>().variance(0), std::true_type{}) test(int);
static decltype(std::declval<C &>().weighted_increase(0, 0.0), std::true_type{}) test(int);
static bool const value = decltype(test<T>(0))::value;
};

View File

@ -1,40 +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_VARIANCE_HPP_
#define _BOOST_HISTOGRAM_DETAIL_VARIANCE_HPP_
#include <boost/histogram/detail/meta.hpp>
namespace boost {
namespace histogram {
namespace detail {
namespace {
template <typename Storage>
typename std::enable_if<has_variance<Storage>::value,
typename Storage::value_type>::type
variance_impl(const Storage &s, std::size_t i) {
return s.variance(i);
} // delegate to Storage implementation
template <typename Storage>
typename std::enable_if<!(has_variance<Storage>::value),
typename Storage::value_type>::type
variance_impl(const Storage &s, std::size_t i) {
return s.value(i);
} // standard Poisson estimate
} // namespace
template <typename Storage>
typename Storage::value_type variance(const Storage &s, std::size_t i) {
return variance_impl<Storage>(s, i);
}
} // namespace detail
} // namespace histogram
} // namespace boost
#endif

View File

@ -122,7 +122,7 @@ public:
throw std::logic_error("axes of histograms differ");
}
for (std::size_t i = 0, n = storage_.size(); i < n; ++i)
storage_.increase(i, rhs.storage_.value(i));
storage_.add(i, rhs.storage_.value(i), rhs.storage_.variance(i));
return *this;
}
@ -147,6 +147,17 @@ public:
}
}
template <typename Iterator, typename = detail::is_iterator<Iterator>>
void fill(Iterator begin, Iterator end, const count &n) noexcept {
BOOST_ASSERT_MSG(std::distance(begin, end) == dim(),
"number of arguments does not match histogram dimension");
std::size_t idx = 0, stride = 1;
apply_lin_iter<detail::xlin>(idx, stride, begin);
if (stride) {
storage_.increase(idx, n);
}
}
template <typename Iterator, typename = detail::is_iterator<Iterator>>
void fill(Iterator begin, Iterator end, const weight &w) noexcept {
BOOST_ASSERT_MSG(std::distance(begin, end) == dim(),
@ -182,8 +193,6 @@ public:
}
template <typename... Indices> value_type variance(Indices... indices) const {
static_assert(detail::has_variance<Storage>::value,
"Storage lacks variance support");
BOOST_ASSERT_MSG(sizeof...(indices) == dim(),
"number of arguments does not match histogram dimension");
std::size_t idx = 0, stride = 1;
@ -196,8 +205,6 @@ public:
template <typename Iterator, typename = detail::is_iterator<Iterator>>
value_type variance(Iterator begin, Iterator end) const {
static_assert(detail::has_variance<Storage>::value,
"Storage lacks variance support");
BOOST_ASSERT_MSG(std::distance(begin, end) == dim(),
"number of arguments does not match histogram dimension");
std::size_t idx = 0, stride = 1;

View File

@ -99,7 +99,7 @@ public:
throw std::logic_error("axes of histograms differ");
}
for (std::size_t i = 0, n = storage_.size(); i < n; ++i)
storage_.increase(i, rhs.storage_.value(i));
storage_.add(i, rhs.storage_.value(i), rhs.storage_.variance(i));
return *this;
}
@ -127,8 +127,6 @@ public:
template <typename... Indices>
value_type variance(const Indices &... indices) const {
static_assert(detail::has_variance<Storage>::value,
"Storage lacks variance support");
static_assert(sizeof...(indices) == axes_size::value,
"number of arguments does not match histogram dimension");
std::size_t idx = 0, stride = 1;

View File

@ -10,10 +10,10 @@
#include <algorithm>
#include <boost/cstdint.hpp>
#include <boost/histogram/detail/meta.hpp>
#include <boost/histogram/detail/variance.hpp>
#include <boost/histogram/detail/weight.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/variant.hpp>
#include <boost/mpl/int.hpp>
#include <limits>
#include <type_traits>
@ -199,6 +199,19 @@ public:
apply_visitor(wincrease_visitor(i, weight, buffer_), buffer_);
}
void add(std::size_t i, const value_type& val, const value_type& var) {
if (val == var) {
apply_visitor(add_visitor<value_type>(i, val, buffer_), buffer_);
} else {
if (!boost::get<array<weight>>(&buffer_)) {
apply_visitor(wincrease_visitor(0, 0.0, buffer_), buffer_);
}
auto& b = boost::get<array<weight>>(buffer_);
b[i].w += val;
b[i].w2 += var;
}
}
value_type value(std::size_t i) const {
return apply_visitor(value_visitor(i), buffer_);
}
@ -437,7 +450,7 @@ private:
return false;
for (std::size_t i = 0; i < b.size; ++i) {
auto &x = b[i];
if (x.w != os.value(i) || x.w2 != detail::variance(os, i))
if (x.w != os.value(i) || x.w2 != os.variance(i))
return false;
}
return true;

View File

@ -70,7 +70,13 @@ public:
void increase(std::size_t i) { ++(container_[i]); }
template <typename Value>
void increase(std::size_t i, const Value& n) { container_[i] += n; }
void add(std::size_t i, const value_type& val, const value_type& /* var */) {
container_[i] += val;
}
value_type value(std::size_t i) const { return container_[i]; }
value_type variance(std::size_t i) const { return container_[i]; }
template <typename C> bool operator==(const container_storage<C> &rhs) {
return container_.size() == rhs.container_.size() &&

View File

@ -345,10 +345,9 @@ int main() {
BOOST_TEST_EQ(b.value(0), x);
BOOST_TEST_EQ(b.variance(0), x);
adaptive_storage<> c(1);
c.weighted_increase(0, 0.0);
c.increase(0, a.value(0));
c.weighted_increase(0, a.value(0));
BOOST_TEST_EQ(c.value(0), x);
BOOST_TEST_EQ(c.variance(0), x);
BOOST_TEST_EQ(c.variance(0), x*x);
}
}

View File

@ -428,25 +428,29 @@ template <typename Type> void run_tests() {
// add_2
{
auto a = make_histogram<adaptive_storage<>>(Type(), integer_axis(-1, 1));
auto b = make_histogram<adaptive_storage<>>(Type(), integer_axis(-1, 1));
auto a = make_histogram<adaptive_storage<>>(Type(), integer_axis(0, 1));
auto b = make_histogram<adaptive_storage<>>(Type(), integer_axis(0, 1));
a.fill(0);
b.fill(weight(3), -1);
BOOST_TEST_EQ(a.variance(0), 1);
b.fill(1, weight(3));
BOOST_TEST_EQ(b.variance(1), 9);
auto c = a;
c += b;
BOOST_TEST_EQ(c.value(-1), 0);
BOOST_TEST_EQ(c.value(0), 3);
BOOST_TEST_EQ(c.value(1), 1);
BOOST_TEST_EQ(c.value(0), 1);
BOOST_TEST_EQ(c.variance(0), 1);
BOOST_TEST_EQ(c.value(1), 3);
BOOST_TEST_EQ(c.variance(1), 9);
BOOST_TEST_EQ(c.value(2), 0);
BOOST_TEST_EQ(c.value(3), 0);
auto d = a;
d += b;
BOOST_TEST_EQ(d.value(-1), 0);
BOOST_TEST_EQ(d.value(0), 3);
BOOST_TEST_EQ(d.value(1), 1);
BOOST_TEST_EQ(d.value(0), 1);
BOOST_TEST_EQ(d.variance(0), 1);
BOOST_TEST_EQ(d.value(1), 3);
BOOST_TEST_EQ(d.variance(1), 9);
BOOST_TEST_EQ(d.value(2), 0);
BOOST_TEST_EQ(d.value(3), 0);
}
// add_3