1 ///////////////////////////////////////////////////////////////////////////////
2 // weighted_mean.hpp
3 //
4 //  Copyright 2006 Eric Niebler, Olivier Gygi. Distributed under the Boost
5 //  Software License, Version 1.0. (See accompanying file
6 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 
8 #ifndef BOOST_ACCUMULATORS_STATISTICS_WEIGHTED_MEAN_HPP_EAN_03_11_2005
9 #define BOOST_ACCUMULATORS_STATISTICS_WEIGHTED_MEAN_HPP_EAN_03_11_2005
10 
11 #include <boost/mpl/assert.hpp>
12 #include <boost/mpl/eval_if.hpp>
13 #include <boost/mpl/placeholders.hpp>
14 #include <boost/type_traits/is_same.hpp>
15 #include <boost/accumulators/framework/accumulator_base.hpp>
16 #include <boost/accumulators/framework/extractor.hpp>
17 #include <boost/accumulators/numeric/functional.hpp>
18 #include <boost/accumulators/framework/parameters/weights.hpp>
19 #include <boost/accumulators/framework/depends_on.hpp>
20 #include <boost/accumulators/statistics_fwd.hpp>
21 #include <boost/accumulators/statistics/sum.hpp>
22 #include <boost/accumulators/statistics/mean.hpp>
23 #include <boost/accumulators/statistics/weighted_sum.hpp>
24 
25 namespace boost { namespace accumulators
26 {
27 
28 namespace impl
29 {
30     ///////////////////////////////////////////////////////////////////////////////
31     // weighted_mean_impl
32     //      lazy, by default
33     template<typename Sample, typename Weight, typename Tag>
34     struct weighted_mean_impl
35       : accumulator_base
36     {
37         typedef typename numeric::functional::multiplies<Sample, Weight>::result_type weighted_sample;
38         // for boost::result_of
39         typedef typename numeric::functional::fdiv<weighted_sample, Weight>::result_type result_type;
40 
weighted_mean_implboost::accumulators::impl::weighted_mean_impl41         weighted_mean_impl(dont_care) {}
42 
43         template<typename Args>
resultboost::accumulators::impl::weighted_mean_impl44         result_type result(Args const &args) const
45         {
46             typedef
47                 typename mpl::if_<
48                     is_same<Tag, tag::sample>
49                   , tag::weighted_sum
50                   , tag::weighted_sum_of_variates<Sample, Tag>
51                 >::type
52             weighted_sum_tag;
53 
54             extractor<weighted_sum_tag> const some_weighted_sum = {};
55 
56             return numeric::fdiv(some_weighted_sum(args), sum_of_weights(args));
57         }
58     };
59 
60     ///////////////////////////////////////////////////////////////////////////////
61     // immediate_weighted_mean_impl
62     //      immediate
63     template<typename Sample, typename Weight, typename Tag>
64     struct immediate_weighted_mean_impl
65       : accumulator_base
66     {
67         typedef typename numeric::functional::multiplies<Sample, Weight>::result_type weighted_sample;
68         // for boost::result_of
69         typedef typename numeric::functional::fdiv<weighted_sample, Weight>::result_type result_type;
70 
71         template<typename Args>
immediate_weighted_mean_implboost::accumulators::impl::immediate_weighted_mean_impl72         immediate_weighted_mean_impl(Args const &args)
73           : mean(
74                 numeric::fdiv(
75                     args[parameter::keyword<Tag>::get() | Sample()]
76                       * numeric::one<Weight>::value
77                   , numeric::one<Weight>::value
78                 )
79             )
80         {
81         }
82 
83         template<typename Args>
operator ()boost::accumulators::impl::immediate_weighted_mean_impl84         void operator ()(Args const &args)
85         {
86             // Matthias:
87             //  need to pass the argument pack since the weight might be an external
88             //  accumulator set passed as a named parameter
89             Weight w_sum = sum_of_weights(args);
90             Weight w = args[weight];
91             weighted_sample const &s = args[parameter::keyword<Tag>::get()] * w;
92             this->mean = numeric::fdiv(this->mean * (w_sum - w) + s, w_sum);
93         }
94 
resultboost::accumulators::impl::immediate_weighted_mean_impl95         result_type result(dont_care) const
96         {
97             return this->mean;
98         }
99 
100         // make this accumulator serializeable
101         template<class Archive>
serializeboost::accumulators::impl::immediate_weighted_mean_impl102         void serialize(Archive & ar, const unsigned int file_version)
103         {
104             ar & mean;
105         }
106 
107     private:
108         result_type mean;
109     };
110 
111 } // namespace impl
112 
113 ///////////////////////////////////////////////////////////////////////////////
114 // tag::weighted_mean
115 // tag::immediate_weighted_mean
116 //
117 namespace tag
118 {
119     struct weighted_mean
120       : depends_on<sum_of_weights, weighted_sum>
121     {
122         /// INTERNAL ONLY
123         ///
124         typedef accumulators::impl::weighted_mean_impl<mpl::_1, mpl::_2, tag::sample> impl;
125     };
126     struct immediate_weighted_mean
127       : depends_on<sum_of_weights>
128     {
129         /// INTERNAL ONLY
130         ///
131         typedef accumulators::impl::immediate_weighted_mean_impl<mpl::_1, mpl::_2, tag::sample> impl;
132     };
133     template<typename VariateType, typename VariateTag>
134     struct weighted_mean_of_variates
135       : depends_on<sum_of_weights, weighted_sum_of_variates<VariateType, VariateTag> >
136     {
137         /// INTERNAL ONLY
138         ///
139         typedef accumulators::impl::weighted_mean_impl<VariateType, mpl::_2, VariateTag> impl;
140     };
141     template<typename VariateType, typename VariateTag>
142     struct immediate_weighted_mean_of_variates
143       : depends_on<sum_of_weights>
144     {
145         /// INTERNAL ONLY
146         ///
147         typedef accumulators::impl::immediate_weighted_mean_impl<VariateType, mpl::_2, VariateTag> impl;
148     };
149 }
150 
151 ///////////////////////////////////////////////////////////////////////////////
152 // extract::weighted_mean
153 // extract::weighted_mean_of_variates
154 //
155 namespace extract
156 {
157     extractor<tag::mean> const weighted_mean = {};
158     BOOST_ACCUMULATORS_DEFINE_EXTRACTOR(tag, weighted_mean_of_variates, (typename)(typename))
159 
160     BOOST_ACCUMULATORS_IGNORE_GLOBAL(weighted_mean)
161 }
162 
163 using extract::weighted_mean;
164 using extract::weighted_mean_of_variates;
165 
166 // weighted_mean(lazy) -> weighted_mean
167 template<>
168 struct as_feature<tag::weighted_mean(lazy)>
169 {
170     typedef tag::weighted_mean type;
171 };
172 
173 // weighted_mean(immediate) -> immediate_weighted_mean
174 template<>
175 struct as_feature<tag::weighted_mean(immediate)>
176 {
177     typedef tag::immediate_weighted_mean type;
178 };
179 
180 // weighted_mean_of_variates<VariateType, VariateTag>(lazy) -> weighted_mean_of_variates<VariateType, VariateTag>
181 template<typename VariateType, typename VariateTag>
182 struct as_feature<tag::weighted_mean_of_variates<VariateType, VariateTag>(lazy)>
183 {
184     typedef tag::weighted_mean_of_variates<VariateType, VariateTag> type;
185 };
186 
187 // weighted_mean_of_variates<VariateType, VariateTag>(immediate) -> immediate_weighted_mean_of_variates<VariateType, VariateTag>
188 template<typename VariateType, typename VariateTag>
189 struct as_feature<tag::weighted_mean_of_variates<VariateType, VariateTag>(immediate)>
190 {
191     typedef tag::immediate_weighted_mean_of_variates<VariateType, VariateTag> type;
192 };
193 
194 }} // namespace boost::accumulators
195 
196 #endif
197