mirror of
https://github.com/boostorg/histogram.git
synced 2025-05-09 23:04:07 +00:00
Division support for weighted_sum (#351)
This commit is contained in:
parent
bf7712f0d7
commit
d736aab212
@ -8,6 +8,7 @@
|
|||||||
#define BOOST_HISTOGRAM_ACCUMULATORS_WEIGHTED_SUM_HPP
|
#define BOOST_HISTOGRAM_ACCUMULATORS_WEIGHTED_SUM_HPP
|
||||||
|
|
||||||
#include <boost/core/nvp.hpp>
|
#include <boost/core/nvp.hpp>
|
||||||
|
#include <boost/histogram/detail/square.hpp>
|
||||||
#include <boost/histogram/fwd.hpp> // for weighted_sum<>
|
#include <boost/histogram/fwd.hpp> // for weighted_sum<>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
@ -46,7 +47,7 @@ public:
|
|||||||
/// Increment by weight.
|
/// Increment by weight.
|
||||||
weighted_sum& operator+=(const weight_type<value_type>& w) {
|
weighted_sum& operator+=(const weight_type<value_type>& w) {
|
||||||
sum_of_weights_ += w.value;
|
sum_of_weights_ += w.value;
|
||||||
sum_of_weights_squared_ += w.value * w.value;
|
sum_of_weights_squared_ += detail::square(w.value);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +58,20 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Divide by another weighted sum.
|
||||||
|
weighted_sum& operator/=(const weighted_sum& rhs) {
|
||||||
|
const auto v = sum_of_weights_;
|
||||||
|
const auto w = sum_of_weights_squared_;
|
||||||
|
const auto rv = rhs.sum_of_weights_;
|
||||||
|
const auto rw = rhs.sum_of_weights_squared_;
|
||||||
|
sum_of_weights_ /= rv;
|
||||||
|
// error propagation for independent a, b:
|
||||||
|
// c = a / b: var(c) = (var(a)/a^2 + var(b)/b^2) c^2
|
||||||
|
using detail::square;
|
||||||
|
sum_of_weights_squared_ = (w / square(v) + rw / square(rv)) * square(sum_of_weights_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/// Scale by value.
|
/// Scale by value.
|
||||||
weighted_sum& operator*=(const_reference x) {
|
weighted_sum& operator*=(const_reference x) {
|
||||||
sum_of_weights_ *= x;
|
sum_of_weights_ *= x;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <boost/histogram/accumulators/ostream.hpp>
|
#include <boost/histogram/accumulators/ostream.hpp>
|
||||||
#include <boost/histogram/accumulators/sum.hpp>
|
#include <boost/histogram/accumulators/sum.hpp>
|
||||||
#include <boost/histogram/accumulators/weighted_sum.hpp>
|
#include <boost/histogram/accumulators/weighted_sum.hpp>
|
||||||
|
#include <boost/histogram/detail/square.hpp>
|
||||||
#include <boost/histogram/weight.hpp>
|
#include <boost/histogram/weight.hpp>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "throw_exception.hpp"
|
#include "throw_exception.hpp"
|
||||||
@ -16,9 +17,10 @@
|
|||||||
using namespace boost::histogram;
|
using namespace boost::histogram;
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
|
||||||
|
using w_t = accumulators::weighted_sum<double>;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
{
|
{
|
||||||
using w_t = accumulators::weighted_sum<double>;
|
|
||||||
w_t w;
|
w_t w;
|
||||||
BOOST_TEST_EQ(str(w), "weighted_sum(0, 0)"s);
|
BOOST_TEST_EQ(str(w), "weighted_sum(0, 0)"s);
|
||||||
BOOST_TEST_EQ(str(w, 20, false), " weighted_sum(0, 0)"s);
|
BOOST_TEST_EQ(str(w, 20, false), " weighted_sum(0, 0)"s);
|
||||||
@ -78,5 +80,35 @@ int main() {
|
|||||||
BOOST_TEST_EQ(s_t() += s_t(), s_t());
|
BOOST_TEST_EQ(s_t() += s_t(), s_t());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// division 1
|
||||||
|
{
|
||||||
|
w_t a{1, 2};
|
||||||
|
w_t b{2, 3};
|
||||||
|
|
||||||
|
auto c = a;
|
||||||
|
c /= b;
|
||||||
|
|
||||||
|
BOOST_TEST_EQ(c.value(), 0.5);
|
||||||
|
// error propagation for independent a and b:
|
||||||
|
// var(c)/c^2 = var(a)/a^2 + var(b)/b^2
|
||||||
|
BOOST_TEST_EQ(c.variance() / detail::square(c.value()),
|
||||||
|
a.variance() / detail::square(a.value()) +
|
||||||
|
b.variance() / detail::square(b.value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// division with implicit conversion
|
||||||
|
{
|
||||||
|
w_t a{1, 2};
|
||||||
|
double b = 2;
|
||||||
|
|
||||||
|
auto c = a;
|
||||||
|
c /= b;
|
||||||
|
|
||||||
|
BOOST_TEST_EQ(c.value(), 0.5);
|
||||||
|
// var(b) = b
|
||||||
|
BOOST_TEST_EQ(c.variance() / detail::square(c.value()),
|
||||||
|
a.variance() / detail::square(a.value()) + 1.0 / b);
|
||||||
|
}
|
||||||
|
|
||||||
return boost::report_errors();
|
return boost::report_errors();
|
||||||
}
|
}
|
||||||
|
@ -160,8 +160,8 @@ void run_tests() {
|
|||||||
auto b = make_s(Tag(), std::vector<accumulators::weighted_sum<>>(), ia);
|
auto b = make_s(Tag(), std::vector<accumulators::weighted_sum<>>(), ia);
|
||||||
|
|
||||||
a(0);
|
a(0);
|
||||||
BOOST_TEST_EQ(a.at(0).variance(), 1);
|
|
||||||
b(weight(3), 1);
|
b(weight(3), 1);
|
||||||
|
BOOST_TEST_EQ(a.at(0).variance(), 1);
|
||||||
BOOST_TEST_EQ(b.at(1).variance(), 9);
|
BOOST_TEST_EQ(b.at(1).variance(), 9);
|
||||||
auto c = a;
|
auto c = a;
|
||||||
c += b;
|
c += b;
|
||||||
@ -187,6 +187,50 @@ void run_tests() {
|
|||||||
BOOST_TEST_EQ(d.at(1).variance(), 11);
|
BOOST_TEST_EQ(d.at(1).variance(), 11);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// division operators with weighted storage
|
||||||
|
{
|
||||||
|
using w_t = accumulators::weighted_sum<>;
|
||||||
|
auto ia = axis::integer<int, axis::null_type, axis::option::none_t>(0, 2);
|
||||||
|
auto a = make_s(Tag(), std::vector<w_t>(), ia);
|
||||||
|
auto b = make_s(Tag(), std::vector<w_t>(), ia);
|
||||||
|
|
||||||
|
a(0);
|
||||||
|
a(1, weight(2));
|
||||||
|
b(weight(4), 0);
|
||||||
|
b(weight(3), 1);
|
||||||
|
|
||||||
|
w_t av[2] = {w_t{1, 1}, w_t{2, 4}};
|
||||||
|
w_t bv[2] = {w_t{4, 16}, w_t{3, 9}};
|
||||||
|
BOOST_TEST_EQ(a.at(0), av[0]);
|
||||||
|
BOOST_TEST_EQ(a.at(1), av[1]);
|
||||||
|
BOOST_TEST_EQ(b.at(0), bv[0]);
|
||||||
|
BOOST_TEST_EQ(b.at(1), bv[1]);
|
||||||
|
|
||||||
|
auto c = a;
|
||||||
|
c /= b;
|
||||||
|
|
||||||
|
w_t cv[2] = {av[0], av[1]};
|
||||||
|
cv[0] /= bv[0];
|
||||||
|
cv[1] /= bv[1];
|
||||||
|
BOOST_TEST_EQ(c.at(0), cv[0]);
|
||||||
|
BOOST_TEST_EQ(c.at(1), cv[1]);
|
||||||
|
|
||||||
|
// division by unweighted histogram
|
||||||
|
auto e = make_s(Tag(), std::vector<double>(), ia);
|
||||||
|
|
||||||
|
e(0);
|
||||||
|
e(0);
|
||||||
|
e(1);
|
||||||
|
|
||||||
|
auto f = a / e;
|
||||||
|
w_t fv[2] = {av[0], av[1]};
|
||||||
|
fv[0] /= e.at(0);
|
||||||
|
fv[1] /= e.at(1);
|
||||||
|
|
||||||
|
BOOST_TEST_EQ(f.at(0), fv[0]);
|
||||||
|
BOOST_TEST_EQ(f.at(1), fv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
// merging add
|
// merging add
|
||||||
{
|
{
|
||||||
using C = axis::category<int, use_default, axis::option::growth_t>;
|
using C = axis::category<int, use_default, axis::option::growth_t>;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user