mirror of
https://github.com/boostorg/histogram.git
synced 2025-05-12 05:31:51 +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
|
## Features
|
||||||
|
|
||||||
* Multi-dimensional histogram
|
* Multi-dimensional histogram
|
||||||
* Simple and convenient interface
|
* Simple and convenient interface in C++11 and Python
|
||||||
* Value semantics with efficient move operations
|
* Static and dynamic implementation in C++ with unified interface
|
||||||
* Support for various binning schemes (e.g. regular steps in log-scale), user-extensible
|
* Counters cannot overflow or be capped (+)
|
||||||
* Optional underflow/overflow bins for each dimension
|
* Higher performance than other libraries (see benchmarks for details)
|
||||||
* Counts cannot overflow or be capped (+)
|
* 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
|
* Support for weighted input
|
||||||
* Statistical variance can be queried for each bin
|
* Support for underflow/overflow bins for each dimension (can be disabled)
|
||||||
* High performance (see benchmarks)
|
* Support for statistical variance queries with zero overhead (++)
|
||||||
* Efficient use of memory for counters (dynamically grows as needed)
|
* Support for addition of histograms
|
||||||
* Serialization support using `boost.serialization`
|
* Support for serialization using `boost.serialization`
|
||||||
* Language support: C++11, Python 2.x and 3.x
|
* Support for Python 2.x and 3.x
|
||||||
* Numpy support
|
* Support for Numpy in Python
|
||||||
|
|
||||||
(+) In the standard configuration and if you don't use weighted input.
|
(+) In the standard configuration and if you don't use weighted input.
|
||||||
|
(++) Overhead only occurs if you use weighted input.
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
|
@ -46,11 +46,12 @@ A `storage_type` is required to:
|
|||||||
* `std::size_t size() const`
|
* `std::size_t size() const`
|
||||||
* `void increase(std::size_t index)`
|
* `void increase(std::size_t index)`
|
||||||
* `void increase(std::size_t index, value_type n)`
|
* `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 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)`
|
* `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.
|
[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 histogram {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <typename T> struct has_variance {
|
template <typename T> struct supports_weights {
|
||||||
template <typename> static std::false_type test(...);
|
template <typename> static std::false_type test(...);
|
||||||
|
|
||||||
template <typename C>
|
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;
|
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");
|
throw std::logic_error("axes of histograms differ");
|
||||||
}
|
}
|
||||||
for (std::size_t i = 0, n = storage_.size(); i < n; ++i)
|
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;
|
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>>
|
template <typename Iterator, typename = detail::is_iterator<Iterator>>
|
||||||
void fill(Iterator begin, Iterator end, const weight &w) noexcept {
|
void fill(Iterator begin, Iterator end, const weight &w) noexcept {
|
||||||
BOOST_ASSERT_MSG(std::distance(begin, end) == dim(),
|
BOOST_ASSERT_MSG(std::distance(begin, end) == dim(),
|
||||||
@ -182,8 +193,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Indices> value_type variance(Indices... indices) const {
|
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(),
|
BOOST_ASSERT_MSG(sizeof...(indices) == dim(),
|
||||||
"number of arguments does not match histogram dimension");
|
"number of arguments does not match histogram dimension");
|
||||||
std::size_t idx = 0, stride = 1;
|
std::size_t idx = 0, stride = 1;
|
||||||
@ -196,8 +205,6 @@ public:
|
|||||||
|
|
||||||
template <typename Iterator, typename = detail::is_iterator<Iterator>>
|
template <typename Iterator, typename = detail::is_iterator<Iterator>>
|
||||||
value_type variance(Iterator begin, Iterator end) const {
|
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(),
|
BOOST_ASSERT_MSG(std::distance(begin, end) == dim(),
|
||||||
"number of arguments does not match histogram dimension");
|
"number of arguments does not match histogram dimension");
|
||||||
std::size_t idx = 0, stride = 1;
|
std::size_t idx = 0, stride = 1;
|
||||||
|
@ -99,7 +99,7 @@ public:
|
|||||||
throw std::logic_error("axes of histograms differ");
|
throw std::logic_error("axes of histograms differ");
|
||||||
}
|
}
|
||||||
for (std::size_t i = 0, n = storage_.size(); i < n; ++i)
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,8 +127,6 @@ public:
|
|||||||
|
|
||||||
template <typename... Indices>
|
template <typename... Indices>
|
||||||
value_type variance(const Indices &... indices) const {
|
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,
|
static_assert(sizeof...(indices) == axes_size::value,
|
||||||
"number of arguments does not match histogram dimension");
|
"number of arguments does not match histogram dimension");
|
||||||
std::size_t idx = 0, stride = 1;
|
std::size_t idx = 0, stride = 1;
|
||||||
|
@ -10,10 +10,10 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <boost/cstdint.hpp>
|
#include <boost/cstdint.hpp>
|
||||||
#include <boost/histogram/detail/meta.hpp>
|
#include <boost/histogram/detail/meta.hpp>
|
||||||
#include <boost/histogram/detail/variance.hpp>
|
|
||||||
#include <boost/histogram/detail/weight.hpp>
|
#include <boost/histogram/detail/weight.hpp>
|
||||||
#include <boost/multiprecision/cpp_int.hpp>
|
#include <boost/multiprecision/cpp_int.hpp>
|
||||||
#include <boost/variant.hpp>
|
#include <boost/variant.hpp>
|
||||||
|
#include <boost/mpl/int.hpp>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
@ -199,6 +199,19 @@ public:
|
|||||||
apply_visitor(wincrease_visitor(i, weight, buffer_), buffer_);
|
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 {
|
value_type value(std::size_t i) const {
|
||||||
return apply_visitor(value_visitor(i), buffer_);
|
return apply_visitor(value_visitor(i), buffer_);
|
||||||
}
|
}
|
||||||
@ -437,7 +450,7 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
for (std::size_t i = 0; i < b.size; ++i) {
|
for (std::size_t i = 0; i < b.size; ++i) {
|
||||||
auto &x = b[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 false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -70,7 +70,13 @@ public:
|
|||||||
void increase(std::size_t i) { ++(container_[i]); }
|
void increase(std::size_t i) { ++(container_[i]); }
|
||||||
template <typename Value>
|
template <typename Value>
|
||||||
void increase(std::size_t i, const Value& n) { container_[i] += n; }
|
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 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) {
|
template <typename C> bool operator==(const container_storage<C> &rhs) {
|
||||||
return container_.size() == rhs.container_.size() &&
|
return container_.size() == rhs.container_.size() &&
|
||||||
|
@ -345,10 +345,9 @@ int main() {
|
|||||||
BOOST_TEST_EQ(b.value(0), x);
|
BOOST_TEST_EQ(b.value(0), x);
|
||||||
BOOST_TEST_EQ(b.variance(0), x);
|
BOOST_TEST_EQ(b.variance(0), x);
|
||||||
adaptive_storage<> c(1);
|
adaptive_storage<> c(1);
|
||||||
c.weighted_increase(0, 0.0);
|
c.weighted_increase(0, a.value(0));
|
||||||
c.increase(0, a.value(0));
|
|
||||||
BOOST_TEST_EQ(c.value(0), x);
|
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
|
// add_2
|
||||||
{
|
{
|
||||||
auto a = 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(-1, 1));
|
auto b = make_histogram<adaptive_storage<>>(Type(), integer_axis(0, 1));
|
||||||
|
|
||||||
a.fill(0);
|
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;
|
auto c = a;
|
||||||
c += b;
|
c += b;
|
||||||
BOOST_TEST_EQ(c.value(-1), 0);
|
BOOST_TEST_EQ(c.value(-1), 0);
|
||||||
BOOST_TEST_EQ(c.value(0), 3);
|
BOOST_TEST_EQ(c.value(0), 1);
|
||||||
BOOST_TEST_EQ(c.value(1), 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(2), 0);
|
||||||
BOOST_TEST_EQ(c.value(3), 0);
|
|
||||||
auto d = a;
|
auto d = a;
|
||||||
d += b;
|
d += b;
|
||||||
BOOST_TEST_EQ(d.value(-1), 0);
|
BOOST_TEST_EQ(d.value(-1), 0);
|
||||||
BOOST_TEST_EQ(d.value(0), 3);
|
BOOST_TEST_EQ(d.value(0), 1);
|
||||||
BOOST_TEST_EQ(d.value(1), 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(2), 0);
|
||||||
BOOST_TEST_EQ(d.value(3), 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add_3
|
// add_3
|
||||||
|
Loading…
x
Reference in New Issue
Block a user