mirror of
https://github.com/boostorg/histogram.git
synced 2025-05-11 05:07:58 +00:00
Merge branch 'master' into reduce
This commit is contained in:
commit
b94d21a46f
26
README.md
26
README.md
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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() &&
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user