|
Boost : |
From: Eric Niebler (eric_at_[hidden])
Date: 2007-07-23 04:16:35
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;
}
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk