From ef28b2b1aac744fbf08e3142144a7ddbe40fd394 Mon Sep 17 00:00:00 2001 From: Quentin Chateau Date: Fri, 21 Dec 2018 00:44:00 +0100 Subject: [PATCH 1/4] sorted rolling window --- .../statistics/sorted_rolling_window.hpp | 99 +++++++++++++++++++ test/Jamfile.v2 | 1 + test/sorted_rolling_window.cpp | 68 +++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 include/boost/accumulators/statistics/sorted_rolling_window.hpp create mode 100644 test/sorted_rolling_window.cpp diff --git a/include/boost/accumulators/statistics/sorted_rolling_window.hpp b/include/boost/accumulators/statistics/sorted_rolling_window.hpp new file mode 100644 index 0000000..56e7638 --- /dev/null +++ b/include/boost/accumulators/statistics/sorted_rolling_window.hpp @@ -0,0 +1,99 @@ +/////////////////////////////////////////////////////////////////////////////// +// sorted_rolling_window.hpp +// +// Copyright 2018 Quentin Chateau. 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) + +#ifndef BOOST_ACCUMULATORS_STATISTICS_SORTED_ROLLING_WINDOW_HPP_QC_20_12_2018 +#define BOOST_ACCUMULATORS_STATISTICS_SORTED_ROLLING_WINDOW_HPP_QC_20_12_2018 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace accumulators +{ + +namespace impl +{ + /////////////////////////////////////////////////////////////////////////////// + // sorted_rolling_window + // stores the latest N samples, where N is specified at construction time + // with the rolling_window_size named parameter. samples are sorted + // on insersion + template + struct sorted_rolling_window_impl + : accumulator_base + { + typedef typename container::multiset::const_iterator const_iterator; + typedef iterator_range result_type; + + template + sorted_rolling_window_impl(Args const &) + {} + + template + void operator ()(Args const &args) + { + if(is_rolling_window_plus1_full(args)) + { + const_iterator it = this->sorted_buffer_.find(rolling_window_plus1(args).front()); + this->sorted_buffer_.erase(it); + } + this->sorted_buffer_.insert(args[sample]); + } + + result_type result(dont_care) const + { + return result_type(this->sorted_buffer_.begin(), this->sorted_buffer_.end()); + } + + private: + container::multiset sorted_buffer_; + }; + +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +// tag::sorted_rolling_window +// +namespace tag +{ + struct sorted_rolling_window + : depends_on< rolling_window_plus1 > + { + /// INTERNAL ONLY + /// + typedef accumulators::impl::sorted_rolling_window_impl< mpl::_1 > impl; + + #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED + /// tag::sorted_rolling_window::size named parameter + static boost::parameter::keyword const window_size; + #endif + }; + +} // namespace tag + +/////////////////////////////////////////////////////////////////////////////// +// extract::sorted_rolling_window +// +namespace extract +{ + extractor const sorted_rolling_window = {}; + + BOOST_ACCUMULATORS_IGNORE_GLOBAL(sorted_rolling_window) +} + +using extract::sorted_rolling_window; + +}} // namespace boost::accumulators + +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 56cab5d..d8cb39e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -49,6 +49,7 @@ test-suite "accumulators" [ run rolling_sum.cpp ] [ run rolling_mean.cpp ] [ run skewness.cpp ] + [ run sorted_rolling_window.cpp ] [ run sum.cpp ] [ run sum_kahan.cpp ] [ run tail.cpp ] diff --git a/test/sorted_rolling_window.cpp b/test/sorted_rolling_window.cpp new file mode 100644 index 0000000..c07e4f5 --- /dev/null +++ b/test/sorted_rolling_window.cpp @@ -0,0 +1,68 @@ +// (C) Copyright Quentin Chateau 2018. +// Use, modification and distribution are subject to 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) + +#include +#include +#include +#include +#include + +using namespace boost; +using namespace unit_test; +using namespace accumulators; +using namespace container; + +typedef accumulator_set > SortedAccumulator; + +/////////////////////////////////////////////////////////////////////////////// +// check_equal +// +void check_equal(const multiset& expected, const SortedAccumulator& acc) +{ + BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), sorted_rolling_window(acc).begin(), sorted_rolling_window(acc).end()); +} + +/////////////////////////////////////////////////////////////////////////////// +// test_stat +// +void test_stat() +{ + SortedAccumulator acc(tag::rolling_window::window_size = 3); + + check_equal({}, acc); + + acc(1); + check_equal({1}, acc); + + acc(3); + check_equal({1, 3}, acc); + + acc(5); + check_equal({1, 3, 5}, acc); + + acc(7); + check_equal({3, 5, 7}, acc); + + acc(6); + check_equal({5, 6, 7}, acc); + + acc(7); + check_equal({6, 7, 7}, acc); + + acc(1); + check_equal({1, 6, 7}, acc); +} + +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("sorted rolling window test"); + + test->add(BOOST_TEST_CASE(&test_stat)); + + return test; +} From bf79b097cc1d435cff13fde00854cc2f219cfbe5 Mon Sep 17 00:00:00 2001 From: Quentin Chateau Date: Fri, 21 Dec 2018 01:07:35 +0100 Subject: [PATCH 2/4] rolling min and max --- doc/accumulators.qbk | 93 +++++++++++++++++++ .../accumulators/statistics/rolling_max.hpp | 77 +++++++++++++++ .../accumulators/statistics/rolling_min.hpp | 77 +++++++++++++++ test/Jamfile.v2 | 2 + test/rolling_max.cpp | 61 ++++++++++++ test/rolling_min.cpp | 58 ++++++++++++ 6 files changed, 368 insertions(+) create mode 100644 include/boost/accumulators/statistics/rolling_max.hpp create mode 100644 include/boost/accumulators/statistics/rolling_min.hpp create mode 100644 test/rolling_max.cpp create mode 100644 test/rolling_min.cpp diff --git a/doc/accumulators.qbk b/doc/accumulators.qbk index 7e6d1f4..8d07a30 100644 --- a/doc/accumulators.qbk +++ b/doc/accumulators.qbk @@ -2077,6 +2077,99 @@ The rolling count is the current number of elements in the rolling window. [endsect] +[section:rolling_max rolling_max] + +The rolling sum is the sum of the last /N/ samples. + +[variablelist + [[Result Type] [``_sample_type_``]] + [[Depends On] [`sorted_rolling_window`]] + [[Variants] [['none]]] + [[Initialization Parameters] [`tag::rolling_window::window_size`]] + [[Accumulator Parameters] [['none]]] + [[Extractor Parameters] [['none]]] + [[Accumulator Complexity] [O(log N), where N is the window size]] + [[Extractor Complexity] [O(1)]] +] + +[*Header] +[def _ROLLING_MAX_HPP_ [headerref boost/accumulators/statistics/rolling_max.hpp]] + + #include <_ROLLING_MAX_HPP_> + +[*Example] + + accumulator_set > acc(tag::rolling_window::window_size = 3); + + acc(1); + BOOST_CHECK_EQUAL(1, rolling_max(acc)); + + acc(2); + BOOST_CHECK_EQUAL(2, rolling_max(acc)); + + acc(3); + BOOST_CHECK_EQUAL(3, rolling_max(acc)); + + acc(1); + BOOST_CHECK_EQUAL(3, rolling_max(acc)); + + acc(-1); + BOOST_CHECK_EQUAL(1, rolling_max(acc)); + + acc(0); + BOOST_CHECK_EQUAL(1, rolling_max(acc)); + +[*See also] + +* [classref boost::accumulators::impl::rolling_max_impl [^rolling_max_impl]] + +[endsect] + +[section:rolling_min rolling_min] + +The rolling sum is the sum of the last /N/ samples. + +[variablelist + [[Result Type] [``_sample_type_``]] + [[Depends On] [`sorted_rolling_window`]] + [[Variants] [['none]]] + [[Initialization Parameters] [`tag::rolling_window::window_size`]] + [[Accumulator Parameters] [['none]]] + [[Extractor Parameters] [['none]]] + [[Accumulator Complexity] [O(log N), where N is the window size]] + [[Extractor Complexity] [O(1)]] +] + +[*Header] +[def _ROLLING_MIN_HPP_ [headerref boost/accumulators/statistics/rolling_min.hpp]] + + #include <_ROLLING_MIN_HPP_> + +[*Example] + + accumulator_set > acc(tag::rolling_window::window_size = 3); + + acc(1); + BOOST_CHECK_EQUAL(1, rolling_min(acc)); + + acc(2); + BOOST_CHECK_EQUAL(1, rolling_min(acc)); + + acc(3); + BOOST_CHECK_EQUAL(1, rolling_min(acc)); + + acc(4); + BOOST_CHECK_EQUAL(2, rolling_min(acc)); + + acc(-1); + BOOST_CHECK_EQUAL(-1, rolling_min(acc)); + +[*See also] + +* [classref boost::accumulators::impl::rolling_min_impl [^rolling_min_impl]] + +[endsect] + [section:rolling_sum rolling_sum] The rolling sum is the sum of the last /N/ samples. diff --git a/include/boost/accumulators/statistics/rolling_max.hpp b/include/boost/accumulators/statistics/rolling_max.hpp new file mode 100644 index 0000000..e24c48e --- /dev/null +++ b/include/boost/accumulators/statistics/rolling_max.hpp @@ -0,0 +1,77 @@ +/////////////////////////////////////////////////////////////////////////////// +// rolling_max.hpp +// +// Copyright 2018 Quentin Chateau. 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) + +#ifndef BOOST_ACCUMULATORS_STATISTICS_ROLLING_MAX_HPP_QC_20_12_2018 +#define BOOST_ACCUMULATORS_STATISTICS_ROLLING_MAX_HPP_QC_20_12_2018 + +#include +#include +#include +#include +#include +#include + +namespace boost { namespace accumulators +{ + +namespace impl +{ + /////////////////////////////////////////////////////////////////////////////// + // rolling_max_impl + template + struct rolling_max_impl + : accumulator_base + { + // for boost::result_of + typedef Sample result_type; + + rolling_max_impl(dont_care) + { + } + + template + result_type result(Args const &args) const + { + if (sorted_rolling_window(args).empty()) + { + return numeric::as_min(Sample()); + } + return sorted_rolling_window(args).back(); + } + }; + +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +// tag::rolling_max +// +namespace tag +{ + struct rolling_max + : depends_on< sorted_rolling_window > + { + /// INTERNAL ONLY + /// + typedef accumulators::impl::rolling_max_impl impl; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// extract::rolling_max +// +namespace extract +{ + extractor const rolling_max = {}; + + BOOST_ACCUMULATORS_IGNORE_GLOBAL(rolling_max) +} + +using extract::rolling_max; + +}} // namespace boost::accumulators + +#endif diff --git a/include/boost/accumulators/statistics/rolling_min.hpp b/include/boost/accumulators/statistics/rolling_min.hpp new file mode 100644 index 0000000..9d0adfb --- /dev/null +++ b/include/boost/accumulators/statistics/rolling_min.hpp @@ -0,0 +1,77 @@ +/////////////////////////////////////////////////////////////////////////////// +// rolling_min.hpp +// +// Copyright 2018 Quentin Chateau. 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) + +#ifndef BOOST_ACCUMULATORS_STATISTICS_ROLLING_MIN_HPP_QC_20_12_2018 +#define BOOST_ACCUMULATORS_STATISTICS_ROLLING_MIN_HPP_QC_20_12_2018 + +#include +#include +#include +#include +#include +#include + +namespace boost { namespace accumulators +{ + +namespace impl +{ + /////////////////////////////////////////////////////////////////////////////// + // rolling_min_impl + template + struct rolling_min_impl + : accumulator_base + { + // for boost::result_of + typedef Sample result_type; + + rolling_min_impl(dont_care) + { + } + + template + result_type result(Args const &args) const + { + if (sorted_rolling_window(args).empty()) + { + return numeric::as_max(Sample()); + } + return sorted_rolling_window(args).front(); + } + }; + +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +// tag::rolling_min +// +namespace tag +{ + struct rolling_min + : depends_on< sorted_rolling_window > + { + /// INTERNAL ONLY + /// + typedef accumulators::impl::rolling_min_impl impl; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// extract::rolling_min +// +namespace extract +{ + extractor const rolling_min = {}; + + BOOST_ACCUMULATORS_IGNORE_GLOBAL(rolling_min) +} + +using extract::rolling_min; + +}} // namespace boost::accumulators + +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index d8cb39e..2b7f84c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -47,7 +47,9 @@ test-suite "accumulators" [ run reference.cpp ] [ run rolling_count.cpp ] [ run rolling_sum.cpp ] + [ run rolling_max.cpp ] [ run rolling_mean.cpp ] + [ run rolling_min.cpp ] [ run skewness.cpp ] [ run sorted_rolling_window.cpp ] [ run sum.cpp ] diff --git a/test/rolling_max.cpp b/test/rolling_max.cpp new file mode 100644 index 0000000..697b994 --- /dev/null +++ b/test/rolling_max.cpp @@ -0,0 +1,61 @@ +// (C) Copyright Quentin Chateau 2018. +// Use, modification and distribution are subject to 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) + +#include +#include +#include +#include +#include + +using namespace boost; +using namespace unit_test; +using namespace accumulators; +using namespace container; + +/////////////////////////////////////////////////////////////////////////////// +// test_stat +// +void test_stat() +{ + accumulator_set > acc(tag::rolling_window::window_size = 3); + + BOOST_CHECK_EQUAL(numeric::as_min(int()), rolling_max(acc)); + + acc(1); + BOOST_CHECK_EQUAL(1, rolling_max(acc)); + + acc(3); + BOOST_CHECK_EQUAL(3, rolling_max(acc)); + + acc(5); + BOOST_CHECK_EQUAL(5, rolling_max(acc)); + + acc(7); + BOOST_CHECK_EQUAL(7, rolling_max(acc)); + + acc(6); + BOOST_CHECK_EQUAL(7, rolling_max(acc)); + + acc(1); + BOOST_CHECK_EQUAL(7, rolling_max(acc)); + + acc(3); + BOOST_CHECK_EQUAL(6, rolling_max(acc)); + + acc(2); + BOOST_CHECK_EQUAL(3, rolling_max(acc)); +} + +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("rolling max test"); + + test->add(BOOST_TEST_CASE(&test_stat)); + + return test; +} diff --git a/test/rolling_min.cpp b/test/rolling_min.cpp new file mode 100644 index 0000000..726f53a --- /dev/null +++ b/test/rolling_min.cpp @@ -0,0 +1,58 @@ +// (C) Copyright Quentin Chateau 2018. +// Use, modification and distribution are subject to 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) + +#include +#include +#include +#include +#include + +using namespace boost; +using namespace unit_test; +using namespace accumulators; +using namespace container; + +/////////////////////////////////////////////////////////////////////////////// +// test_stat +// +void test_stat() +{ + accumulator_set > acc(tag::rolling_window::window_size = 3); + + BOOST_CHECK_EQUAL(numeric::as_max(int()), rolling_min(acc)); + + acc(1); + BOOST_CHECK_EQUAL(1, rolling_min(acc)); + + acc(3); + BOOST_CHECK_EQUAL(1, rolling_min(acc)); + + acc(5); + BOOST_CHECK_EQUAL(1, rolling_min(acc)); + + acc(7); + BOOST_CHECK_EQUAL(3, rolling_min(acc)); + + acc(6); + BOOST_CHECK_EQUAL(5, rolling_min(acc)); + + acc(7); + BOOST_CHECK_EQUAL(6, rolling_min(acc)); + + acc(1); + BOOST_CHECK_EQUAL(1, rolling_min(acc));\ +} + +/////////////////////////////////////////////////////////////////////////////// +// init_unit_test_suite +// +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite *test = BOOST_TEST_SUITE("rolling min test"); + + test->add(BOOST_TEST_CASE(&test_stat)); + + return test; +} From e43575ccf6cc938280a120290386ffbf8e6a2be2 Mon Sep 17 00:00:00 2001 From: Quentin Chateau Date: Mon, 24 Dec 2018 11:08:22 +0100 Subject: [PATCH 3/4] Fixed rolling_window extractor beeing declared after use in the TU --- .../statistics/rolling_window.hpp | 56 ++++++++++++------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/include/boost/accumulators/statistics/rolling_window.hpp b/include/boost/accumulators/statistics/rolling_window.hpp index 2e0a334..cdb7743 100644 --- a/include/boost/accumulators/statistics/rolling_window.hpp +++ b/include/boost/accumulators/statistics/rolling_window.hpp @@ -93,6 +93,43 @@ namespace impl return find_accumulator(args[accumulator]).full(); } +} // namespace impl + +/////////////////////////////////////////////////////////////////////////////// +// tag::rolling_window_plus1 +// +namespace tag +{ + struct rolling_window_plus1 + : depends_on<> + , tag::rolling_window_size + { + /// INTERNAL ONLY + /// + typedef accumulators::impl::rolling_window_plus1_impl< mpl::_1 > impl; + + #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED + /// tag::rolling_window::size named parameter + static boost::parameter::keyword const window_size; + #endif + }; + +} // namespace tag + +/////////////////////////////////////////////////////////////////////////////// +// extract::rolling_window_plus1 +// +namespace extract +{ + extractor const rolling_window_plus1 = {}; + + BOOST_ACCUMULATORS_IGNORE_GLOBAL(rolling_window_plus1) +} + +using extract::rolling_window_plus1; + +namespace impl +{ /////////////////////////////////////////////////////////////////////////////// // rolling_window_impl // stores the latest N samples, where N is specified at construction type @@ -117,25 +154,10 @@ namespace impl } // namespace impl /////////////////////////////////////////////////////////////////////////////// -// tag::rolling_window_plus1 // tag::rolling_window // namespace tag { - struct rolling_window_plus1 - : depends_on<> - , tag::rolling_window_size - { - /// INTERNAL ONLY - /// - typedef accumulators::impl::rolling_window_plus1_impl< mpl::_1 > impl; - - #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED - /// tag::rolling_window::size named parameter - static boost::parameter::keyword const window_size; - #endif - }; - struct rolling_window : depends_on< rolling_window_plus1 > { @@ -152,19 +174,15 @@ namespace tag } // namespace tag /////////////////////////////////////////////////////////////////////////////// -// extract::rolling_window_plus1 // extract::rolling_window // namespace extract { - extractor const rolling_window_plus1 = {}; extractor const rolling_window = {}; - BOOST_ACCUMULATORS_IGNORE_GLOBAL(rolling_window_plus1) BOOST_ACCUMULATORS_IGNORE_GLOBAL(rolling_window) } -using extract::rolling_window_plus1; using extract::rolling_window; }} // namespace boost::accumulators From 5f7d12c121d4954df3d060faeea724548a9bbc03 Mon Sep 17 00:00:00 2001 From: Quentin Chateau Date: Mon, 24 Dec 2018 11:25:39 +0100 Subject: [PATCH 4/4] Added lazy/immediate implementations for rolling min and max --- doc/accumulators.qbk | 34 ++++--- .../accumulators/statistics/rolling_max.hpp | 96 ++++++++++++++++++- .../accumulators/statistics/rolling_min.hpp | 96 ++++++++++++++++++- test/rolling_max.cpp | 29 +++++- test/rolling_min.cpp | 31 ++++-- 5 files changed, 253 insertions(+), 33 deletions(-) diff --git a/doc/accumulators.qbk b/doc/accumulators.qbk index 8d07a30..0cb3455 100644 --- a/doc/accumulators.qbk +++ b/doc/accumulators.qbk @@ -2079,17 +2079,21 @@ The rolling count is the current number of elements in the rolling window. [section:rolling_max rolling_max] -The rolling sum is the sum of the last /N/ samples. +The rolling max is the max of the last /N/ samples. [variablelist [[Result Type] [``_sample_type_``]] - [[Depends On] [`sorted_rolling_window`]] - [[Variants] [['none]]] + [[Depends On] [`lazy_rolling_max` depends on `rolling_window` \n + `immediate_rolling_max` depends on `sorted_rolling_window`]] + [[Variants] [`lazy_rolling_max` (a.k.a. `rolling_max(lazy)`) \n + `immediate_rolling_max` (a.k.a. `rolling_max(immediate)`)]] [[Initialization Parameters] [`tag::rolling_window::window_size`]] [[Accumulator Parameters] [['none]]] [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(log N), where N is the window size]] - [[Extractor Complexity] [O(1)]] + [[Accumulator Complexity] [`lazy_rolling_max` is O(1) \n + `immediate_rolling_max` is O(log N), where N is the window size]] + [[Extractor Complexity] [`lazy_rolling_max` is O(N), where N is the window size \n + `immediate_rolling_max` is O(1)]] ] [*Header] @@ -2121,23 +2125,28 @@ The rolling sum is the sum of the last /N/ samples. [*See also] -* [classref boost::accumulators::impl::rolling_max_impl [^rolling_max_impl]] +* [classref boost::accumulators::impl::lazy_rolling_max_impl [^lazy_rolling_max_impl]] +* [classref boost::accumulators::impl::immediate_rolling_max_impl [^immediate_rolling_max_impl]] [endsect] [section:rolling_min rolling_min] -The rolling sum is the sum of the last /N/ samples. +The rolling min is the min of the last /N/ samples. [variablelist [[Result Type] [``_sample_type_``]] - [[Depends On] [`sorted_rolling_window`]] - [[Variants] [['none]]] + [[Depends On] [`lazy_rolling_min` depends on `rolling_window` \n + `immediate_rolling_min` depends on `sorted_rolling_window`]] + [[Variants] [`lazy_rolling_min` (a.k.a. `rolling_min(lazy)`) \n + `immediate_rolling_min` (a.k.a. `rolling_min(immediate)`)]] [[Initialization Parameters] [`tag::rolling_window::window_size`]] [[Accumulator Parameters] [['none]]] [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(log N), where N is the window size]] - [[Extractor Complexity] [O(1)]] + [[Accumulator Complexity] [`lazy_rolling_min` is O(1) \n + `immediate_rolling_min` is O(log N), where N is the window size]] + [[Extractor Complexity] [`lazy_rolling_min` is O(N), where N is the window size \n + `immediate_rolling_min` is O(1)]] ] [*Header] @@ -2166,7 +2175,8 @@ The rolling sum is the sum of the last /N/ samples. [*See also] -* [classref boost::accumulators::impl::rolling_min_impl [^rolling_min_impl]] +* [classref boost::accumulators::impl::lazy_rolling_min_impl [^lazy_rolling_min_impl]] +* [classref boost::accumulators::impl::immediate_rolling_min_impl [^immediate_rolling_min_impl]] [endsect] diff --git a/include/boost/accumulators/statistics/rolling_max.hpp b/include/boost/accumulators/statistics/rolling_max.hpp index e24c48e..c3b57b7 100644 --- a/include/boost/accumulators/statistics/rolling_max.hpp +++ b/include/boost/accumulators/statistics/rolling_max.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace boost { namespace accumulators @@ -21,15 +22,16 @@ namespace boost { namespace accumulators namespace impl { /////////////////////////////////////////////////////////////////////////////// - // rolling_max_impl + // immediate_rolling_max_impl + // max is calculated on insersion using a sorted_rolling_window template - struct rolling_max_impl + struct immediate_rolling_max_impl : accumulator_base { // for boost::result_of typedef Sample result_type; - rolling_max_impl(dont_care) + immediate_rolling_max_impl(dont_care) { } @@ -44,20 +46,68 @@ namespace impl } }; + /////////////////////////////////////////////////////////////////////////////// + // lazy_rolling_max_impl + // max is calculated on extraction by iterating the rolling window + template + struct lazy_rolling_max_impl + : accumulator_base + { + // for boost::result_of + typedef Sample result_type; + + lazy_rolling_max_impl(dont_care) + { + } + + template + result_type result(Args const &args) const + { + if (rolling_window(args).empty()) + { + return numeric::as_min(Sample()); + } + return *max_element(rolling_window(args).begin(), rolling_window(args).end()); + } + }; + } // namespace impl /////////////////////////////////////////////////////////////////////////////// +// tag::immediate_rolling_max +// tag::lazy_rolling_max // tag::rolling_max // namespace tag { - struct rolling_max + struct immediate_rolling_max : depends_on< sorted_rolling_window > { /// INTERNAL ONLY /// - typedef accumulators::impl::rolling_max_impl impl; + typedef accumulators::impl::immediate_rolling_max_impl impl; + +#ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED + /// tag::rolling_window::window_size named parameter + static boost::parameter::keyword const window_size; +#endif + }; + + struct lazy_rolling_max + : depends_on< rolling_window > + { + /// INTERNAL ONLY + /// + typedef accumulators::impl::lazy_rolling_max_impl impl; + +#ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED + /// tag::rolling_window::window_size named parameter + static boost::parameter::keyword const window_size; +#endif }; + + // make lazy_rolling_max the default implementation + struct rolling_max : lazy_rolling_max {}; } /////////////////////////////////////////////////////////////////////////////// @@ -65,13 +115,49 @@ namespace tag // namespace extract { + extractor const immediate_rolling_max = {}; + extractor const lazy_rolling_max = {}; extractor const rolling_max = {}; + BOOST_ACCUMULATORS_IGNORE_GLOBAL(immediate_rolling_max) + BOOST_ACCUMULATORS_IGNORE_GLOBAL(lazy_rolling_max) BOOST_ACCUMULATORS_IGNORE_GLOBAL(rolling_max) } +using extract::immediate_rolling_max; +using extract::lazy_rolling_max; using extract::rolling_max; +// rolling_max(lazy) -> lazy_rolling_max +template<> +struct as_feature +{ + typedef tag::lazy_rolling_max type; +}; + +// rolling_max(immediate) -> immediate_rolling_max +template<> +struct as_feature +{ + typedef tag::immediate_rolling_max type; +}; + +// for the purposes of feature-based dependency resolution, +// immediate_rolling_max provides the same feature as rolling_max +template<> +struct feature_of + : feature_of +{ +}; + +// for the purposes of feature-based dependency resolution, +// lazy_rolling_max provides the same feature as rolling_max +template<> +struct feature_of + : feature_of +{ +}; + }} // namespace boost::accumulators #endif diff --git a/include/boost/accumulators/statistics/rolling_min.hpp b/include/boost/accumulators/statistics/rolling_min.hpp index 9d0adfb..c4fa4e0 100644 --- a/include/boost/accumulators/statistics/rolling_min.hpp +++ b/include/boost/accumulators/statistics/rolling_min.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace boost { namespace accumulators @@ -21,15 +22,16 @@ namespace boost { namespace accumulators namespace impl { /////////////////////////////////////////////////////////////////////////////// - // rolling_min_impl + // immediate_rolling_min_impl + // min is calculated on insersion using a sorted_rolling_window template - struct rolling_min_impl + struct immediate_rolling_min_impl : accumulator_base { // for boost::result_of typedef Sample result_type; - rolling_min_impl(dont_care) + immediate_rolling_min_impl(dont_care) { } @@ -44,20 +46,68 @@ namespace impl } }; + /////////////////////////////////////////////////////////////////////////////// + // lazy_rolling_min_impl + // min is calculated on extraction by iterating the rolling window + template + struct lazy_rolling_min_impl + : accumulator_base + { + // for boost::result_of + typedef Sample result_type; + + lazy_rolling_min_impl(dont_care) + { + } + + template + result_type result(Args const &args) const + { + if (rolling_window(args).empty()) + { + return numeric::as_max(Sample()); + } + return *min_element(rolling_window(args).begin(), rolling_window(args).end()); + } + }; + } // namespace impl /////////////////////////////////////////////////////////////////////////////// +// tag::immediate_rolling_min +// tag::lazy_rolling_min // tag::rolling_min // namespace tag { - struct rolling_min + struct immediate_rolling_min : depends_on< sorted_rolling_window > { /// INTERNAL ONLY /// - typedef accumulators::impl::rolling_min_impl impl; + typedef accumulators::impl::immediate_rolling_min_impl impl; + +#ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED + /// tag::rolling_window::window_size named parameter + static boost::parameter::keyword const window_size; +#endif + }; + + struct lazy_rolling_min + : depends_on< rolling_window > + { + /// INTERNAL ONLY + /// + typedef accumulators::impl::lazy_rolling_min_impl impl; + +#ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED + /// tag::rolling_window::window_size named parameter + static boost::parameter::keyword const window_size; +#endif }; + + // make lazy_rolling_min the default implementation + struct rolling_min : lazy_rolling_min {}; } /////////////////////////////////////////////////////////////////////////////// @@ -65,13 +115,49 @@ namespace tag // namespace extract { + extractor const immediate_rolling_min = {}; + extractor const lazy_rolling_min = {}; extractor const rolling_min = {}; + BOOST_ACCUMULATORS_IGNORE_GLOBAL(immediate_rolling_min) + BOOST_ACCUMULATORS_IGNORE_GLOBAL(lazy_rolling_min) BOOST_ACCUMULATORS_IGNORE_GLOBAL(rolling_min) } +using extract::immediate_rolling_min; +using extract::lazy_rolling_min; using extract::rolling_min; +// rolling_min(lazy) -> lazy_rolling_min +template<> +struct as_feature +{ + typedef tag::lazy_rolling_min type; +}; + +// rolling_min(immediate) -> immediate_rolling_min +template<> +struct as_feature +{ + typedef tag::immediate_rolling_min type; +}; + +// for the purposes of feature-based dependency resolution, +// immediate_rolling_min provides the same feature as rolling_min +template<> +struct feature_of + : feature_of +{ +}; + +// for the purposes of feature-based dependency resolution, +// lazy_rolling_min provides the same feature as rolling_min +template<> +struct feature_of + : feature_of +{ +}; + }} // namespace boost::accumulators #endif diff --git a/test/rolling_max.cpp b/test/rolling_max.cpp index 697b994..720560a 100644 --- a/test/rolling_max.cpp +++ b/test/rolling_max.cpp @@ -14,13 +14,14 @@ using namespace unit_test; using namespace accumulators; using namespace container; +size_t window_size = 3; + /////////////////////////////////////////////////////////////////////////////// -// test_stat +// test_impl // -void test_stat() +template +void test_impl(Accumulator& acc) { - accumulator_set > acc(tag::rolling_window::window_size = 3); - BOOST_CHECK_EQUAL(numeric::as_min(int()), rolling_max(acc)); acc(1); @@ -48,6 +49,24 @@ void test_stat() BOOST_CHECK_EQUAL(3, rolling_max(acc)); } +void test_rolling_max() +{ + accumulator_set > acc_default(tag::rolling_window::window_size = window_size); + test_impl(acc_default); + + accumulator_set > acc_lazy(tag::rolling_window::window_size = window_size); + test_impl(acc_lazy); + + accumulator_set > acc_lazy2(tag::rolling_window::window_size = window_size); + test_impl(acc_lazy2); + + accumulator_set > acc_immediate(tag::rolling_window::window_size = window_size); + test_impl(acc_immediate); + + accumulator_set > acc_immediate2(tag::rolling_window::window_size = window_size); + test_impl(acc_immediate2); +} + /////////////////////////////////////////////////////////////////////////////// // init_unit_test_suite // @@ -55,7 +74,7 @@ test_suite* init_unit_test_suite( int argc, char* argv[] ) { test_suite *test = BOOST_TEST_SUITE("rolling max test"); - test->add(BOOST_TEST_CASE(&test_stat)); + test->add(BOOST_TEST_CASE(&test_rolling_max)); return test; } diff --git a/test/rolling_min.cpp b/test/rolling_min.cpp index 726f53a..8e522a8 100644 --- a/test/rolling_min.cpp +++ b/test/rolling_min.cpp @@ -14,13 +14,14 @@ using namespace unit_test; using namespace accumulators; using namespace container; +size_t window_size = 3; + /////////////////////////////////////////////////////////////////////////////// -// test_stat +// test_impl // -void test_stat() +template +void test_impl(Accumulator& acc) { - accumulator_set > acc(tag::rolling_window::window_size = 3); - BOOST_CHECK_EQUAL(numeric::as_max(int()), rolling_min(acc)); acc(1); @@ -42,7 +43,25 @@ void test_stat() BOOST_CHECK_EQUAL(6, rolling_min(acc)); acc(1); - BOOST_CHECK_EQUAL(1, rolling_min(acc));\ + BOOST_CHECK_EQUAL(1, rolling_min(acc)); +} + +void test_rolling_min() +{ + accumulator_set > acc_default(tag::rolling_window::window_size = window_size); + test_impl(acc_default); + + accumulator_set > acc_lazy(tag::rolling_window::window_size = window_size); + test_impl(acc_lazy); + + accumulator_set > acc_lazy2(tag::rolling_window::window_size = window_size); + test_impl(acc_lazy2); + + accumulator_set > acc_immediate(tag::rolling_window::window_size = window_size); + test_impl(acc_immediate); + + accumulator_set > acc_immediate2(tag::rolling_window::window_size = window_size); + test_impl(acc_immediate2); } /////////////////////////////////////////////////////////////////////////////// @@ -52,7 +71,7 @@ test_suite* init_unit_test_suite( int argc, char* argv[] ) { test_suite *test = BOOST_TEST_SUITE("rolling min test"); - test->add(BOOST_TEST_CASE(&test_stat)); + test->add(BOOST_TEST_CASE(&test_rolling_min)); return test; }