1 ///////////////////////////////////////////////////////////////////////////////
2 // rolling_mean.hpp
3 // Copyright (C) 2008 Eric Niebler.
4 // Copyright (C) 2012 Pieter Bastiaan Ober (Integricom).
5 // Distributed under the Boost Software License, Version 1.0.
6 // (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 
9 #ifndef BOOST_ACCUMULATORS_STATISTICS_ROLLING_MEAN_HPP_EAN_26_12_2008
10 #define BOOST_ACCUMULATORS_STATISTICS_ROLLING_MEAN_HPP_EAN_26_12_2008
11 
12 #include <boost/mpl/placeholders.hpp>
13 #include <boost/accumulators/framework/accumulator_base.hpp>
14 #include <boost/accumulators/framework/extractor.hpp>
15 #include <boost/accumulators/numeric/functional.hpp>
16 #include <boost/accumulators/framework/parameters/sample.hpp>
17 #include <boost/accumulators/framework/depends_on.hpp>
18 #include <boost/accumulators/statistics_fwd.hpp>
19 #include <boost/accumulators/statistics/rolling_sum.hpp>
20 #include <boost/accumulators/statistics/rolling_count.hpp>
21 
22 namespace boost { namespace accumulators
23 {
24    namespace impl
25    {
26       ///////////////////////////////////////////////////////////////////////////////
27       // lazy_rolling_mean_impl
28       //    returns the mean over the rolling window and is calculated only
29       //    when the result is requested
30       template<typename Sample>
31       struct lazy_rolling_mean_impl
32          : accumulator_base
33       {
34          // for boost::result_of
35          typedef typename numeric::functional::fdiv<Sample, std::size_t, void, void>::result_type result_type;
36 
lazy_rolling_mean_implboost::accumulators::impl::lazy_rolling_mean_impl37          lazy_rolling_mean_impl(dont_care)
38          {
39          }
40 
41          template<typename Args>
resultboost::accumulators::impl::lazy_rolling_mean_impl42          result_type result(Args const &args) const
43          {
44             return numeric::fdiv(rolling_sum(args), rolling_count(args));
45          }
46 
47          // serialization is done by accumulators it depends on
48          template<class Archive>
serializeboost::accumulators::impl::lazy_rolling_mean_impl49          void serialize(Archive & ar, const unsigned int file_version) {}
50       };
51 
52       ///////////////////////////////////////////////////////////////////////////////
53       // immediate_rolling_mean_impl
54       //     The non-lazy version computes the rolling mean recursively when a new
55       //     sample is added
56       template<typename Sample>
57       struct immediate_rolling_mean_impl
58          : accumulator_base
59       {
60          // for boost::result_of
61          typedef typename numeric::functional::fdiv<Sample, std::size_t>::result_type result_type;
62 
63          template<typename Args>
immediate_rolling_mean_implboost::accumulators::impl::immediate_rolling_mean_impl64          immediate_rolling_mean_impl(Args const &args)
65             : mean_(numeric::fdiv(args[sample | Sample()],numeric::one<std::size_t>::value))
66          {
67          }
68 
69          template<typename Args>
operator ()boost::accumulators::impl::immediate_rolling_mean_impl70          void operator()(Args const &args)
71          {
72             if(is_rolling_window_plus1_full(args))
73             {
74                if (rolling_window_plus1(args).front() > args[sample])
75                   mean_ -= numeric::fdiv(rolling_window_plus1(args).front()-args[sample],rolling_count(args));
76                else if (rolling_window_plus1(args).front() < args[sample])
77                   mean_ += numeric::fdiv(args[sample]-rolling_window_plus1(args).front(),rolling_count(args));
78             }
79             else
80             {
81                result_type prev_mean = mean_;
82                if (prev_mean > args[sample])
83                    mean_ -= numeric::fdiv(prev_mean-args[sample],rolling_count(args));
84                else if (prev_mean < args[sample])
85                    mean_ += numeric::fdiv(args[sample]-prev_mean,rolling_count(args));
86             }
87          }
88 
89          template<typename Args>
resultboost::accumulators::impl::immediate_rolling_mean_impl90          result_type result(Args const &) const
91          {
92             return mean_;
93          }
94 
95          // make this accumulator serializeable
96          template<class Archive>
serializeboost::accumulators::impl::immediate_rolling_mean_impl97          void serialize(Archive & ar, const unsigned int file_version)
98          {
99             ar & mean_;
100          }
101 
102       private:
103 
104          result_type mean_;
105       };
106    } // namespace impl
107 
108    ///////////////////////////////////////////////////////////////////////////////
109    // tag::lazy_rolling_mean
110    // tag::immediate_rolling_mean
111    // tag::rolling_mean
112    //
113    namespace tag
114    {
115       struct lazy_rolling_mean
116          : depends_on< rolling_sum, rolling_count >
117       {
118          /// INTERNAL ONLY
119          ///
120          typedef accumulators::impl::lazy_rolling_mean_impl< mpl::_1 > impl;
121 
122 #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
123          /// tag::rolling_window::window_size named parameter
124          static boost::parameter::keyword<tag::rolling_window_size> const window_size;
125 #endif
126       };
127 
128       struct immediate_rolling_mean
129          : depends_on< rolling_window_plus1, rolling_count>
130       {
131          /// INTERNAL ONLY
132          ///
133          typedef accumulators::impl::immediate_rolling_mean_impl< mpl::_1> impl;
134 
135 #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
136          /// tag::rolling_window::window_size named parameter
137          static boost::parameter::keyword<tag::rolling_window_size> const window_size;
138 #endif
139       };
140 
141       // make immediate_rolling_mean the default implementation
142       struct rolling_mean : immediate_rolling_mean {};
143    } // namespace tag
144 
145    ///////////////////////////////////////////////////////////////////////////////
146    // extract::lazy_rolling_mean
147    // extract::immediate_rolling_mean
148    // extract::rolling_mean
149    //
150    namespace extract
151    {
152       extractor<tag::lazy_rolling_mean> const lazy_rolling_mean = {};
153       extractor<tag::immediate_rolling_mean> const immediate_rolling_mean = {};
154       extractor<tag::rolling_mean> const rolling_mean = {};
155 
156       BOOST_ACCUMULATORS_IGNORE_GLOBAL(lazy_rolling_mean)
157          BOOST_ACCUMULATORS_IGNORE_GLOBAL(immediate_rolling_mean)
158          BOOST_ACCUMULATORS_IGNORE_GLOBAL(rolling_mean)
159    }
160 
161    using extract::lazy_rolling_mean;
162    using extract::immediate_rolling_mean;
163    using extract::rolling_mean;
164 
165    // rolling_mean(lazy) -> lazy_rolling_mean
166    template<>
167    struct as_feature<tag::rolling_mean(lazy)>
168    {
169       typedef tag::lazy_rolling_mean type;
170    };
171 
172    // rolling_mean(immediate) -> immediate_rolling_mean
173    template<>
174    struct as_feature<tag::rolling_mean(immediate)>
175    {
176       typedef tag::immediate_rolling_mean type;
177    };
178 
179    // for the purposes of feature-based dependency resolution,
180    // immediate_rolling_mean provides the same feature as rolling_mean
181    template<>
182    struct feature_of<tag::immediate_rolling_mean>
183       : feature_of<tag::rolling_mean>
184    {
185    };
186 
187    // for the purposes of feature-based dependency resolution,
188    // lazy_rolling_mean provides the same feature as rolling_mean
189    template<>
190    struct feature_of<tag::lazy_rolling_mean>
191       : feature_of<tag::rolling_mean>
192    {
193    };
194 }} // namespace boost::accumulators
195 
196 #endif
197