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 <typename RealType>
20 class weighted_sum {
21 public:
22   weighted_sum() = default;
weighted_sum(const RealType & value)23   explicit weighted_sum(const RealType& value) noexcept
24       : sum_of_weights_(value), sum_of_weights_squared_(value) {}
weighted_sum(const RealType & value,const RealType & variance)25   weighted_sum(const RealType& value, const RealType& variance) noexcept
26       : sum_of_weights_(value), sum_of_weights_squared_(variance) {}
27 
28   /// Increment by one.
operator ++()29   weighted_sum& operator++() { return operator+=(1); }
30 
31   /// Increment by value.
32   template <typename T>
operator +=(const T & value)33   weighted_sum& operator+=(const T& value) {
34     sum_of_weights_ += value;
35     sum_of_weights_squared_ += value * value;
36     return *this;
37   }
38 
39   /// Added another weighted sum.
40   template <typename T>
operator +=(const weighted_sum<T> & rhs)41   weighted_sum& operator+=(const weighted_sum<T>& rhs) {
42     sum_of_weights_ += static_cast<RealType>(rhs.sum_of_weights_);
43     sum_of_weights_squared_ += static_cast<RealType>(rhs.sum_of_weights_squared_);
44     return *this;
45   }
46 
47   /// Scale by value.
operator *=(const RealType & x)48   weighted_sum& operator*=(const RealType& x) {
49     sum_of_weights_ *= x;
50     sum_of_weights_squared_ *= x * x;
51     return *this;
52   }
53 
operator ==(const RealType & rhs) const54   bool operator==(const RealType& rhs) const noexcept {
55     return sum_of_weights_ == rhs && sum_of_weights_squared_ == rhs;
56   }
57 
58   template <typename T>
operator ==(const weighted_sum<T> & rhs) const59   bool operator==(const weighted_sum<T>& rhs) const noexcept {
60     return sum_of_weights_ == rhs.sum_of_weights_ &&
61            sum_of_weights_squared_ == rhs.sum_of_weights_squared_;
62   }
63 
64   template <typename T>
operator !=(const T & rhs) const65   bool operator!=(const T& rhs) const noexcept {
66     return !operator==(rhs);
67   }
68 
69   /// Return value of the sum.
value() const70   const RealType& value() const noexcept { return sum_of_weights_; }
71 
72   /// Return estimated variance of the sum.
variance() const73   const RealType& variance() const noexcept { return sum_of_weights_squared_; }
74 
75   // lossy conversion must be explicit
76   template <class T>
operator T() const77   explicit operator T() const {
78     return static_cast<T>(sum_of_weights_);
79   }
80 
81   template <class Archive>
serialize(Archive & ar,unsigned)82   void serialize(Archive& ar, unsigned /* version */) {
83     ar& make_nvp("sum_of_weights", sum_of_weights_);
84     ar& make_nvp("sum_of_weights_squared", sum_of_weights_squared_);
85   }
86 
87 private:
88   RealType sum_of_weights_ = RealType();
89   RealType sum_of_weights_squared_ = RealType();
90 };
91 
92 } // namespace accumulators
93 } // namespace histogram
94 } // namespace boost
95 
96 #ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED
97 namespace std {
98 template <class T, class U>
99 struct common_type<boost::histogram::accumulators::weighted_sum<T>,
100                    boost::histogram::accumulators::weighted_sum<U>> {
101   using type = boost::histogram::accumulators::weighted_sum<common_type_t<T, U>>;
102 };
103 
104 template <class T, class U>
105 struct common_type<boost::histogram::accumulators::weighted_sum<T>, U> {
106   using type = boost::histogram::accumulators::weighted_sum<common_type_t<T, U>>;
107 };
108 
109 template <class T, class U>
110 struct common_type<T, boost::histogram::accumulators::weighted_sum<U>> {
111   using type = boost::histogram::accumulators::weighted_sum<common_type_t<T, U>>;
112 };
113 } // namespace std
114 #endif
115 
116 #endif
117