Skip to content

Commit ef28b2b

Browse files
committed
sorted rolling window
1 parent fdabe51 commit ef28b2b

3 files changed

Lines changed: 168 additions & 0 deletions

File tree

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
///////////////////////////////////////////////////////////////////////////////
2+
// sorted_rolling_window.hpp
3+
//
4+
// Copyright 2018 Quentin Chateau. 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_SORTED_ROLLING_WINDOW_HPP_QC_20_12_2018
9+
#define BOOST_ACCUMULATORS_STATISTICS_SORTED_ROLLING_WINDOW_HPP_QC_20_12_2018
10+
11+
#include <boost/container/set.hpp>
12+
#include <boost/range/iterator_range.hpp>
13+
#include <boost/accumulators/accumulators_fwd.hpp>
14+
#include <boost/accumulators/framework/extractor.hpp>
15+
#include <boost/accumulators/framework/depends_on.hpp>
16+
#include <boost/accumulators/framework/accumulator_base.hpp>
17+
#include <boost/accumulators/framework/parameters/sample.hpp>
18+
#include <boost/accumulators/framework/parameters/accumulator.hpp>
19+
#include <boost/accumulators/statistics_fwd.hpp>
20+
#include <boost/accumulators/statistics/rolling_window.hpp>
21+
22+
namespace boost { namespace accumulators
23+
{
24+
25+
namespace impl
26+
{
27+
///////////////////////////////////////////////////////////////////////////////
28+
// sorted_rolling_window
29+
// stores the latest N samples, where N is specified at construction time
30+
// with the rolling_window_size named parameter. samples are sorted
31+
// on insersion
32+
template<typename Sample>
33+
struct sorted_rolling_window_impl
34+
: accumulator_base
35+
{
36+
typedef typename container::multiset<Sample>::const_iterator const_iterator;
37+
typedef iterator_range<const_iterator> result_type;
38+
39+
template<typename Args>
40+
sorted_rolling_window_impl(Args const &)
41+
{}
42+
43+
template<typename Args>
44+
void operator ()(Args const &args)
45+
{
46+
if(is_rolling_window_plus1_full(args))
47+
{
48+
const_iterator it = this->sorted_buffer_.find(rolling_window_plus1(args).front());
49+
this->sorted_buffer_.erase(it);
50+
}
51+
this->sorted_buffer_.insert(args[sample]);
52+
}
53+
54+
result_type result(dont_care) const
55+
{
56+
return result_type(this->sorted_buffer_.begin(), this->sorted_buffer_.end());
57+
}
58+
59+
private:
60+
container::multiset<Sample> sorted_buffer_;
61+
};
62+
63+
} // namespace impl
64+
65+
///////////////////////////////////////////////////////////////////////////////
66+
// tag::sorted_rolling_window
67+
//
68+
namespace tag
69+
{
70+
struct sorted_rolling_window
71+
: depends_on< rolling_window_plus1 >
72+
{
73+
/// INTERNAL ONLY
74+
///
75+
typedef accumulators::impl::sorted_rolling_window_impl< mpl::_1 > impl;
76+
77+
#ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
78+
/// tag::sorted_rolling_window::size named parameter
79+
static boost::parameter::keyword<tag::rolling_window_size> const window_size;
80+
#endif
81+
};
82+
83+
} // namespace tag
84+
85+
///////////////////////////////////////////////////////////////////////////////
86+
// extract::sorted_rolling_window
87+
//
88+
namespace extract
89+
{
90+
extractor<tag::sorted_rolling_window> const sorted_rolling_window = {};
91+
92+
BOOST_ACCUMULATORS_IGNORE_GLOBAL(sorted_rolling_window)
93+
}
94+
95+
using extract::sorted_rolling_window;
96+
97+
}} // namespace boost::accumulators
98+
99+
#endif

test/Jamfile.v2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ test-suite "accumulators"
4949
[ run rolling_sum.cpp ]
5050
[ run rolling_mean.cpp ]
5151
[ run skewness.cpp ]
52+
[ run sorted_rolling_window.cpp ]
5253
[ run sum.cpp ]
5354
[ run sum_kahan.cpp ]
5455
[ run tail.cpp ]

test/sorted_rolling_window.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// (C) Copyright Quentin Chateau 2018.
2+
// Use, modification and distribution are subject to the
3+
// Boost Software License, Version 1.0. (See accompanying file
4+
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5+
6+
#include <boost/test/unit_test.hpp>
7+
#include <boost/container/set.hpp>
8+
#include <boost/accumulators/accumulators.hpp>
9+
#include <boost/accumulators/statistics/stats.hpp>
10+
#include <boost/accumulators/statistics/sorted_rolling_window.hpp>
11+
12+
using namespace boost;
13+
using namespace unit_test;
14+
using namespace accumulators;
15+
using namespace container;
16+
17+
typedef accumulator_set<int, stats<tag::sorted_rolling_window> > SortedAccumulator;
18+
19+
///////////////////////////////////////////////////////////////////////////////
20+
// check_equal
21+
//
22+
void check_equal(const multiset<int>& expected, const SortedAccumulator& acc)
23+
{
24+
BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), sorted_rolling_window(acc).begin(), sorted_rolling_window(acc).end());
25+
}
26+
27+
///////////////////////////////////////////////////////////////////////////////
28+
// test_stat
29+
//
30+
void test_stat()
31+
{
32+
SortedAccumulator acc(tag::rolling_window::window_size = 3);
33+
34+
check_equal({}, acc);
35+
36+
acc(1);
37+
check_equal({1}, acc);
38+
39+
acc(3);
40+
check_equal({1, 3}, acc);
41+
42+
acc(5);
43+
check_equal({1, 3, 5}, acc);
44+
45+
acc(7);
46+
check_equal({3, 5, 7}, acc);
47+
48+
acc(6);
49+
check_equal({5, 6, 7}, acc);
50+
51+
acc(7);
52+
check_equal({6, 7, 7}, acc);
53+
54+
acc(1);
55+
check_equal({1, 6, 7}, acc);
56+
}
57+
58+
///////////////////////////////////////////////////////////////////////////////
59+
// init_unit_test_suite
60+
//
61+
test_suite* init_unit_test_suite( int argc, char* argv[] )
62+
{
63+
test_suite *test = BOOST_TEST_SUITE("sorted rolling window test");
64+
65+
test->add(BOOST_TEST_CASE(&test_stat));
66+
67+
return test;
68+
}

0 commit comments

Comments
 (0)