boost::time_series pre-review questions

I've modified the "simple_moving_average_functor" according to your suggestions of using the boost::circular_buffer container. (see below) I'm still unclear about how to incorporate the offsets, "start" and "stop". It might be easier if you illustrate this by modifying the function "operator()". I'm not shur how to proceed. Also, what should I do with the "finalize()" function. Its required that I implement this part of the interface, but its not needed to calculate the moving_average. Yet, it requires me to return a value. Which value should I return? template<typename out_t> struct simple_moving_average_functor { double total; out_t out; boost::circular_buffer<double> buffer; simple_moving_average_functor(const out_t& out, std::size_t periods) : out(out), total(0), buffer(0) { //BUG: a bug in circular_buffer causes me to resize the //buffer here in the constructor, after initializing it to zero. BOOST_ASSERT(periods > 0); buffer.resize(periods); } template <typename value_t, typename offset_t> void operator ()(const value_t& value, offset_t start, offset_t stop) { if (buffer.full()) { total -= buffer[0]; total += value; out(total/buffer.size(), start,stop); } else { total += value; } buffer.push_back(value); } out_t const &finalize() { } };

Tom Brinkman wrote:
I've modified the "simple_moving_average_functor" according to your suggestions of using the boost::circular_buffer container. (see below)
I'm still unclear about how to incorporate the offsets, "start" and "stop". It might be easier if you illustrate this by modifying the function "operator()". I'm not shur how to proceed.
Hey, no fair! You volunteered! OK, see below. :-)
Also, what should I do with the "finalize()" function. Its required that I implement this part of the interface
Actually, it's not. Like I said, range_run_storage::for_each() requires TernaryFunction, and finalize() is not part of that concept. , but its not needed to
calculate the moving_average.
Actually, it is. Because after the last run, the rolling average will peter out, and this petering will need to be calculated after for_each() has returned. That's why so many of time_series' function objects have finalize() methods---to do any clean-up and calculate any petering out. Yet, it requires me to return a value.
Which value should I return?
When I've needed a finalizer, I've found it to be handy if it returns the internally stored output inserter. Anyway, I've attached my first crack at this problem. It's a little tricky, and it's not 100% there yet, but it should get you going in the right direction. HTH, -- Eric Niebler Boost Consulting www.boost-consulting.com The Astoria Seminar ==> http://www.astoriaseminar.com /////////////////////////////////////////////////////////////////////////////// // Copyright 2006 Eric Niebler. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #define BOOST_CB_TEST // BUGBUG why is this needed? Bug in circular_bummer (sic). #include <iostream> #include <boost/time_series/ordered_inserter.hpp> #include <boost/time_series/piecewise_constant_series.hpp> #include <boost/range_run_storage/algorithm/for_each.hpp> #include <boost/circular_buffer.hpp> using namespace boost; namespace ts = time_series; namespace rrs = range_run_storage; namespace seq = sequence; template<typename Out, typename Series> struct simple_moving_average_functor { typedef ts::concepts::TimeSeries<Series> series_concept; typedef typename series_concept::value_type value_type; typedef typename series_concept::offset_type offset_type; typedef typename numeric::functional::average<value_type, value_type>::result_type average_type; simple_moving_average_functor(Out const &out, Series const &series, std::size_t periods) : out_(out) , zero_(implicit_cast<value_type const &>(rrs::zero(series))) , total_(0) , offset_(-ts::inf) , buffer_(periods) { BOOST_ASSERT(periods > 0); } simple_moving_average_functor(simple_moving_average_functor const &that) : out_(that.out_) , zero_(that.zero_) , total_(that.total_) , offset_(that.offset_) , buffer_(that.buffer_) { this->buffer_.set_capacity(that.buffer_.capacity()); } void operator ()(value_type const &value, offset_type start, offset_type stop) { if(static_cast<std::size_t>(start - this->offset_) > this->buffer_.capacity()) { for(std::size_t i = 0; i < this->buffer_.capacity(); ++i) { this->push_back_(this->zero_); } this->offset_ = start; } else { while(this->offset_ < start) { this->push_back_(this->zero_); } } if(static_cast<std::size_t>(stop - start) > this->buffer_.capacity()) { for(std::size_t i = 0; i < this->buffer_.capacity(); ++i) { this->push_back_(value); } this->out_(value, this->offset_, stop); this->offset_ = stop; } else { while(this->offset_ < stop) { this->push_back_(value); } } } Out const &finalize() { if(this->offset_ != ts::inf) { for(std::size_t i = 0; i < this->buffer_.capacity(); ++i) { this->push_back_(this->zero_); } } return this->out_; } private: void push_back_(value_type const &value) { if(this->buffer_.full()) { this->total_ -= this->buffer_[0]; this->total_ += value; this->out_(numeric::average(this->total_, this->buffer_.capacity()), this->offset_); } else { this->total_ += value; } this->buffer_.push_back(value); ++this->offset_; } Out out_; value_type zero_; value_type total_; offset_type offset_; circular_buffer<average_type> buffer_; }; int main() { ts::piecewise_constant_series<int> pwc1; ts::make_ordered_inserter(pwc1) (-42, -ts::inf, -56) (-10, -10, 0) (10, 1, 10) (42, 56, ts::inf) .commit(); ts::piecewise_constant_series<double> pwc2; ts::ordered_inserter<ts::piecewise_constant_series<double> > out(pwc2); simple_moving_average_functor< ts::ordered_inserter<ts::piecewise_constant_series<double> > , ts::piecewise_constant_series<int> > fun(out, pwc1, 2); // window size == 2 rrs::for_each(pwc1, fun).finalize(); out.commit(); std::cout << pwc1 << std::endl; std::cout << pwc2 << std::endl; return 0; }
participants (2)
-
Eric Niebler
-
Tom Brinkman