1 // Copyright 2015-2018 Hans Dembinski
2 //
3 // Distributed under the Boost Software License, version 1.0.
4 // (See accompanying file LICENSE_1_0.txt
5 // or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 #ifndef BOOST_HISTOGRAM_ACCUMULATORS_WEIGHTED_SUM_HPP
8 #define BOOST_HISTOGRAM_ACCUMULATORS_WEIGHTED_SUM_HPP
9 
10 #include <boost/core/nvp.hpp>
11 #include <boost/histogram/fwd.hpp> // for weighted_sum<>
12 #include <type_traits>
13 
14 namespace boost {
15 namespace histogram {
16 namespace accumulators {
17 
18 /// Holds sum of weights and its variance estimate
19 template <class ValueType>
20 class weighted_sum {
21 public:
22   using value_type = ValueType;
23   using const_reference = const value_type&;
24 
25   weighted_sum() = default;
26 
27   /// Initialize sum to value and allow implicit conversion
weighted_sum(const_reference value)28   weighted_sum(const_reference value) noexcept : weighted_sum(value, value) {}
29 
30   /// Allow implicit conversion from sum<T>
31   template <class T>
weighted_sum(const weighted_sum<T> & s)32   weighted_sum(const weighted_sum<T>& s) noexcept
33       : weighted_sum(s.value(), s.variance()) {}
34 
35   /// Initialize sum to value and variance
weighted_sum(const_reference value,const_reference variance)36   weighted_sum(const_reference value, const_reference variance) noexcept
37       : sum_of_weights_(value), sum_of_weights_squared_(variance) {}
38 
39   /// Increment by one.
operator ++()40   weighted_sum& operator++() {
41     ++sum_of_weights_;
42     ++sum_of_weights_squared_;
43     return *this;
44   }
45 
46   /// Increment by weight.
47   template <class T>
operator +=(const weight_type<T> & w)48   weighted_sum& operator+=(const weight_type<T>& w) {
49     sum_of_weights_ += w.value;
50     sum_of_weights_squared_ += w.value * w.value;
51     return *this;
52   }
53 
54   /// Added another weighted sum.
operator +=(const weighted_sum & rhs)55   weighted_sum& operator+=(const weighted_sum& rhs) {
56     sum_of_weights_ += rhs.sum_of_weights_;
57     sum_of_weights_squared_ += rhs.sum_of_weights_squared_;
58     return *this;
59   }
60 
61   /// Scale by value.
operator *=(const_reference x)62   weighted_sum& operator*=(const_reference x) {
63     sum_of_weights_ *= x;
64     sum_of_weights_squared_ *= x * x;
65     return *this;
66   }
67 
operator ==(const weighted_sum & rhs) const68   bool operator==(const weighted_sum& rhs) const noexcept {
69     return sum_of_weights_ == rhs.sum_of_weights_ &&
70            sum_of_weights_squared_ == rhs.sum_of_weights_squared_;
71   }
72 
operator !=(const weighted_sum & rhs) const73   bool operator!=(const weighted_sum& rhs) const noexcept { return !operator==(rhs); }
74 
75   /// Return value of the sum.
value() const76   const_reference value() const noexcept { return sum_of_weights_; }
77 
78   /// Return estimated variance of the sum.
variance() const79   const_reference variance() const noexcept { return sum_of_weights_squared_; }
80 
81   // lossy conversion must be explicit
operator const_reference() const82   explicit operator const_reference() const { return sum_of_weights_; }
83 
84   template <class Archive>
serialize(Archive & ar,unsigned)85   void serialize(Archive& ar, unsigned /* version */) {
86     ar& make_nvp("sum_of_weights", sum_of_weights_);
87     ar& make_nvp("sum_of_weights_squared", sum_of_weights_squared_);
88   }
89 
90 private:
91   value_type sum_of_weights_{};
92   value_type sum_of_weights_squared_{};
93 };
94 
95 } // namespace accumulators
96 } // namespace histogram
97 } // namespace boost
98 
99 #ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED
100 namespace std {
101 template <class T, class U>
102 struct common_type<boost::histogram::accumulators::weighted_sum<T>,
103                    boost::histogram::accumulators::weighted_sum<U>> {
104   using type = boost::histogram::accumulators::weighted_sum<common_type_t<T, U>>;
105 };
106 
107 template <class T, class U>
108 struct common_type<boost::histogram::accumulators::weighted_sum<T>, U> {
109   using type = boost::histogram::accumulators::weighted_sum<common_type_t<T, U>>;
110 };
111 
112 template <class T, class U>
113 struct common_type<T, boost::histogram::accumulators::weighted_sum<U>> {
114   using type = boost::histogram::accumulators::weighted_sum<common_type_t<T, U>>;
115 };
116 } // namespace std
117 #endif
118 
119 #endif
120