diff --git a/doc/Jamfile b/doc/Jamfile new file mode 100644 index 00000000..1c4596ac --- /dev/null +++ b/doc/Jamfile @@ -0,0 +1,197 @@ +# +# Copyright Eric Niebler 2005. +# Copyright (c) 2025 Dmitry Arkhipov (grisumbras@gmail.com) +# Copyright (C) 2026 Ming Yang Zhang, Leo Chen +# +# 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) +# +# Official repository: https://github.com/boostorg/accumulators +# + +project accumulators/doc + : default-build + on + ; + +import path ; + +local here-dir = [ path.root $(__file__:D) [ path.pwd ] ] ; + +import-search $(here-dir)/docca_runner ; +import-search /boost/docca ; +using asciidoctor ; + +import common ; +import docca ; +import accumulators_docca ; +import feature ; +import property-set ; + +if ! ( htmldir in [ feature.values asciidoctor-backend ] ) +{ + feature.extend asciidoctor-backend : htmldir ; +} + +local include-prefix = [ path.native $(here-dir:D)/include ] ; + +local docca-sources = + [ glob-tree-ex ../include/boost/accumulators : *.hpp : detail ] + externals.hpp ; + +local docca-params = + ALIASES="esafe=\"@par Exception Safety\"" + DISTRIBUTE_GROUP_DOC=YES + MACRO_EXPANSION=YES + EXPAND_ONLY_PREDEF=YES + "PREDEFINED=\\ + BOOST_ACCUMULATORS_DOXYGEN_INVOKED=1 \\ + BOOST_NUMERIC_FUNCTIONAL_DOXYGEN_INVOKED=1 \\ + BOOST_NUMERIC_FUNCTIONAL_STD_VECTOR_SUPPORT=1 \\ + BOOST_NUMERIC_FUNCTIONAL_STD_VALARRAY_SUPPORT=1 \\ + BOOST_NUMERIC_FUNCTIONAL_STD_COMPLEX_SUPPORT=1 \\ + BOOST_PP_REPEAT_FROM_TO(a,b,c,d)= \\ + BOOST_PP_REPEAT(a,b,c)= \\ + \"BOOST_PARAMETER_KEYWORD(a,b)=namespace a { struct b {}; } boost::parameter::keyword const b;\" \\ + \"BOOST_PP_ENUM_PARAMS(a,b)=b ## 1, b ## 2, ...\" \\ + \"BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(a,b,c)=namespace functional { template struct a ## _base : std::binary_function() b lvalue())> { result_type operator()(Left &left, Right &right) const; }; template::type, class RightTag=typename tag::type> struct a : a ## _base {}; } namespace op { struct a : boost::detail::function2< functional::a<_1,_2,functional::tag<_1>,functional::tag<_2> > > {}; } namespace { op::a const & a = boost::detail::pod_singleton::instance; }\" \\ + \"BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(a,b)=namespace functional { template struct a ## _base : std::unary_function())> { result_type operator()(Arg & arg) const; }; template::type> struct a : a ## _base {}; } namespace op { struct a : boost::detail::function1< functional::a<_,functional::tag<_> > > {}; } namespace { op::a const & a = boost::detail::pod_singleton::instance; }\"" + HIDE_UNDOC_MEMBERS=NO + EXTRACT_PRIVATE=NO + ENABLE_PREPROCESSING=YES + SEARCH_INCLUDES=NO + ABBREVIATE_BRIEF= + INLINE_INHERITED_MEMB=YES + JAVADOC_AUTOBRIEF=YES + AUTOLINK_SUPPORT=NO + EXTRACT_ALL=YES + EXTRACT_LOCAL_CLASSES=NO + STRIP_FROM_PATH=$(include-prefix) + reference.adoc.jinja2 + config.json ; + +accumulators_docca.pyreference entities_framework.adoc + : $(docca-sources) + : $(docca-params) + partition=framework + ; + +make _entities_statistics-dir/docca-config.json + : : docca.make-docca-config + : $(docca-params) + partition=statistics + ; + +make _entities_numeric-dir/docca-config.json + : : docca.make-docca-config + : $(docca-params) + partition=numeric + ; + +make entities_statistics.adoc + : entities_framework.adoc reference.adoc.jinja2 config.json + _entities_statistics-dir/docca-config.json + : accumulators_docca.partition-reference + : $(docca-params) + partition=statistics + ; + +make entities_numeric.adoc + : entities_framework.adoc reference.adoc.jinja2 config.json + _entities_numeric-dir/docca-config.json + : accumulators_docca.partition-reference + : $(docca-params) + partition=numeric + ; + +generate with-path-framework : entities_framework.adoc + : @with-path-framework ; +generate with-path-statistics : entities_statistics.adoc + : @with-path-statistics ; +generate with-path-numeric : entities_numeric.adoc + : @with-path-numeric ; + +install images + : [ glob images/*.png ] + : html/images + ; +explicit images ; + +#------------------------------------------------------------------------------- +# +# HTML documentation +# +#------------------------------------------------------------------------------- + +local backend-module = [ path.root htmldir.rb $(here-dir) ] ; +html index + : pages/main.adoc + : html + images + with-path-framework + with-path-statistics + with-path-numeric + + /boost/boostlook//boostlook + + nofooter + nofootnotes + source-highlighter=highlightjs + source-language=c++ + pagelevels=1 + icons=font + project-dir=$(here-dir:D) + "project-gh=https://github.com/boostorg/accumulators/edit/develop" + + docinfo=shared-head,shared-footer + pages/docinfo.html + pages/docinfo-footer.html + + htmldir + htmldir.rb + "-r $(backend-module)" + + attribute-missing=warn + -v + --trace + all:-w + extra:-w + pedantic:-w + on:--failure-level=WARN + ; + +alias boostdoc ; +explicit boostdoc ; + +alias boostrelease : index ; +explicit boostrelease ; + +rule with-path-partition ( project name : ps : src : attr-name ) +{ + local pwd = [ path.pwd ] ; + local here = [ path.root $(__file__:D) $(pwd) ] ; + + local path = [ path.root [ $(src).name ] [ $(src).path ] ] ; + path = [ path.root $(path) $(pwd) ] ; + path = [ path.relative-to $(here)/pages/ref $(path) ] ; + return [ $(ps).add-raw $(attr-name)=$(path) ] + $(src) ; +} + +rule with-path-framework ( project name : ps : src ) +{ + return [ with-path-partition $(project) $(name) : $(ps) : $(src) + : entities-framework-file ] ; +} + +rule with-path-statistics ( project name : ps : src ) +{ + return [ with-path-partition $(project) $(name) : $(ps) : $(src) + : entities-statistics-file ] ; +} + +rule with-path-numeric ( project name : ps : src ) +{ + return [ with-path-partition $(project) $(name) : $(ps) : $(src) + : entities-numeric-file ] ; +} diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 deleted file mode 100644 index 42fc2311..00000000 --- a/doc/Jamfile.v2 +++ /dev/null @@ -1,257 +0,0 @@ -# Copyright Eric Niebler 2005. 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) - -import os ; -import common ; -import doxygen ; -import quickbook ; - -# -# Accumulators docs are dependent upon -# latex dvips and ps being in your PATH. -# This is true for most Unix installs, but -# not on Win32, where you will need to install -# MkTex and Ghostscript and add these tools -# to your path. -# -make latex.check : : @check-latex ; -actions check-latex -{ - latex -version > latex.version -} - -make dvips.check : : @check-dvips ; -actions check-dvips -{ - dvips -version > dvips.version -} - -make gs.check : : @check-gs ; - -import os ; - -if [ os.name ] = "NT" -{ - actions check-gs - { - gswin32c -version > gs.version - } -} -else -{ - actions check-gs - { - gs -version > gs.version - } -} - -# Use Doxygen to emit a tagfile with the definition of depends_on<>. That -# tagfile will be used by Doxygen below when generating the Statistics Library -# Reference. This is all so that the Doxygen-generated documentation for the -# features shows the dependency relationships between them. -doxygen tagfile - : - ../include/boost/accumulators/framework/depends_on.hpp - ../include/boost/accumulators/framework/extractor.hpp - : - MACRO_EXPANSION=YES - EXPAND_ONLY_PREDEF=YES - GENERATE_TAGFILE=accumulators.tag - "PREDEFINED=\"BOOST_ACCUMULATORS_DOXYGEN_INVOKED=1\" \\ - \"BOOST_PP_REPEAT_FROM_TO(a,b,c,d)=\" \\ - \"BOOST_PP_ENUM_PARAMS(a,b)=b ## 1, b ## 2, ...\"" - latex.check - dvips.check - gs.check - ; - -doxygen accdoc - : - [ glob ../include/boost/accumulators/accumulators*.hpp ] - [ glob ../include/boost/accumulators/framework/*.hpp ] - [ glob ../include/boost/accumulators/framework/parameters/*.hpp ] - [ glob ../include/boost/accumulators/framework/accumulators/*.hpp ] - : - EXTRACT_ALL=YES - "PREDEFINED=\"BOOST_ACCUMULATORS_DOXYGEN_INVOKED=1\" \\ - \"BOOST_PP_REPEAT_FROM_TO(a,b,c,d)=\" \\ - \"BOOST_PP_REPEAT(a,b,c)=\" \\ - \"BOOST_PARAMETER_KEYWORD(a,b)=\\ - namespace a { struct b {}; } \\ - boost::parameter::keyword const b;\" \\ - \"BOOST_PP_ENUM_PARAMS(a,b)=b ## 1, b ## 2, ...\"" - HIDE_UNDOC_MEMBERS=NO - EXTRACT_PRIVATE=NO - ENABLE_PREPROCESSING=YES - MACRO_EXPANSION=YES - EXPAND_ONLY_PREDEF=YES - SEARCH_INCLUDES=NO - "Accumulators Framework Reference" - latex.check - dvips.check - gs.check - ; - -# Generate the HTML form of the stats documentation, as this causes Doxygen to -# generate .png images for the LaTeX formulas embedded in the doc comments. -doxygen statsdoc.html - : - [ glob ../include/boost/accumulators/statistics*.hpp ] - [ glob ../include/boost/accumulators/statistics/*.hpp ] - [ glob ../include/boost/accumulators/statistics/variates/*.hpp ] - : - latex.check - dvips.check - gs.check - ; - -if [ os.name ] = NT -{ - CP = copy /y ; - MKDIR = mkdir ; - FROM = \\..\\..\\..\\html\\statsdoc\\*.png ; - TOHTML = .\\html\\images\\accumulators ; - TOPDF = \\images\\accumulators ; -} -else -{ - CP = cp ; - MKDIR = mkdir -p ; - FROM = /../../html/statsdoc/*.png ; - TOHTML = ./html/images/accumulators ; - TOPDF = /images/accumulators ; -} - -actions copy-latex-pngs -{ - $(MKDIR) $(TOHTML) - $(MKDIR) $(<:D)$(TOPDF) - $(CP) $(<:D)$(FROM) $(TOHTML) - $(CP) $(<:D)$(FROM) $(<:D)$(TOPDF) - echo "Stamped" > "$(<)" -} - -# This causes the png files built above to be copied into the -# html/images/accumulators directory. -make statsdoclatex.tag - : statsdoc.html - : @copy-latex-pngs - ; - -doxygen statsdoc - : - [ glob ../include/boost/accumulators/statistics*.hpp ] - [ glob ../include/boost/accumulators/statistics/*.hpp ] - [ glob ../include/boost/accumulators/statistics/variates/*.hpp ] - : - EXTRACT_ALL=YES - "PREDEFINED=\"BOOST_ACCUMULATORS_DOXYGEN_INVOKED=1\" \\ - \"BOOST_PP_REPEAT_FROM_TO(a,b,c,d)=\" \\ - \"BOOST_PP_REPEAT(a,b,c)=\" \\ - \"BOOST_PARAMETER_KEYWORD(a,b)=\\ - namespace a { struct b {}; } \\ - boost::parameter::keyword const b;\" \\ - \"BOOST_PP_ENUM_PARAMS(a,b)=b ## 1, b ## 2, ...\"" - HIDE_UNDOC_MEMBERS=NO - EXTRACT_PRIVATE=NO - ENABLE_PREPROCESSING=YES - MACRO_EXPANSION=YES - EXPAND_ONLY_PREDEF=YES - SEARCH_INCLUDES=NO - TAGFILES=accumulators.tag - boost.doxygen.formuladir=images/accumulators/ - "Statistics Library Reference" - tagfile - statsdoclatex.tag - latex.check - dvips.check - gs.check - ; - -doxygen opdoc - : - [ glob ../include/boost/accumulators/numeric/functional.hpp ] - [ glob ../include/boost/accumulators/numeric/functional/*.hpp ] - : - EXTRACT_ALL=YES - "PREDEFINED=\"BOOST_NUMERIC_FUNCTIONAL_DOXYGEN_INVOKED=1\" \\ - \"BOOST_NUMERIC_FUNCTIONAL_DEFINE_BINARY_OP(a,b,c)=\\ - namespace functional { \\ - template struct a ## _base \\ - : std::binary_function() b lvalue())> { \\ - /** \\return left b right */ \\ - result_type operator()(Left &left, Right &right) const; }; \\ - template::type, \\ - class RightTag=typename tag::type> \\ - struct a : a ## _base {}; } \\ - namespace op { \\ - struct a : boost::detail::function2< \\ - functional::a<_1,_2,functional::tag<_1>,functional::tag<_2> > > {}; } \\ - namespace { \\ - /** \\return functional::a()(left, right) */ \\ - op::a const & a = boost::detail::pod_singleton::instance; } \" \\ - \"BOOST_NUMERIC_FUNCTIONAL_DEFINE_UNARY_OP(a,b)=\\ - namespace functional { \\ - template struct a ## _base \\ - : std::unary_function())> { \\ - /** \\return b arg */ \\ - result_type operator()(Arg & arg) const; }; \\ - template::type> \\ - struct a : a ## _base {}; } \\ - namespace op { \\ - struct a : boost::detail::function1< \\ - functional::a<_,functional::tag<_> > > {}; } \\ - namespace { \\ - /** \\return functional::a()(arg) */ \\ - op::a const & a = boost::detail::pod_singleton::instance; }\"" - HIDE_UNDOC_MEMBERS=NO - EXTRACT_PRIVATE=NO - ENABLE_PREPROCESSING=YES - MACRO_EXPANSION=YES - EXPAND_ONLY_PREDEF=YES - SEARCH_INCLUDES=NO - "Numeric Operators Library Reference" - latex.check - dvips.check - gs.check - ; - -xml accumulators - : - accumulators.qbk - : - boost.max.id.length=1024 - toc.max.depth=4 - toc.section.depth=4 - chunk.section.depth=2 - ; - -path-constant images_location : html ; - -boostbook standalone - : - accumulators - : - boost.root=../../../.. - boost.max.id.length=1024 - toc.max.depth=4 - toc.section.depth=4 - chunk.section.depth=2 - accdoc - statsdoc - opdoc - pdf:img.src.path=$(images_location)/ - pdf:boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html - ; - -############################################################################### -alias boostdoc - : accumulators - : - : accdoc statsdoc opdoc - : ; -explicit boostdoc ; -alias boostrelease ; -explicit boostrelease ; diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 00000000..0c353f3e --- /dev/null +++ b/doc/README.md @@ -0,0 +1,26 @@ +## Building the documentation + +Use the Boost release-tools script from this directory: + +```bash +./macosdocs.sh +``` + +Or from a full Boost tree: + +```bash +cd libs/accumulators/doc +./macosdocs.sh .. +``` + +Output is written to `html/index.html` (site home and table of contents). + +Narrative chapters build to `html/*.html` at the top level (for example `user_s_guide.html`, `the_statistical_accumulators_library.html`). The API reference follows the same layout as [Boost.JSON](https://www.boost.org/doc/libs/latest/libs/json/doc/html/ref.html): an index page at `html/ref.html` plus one HTML file per documented entity under `html/ref/`. + +To change how many HTML files are generated, adjust `pagelevels` on sections in `pages/main.adoc` / `pages/reference.adoc` and see `htmldir.rb`. + +The chapter TOC in the left sidebar is the same on every page; it is built in `htmldir.rb` (`convert_accumulators_home_outline`). + +Narrative pages under `pages/` were migrated from QuickBook. The conversion helper `qbk_to_adoc.py` remains for reference; restore `accumulators.qbk` from git history to re-run it. + +API reference generation uses `docca_runner/` (`accumulators_docca.py` + `accumulators_docca.jam`) so Accumulators-specific Doxygen output works without modifying `tools/docca/docca.py`. See `docca_runner/README.md`. diff --git a/doc/accumulators.qbk b/doc/accumulators.qbk deleted file mode 100644 index 7e6d1f43..00000000 --- a/doc/accumulators.qbk +++ /dev/null @@ -1,4180 +0,0 @@ - -[library Boost.Accumulators - [quickbook 1.3] - [authors [Niebler, Eric]] - [copyright 2005 2006 Eric Niebler] - [category math] - [id accumulators] - [dirname accumulators] - [purpose - Incremental accumulation framework and statistical accumulator library. - ] - [license - 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]) - ] -] - -[/ Images ] - -[def _note_ [$images/note.png]] -[def _alert_ [$images/caution.png]] -[def _detail_ [$images/note.png]] -[def _tip_ [$images/tip.png]] - -[/ Links ] - -[def _sample_type_ '''sample-type'''] -[def _weight_type_ '''weight-type'''] -[def _variate_type_ '''variate-type'''] -[def _variate_tag_ '''variate-tag'''] -[def _left_or_right_ '''left-or-right'''] -[def _implementation_defined_ '''implementation-defined'''] -[def _boost_ [@http://www.boost.org Boost]] -[def _mpl_ [@../../libs/mpl/index.html MPL]] -[def _mpl_lambda_expression_ [@../../libs/mpl/doc/refmanual/lambda-expression.html MPL Lambda Expression]] -[def _parameter_ [@../../libs/parameter/index.html Boost.Parameter]] -[def _accumulator_set_ [classref boost::accumulators::accumulator_set `accumulator_set<>`]] -[def _accumulator_base_ [classref boost::accumulators::accumulator_base `accumulator_base`]] -[def _depends_on_ [classref boost::accumulators::depends_on `depends_on<>`]] -[def _feature_of_ [classref boost::accumulators::feature_of `feature_of<>`]] -[def _as_feature_ [classref boost::accumulators::as_feature `as_feature<>`]] -[def _features_ [classref boost::accumulators::features `features<>`]] -[def _external_ [classref boost::accumulators::external `external<>`]] -[def _droppable_ [classref boost::accumulators::droppable `droppable<>`]] -[def _droppable_accumulator_ [classref boost::accumulators::droppable_accumulator `droppable_accumulator<>`]] -[def _extractor_ [classref boost::accumulators::tag::extractor `extractor<>`]] -[def _tail_ [classref boost::accumulators::tag::tail `tail`]] -[def _tail_variate_ [classref boost::accumulators::tag::tail_variate `tail_variate<>`]] -[def _extract_result_ [funcref boost::accumulators::extract_result `extract_result()`]] -[def _ZKB_ [@http://www.zkb.com Z'''ü'''rcher Kantonalbank]] - -[section Preface] - -[:["It is better to be approximately right than exactly wrong.]\n['-- Old adage]] - -[h2 Description] - -Boost.Accumulators is both a library for incremental statistical computation as -well as an extensible framework for incremental calculation in general. The library -deals primarily with the concept of an ['accumulator], which is a primitive -computational entity that accepts data one sample at a time and maintains some -internal state. These accumulators may offload some of their computations on other -accumulators, on which they depend. Accumulators are grouped within an ['accumulator -set]. Boost.Accumulators resolves the inter-dependencies between accumulators in a -set and ensures that accumulators are processed in the proper order. - -[endsect] - -[section User's Guide] - -This section describes how to use the Boost.Accumulators framework to create new -accumulators and how to use the existing statistical accumulators to perform incremental -statistical computation. For detailed information regarding specific components in -Boost.Accumulators, check the [link accumulators_framework_reference Reference] section. - -[h2 Hello, World!] - -Below is a complete example of how to use the Accumulators Framework and the -Statistical Accumulators to perform an incremental statistical calculation. It -calculates the mean and 2nd moment of a sequence of doubles. - - #include - #include - #include - #include - #include - using namespace boost::accumulators; - - int main() - { - // Define an accumulator set for calculating the mean and the - // 2nd moment ... - accumulator_set > > acc; - - // push in some data ... - acc(1.2); - acc(2.3); - acc(3.4); - acc(4.5); - - // Display the results ... - std::cout << "Mean: " << mean(acc) << std::endl; - std::cout << "Moment: " << moment<2>(acc) << std::endl; - - return 0; - } - -This program displays the following: - -[pre -Mean: 2.85 -Moment: 9.635 -] - -[section The Accumulators Framework] - -The Accumulators Framework is framework for performing incremental calculations. Usage -of the framework follows the following pattern: - -* Users build a computational object, called an ['_accumulator_set_], by selecting - the computations in which they are interested, or authoring their own computational - primitives which fit within the framework. -* Users push data into the _accumulator_set_ object one sample at a time. -* The _accumulator_set_ computes the requested quantities in the most efficient method - possible, resolving dependencies between requested calculations, possibly caching - intermediate results. - -The Accumulators Framework defines the utilities needed for defining primitive -computational elements, called ['accumulators]. It also provides the _accumulator_set_ -type, described above. - -[h2 Terminology] - -The following terms are used in the rest of the documentation. - -[variablelist - [[Sample] [[#sample_type] A datum that is pushed into an _accumulator_set_. - The type of the sample is the ['sample type].]] - [[Weight] [[#weight_type] An optional scalar value passed along with the - sample specifying the weight of the sample. Conceptually, each - sample is multiplied with its weight. The type of the weight is - the ['weight type].]] - [[Feature] [An abstract primitive computational entity. When defining an - _accumulator_set_, users specify the features in which they are - interested, and the _accumulator_set_ figures out which - ['accumulators] would best provide those features. Features may - depend on other features. If they do, the accumulator set figures - out which accumulators to add to satisfy the dependencies.]] - [[Accumulator] [A concrete primitive computational entity. An accumulator is a - concrete implementation of a feature. It satisfies exactly one - abstract feature. Several different accumulators may provide the - same feature, but may represent different implementation strategies.]] - [[Accumulator Set] [A collection of accumulators. An accumulator set is specified with - a sample type and a list of features. The accumulator set uses this - information to generate an ordered set of accumulators depending on - the feature dependency graph. An accumulator set accepts samples one - datum at a time, propagating them to each accumulator in order. At any - point, results can be extracted from the accumulator set.]] - [[Extractor] [A function or function object that can be used to extract a result - from an _accumulator_set_.]] -] - -[h2 Overview] - -Here is a list of the important types and functions in the Accumulator Framework and -a brief description of each. - -[table Accumulators Toolbox - [[Tool] [Description]] - [[_accumulator_set_] [This is the most important type in the Accumulators Framework. - It is a collection of accumulators. A datum pushed into an - _accumulator_set_ is forwarded to each accumulator, in an order - determined by the dependency relationships between the - accumulators. Computational results can be extracted from an - accumulator at any time.]] - [[_depends_on_ ] [Used to specify which other features a feature depends on.]] - [[_feature_of_ ] [Trait used to tell the Accumulators Framework that, for the purpose - of feature-based dependency resolution, one feature should be - treated the same as another.]] - [[_as_feature_ ] [Used to create an alias for a feature. For example, if there are - two features, fast_X and accurate_X, they can be mapped to - X(fast) and X(accurate) with _as_feature_. This is just syntactic - sugar.]] - [[_features_ ] [An _mpl_ sequence. We can use _features_ as the second template - parameter when declaring an _accumulator_set_.]] - [[_external_ ] [Used when declaring an _accumulator_set_. If the weight type is - specified with _external_, then the weight accumulators are - assumed to reside in a separate accumulator set which will be passed - in with a named parameter.]] - [[_extractor_ ] [A class template useful for creating an extractor function object. - It is parameterized on a feature, and it has member functions for - extracting from an _accumulator_set_ the result corresponding to - that feature.]] -] - -[section Using [^accumulator_set<>]] - -Our tour of the _accumulator_set_ class template begins with the forward declaration: - - template< typename Sample, typename Features, typename Weight = void > - struct accumulator_set; - -The template parameters have the following meaning: - -[variablelist - [[`Sample`] [The type of the data that will be accumulated.]] - [[`Features`] [An _mpl_ sequence of features to be calculated.]] - [[`Weight`] [The type of the (optional) weight paramter.]] -] - -For example, the following line declares an _accumulator_set_ that will accept -a sequence of doubles one at a time and calculate the min and mean: - - accumulator_set< double, features< tag::min, tag::mean > > acc; - -Notice that we use the _features_ template to specify a list of features to be calculated. -_features_ is an MPL sequence of features. - -[note _features_ is a synonym of `mpl::vector<>`. In fact, we could use `mpl::vector<>` - or any MPL sequence if we prefer, and the meaning would be the same.] - -Once we have defined an _accumulator_set_, we can then push data into it, -and it will calculate the quantities you requested, as shown below. - - // push some data into the accumulator_set ... - acc(1.2); - acc(2.3); - acc(3.4); - -Since _accumulator_set_ defines its accumulate function to be the function call operator, -we might be tempted to use an _accumulator_set_ as a UnaryFunction to a standard -algorithm such as `std::for_each`. That's fine as long as we keep in mind that the standard -algorithms take UnaryFunction objects by value, which involves making a copy of the -_accumulator_set_ object. Consider the following: - - // The data for which we wish to calculate statistical properties: - std::vector< double > data( /* stuff */ ); - - // The accumulator set which will calculate the properties for us: - accumulator_set< double, features< tag::min, tag::mean > > acc; - - // Use std::for_each to accumulate the statistical properties: - acc = std::for_each( data.begin(), data.end(), acc ); - -Notice how we must assign the return value of `std::for_each` back to the _accumulator_set_. -This works, but some accumulators are not cheap to copy. For -example, the _tail_ and _tail_variate_ accumulators must store a `std::vector<>`, so copying -these accumulators involves a dynamic allocation. We might be better off in this -case passing the accumulator by reference, with the help of `boost::bind()` and -`boost::ref()`. See below: - - // The data for which we wish to calculate statistical properties: - std::vector< double > data( /* stuff */ ); - - // The accumulator set which will calculate the properties for us: - accumulator_set< double, features< tag::tail > > acc( - tag::tail::cache_size = 4 ); - - // Use std::for_each to accumulate the statistical properties: - std::for_each( data.begin(), data.end(), bind( ref(acc), _1 ) ); - -Notice now that we don't care about the return value of `std::for_each()` anymore because -`std::for_each()` is modifying `acc` directly. - -[note To use `boost::bind()` and `boost::ref()`, you must `#include` [^] -and [^]] - -[endsect] - -[section Extracting Results] - -Once we have declared an _accumulator_set_ and pushed data into it, we need to be able -to extract results from it. For each feature we can add to an _accumulator_set_, there -is a corresponding extractor for fetching its result. Usually, the extractor has the -same name as the feature, but in a different namespace. For example, if we accumulate -the `tag::min` and `tag::max` features, we can extract the results with the `min` and `max` -extractors, as follows: - - // Calculate the minimum and maximum for a sequence of integers. - accumulator_set< int, features< tag::min, tag::max > > acc; - acc( 2 ); - acc( -1 ); - acc( 1 ); - - // This displays "(-1, 2)" - std::cout << '(' << min( acc ) << ", " << max( acc ) << ")\n"; - -The extractors are all declared in the `boost::accumulators::extract` namespace, but they -are brought into the `boost::accumulators` namespace with a `using` declaration. - -[tip On the Windows platform, `min` and `max` are preprocessor macros defined in [^WinDef.h]. - To use the `min` and `max` extractors, you should either compile with `NOMINMAX` defined, or - you should invoke the extractors like: `(min)( acc )` and `(max)( acc )`. The parentheses - keep the macro from being invoked.] - -Another way to extract a result from an _accumulator_set_ is with the -`extract_result()` function. This can be more convenient if there isn't an extractor -object handy for a certain feature. The line above which displays results could -equally be written as: - - // This displays "(-1, 2)" - std::cout << '(' << extract_result< tag::min >( acc ) - << ", " << extract_result< tag::max >( acc ) << ")\n"; - -Finally, we can define our own extractor using the _extractor_ class template. For -instance, another way to avoid the `min` / `max` macro business would be to define -extractors with names that don't conflict with the macros, like this: - - extractor< tag::min > min_; - extractor< tag::min > max_; - - // This displays "(-1, 2)" - std::cout << '(' << min_( acc ) << ", " << max_( acc ) << ")\n"; - -[endsect] - -[section Passing Optional Parameters] - -Some accumulators need initialization parameters. In addition, perhaps some auxiliary -information needs to be passed into the _accumulator_set_ along with each sample. -Boost.Accumulators handles these cases with named parameters from the _parameter_ -library. - -For example, consider the _tail_ and _tail_variate_ features. _tail_ keeps -an ordered list of the largest [^['N]] samples, where [^['N]] can be specified at -construction time. Also, the _tail_variate_ feature, which depends on _tail_, keeps -track of some data that is covariate with the [^['N]] samples tracked by _tail_. The -code below shows how this all works, and is described in more detail below. - - // Define a feature for tracking covariate data - typedef tag::tail_variate< int, tag::covariate1, left > my_tail_variate_tag; - - // This will calculate the left tail and my_tail_variate_tag for N == 2 - // using the tag::tail::cache_size named parameter - accumulator_set< double, features< my_tail_variate_tag > > acc( - tag::tail::cache_size = 2 ); - - // push in some samples and some covariates by using - // the covariate1 named parameter - acc( 1.2, covariate1 = 12 ); - acc( 2.3, covariate1 = -23 ); - acc( 3.4, covariate1 = 34 ); - acc( 4.5, covariate1 = -45 ); - - // Define an extractor for the my_tail_variate_tag feature - extractor< my_tail_variate_tag > my_tail_variate; - - // Write the tail statistic to std::cout. This will print "4.5, 3.4, " - std::ostream_iterator< double > dout( std::cout, ", " ); - std::copy( tail( acc ).begin(), tail( acc ).end(), dout ); - - // Write the tail_variate statistic to std::cout. This will print "-45, 34, " - std::ostream_iterator< int > iout( std::cout, ", " ); - std::copy( my_tail_variate( acc ).begin(), my_tail_variate( acc ).end(), iout ); - -There are several things to note about the code above. First, notice that we didn't have -to request that the _tail_ feature be calculated. That is implicit because the _tail_variate_ -feature depends on the _tail_ feature. Next, notice how the `acc` object -is initialized: `acc( tag::tail::cache_size = 2 )`. Here, `cache_size` is a named parameter. -It is used to tell the _tail_ and _tail_variate_ accumulators how many samples and -covariates to store. Conceptually, every construction parameter is made available to -every accumulator in an accumulator set. - -We also use a named parameter to pass covariate data into the accumulator set along with -the samples. As with the constructor parameters, all parameters to the accumulate function -are made available to all the accumulators in the set. In this case, only the accumulator -for the `my_tail_variate` feature would be interested in the value of the `covariate1` named -parameter. - -We can make one final observation about the example above. Since _tail_ and _tail_variate_ -are multi-valued features, the result we extract for them is represented as an iterator -range. That is why we can say `tail( acc ).begin()` and `tail( acc ).end()`. - -Even the extractors can accept named parameters. In a bit, we'll see a situation where that -is useful. - -[endsect] - -[section Weighted Samples] - -Some accumulators, statistical accumulators in particular, deal with data that are -['weighted]. Each sample pushed into the accumulator has an associated weight, by which -the sample is conceptually multiplied. The Statistical Accumulators Library provides an -assortment of these weighted statistical accumulators. And many unweighted statistical -accumulators have weighted variants. For instance, the weighted variant of the `sum` -accumulator is called `weighted_sum`, and is calculated by accumulating all the -samples multiplied by their weights. - -To declare an _accumulator_set_ that accepts weighted samples, you must specify the -type of the weight parameter as the 3rd template parameter, as follows: - - // 3rd template parameter 'int' means this is a weighted - // accumulator set where the weights have type 'int' - accumulator_set< int, features< tag::sum >, int > acc; - -When you specify a weight, all the accumulators in the set are replaced with -their weighted equivalents. For example, the above _accumulator_set_ declaration -is equivalent to the following: - - // Since we specified a weight, tag::sum becomes tag::weighted_sum - accumulator_set< int, features< tag::weighted_sum >, int > acc; - -When passing samples to the accumulator set, you must also specify the -weight of each sample. You can do that with the `weight` named parameter, -as follows: - - acc(1, weight = 2); // 1 * 2 - acc(2, weight = 4); // 2 * 4 - acc(3, weight = 6); // + 3 * 6 - // ------- - // = 28 - -You can then extract the result with the `sum()` extractor, as follows: - - // This prints "28" - std::cout << sum(acc) << std::endl; - -[note When working with weighted statistical accumulators from the Statistical -Accumulators Library, be sure to include the appropriate header. For instance, -`weighted_sum` is defined in ``.] - -[endsect] - -[section Numeric Operators Sub-Library] - -This section describes the function objects in the `boost::numeric` namespace, which -is a sub-library that provides function objects and meta-functions corresponding -to the infix operators in C++. - -In the `boost::numeric::operators` namespace are additional operator overloads for -some useful operations not provided by the standard library, such as multiplication -of a `std::complex<>` with a scalar. - -In the `boost::numeric::functional` namespace are function object equivalents of -the infix operators. These function object types are heterogeneous, and so are more -general than the standard ones found in the [^] header. They use the -Boost.Typeof library to deduce the return types of the infix expressions they -evaluate. In addition, they look within the `boost::numeric::operators` namespace -to consider any additional overloads that might be defined there. - -In the `boost::numeric` namespace are global polymorphic function objects -corresponding to the function object types defined in the `boost::numeric::functional` -namespace. For example, `boost::numeric::plus(a, b)` is equivalent to -`boost::numeric::functional::plus()(a, b)`, and both are equivalent to -`using namespace boost::numeric::operators; a + b;`. - -The Numeric Operators Sub-Library also gives several ways to sub-class and -a way to sub-class and specialize operations. One way uses tag dispatching on -the types of the operands. The other way is based on the compile-time -properties of the operands. - -[endsect] - -[section Extending the Accumulators Framework] - -This section describes how to extend the Accumulators Framework by defining new accumulators, -features and extractors. Also covered are how to control the dependency resolution of -features within an accumulator set. - -[section Defining a New Accumulator] - -All new accumulators must satisfy the [link -accumulators.user_s_guide.the_accumulators_framework.concepts.accumulator_concept Accumulator -Concept]. Below is a sample class that satisfies the accumulator concept, which simply sums -the values of all samples passed into it. - - #include - #include - - namespace boost { // Putting your accumulators in the - namespace accumulators { // impl namespace has some - namespace impl { // advantages. See below. - - template - struct sum_accumulator // All accumulators should inherit from - : accumulator_base // accumulator_base. - { - typedef Sample result_type; // The type returned by result() below. - - template // The constructor takes an argument pack. - sum_accumulator(Args const & args) - : sum(args[sample | Sample()]) // Maybe there is an initial value in the - { // argument pack. ('sample' is defined in - } // sample.hpp, included above.) - - template // The accumulate function is the function - void operator ()(Args const & args) // call operator, and it also accepts an - { // argument pack. - this->sum += args[sample]; - } - - result_type result(dont_care) const // The result function will also be passed - { // an argument pack, but we don't use it here, - return this->sum; // so we use "dont_care" as the argument type. - } - private: - Sample sum; - }; - - }}} - -Much of the above should be pretty self-explanatory, except for the use of argument packs -which may be confusing if you have never used the _parameter_ library before. An argument -pack is a cluster of values, each of which can be accessed with a key. So `args[sample]` -extracts from the pack the value associated with the `sample` key. And the cryptic -`args[sample | Sample()]` evaluates to the value associated with the `sample` key if it -exists, or a default-constructed `Sample` if it doesn't. - -The example above demonstrates the most common attributes of an accumulator. There are -other optional member functions that have special meaning. In particular: - -[variablelist Optional Accumulator Member Functions -[[[^on_drop(Args)]] [Defines an action to be taken when this accumulator is - dropped. See the section on - [link accumulators.user_s_guide.the_accumulators_framework.extending_the_accumulators_framework.defining_a_new_accumulator.droppable_accumulators - Droppable Accumulators].]] -] - -[h3 Accessing Other Accumulators in the Set] - -Some accumulators depend on other accumulators within the same accumulator set. In those -cases, it is necessary to be able to access those other accumulators. To make this possible, -the _accumulator_set_ passes a reference to itself when invoking the member functions of -its contained accumulators. It can be accessed by using the special `accumulator` key with -the argument pack. Consider how we might implement `mean_accumulator`: - - // Mean == (Sum / Count) - template - struct mean_accumulator : accumulator_base - { - typedef Sample result_type; - mean_accumulator(dont_care) {} - - template - result_type result(Args const &args) const - { - return sum(args[accumulator]) / count(args[accumulator]); - } - }; - -`mean` depends on the `sum` and `count` accumulators. (We'll see in the next section how -to specify these dependencies.) The result of the mean accumulator is merely the result of -the sum accumulator divided by the result of the count accumulator. Consider how we write -that: `sum(args[accumulator]) / count(args[accumulator])`. The expression `args[accumulator]` -evaluates to a reference to the _accumulator_set_ that contains this `mean_accumulator`. It -also contains the `sum` and `count` accumulators, and we can access their results with the -extractors defined for those features: `sum` and `count`. - -[note Accumulators that inherit from _accumulator_base_ get an empty `operator ()`, so - accumulators like `mean_accumulator` above need not define one.] - -All the member functions that accept an argument pack have access to the enclosing -_accumulator_set_ via the `accumulator` key, including the constructor. The -accumulators within the set are constructed in an order determined by their interdependencies. -As a result, it is safe for an accumulator to access one on which it depends during construction. - -[h3 Infix Notation and the Numeric Operators Sub-Library] - -Although not necessary, it can be a good idea to put your accumulator implementations in -the `boost::accumulators::impl` namespace. This namespace pulls in any operators defined -in the `boost::numeric::operators` namespace with a using directive. The Numeric Operators -Sub-Library defines some additional overloads that will make your accumulators work with -all sorts of data types. - -Consider `mean_accumulator` defined above. It divides the sum of the samples by the count. -The type of the count is `std::size_t`. What if the sample type doesn't define division by -`std::size_t`? That's the case for `std::complex<>`. You might think that if the sample type -is `std::complex<>`, the code would not work, but in fact it does. That's because -Numeric Operators Sub-Library defines an overloaded `operator/` for `std::complex<>` -and `std::size_t`. This operator is defined in the `boost::numeric::operators` namespace and -will be found within the `boost::accumulators::impl` namespace. That's why it's a good idea -to put your accumulators there. - -[h3 Droppable Accumulators] - -The term "droppable" refers to an accumulator that can be removed from the _accumulator_set_. -You can request that an accumulator be made droppable by using the _droppable_ class template. - - // calculate sum and count, make sum droppable: - accumulator_set< double, features< tag::count, droppable > > acc; - - // add some data - acc(3.0); - acc(2.0); - - // drop the sum (sum is 5 here) - acc.drop(); - - // add more data - acc(1.0); - - // This will display "3" and "5" - std::cout << count(acc) << ' ' << sum(acc); - -Any accumulators that get added to an accumulator set in order to satisfy -dependencies on droppable accumulators are themselves droppable. Consider -the following accumulator: - - // Sum is not droppable. Mean is droppable. Count, brought in to - // satisfy mean's dependencies, is implicitly droppable, too. - accumulator_set< double, features< tag::sum, droppable > > acc; - -`mean` depends on `sum` and `count`. Since `mean` is droppable, so too is `count`. -However, we have explicitly requested that `sum` be not droppable, so it isn't. Had -we left `tag::sum` out of the above declaration, the `sum` accumulator would have -been implicitly droppable. - -A droppable accumulator is reference counted, and is only really dropped after all the -accumulators that depend on it have been dropped. This can lead to some surprising -behavior in some situations. - - // calculate sum and mean, make mean droppable. - accumulator_set< double, features< tag::sum, droppable > > acc; - - // add some data - acc(1.0); - acc(2.0); - - // drop the mean. mean's reference count - // drops to 0, so it's really dropped. So - // too, count's reference count drops to 0 - // and is really dropped. - acc.drop(); - - // add more data. Sum continues to accumulate! - acc(3.0); - - // This will display "6 2 3" - std::cout << sum(acc) << ' ' - << count(acc) << ' ' - << mean(acc); - -Note that at the point at which `mean` is dropped, `sum` is 3, `count` is 2, and -therefore `mean` is 1.5. But since `sum` continues to accumulate even after `mean` -has been dropped, the value of `mean` continues to change. If you want to remember -the value of `mean` at the point it is dropped, you should save its value into -a local variable. - -The following rules more precisely specify how droppable and non-droppable -accumulators behave within an accumulator set. - -* There are two types of accumulators: droppable and non-droppable. - The default is non-droppable. -* For any feature `X`, both `X` and `droppable` satisfy the `X` dependency. -* If feature `X` depends on `Y` and `Z`, then `droppable` depends on - `droppable` and `droppable`. -* All accumulators have `add_ref()` and `drop()` member functions. -* For non-droppable accumulators, `drop()` is a no-op, and `add_ref()` - invokes `add_ref()` on all accumulators corresponding to the features - upon which the current accumulator depends. -* Droppable accumulators have a reference count and define `add_ref()` - and `drop()` to manipulate the reference count. -* For droppable accumulators, `add_ref()` increments the accumulator's - reference count, and also `add_ref()`'s the accumulators corresponding - to the features upon which the current accumulator depends. -* For droppable accumulators, `drop()` decrements the accumulator's - reference count, and also `drop()`'s the accumulators corresponding to - the features upon which the current accumulator depends. -* The accumulator_set constructor walks the list of *user-specified* - features and `add_ref()`'s the accumulator that corresponds to each of - them. (Note: that means that an accumulator that is not user-specified - but in the set merely to satisfy a dependency will be dropped as soon - as all its dependencies have been dropped. Ones that have been user - specified are not dropped until their dependencies have been - dropped *and* the user has explicitly dropped the accumulator.) -* Droppable accumulators check their reference count in their - accumulate member function. If the reference count is 0, the function - is a no-op. -* Users are not allowed to drop a feature that is not user-specified and - marked as droppable. - -And as an optimization: - -* If the user specifies the non-droppable feature `X`, which depends on `Y` - and `Z`, then the accumulators for `Y` and `Z` can be safely made - non-droppable, as well as any accumulators on which they depend. - -[endsect] - -[section Defining a New Feature] - -Once we have implemented an accumulator, we must define a feature for it so -that users can specify the feature when declaring an _accumulator_set_. We -typically put the features into a nested namespace, so that later we can -define an extractor of the same name. All features must satisfy the -[link accumulators.user_s_guide.the_accumulators_framework.concepts.feature_concept -Feature Concept]. Using _depends_on_ makes satisfying the concept simple. -Below is an example of a feature definition. - - namespace boost { namespace accumulators { namespace tag { - - struct mean // Features should inherit from - : depends_on< count, sum > // depends_on<> to specify dependencies - { - // Define a nested typedef called 'impl' that specifies which - // accumulator implements this feature. - typedef accumulators::impl::mean_accumulator< mpl::_1 > impl; - }; - - }}} - -The only two things we must do to define the `mean` feature is to specify the -dependencies with _depends_on_ and define the nested `impl` typedef. Even features -that have no dependencies should inherit from _depends_on_. The nested `impl` type -must be an _mpl_lambda_expression_. The result of -`mpl::apply< impl, _sample_type_, _weight_type_ >::type` must be -be the type of the accumulator that implements this feature. The use of _mpl_ -placeholders like `mpl::_1` make it especially easy to make a template such -as `mean_accumulator<>` an _mpl_lambda_expression_. Here, `mpl::_1` will be -replaced with the sample type. Had we used `mpl::_2`, it would have been replaced -with the weight type. - -What about accumulator types that are not templates? If you have a `foo_accumulator` -which is a plain struct and not a template, you could turn it into an -_mpl_lambda_expression_ using `mpl::always<>`, like this: - - // An MPL lambda expression that always evaluates to - // foo_accumulator: - typedef mpl::always< foo_accumulator > impl; - -If you are ever unsure, or if you are not comfortable with MPL lambda expressions, -you could always define `impl` explicitly: - - // Same as 'typedef mpl::always< foo_accumulator > impl;' - struct impl - { - template< typename Sample, typename Weight > - struct apply - { - typedef foo_accumulator type; - }; - }; - -Here, `impl` is a binary [@../../libs/mpl/doc/refmanual/metafunction-class.html -MPL Metafunction Class], which is a kind of _mpl_lambda_expression_. The nested -`apply<>` template is part of the metafunction class protocol and tells MPL how -to build the accumulator type given the sample and weight types. - -All features must also provide a nested `is_weight_accumulator` typedef. It must -be either `mpl::true_` or `mpl::false_`. _depends_on_ provides a default of -`mpl::false_` for all features that inherit from it, but that can be overridden -(or hidden, technically speaking) in the derived type. When the feature represents -an accumulation of information about the weights instead of the samples, we -can mark this feature as such with `typedef mpl::true_ is_weight_accumulator;`. -The weight accumulators are made external if the weight type is specified using -the _external_ template. - -[endsect] - -[section Defining a New Extractor] - -Now that we have an accumulator and a feature, the only thing lacking is a way -to get results from the accumulator set. The Accumulators Framework provides the -_extractor_ class template to make it simple to define an extractor for your -feature. Here's an extractor for the `mean` feature we defined above: - - namespace boost { - namespace accumulators { // By convention, we put extractors - namespace extract { // in the 'extract' namespace - - extractor< tag::mean > const mean = {}; // Simply define our extractor with - // our feature tag, like this. - } - using extract::mean; // Pull the extractor into the - // enclosing namespace. - }} - -Once defined, the `mean` extractor can be used to extract the result of the -`tag::mean` feature from an _accumulator_set_. - -Parameterized features complicate this simple picture. Consider the `moment` -feature, for calculating the [^['N]]-th moment, where [^['N]] is specified as -a template parameter: - - // An accumulator set for calculating the N-th moment, for N == 2 ... - accumulator_set< double, features< tag::moment<2> > > acc; - - // ... add some data ... - - // Display the 2nd moment ... - std::cout << "2nd moment is " << accumulators::moment<2>(acc) << std::endl; - -In the expression `accumulators::moment<2>(acc)`, what is `moment`? It cannot be an object -- -the syntax of C++ will not allow it. Clearly, if we want to provide this syntax, -we must make `moment` a function template. Here's what the definition of the -`moment` extractor looks like: - - namespace boost { - namespace accumulators { // By convention, we put extractors - namespace extract { // in the 'extract' namespace - - template - typename mpl::apply >::type::result_type - moment(AccumulatorSet const &acc) - { - return extract_result >(acc); - } - - } - using extract::moment; // Pull the extractor into the - // enclosing namespace. - }} - -The return type deserves some explanation. Every _accumulator_set_ type -is actually a unary [@../../libs/mpl/doc/refmanual/metafunction-class.html -MPL Metafunction Class]. When you `mpl::apply<>` an _accumulator_set_ and -a feature, the result is the type of the accumulator within the set that -implements that feature. And every accumulator provides a nested `result_type` -typedef that tells what its return type is. The extractor simply delegates -its work to the _extract_result_ function. - -[endsect] - -[section Controlling Dependencies] - -The feature-based dependency resolution of the Accumulators Framework is -designed to allow multiple different implementation strategies for each -feature. For instance, two different accumulators may calculate the same -quantity with different rounding modes, or using different algorithms with -different size/speed tradeoffs. Other accumulators that depend on that -quantity shouldn't care how it's calculated. The Accumulators Framework -handles this by allowing several different accumulators satisfy the same -feature. - -[*Aliasing feature dependencies with [^feature_of<>]] - -Imagine that you would like to implement the hypothetical ['fubar] statistic, -and that you know two ways to calculate fubar on a bunch of samples: an -accurate but slow calculation and an approximate but fast calculation. You -might opt to make the accurate calculation the default, so you implement -two accumulators and call them `impl::fubar_impl` and `impl::fast_fubar_impl`. -You would also define the `tag::fubar` and `tag::fast_fubar` features as described -[link accumulators.user_s_guide.the_accumulators_framework.extending_the_accumulators_framework.defining_a_new_feature above]. -Now, you would like to inform the Accumulators Framework that these two features -are the same from the point of view of dependency resolution. You can do that -with _feature_of_, as follows: - - namespace boost { namespace accumulators - { - // For the purposes of feature-based dependency resolution, - // fast_fubar provides the same feature as fubar - template<> - struct feature_of - : feature_of - { - }; - }} - -The above code instructs the Accumulators Framework that, if another accumulator -in the set depends on the `tag::fubar` feature, the `tag::fast_fubar` feature -is an acceptable substitute. - -[*Registering feature variants with [^as_feature<>]] - -You may have noticed that some feature variants in the Accumulators Framework can be -specified with a nicer syntax. For instance, instead of `tag::mean` and `tag::immediate_mean` -you can specify them with `tag::mean(lazy)` and `tag::mean(immediate)` respectively. -These are merely aliases, but the syntax makes the relationship between the two clearer. -You can create these feature aliases with the _as_feature_ trait. Given the fubar example -above, you might decide to alias `tag::fubar(accurate)` with `tag::fubar` and -`tag::fubar(fast)` with `tag::fast_fubar`. You would do that as follows: - - namespace boost { namespace accumulators - { - struct fast {}; // OK to leave these tags empty - struct accurate {}; - - template<> - struct as_feature - { - typedef tag::fubar type; - }; - - template<> - struct as_feature - { - typedef tag::fast_fubar type; - }; - }} - -Once you have done this, users of your fubar accumulator can request the `tag::fubar(fast)` -and `tag::fubar(accurate)` features when defining their `accumulator_set`s and get the correct -accumulator. - -[endsect] - -[section:operators_ex Specializing Numeric Operators] - -This section describes how to adapt third-party numeric types to work with the Accumulator -Framework. - -Rather than relying on the built-in operators, the Accumulators Framework relies on functions -and operator overloads defined in the -[link accumulators.user_s_guide.the_accumulators_framework.numeric_operators_sub_library -Numeric Operators Sub-Library] for many of its numeric operations. This is so that it -is possible to assign non-standard meanings to arithmetic operations. For instance, when -calculating an average by dividing two integers, the standard integer division behavior -would be mathematically incorrect for most statistical quantities. So rather than use `x / y`, -the Accumulators Framework uses `numeric::fdiv(x, y)`, which does floating-point division -even if both `x` and `y` are integers. - -Another example where the Numeric Operators Sub-Library is useful is when a type does not -define the operator overloads required to use it for some statistical calculations. For instance, -`std::vector<>` does not overload any arithmetic operators, yet it may be useful to use -`std::vector<>` as a sample or variate type. The Numeric Operators Sub-Library -defines the necessary operator overloads in the `boost::numeric::operators` namespace, -which is brought into scope by the Accumulators Framework with a using directive. - -[*Numeric Function Objects and Tag Dispatching] - -How are the numeric function object defined by the Numeric Operators Sub-Library made -to work with types such as `std::vector<>`? The free functions in the `boost::numeric` namespace -are implemented in terms of the function objects in the `boost::numeric::functional` namespace, -so to make `boost::numeric::fdiv()` do something sensible with a `std::vector<>`, for instance, -we'll need to partially specialize the `boost::numeric::functional::fdiv<>` function object. - -The functional objects make use of a technique known as -[@http://www.boost.org/community/generic_programming.html#tag_dispatching ['tag dispatching]] to -select the proper implementation for the given operands. It works as follows: - - namespace boost { namespace numeric { namespace functional - { - // Metafunction for looking up the tag associated with - // a given numeric type T. - template - struct tag - { - // by default, all types have void as a tag type - typedef void type; - }; - - // Forward declaration looks up the tag types of each operand - template< - typename Left - , typename Right - , typename LeftTag = typename tag::type - , typename RightTag = typename tag::type - > - struct fdiv; - }}} - -If you have some user-defined type `MyDouble` for which you would like to customize the behavior -of `numeric::fdiv()`, you would specialize `numeric::functional::fdiv<>` by -first defining a tag type, as shown below: - - namespace boost { namespace numeric { namespace functional - { - // Tag type for MyDouble - struct MyDoubleTag {}; - - // Specialize tag<> for MyDouble. - // This only needs to be done once. - template<> - struct tag - { - typedef MyDoubleTag type; - }; - - // Specify how to divide a MyDouble by an integral count - template - struct fdiv - { - // Define the type of the result - typedef ... result_type; - - result_type operator()(Left & left, Right & right) const - { - return ...; - } - }; - }}} - -Once you have done this, `numeric::fdiv()` will use your specialization -of `numeric::functional::fdiv<>` when the first argument is a `MyDouble` -object. All of the function objects in the Numeric Operators Sub-Library can -be customized in a similar fashion. - -[endsect] - -[endsect] - -[section Concepts] - -[h2 Accumulator Concept] - -In the following table, `Acc` is the type of an accumulator, `acc` and `acc2` are objects of type -`Acc`, and `args` is the name of an argument pack from the _parameter_ library. - -[table Accumulator Requirements - [[[*Expression]] [[*Return type]] [[*Assertion / Note / - Pre- / Post-condition]]] - [[`Acc::result_type`] [['implementation - defined]] [The type returned by `Acc::result()`.]] - [[`Acc acc(args)`] [none] [Construct from an argument pack.]] - [[`Acc acc(acc2)`] [none] [Post: `acc.result(args)` is equivalent - to `acc2.result(args)`]] - [[`acc(args)`] [['unspecified]] []] - [[`acc.on_drop(args)`] [['unspecified]] []] - [[`acc.result(args)`] [`Acc::result_type`] []] -] - -[h2 Feature Concept] - -In the following table, `F` is the type of a feature and `S` is some scalar type. - -[table Feature Requirements - [[[*Expression]] [[*Return type]] [[*Assertion / Note / - Pre- / Post-condition]]] - [[`F::dependencies`] [['unspecified]] [An MPL sequence of other features on - which `F` depends.]] - [[`F::is_weight_accumulator`] [`mpl::true_` or - `mpl::false_`] [`mpl::true_` if the accumulator for - this feature should be made external - when the weight type for the accumulator - set is `external`, `mpl::false_` - otherwise.]] - [[`F::impl`] [['unspecified]] [An _mpl_lambda_expression_ that - returns the type of the accumulator that - implements this feature when passed a - sample type and a weight type.]] -] - -[endsect] - -[endsect] - -[section The Statistical Accumulators Library] - -The Statistical Accumulators Library defines accumulators for incremental statistical -computations. It is built on top of [link accumulators.user_s_guide.the_accumulators_framework -The Accumulator Framework]. - -[section:count count] - -The `count` feature is a simple counter that tracks the -number of samples pushed into the accumulator set. - -[variablelist - [[Result Type] [`` - std::size_t - ``]] - [[Depends On] [['none]]] - [[Variants] [['none]]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _COUNT_HPP_ [headerref boost/accumulators/statistics/count.hpp]] - - #include <_COUNT_HPP_> - -[*Example] - - accumulator_set > acc; - acc(0); - acc(0); - acc(0); - assert(3 == count(acc)); - -[*See also] - -* [classref boost::accumulators::impl::count_impl `count_impl`] - -[endsect] - -[section:covariance covariance] - -The `covariance` feature is an iterative Monte Carlo estimator for the covariance. -It is specified as `tag::covariance<_variate_type_, _variate_tag_>`. - -[variablelist - [[Result Type] [`` - numeric::functional::outer_product< - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - , numeric::functional::fdiv<_variate_type_, std::size_t>::result_type - >::result_type - ``]] - [[Depends On] [`count` \n `mean` \n `mean_of_variates<_variate_type_, _variate_tag_>`]] - [[Variants] [`abstract_covariance`]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [[~variate-tag]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [O(1)]] -] - -[*Headers] -[def _COVARIANCE_HPP_ [headerref boost/accumulators/statistics/covariance.hpp]] -[def _COVARIATE_HPP_ [headerref boost/accumulators/statistics/variates/covariate.hpp]] - - #include <_COVARIANCE_HPP_> - #include <_COVARIATE_HPP_> - -[*Example] - - accumulator_set > > acc; - acc(1., covariate1 = 2.); - acc(1., covariate1 = 4.); - acc(2., covariate1 = 3.); - acc(6., covariate1 = 1.); - assert(covariance(acc) == -1.75); - -[*See also] - -* [classref boost::accumulators::impl::covariance_impl [^covariance_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.mean [^mean]] - -[endsect] - -[section:density density] - -The `tag::density` feature returns a histogram of the sample distribution. For more -implementation details, see [classref boost::accumulators::impl::density_impl [^density_impl]]. - -[variablelist - [[Result Type] [`` - iterator_range< - std::vector< - std::pair< - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - , numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - > - >::iterator - > - ``]] - [[Depends On] [`count` \n `min` \n `max`]] - [[Variants] [['none]]] - [[Initialization Parameters] [`density::cache_size` \n `density::num_bins`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [O(N), when N is `density::num_bins`]] -] - -[*Header] -[def _DENSITY_HPP_ [headerref boost/accumulators/statistics/density.hpp]] - - #include <_DENSITY_HPP_> - -[*Note] - -Results from the `density` accumulator can only be extracted after the number of -samples meets or exceeds the cache size. - -[/ TODO add example ] - -[*See also] - -* [classref boost::accumulators::impl::density_impl [^density_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.min [^min]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.max [^max]] - -[endsect] - -[section:error_of_mean error_of] - -The `error_of` feature calculates the error of the mean feature. It is equal to -`sqrt(variance / (count - 1))`. - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - ``]] - [[Depends On] [`count` \n `variance`]] - [[Variants] [`error_of`]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _ERROR_OF_HPP_ [headerref boost/accumulators/statistics/error_of.hpp]] -[def _ERROR_OF_MEAN_HPP_ [headerref boost/accumulators/statistics/error_of_mean.hpp]] - - #include <_ERROR_OF_HPP_> - #include <_ERROR_OF_MEAN_HPP_> - -[*Example] - - accumulator_set > > acc; - acc(1.1); - acc(1.2); - acc(1.3); - assert(0.057735 == error_of(acc)); - -[*See also] - -* [classref boost::accumulators::impl::error_of_mean_impl [^error_of_mean_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.variance [^variance]] - -[endsect] - -[section:extended_p_square extended_p_square] - -Multiple quantile estimation with the extended [^P^2] algorithm. For further -details, see [classref boost::accumulators::impl::extended_p_square_impl [^extended_p_square_impl]]. - -[variablelist - [[Result Type] [`` - boost::iterator_range< - _implementation_defined_ - > - ``]] - [[Depends On] [`count`]] - [[Variants] [['none]]] - [[Initialization Parameters] [`tag::extended_p_square::probabilities`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _EXTENDED_P_SQUARE_HPP_ [headerref boost/accumulators/statistics/extended_p_square.hpp]] - - #include <_EXTENDED_P_SQUARE_HPP_> - -[*Example] - - boost::array probs = {0.001,0.01,0.1,0.25,0.5,0.75,0.9,0.99,0.999}; - accumulator_set > - acc(tag::extended_p_square::probabilities = probs); - - boost::lagged_fibonacci607 rng; // a random number generator - for (int i=0; i<10000; ++i) - acc(rng()); - - BOOST_CHECK_CLOSE(extended_p_square(acc)[0], probs[0], 25); - BOOST_CHECK_CLOSE(extended_p_square(acc)[1], probs[1], 10); - BOOST_CHECK_CLOSE(extended_p_square(acc)[2], probs[2], 5); - - for (std::size_t i=3; i < probs.size(); ++i) - { - BOOST_CHECK_CLOSE(extended_p_square(acc)[i], probs[i], 2); - } - -[*See also] - -* [classref boost::accumulators::impl::extended_p_square_impl [^extended_p_square_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] - -[endsect] - -[section:extended_p_square_quantile extended_p_square_quantile ['and variants]] - -Quantile estimation using the extended [^P^2] algorithm for weighted and unweighted samples. -By default, the calculation is linear and unweighted, but quadratic and weighted variants -are also provided. For further implementation details, see -[classref boost::accumulators::impl::extended_p_square_quantile_impl [^extended_p_square_quantile_impl]]. - -All the variants share the `tag::quantile` feature and can be extracted using the `quantile()` -extractor. - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - ``]] - [[Depends On] [weighted variants depend on `weighted_extended_p_square` \n - unweighted variants depend on `extended_p_square`]] - [[Variants] [`extended_p_square_quantile_quadratic` \n - `weighted_extended_p_square_quantile` \n - `weighted_extended_p_square_quantile_quadratic`]] - [[Initialization Parameters] [`tag::extended_p_square::probabilities`]] - [[Accumulator Parameters] [`weight` for the weighted variants]] - [[Extractor Parameters] [`quantile_probability`]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [O(N) where N is the count of probabilities.]] -] - -[*Header] -[def _EXTENDED_P_SQUARE_QUANTILE_HPP_ [headerref boost/accumulators/statistics/extended_p_square_quantile.hpp]] - - #include <_EXTENDED_P_SQUARE_QUANTILE_HPP_> - -[*Example] - - typedef accumulator_set > - accumulator_t; - typedef accumulator_set, double > - accumulator_t_weighted; - typedef accumulator_set > - accumulator_t_quadratic; - typedef accumulator_set, double > - accumulator_t_weighted_quadratic; - - // tolerance - double epsilon = 1; - - // a random number generator - boost::lagged_fibonacci607 rng; - - boost::array probs = { 0.990, 0.991, 0.992, 0.993, 0.994, - 0.995, 0.996, 0.997, 0.998, 0.999 }; - accumulator_t acc(extended_p_square_probabilities = probs); - accumulator_t_weighted acc_weighted(extended_p_square_probabilities = probs); - accumulator_t_quadratic acc2(extended_p_square_probabilities = probs); - accumulator_t_weighted_quadratic acc_weighted2(extended_p_square_probabilities = probs); - - for (int i=0; i<10000; ++i) - { - double sample = rng(); - acc(sample); - acc2(sample); - acc_weighted(sample, weight = 1.); - acc_weighted2(sample, weight = 1.); - } - - for (std::size_t i = 0; i < probs.size() - 1; ++i) - { - BOOST_CHECK_CLOSE( - quantile(acc, quantile_probability = 0.99025 + i*0.001) - , 0.99025 + i*0.001 - , epsilon - ); - BOOST_CHECK_CLOSE( - quantile(acc2, quantile_probability = 0.99025 + i*0.001) - , 0.99025 + i*0.001 - , epsilon - ); - BOOST_CHECK_CLOSE( - quantile(acc_weighted, quantile_probability = 0.99025 + i*0.001) - , 0.99025 + i*0.001 - , epsilon - ); - BOOST_CHECK_CLOSE( - quantile(acc_weighted2, quantile_probability = 0.99025 + i*0.001) - , 0.99025 + i*0.001 - , epsilon - ); - } - -[*See also] - -* [classref boost::accumulators::impl::extended_p_square_quantile_impl [^extended_p_square_quantile_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.extended_p_square [^extended_p_square]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.weighted_extended_p_square [^weighted_extended_p_square]] - -[endsect] - -[section:kurtosis kurtosis] - -The kurtosis of a sample distribution is defined as the ratio of the 4th central moment and the -square of the 2nd central moment (the variance) of the samples, minus 3. The term [^-3] is added -in order to ensure that the normal distribution has zero kurtosis. For more implementation -details, see [classref boost::accumulators::impl::kurtosis_impl [^kurtosis_impl]] - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, _sample_type_>::result_type - ``]] - [[Depends On] [`mean` \n `moment<2>` \n `moment<3>` \n `moment<4>`]] - [[Variants] [['none]]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _KURTOSIS_HPP_ [headerref boost/accumulators/statistics/kurtosis.hpp]] - - #include <_KURTOSIS_HPP_> - -[*Example] - - accumulator_set > acc; - - acc(2); - acc(7); - acc(4); - acc(9); - acc(3); - - BOOST_CHECK_EQUAL( mean(acc), 5 ); - BOOST_CHECK_EQUAL( accumulators::moment<2>(acc), 159./5. ); - BOOST_CHECK_EQUAL( accumulators::moment<3>(acc), 1171./5. ); - BOOST_CHECK_EQUAL( accumulators::moment<4>(acc), 1863 ); - BOOST_CHECK_CLOSE( kurtosis(acc), -1.39965397924, 1e-6 ); - -[*See also] - -* [classref boost::accumulators::impl::kurtosis_impl [^kurtosis_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.mean [^mean]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.moment [^moment]] - -[endsect] - -[section:max max] - -Calculates the maximum value of all the samples. - -[variablelist - [[Result Type] [`` - _sample_type_ - ``]] - [[Depends On] [['none]]] - [[Variants] [['none]]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _MAX_HPP_ [headerref boost/accumulators/statistics/max.hpp]] - - #include <_MAX_HPP_> - -[*Example] - - accumulator_set > acc; - - acc(1); - BOOST_CHECK_EQUAL(1, (max)(acc)); - - acc(0); - BOOST_CHECK_EQUAL(1, (max)(acc)); - - acc(2); - BOOST_CHECK_EQUAL(2, (max)(acc)); - -[*See also] - -* [classref boost::accumulators::impl::max_impl [^max_impl]] - -[endsect] - -[section:mean mean ['and variants]] - -Calculates the mean of samples, weights or variates. The calculation is either -lazy (in the result extractor), or immediate (in the accumulator). The lazy implementation -is the default. For more implementation details, see -[classref boost::accumulators::impl::mean_impl [^mean_impl]] or. -[classref boost::accumulators::impl::immediate_mean_impl [^immediate_mean_impl]] - -[variablelist - [[Result Type] [For samples, `numeric::functional::fdiv<_sample_type_, std::size_t>::result_type` \n - For weights, `numeric::functional::fdiv<_weight_type_, std::size_t>::result_type` \n - For variates, `numeric::functional::fdiv<_variate_type_, std::size_t>::result_type`]] - [[Depends On] [`count` \n - The lazy mean of samples depends on `sum` \n - The lazy mean of weights depends on `sum_of_weights` \n - The lazy mean of variates depends on `sum_of_variates<>`]] - [[Variants] [`mean_of_weights` \n - `mean_of_variates<_variate_type_, _variate_tag_>` \n - `immediate_mean` \n - `immediate_mean_of_weights` \n - `immediate_mean_of_variates<_variate_type_, _variate_tag_>`]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _MEAN_HPP_ [headerref boost/accumulators/statistics/mean.hpp]] - - #include <_MEAN_HPP_> - -[*Example] - - accumulator_set< - int - , stats< - tag::mean - , tag::mean_of_weights - , tag::mean_of_variates - > - , int - > acc; - - acc(1, weight = 2, covariate1 = 3); - BOOST_CHECK_CLOSE(1., mean(acc), 1e-5); - BOOST_CHECK_EQUAL(1u, count(acc)); - BOOST_CHECK_EQUAL(2, sum(acc)); - BOOST_CHECK_CLOSE(2., mean_of_weights(acc), 1e-5); - BOOST_CHECK_CLOSE(3., (accumulators::mean_of_variates(acc)), 1e-5); - - acc(0, weight = 4, covariate1 = 4); - BOOST_CHECK_CLOSE(0.33333333333333333, mean(acc), 1e-5); - BOOST_CHECK_EQUAL(2u, count(acc)); - BOOST_CHECK_EQUAL(2, sum(acc)); - BOOST_CHECK_CLOSE(3., mean_of_weights(acc), 1e-5); - BOOST_CHECK_CLOSE(3.5, (accumulators::mean_of_variates(acc)), 1e-5); - - acc(2, weight = 9, covariate1 = 8); - BOOST_CHECK_CLOSE(1.33333333333333333, mean(acc), 1e-5); - BOOST_CHECK_EQUAL(3u, count(acc)); - BOOST_CHECK_EQUAL(20, sum(acc)); - BOOST_CHECK_CLOSE(5., mean_of_weights(acc), 1e-5); - BOOST_CHECK_CLOSE(5., (accumulators::mean_of_variates(acc)), 1e-5); - - accumulator_set< - int - , stats< - tag::mean(immediate) - , tag::mean_of_weights(immediate) - , tag::mean_of_variates(immediate) - > - , int - > acc2; - - acc2(1, weight = 2, covariate1 = 3); - BOOST_CHECK_CLOSE(1., mean(acc2), 1e-5); - BOOST_CHECK_EQUAL(1u, count(acc2)); - BOOST_CHECK_CLOSE(2., mean_of_weights(acc2), 1e-5); - BOOST_CHECK_CLOSE(3., (accumulators::mean_of_variates(acc2)), 1e-5); - - acc2(0, weight = 4, covariate1 = 4); - BOOST_CHECK_CLOSE(0.33333333333333333, mean(acc2), 1e-5); - BOOST_CHECK_EQUAL(2u, count(acc2)); - BOOST_CHECK_CLOSE(3., mean_of_weights(acc2), 1e-5); - BOOST_CHECK_CLOSE(3.5, (accumulators::mean_of_variates(acc2)), 1e-5); - - acc2(2, weight = 9, covariate1 = 8); - BOOST_CHECK_CLOSE(1.33333333333333333, mean(acc2), 1e-5); - BOOST_CHECK_EQUAL(3u, count(acc2)); - BOOST_CHECK_CLOSE(5., mean_of_weights(acc2), 1e-5); - BOOST_CHECK_CLOSE(5., (accumulators::mean_of_variates(acc2)), 1e-5); - -[*See also] - -* [classref boost::accumulators::impl::mean_impl [^mean_impl]] -* [classref boost::accumulators::impl::immediate_mean_impl [^immediate_mean_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.sum [^sum]] - -[endsect] - -[section:median median ['and variants]] - -Median estimation based on the [^P^2] quantile estimator, the density estimator, or -the [^P^2] cumulative distribution estimator. For more implementation details, see -[classref boost::accumulators::impl::median_impl [^median_impl]], -[classref boost::accumulators::impl::with_density_median_impl [^with_density_median_impl]], -and [classref boost::accumulators::impl::with_p_square_cumulative_distribution_median_impl [^with_p_square_cumulative_distribution_median_impl]]. - -The three median accumulators all satisfy the `tag::median` feature, and can all be -extracted with the `median()` extractor. - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - ``]] - [[Depends On] [`median` depends on `p_square_quantile_for_median` \n - `with_density_median` depends on `count` and `density` \n - `with_p_square_cumulative_distribution_median` depends on `p_square_cumulative_distribution`]] - [[Variants] [`with_density_median` \n - `with_p_square_cumulative_distribution_median`]] - [[Initialization Parameters] [`with_density_median` requires `tag::density::cache_size` and `tag::density::num_bins` \n - `with_p_square_cumulative_distribution_median` requires `tag::p_square_cumulative_distribution::num_cells`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [TODO]] -] - -[*Header] -[def _MEDIAN_HPP_ [headerref boost/accumulators/statistics/median.hpp]] - - #include <_MEDIAN_HPP_> - -[*Example] - - // two random number generators - double mu = 1.; - boost::lagged_fibonacci607 rng; - boost::normal_distribution<> mean_sigma(mu,1); - boost::variate_generator > - normal(rng, mean_sigma); - - accumulator_set > acc; - accumulator_set > - acc_dens( density_cache_size = 10000, density_num_bins = 1000 ); - accumulator_set > - acc_cdist( p_square_cumulative_distribution_num_cells = 100 ); - - for (std::size_t i=0; i<100000; ++i) - { - double sample = normal(); - acc(sample); - acc_dens(sample); - acc_cdist(sample); - } - - BOOST_CHECK_CLOSE(1., median(acc), 1.); - BOOST_CHECK_CLOSE(1., median(acc_dens), 1.); - BOOST_CHECK_CLOSE(1., median(acc_cdist), 3.); - -[*See also] - -* [classref boost::accumulators::impl::median_impl [^median_impl]] -* [classref boost::accumulators::impl::with_density_median_impl [^with_density_median_impl]] -* [classref boost::accumulators::impl::with_p_square_cumulative_distribution_median_impl [^with_p_square_cumulative_distribution_median_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.p_square_quantile [^p_square_quantile]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.p_square_cumulative_distribution [^p_square_cumulative_distribution]] - -[endsect] - -[section:min min] - -Calculates the minimum value of all the samples. - -[variablelist - [[Result Type] [`` - _sample_type_ - ``]] - [[Depends On] [['none]]] - [[Variants] [['none]]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _MIN_HPP_ [headerref boost/accumulators/statistics/min.hpp]] - - #include <_MIN_HPP_> - -[*Example] - - accumulator_set > acc; - - acc(1); - BOOST_CHECK_EQUAL(1, (min)(acc)); - - acc(0); - BOOST_CHECK_EQUAL(0, (min)(acc)); - - acc(2); - BOOST_CHECK_EQUAL(0, (min)(acc)); - -[*See also] - -* [classref boost::accumulators::impl::min_impl [^min_impl]] - -[endsect] - -[section:moment moment] - -Calculates the N-th moment of the samples, which is defined as the sum of the N-th power of the -samples over the count of samples. - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - ``]] - [[Depends On] [`count`]] - [[Variants] [['none]]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _MOMENT_HPP_ [headerref boost/accumulators/statistics/moment.hpp]] - - #include <_MOMENT_HPP_> - -[*Example] - - accumulator_set > > acc1; - - acc1(2); // 4 - acc1(4); // 16 - acc1(5); // + 25 - // = 45 / 3 = 15 - - BOOST_CHECK_CLOSE(15., accumulators::moment<2>(acc1), 1e-5); - - accumulator_set > > acc2; - - acc2(2); // 32 - acc2(3); // 243 - acc2(4); // 1024 - acc2(5); // + 3125 - // = 4424 / 4 = 1106 - - BOOST_CHECK_CLOSE(1106., accumulators::moment<5>(acc2), 1e-5); - -[*See also] - -* [classref boost::accumulators::impl::moment_impl [^moment_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] - -[endsect] - -[section:p_square_cumulative_distribution p_square_cumulative_distribution] - -Histogram calculation of the cumulative distribution with the [^P^2] algorithm. -For more implementation details, see -[classref boost::accumulators::impl::p_square_cumulative_distribution_impl [^p_square_cumulative_distribution_impl]] - -[variablelist - [[Result Type] [`` - iterator_range< - std::vector< - std::pair< - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - , numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - > - >::iterator - > - ``]] - [[Depends On] [`count`]] - [[Variants] [['none]]] - [[Initialization Parameters] [`tag::p_square_cumulative_distribution::num_cells`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [O(N) where N is `num_cells`]] -] - -[*Header] -[def _P_SQUARE_CUMULATIVE_DISTRIBUTION_HPP_ [headerref boost/accumulators/statistics/p_square_cumul_dist.hpp]] - - #include <_P_SQUARE_CUMULATIVE_DISTRIBUTION_HPP_> - -[*Example] - - // tolerance in % - double epsilon = 3; - - typedef accumulator_set > accumulator_t; - - accumulator_t acc(tag::p_square_cumulative_distribution::num_cells = 100); - - // two random number generators - boost::lagged_fibonacci607 rng; - boost::normal_distribution<> mean_sigma(0,1); - boost::variate_generator > normal(rng, mean_sigma); - - for (std::size_t i=0; i<100000; ++i) - { - acc(normal()); - } - - typedef iterator_range >::iterator > histogram_type; - histogram_type histogram = p_square_cumulative_distribution(acc); - - for (std::size_t i = 0; i < histogram.size(); ++i) - { - // problem with small results: epsilon is relative (in percent), not absolute! - if ( histogram[i].second > 0.001 ) - BOOST_CHECK_CLOSE( 0.5 * (1.0 + erf( histogram[i].first / sqrt(2.0) )), histogram[i].second, epsilon ); - } - -[*See also] - -* [classref boost::accumulators::impl::p_square_cumulative_distribution_impl [^p_square_cumulative_distribution_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] - -[endsect] - -[section:p_square_quantile p_square_quantile ['and variants]] - -Single quantile estimation with the [^P^2] algorithm. For more implementation details, see -[classref boost::accumulators::impl::p_square_quantile_impl [^p_square_quantile_impl]] - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - ``]] - [[Depends On] [`count`]] - [[Variants] [`p_square_quantile_for_median`]] - [[Initialization Parameters] [`quantile_probability`, which defaults to `0.5`. - (Note: for `p_square_quantile_for_median`, the `quantile_probability` - parameter is ignored and is always `0.5`.)]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _P_SQUARE_QUANTILE_HPP_ [headerref boost/accumulators/statistics/p_square_quantile.hpp]] - - #include <_P_SQUARE_QUANTILE_HPP_> - -[*Example] - - typedef accumulator_set > accumulator_t; - - // tolerance in % - double epsilon = 1; - - // a random number generator - boost::lagged_fibonacci607 rng; - - accumulator_t acc0(quantile_probability = 0.001); - accumulator_t acc1(quantile_probability = 0.01 ); - accumulator_t acc2(quantile_probability = 0.1 ); - accumulator_t acc3(quantile_probability = 0.25 ); - accumulator_t acc4(quantile_probability = 0.5 ); - accumulator_t acc5(quantile_probability = 0.75 ); - accumulator_t acc6(quantile_probability = 0.9 ); - accumulator_t acc7(quantile_probability = 0.99 ); - accumulator_t acc8(quantile_probability = 0.999); - - for (int i=0; i<100000; ++i) - { - double sample = rng(); - acc0(sample); - acc1(sample); - acc2(sample); - acc3(sample); - acc4(sample); - acc5(sample); - acc6(sample); - acc7(sample); - acc8(sample); - } - - BOOST_CHECK_CLOSE( p_square_quantile(acc0), 0.001, 15*epsilon ); - BOOST_CHECK_CLOSE( p_square_quantile(acc1), 0.01 , 5*epsilon ); - BOOST_CHECK_CLOSE( p_square_quantile(acc2), 0.1 , epsilon ); - BOOST_CHECK_CLOSE( p_square_quantile(acc3), 0.25 , epsilon ); - BOOST_CHECK_CLOSE( p_square_quantile(acc4), 0.5 , epsilon ); - BOOST_CHECK_CLOSE( p_square_quantile(acc5), 0.75 , epsilon ); - BOOST_CHECK_CLOSE( p_square_quantile(acc6), 0.9 , epsilon ); - BOOST_CHECK_CLOSE( p_square_quantile(acc7), 0.99 , epsilon ); - BOOST_CHECK_CLOSE( p_square_quantile(acc8), 0.999, epsilon ); - -[*See also] - -* [classref boost::accumulators::impl::p_square_quantile_impl [^p_square_quantile_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] - -[endsect] - -[section:peaks_over_threshold peaks_over_threshold ['and variants]] - -Peaks Over Threshold method for quantile and tail mean estimation. For implementation -details, see [classref boost::accumulators::impl::peaks_over_threshold_impl [^peaks_over_threshold_impl]] -and [classref boost::accumulators::impl::peaks_over_threshold_prob_impl [^peaks_over_threshold_prob_impl]]. - -Both `tag::peaks_over_threshold` and `tag::peaks_over_threshold_prob<>` satisfy the `tag::abstract_peaks_over_threshold` -feature, and can be extracted with the `peaks_over_threshold()` extractor. The result is a 3-tuple representing -the fit parameters `u_bar`, `beta_bar` and `xi_hat`. - -[variablelist - [[Result Type] [`` - boost::tuple< - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type // u_bar - , numeric::functional::fdiv<_sample_type_, std::size_t>::result_type // beta_bar - , numeric::functional::fdiv<_sample_type_, std::size_t>::result_type // xi_hat - > - ``]] - [[Depends On] [`count` \n - In addition, `tag::peaks_over_threshold_prob<>` depends on `tail<_left_or_right_>`]] - [[Variants] [`peaks_over_threshold_prob<_left_or_right_>`]] - [[Initialization Parameters] [ `tag::peaks_over_threshold::threshold_value` \n - `tag::peaks_over_threshold_prob::threshold_probability` \n - `tag::tail<_left_or_right_>::cache_size` ]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [TODO]] -] - -[*Header] -[def _PEAKS_OVER_THRESHOLD_HPP_ [headerref boost/accumulators/statistics/peaks_over_threshold.hpp]] - - #include <_PEAKS_OVER_THRESHOLD_HPP_> - -[*Example] - -See example for [link accumulators.user_s_guide.the_statistical_accumulators_library.pot_quantile [^pot_quantile]]. - -[*See also] - -* [classref boost::accumulators::impl::peaks_over_threshold_impl [^peaks_over_threshold_impl]] -* [classref boost::accumulators::impl::peaks_over_threshold_prob_impl [^peaks_over_threshold_prob_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.tail [^tail]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.pot_quantile [^pot_quantile]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.pot_tail_mean [^pot_tail_mean]] - -[endsect] - -[section:pot_quantile pot_quantile ['and variants]] - -Quantile estimation based on Peaks over Threshold method (for both left and right tails). For -implementation details, see [classref boost::accumulators::impl::pot_quantile_impl [^pot_quantile_impl]]. - -Both `tag::pot_quantile<_left_or_right_>` and `tag::pot_quantile_prob<_left_or_right_>` satisfy the -`tag::quantile` feature and can be extracted using the `quantile()` extractor. - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - ``]] - [[Depends On] [`pot_quantile<_left_or_right_>` depends on `peaks_over_threshold<_left_or_right_>` \n - `pot_quantile_prob<_left_or_right_>` depends on `peaks_over_threshold_prob<_left_or_right_>` ]] - [[Variants] [`pot_quantile_prob<_left_or_right_>`]] - [[Initialization Parameters] [ `tag::peaks_over_threshold::threshold_value` \n - `tag::peaks_over_threshold_prob::threshold_probability` \n - `tag::tail<_left_or_right_>::cache_size` ]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [`quantile_probability`]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [TODO]] -] - -[*Header] -[def _POT_QUANTILE_HPP_ [headerref boost/accumulators/statistics/pot_quantile.hpp]] - - #include <_POT_QUANTILE_HPP_> - -[*Example] - - // tolerance in % - double epsilon = 1.; - - double alpha = 0.999; - double threshold_probability = 0.99; - double threshold = 3.; - - // two random number generators - boost::lagged_fibonacci607 rng; - boost::normal_distribution<> mean_sigma(0,1); - boost::exponential_distribution<> lambda(1); - boost::variate_generator > normal(rng, mean_sigma); - boost::variate_generator > exponential(rng, lambda); - - accumulator_set(with_threshold_value)> > acc1( - tag::peaks_over_threshold::threshold_value = threshold - ); - accumulator_set(with_threshold_probability)> > acc2( - tag::tail::cache_size = 2000 - , tag::peaks_over_threshold_prob::threshold_probability = threshold_probability - ); - - threshold_probability = 0.995; - threshold = 5.; - - accumulator_set(with_threshold_value)> > acc3( - tag::peaks_over_threshold::threshold_value = threshold - ); - accumulator_set(with_threshold_probability)> > acc4( - tag::tail::cache_size = 2000 - , tag::peaks_over_threshold_prob::threshold_probability = threshold_probability - ); - - for (std::size_t i = 0; i < 100000; ++i) - { - double sample = normal(); - acc1(sample); - acc2(sample); - } - - for (std::size_t i = 0; i < 100000; ++i) - { - double sample = exponential(); - acc3(sample); - acc4(sample); - } - - BOOST_CHECK_CLOSE( quantile(acc1, quantile_probability = alpha), 3.090232, epsilon ); - BOOST_CHECK_CLOSE( quantile(acc2, quantile_probability = alpha), 3.090232, epsilon ); - - BOOST_CHECK_CLOSE( quantile(acc3, quantile_probability = alpha), 6.908, epsilon ); - BOOST_CHECK_CLOSE( quantile(acc4, quantile_probability = alpha), 6.908, epsilon ); - -[*See also] - -* [classref boost::accumulators::impl::pot_quantile_impl [^pot_quantile_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.peaks_over_threshold [^peaks_over_threshold]] - -[endsect] - -[section:pot_tail_mean pot_tail_mean] - -Estimation of the (coherent) tail mean based on the peaks over threshold method (for both left and right tails). -For implementation details, see [classref boost::accumulators::impl::pot_tail_mean_impl [^pot_tail_mean_impl]]. - -Both `tag::pot_tail_mean<_left_or_right_>` and `tag::pot_tail_mean_prob<_left_or_right_>` satisfy the -`tag::tail_mean` feature and can be extracted using the `tail_mean()` extractor. - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - ``]] - [[Depends On] [`pot_tail_mean<_left_or_right_>` depends on `peaks_over_threshold<_left_or_right_>` - and `pot_quantile<_left_or_right_>` \n - `pot_tail_mean_prob<_left_or_right_>` depends on `peaks_over_threshold_prob<_left_or_right_>` - and `pot_quantile_prob<_left_or_right_>` ]] - [[Variants] [`pot_tail_mean_prob<_left_or_right_>`]] - [[Initialization Parameters] [ `tag::peaks_over_threshold::threshold_value` \n - `tag::peaks_over_threshold_prob::threshold_probability` \n - `tag::tail<_left_or_right_>::cache_size` ]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [`quantile_probability`]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [TODO]] -] - -[*Header] -[def _POT_TAIL_MEAN_HPP_ [headerref boost/accumulators/statistics/pot_tail_mean.hpp]] - - #include <_POT_TAIL_MEAN_HPP_> - -[*Example] - - // TODO - -[*See also] - -* [classref boost::accumulators::impl::pot_tail_mean_impl [^pot_tail_mean_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.peaks_over_threshold [^peaks_over_threshold]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.pot_quantile [^pot_quantile]] - -[endsect] - -[section:rolling_count rolling_count] - -The rolling count is the current number of elements in the rolling window. - -[variablelist - [[Result Type] [``std::size_t``]] - [[Depends On] [`rolling_window_plus1`]] - [[Variants] [['none]]] - [[Initialization Parameters] [`tag::rolling_window::window_size`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _ROLLING_COUNT_HPP_ [headerref boost/accumulators/statistics/rolling_count.hpp]] - - #include <_ROLLING_COUNT_HPP_> - -[*Example] - - accumulator_set > acc(tag::rolling_window::window_size = 3); - - BOOST_CHECK_EQUAL(0u, rolling_count(acc)); - - acc(1); - BOOST_CHECK_EQUAL(1u, rolling_count(acc)); - - acc(1); - BOOST_CHECK_EQUAL(2u, rolling_count(acc)); - - acc(1); - BOOST_CHECK_EQUAL(3u, rolling_count(acc)); - - acc(1); - BOOST_CHECK_EQUAL(3u, rolling_count(acc)); - - acc(1); - BOOST_CHECK_EQUAL(3u, rolling_count(acc)); - -[*See also] - -* [classref boost::accumulators::impl::rolling_count_impl [^rolling_count_impl]] - -[endsect] - -[section:rolling_sum rolling_sum] - -The rolling sum is the sum of the last /N/ samples. - -[variablelist - [[Result Type] [``_sample_type_``]] - [[Depends On] [`rolling_window_plus1`]] - [[Variants] [['none]]] - [[Initialization Parameters] [`tag::rolling_window::window_size`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _ROLLING_SUM_HPP_ [headerref boost/accumulators/statistics/rolling_sum.hpp]] - - #include <_ROLLING_SUM_HPP_> - -[*Example] - - accumulator_set > acc(tag::rolling_window::window_size = 3); - - BOOST_CHECK_EQUAL(0, rolling_sum(acc)); - - acc(1); - BOOST_CHECK_EQUAL(1, rolling_sum(acc)); - - acc(2); - BOOST_CHECK_EQUAL(3, rolling_sum(acc)); - - acc(3); - BOOST_CHECK_EQUAL(6, rolling_sum(acc)); - - acc(4); - BOOST_CHECK_EQUAL(9, rolling_sum(acc)); - - acc(5); - BOOST_CHECK_EQUAL(12, rolling_sum(acc)); - -[*See also] - -* [classref boost::accumulators::impl::rolling_sum_impl [^rolling_sum_impl]] - -[endsect] - -[section:rolling_mean rolling_mean] - -The rolling mean is the mean over the last /N/ samples. It is computed by dividing -the rolling sum by the rolling count. - -Lazy or iterative calculation of the mean over the last /N/ samples. The lazy calculation is associated with the `tag::lazy_rolling_mean` -feature, and the iterative calculation (which is the default) with the `tag::immediate_rolling_mean` feature. Both can be extracted -using the `tag::rolling_mean()` extractor. For more implementation details, see -[classref boost::accumulators::impl::lazy_rolling_mean_impl [^lazy_rolling_mean_impl]] and -[classref boost::accumulators::impl::immediate_rolling_mean_impl [^immediate_rolling_mean_impl]] - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - ``]] - [[Depends On] [`lazy_rolling_mean` depends on `rolling_sum` and `rolling_count` \n - `immediate_rolling_mean` depends on `rolling_count`]] - [[Variants] [`lazy_rolling_mean` (a.k.a. `rolling_mean(lazy))` \n - `immediate_rolling_mean` (a.k.a. `rolling_mean(immediate)`)]] - [[Initialization Parameters] [`tag::rolling_window::window_size`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _ROLLING_MEAN_HPP_ [headerref boost/accumulators/statistics/rolling_mean.hpp]] - - #include <_ROLLING_MEAN_HPP_> - -[*Example] - - accumulator_set > acc(tag::rolling_window::window_size = 5); - - acc(1); - acc(2); - acc(3); - - BOOST_CHECK_CLOSE( rolling_mean(acc), 2.0, 1e-6 ); - - acc(4); - acc(5); - acc(6); - acc(7); - - BOOST_CHECK_CLOSE( rolling_mean(acc), 5.0, 1e-6 ); - -[*See also] - -* [classref boost::accumulators::impl::lazy_rolling_mean_impl [^lazy_rolling_mean_impl]] -* [classref boost::accumulators::impl::immediate_rolling_mean_impl [^immediate_rolling_mean_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.rolling_count [^rolling_count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.rolling_sum [^rolling_sum]] - -[endsect] - -[section:rolling_moment rolling_moment] - -rolling_moment calculates the /M/-th moment of the samples, which is defined as the sum of the /M/-th power of the samples over the count of samples, over the last /N/ samples. - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - ``]] - [[Depends On] [['none]]] - [[Variants] [['none]]] - [[Initialization Parameters] [`tag::rolling_window::window_size`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _ROLLING_MOMENT_HPP_ [headerref boost/accumulators/statistics/rolling_moment.hpp]] - - #include <_ROLLING_MOMENT_HPP_> - -[*Example] - - accumulator_set > > acc(tag::rolling_window::window_size = 3); - - acc(2); - acc(4); - - BOOST_CHECK_CLOSE( rolling_moment<2>(acc), (4.0 + 16.0)/2, 1e-5 ); - - acc(5); - acc(6); - - BOOST_CHECK_CLOSE( rolling_moment<2>(acc), (16.0 + 25.0 + 36.0)/3, 1e-5 ); - -[*See also] - -* [classref boost::accumulators::impl::rolling_moment_impl [^rolling_moment_impl]] - -[endsect] - -[section:rolling_variance rolling_variance] - -Lazy or iterative calculation of the variance over the last /N/ samples. The lazy calculation is associated with the `tag::lazy_rolling_variance` -feature, and the iterative calculation with the `tag::immediate_rolling_variance` feature. Both can be extracted using the `tag::rolling_variance()` extractor. -For more implementation details, see -[classref boost::accumulators::impl::lazy_rolling_variance_impl [^lazy_rolling_variance_impl]] and -[classref boost::accumulators::impl::immediate_rolling_variance_impl [^immediate_rolling_variance_impl]] - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - ``]] - [[Depends On] [`lazy_rolling_variance` depends on `rolling_moment<2>`, `rolling_count` and `rolling_mean` \n - `immediate_rolling_variance` depends on `rolling_count` and `immediate_rolling_mean`]] - [[Variants] [`lazy_rolling_variance` (a.k.a. `rolling_variance(lazy))` \n - `immediate_rolling_variance` (a.k.a. `rolling_variance(immediate)`)]] - [[Initialization Parameters] [`tag::rolling_window::window_size`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _ROLLING_VARIANCE_HPP_ [headerref boost/accumulators/statistics/rolling_variance.hpp]] - - #include <_ROLLING_VARIANCE_HPP_> - -[*Example] - - accumulator_set > acc(tag::rolling_window::window_size = 4); - - acc(1.2); - - BOOST_CHECK_CLOSE( rolling_variance(acc), 0.0, 1e-10 ); // variance is not defined for a single sample - - acc(2.3); - acc(3.4); - - BOOST_CHECK_CLOSE( rolling_variance(acc), 1.21, 1e-10 ); // variance over samples 1-3 - - acc(4.5); - acc(0.4); - acc(2.2); - acc(7.1); - - BOOST_CHECK_CLOSE( rolling_variance(acc), 8.41666666666667, 1e-10 ); // variance over samples 4-7 - -[*See also] - -* [classref boost::accumulators::impl::lazy_rolling_variance_impl [^lazy_rolling_variance_impl]] -* [classref boost::accumulators::impl::immediate_rolling_variance_impl [^immediate_rolling_variance_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.rolling_count [^rolling_count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.rolling_mean [^rolling_mean]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.immediate_rolling_mean [^immediate_rolling_mean]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.rolling_moment [^rolling_moment]] - -[endsect] - - -[section:skewness skewness] - -The skewness of a sample distribution is defined as the ratio of the 3rd central moment and the [^3/2]-th power -of the 2nd central moment (the variance) of the samples 3. For implementation details, see -[classref boost::accumulators::impl::skewness_impl [^skewness_impl]]. - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, _sample_type_>::result_type - ``]] - [[Depends On] [`mean` \n `moment<2>` \n `moment<3>`]] - [[Variants] [['none]]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _SKEWNESS_HPP_ [headerref boost/accumulators/statistics/skewness.hpp]] - - #include <_SKEWNESS_HPP_> - -[*Example] - - accumulator_set > acc2; - - acc2(2); - acc2(7); - acc2(4); - acc2(9); - acc2(3); - - BOOST_CHECK_EQUAL( mean(acc2), 5 ); - BOOST_CHECK_EQUAL( accumulators::moment<2>(acc2), 159./5. ); - BOOST_CHECK_EQUAL( accumulators::moment<3>(acc2), 1171./5. ); - BOOST_CHECK_CLOSE( skewness(acc2), 0.406040288214, 1e-6 ); - -[*See also] - -* [classref boost::accumulators::impl::skewness_impl [^skewness_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.mean [^mean]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.moment [^moment]] - -[endsect] - -[section:sum sum ['and variants]] - -For summing the samples, weights or variates. The default implementation uses the standard sum operation, -but variants using the Kahan summation algorithm are also provided. - -[variablelist - [[Result Type] [`_sample_type_` for summing samples \n - `_weight_type_` for summing weights \n - `_variate_type_` for summing variates]] - [[Depends On] [['none]]] - [[Variants] [`tag::sum` \n - `tag::sum_of_weights` \n - `tag::sum_of_variates<_variate_type_, _variate_tag_>` \n - `tag::sum_kahan` (a.k.a. `tag::sum(kahan)`) \n - `tag::sum_of_weights_kahan` (a.k.a. `tag::sum_of_weights(kahan)`) \n - `tag::sum_of_variates_kahan<_variate_type_, _variate_tag_>` \n]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [`weight` for summing weights \n - `_variate_tag_` for summing variates]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1). Note that the Kahan sum performs four floating-point sum - operations per accumulated value, whereas the naive sum - performs only one.]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _SUM_HPP_ [headerref boost/accumulators/statistics/sum.hpp]] -[def _SUM_KAHAN_HPP_ [headerref boost/accumulators/statistics/sum_kahan.hpp]] - - #include <_SUM_HPP_> - #include <_SUM_KAHAN_HPP_> - -[*Example] - - accumulator_set< - int - , stats< - tag::sum - , tag::sum_of_weights - , tag::sum_of_variates - > - , int - > acc; - - acc(1, weight = 2, covariate1 = 3); - BOOST_CHECK_EQUAL(2, sum(acc)); // weighted sample = 1 * 2 - BOOST_CHECK_EQUAL(2, sum_of_weights(acc)); - BOOST_CHECK_EQUAL(3, sum_of_variates(acc)); - - acc(2, weight = 4, covariate1 = 6); - BOOST_CHECK_EQUAL(10, sum(acc)); // weighted sample = 2 * 4 - BOOST_CHECK_EQUAL(6, sum_of_weights(acc)); - BOOST_CHECK_EQUAL(9, sum_of_variates(acc)); - - acc(3, weight = 6, covariate1 = 9); - BOOST_CHECK_EQUAL(28, sum(acc)); // weighted sample = 3 * 6 - BOOST_CHECK_EQUAL(12, sum_of_weights(acc)); - BOOST_CHECK_EQUAL(18, sum_of_variates(acc)); - - // demonstrate Kahan summation - accumulator_set > acc; - BOOST_CHECK_EQUAL(0.0f, sum_kahan(acc)); - for (size_t i = 0; i < 1e6; ++i) { - acc(1e-6f); - } - BOOST_CHECK_EQUAL(1.0f, sum_kahan(acc)); - -[*See also] - -* [classref boost::accumulators::impl::sum_impl [^sum_impl]] -* [classref boost::accumulators::impl::sum_kahan_impl [^sum_kahan_impl]] - -[endsect] - -[section:tail tail] - -Tracks the largest or smallest [^N] values. `tag::tail` tracks the largest [^N], -and `tag::tail` tracks the smallest. The parameter [^N] is specified with the -`tag::tail<_left_or_right_>::cache_size` initialization parameter. For implementation details, see -[classref boost::accumulators::impl::tail_impl [^tail_impl]]. - -Both `tag::tail` and `tag::tail` satisfy the `tag::abstract_tail` feature and -can be extracted with the `tail()` extractor. - -[variablelist - [[Result Type] [`` - boost::iterator_range< - boost::reverse_iterator< - boost::permutation_iterator< - std::vector<_sample_type_>::const_iterator // samples - , std::vector::iterator // indices - > - > - > - ``]] - [[Depends On] [['none]]] - [[Variants] [`abstract_tail`]] - [[Initialization Parameters] [`tag::tail<_left_or_right_>::cache_size`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(log N), where N is the cache size]] - [[Extractor Complexity] [O(N log N), where N is the cache size]] -] - -[*Header] -[def _TAIL_HPP_ [headerref boost/accumulators/statistics/tail.hpp]] - - #include <_TAIL_HPP_> - -[*Example] - -See the Example for [link accumulators.user_s_guide.the_statistical_accumulators_library.tail_variate [^tail_variate]]. - -[*See also] - -* [classref boost::accumulators::impl::tail_impl [^tail_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.tail_variate [^tail_variate]] - -[endsect] - -[section:coherent_tail_mean coherent_tail_mean] - -Estimation of the coherent tail mean based on order statistics (for both left and right tails). -The left coherent tail mean feature is `tag::coherent_tail_mean`, and the right coherent -tail mean feature is `tag::coherent_tail_mean`. They both share the `tag::tail_mean` feature -and can be extracted with the `tail_mean()` extractor. For more implementation details, see -[classref boost::accumulators::impl::coherent_tail_mean_impl [^coherent_tail_mean_impl]] - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - ``]] - [[Depends On] [`count` \n `quantile` \n `non_coherent_tail_mean<_left_or_right_>`]] - [[Variants] [['none]]] - [[Initialization Parameters] [`tag::tail<_left_or_right_>::cache_size`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [`quantile_probability`]] - [[Accumulator Complexity] [O(log N), where N is the cache size]] - [[Extractor Complexity] [O(N log N), where N is the cache size]] -] - -[*Header] -[def _TAIL_MEAN_HPP_ [headerref boost/accumulators/statistics/tail_mean.hpp]] - - #include <_TAIL_MEAN_HPP_> - -[*Example] - -See the example for -[link accumulators.user_s_guide.the_statistical_accumulators_library.non_coherent_tail_mean [^non_coherent_tail_mean]]. - -[*See also] - -* [classref boost::accumulators::impl::coherent_tail_mean_impl [^coherent_tail_mean_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.extended_p_square_quantile [^extended_p_square_quantile]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.pot_quantile [^pot_quantile]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.tail_quantile [^tail_quantile]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.non_coherent_tail_mean [^non_coherent_tail_mean]] - -[endsect] - -[section:non_coherent_tail_mean non_coherent_tail_mean] - -Estimation of the (non-coherent) tail mean based on order statistics (for both left and right tails). -The left non-coherent tail mean feature is `tag::non_coherent_tail_mean`, and the right non-choherent -tail mean feature is `tag::non_coherent_tail_mean`. They both share the `tag::abstract_non_coherent_tail_mean` -feature and can be extracted with the `non_coherent_tail_mean()` extractor. For more implementation details, see -[classref boost::accumulators::impl::non_coherent_tail_mean_impl [^non_coherent_tail_mean_impl]] - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - ``]] - [[Depends On] [`count` \n `tail<_left_or_right_>`]] - [[Variants] [`abstract_non_coherent_tail_mean`]] - [[Initialization Parameters] [`tag::tail<_left_or_right_>::cache_size`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [`quantile_probability`]] - [[Accumulator Complexity] [O(log N), where N is the cache size]] - [[Extractor Complexity] [O(N log N), where N is the cache size]] -] - -[*Header] -[def _TAIL_MEAN_HPP_ [headerref boost/accumulators/statistics/tail_mean.hpp]] - - #include <_TAIL_MEAN_HPP_> - -[*Example] - - // tolerance in % - double epsilon = 1; - - std::size_t n = 100000; // number of MC steps - std::size_t c = 10000; // cache size - - typedef accumulator_set, tag::tail_quantile > > accumulator_t_right1; - typedef accumulator_set, tag::tail_quantile > > accumulator_t_left1; - typedef accumulator_set, tag::tail_quantile > > accumulator_t_right2; - typedef accumulator_set, tag::tail_quantile > > accumulator_t_left2; - - accumulator_t_right1 acc0( right_tail_cache_size = c ); - accumulator_t_left1 acc1( left_tail_cache_size = c ); - accumulator_t_right2 acc2( right_tail_cache_size = c ); - accumulator_t_left2 acc3( left_tail_cache_size = c ); - - // a random number generator - boost::lagged_fibonacci607 rng; - - for (std::size_t i = 0; i < n; ++i) - { - double sample = rng(); - acc0(sample); - acc1(sample); - acc2(sample); - acc3(sample); - } - - // check uniform distribution - BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc0, quantile_probability = 0.95), 0.975, epsilon ); - BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc0, quantile_probability = 0.975), 0.9875, epsilon ); - BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc0, quantile_probability = 0.99), 0.995, epsilon ); - BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc0, quantile_probability = 0.999), 0.9995, epsilon ); - BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc1, quantile_probability = 0.05), 0.025, epsilon ); - BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc1, quantile_probability = 0.025), 0.0125, epsilon ); - BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc1, quantile_probability = 0.01), 0.005, 5 ); - BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc1, quantile_probability = 0.001), 0.0005, 10 ); - BOOST_CHECK_CLOSE( tail_mean(acc2, quantile_probability = 0.95), 0.975, epsilon ); - BOOST_CHECK_CLOSE( tail_mean(acc2, quantile_probability = 0.975), 0.9875, epsilon ); - BOOST_CHECK_CLOSE( tail_mean(acc2, quantile_probability = 0.99), 0.995, epsilon ); - BOOST_CHECK_CLOSE( tail_mean(acc2, quantile_probability = 0.999), 0.9995, epsilon ); - BOOST_CHECK_CLOSE( tail_mean(acc3, quantile_probability = 0.05), 0.025, epsilon ); - BOOST_CHECK_CLOSE( tail_mean(acc3, quantile_probability = 0.025), 0.0125, epsilon ); - BOOST_CHECK_CLOSE( tail_mean(acc3, quantile_probability = 0.01), 0.005, 5 ); - BOOST_CHECK_CLOSE( tail_mean(acc3, quantile_probability = 0.001), 0.0005, 10 ); - -[*See also] - -* [classref boost::accumulators::impl::non_coherent_tail_mean_impl [^non_coherent_tail_mean_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.tail [^tail]] - -[endsect] - -[section:tail_quantile tail_quantile] - -Tail quantile estimation based on order statistics (for both left and right tails). -The left tail quantile feature is `tag::tail_quantile`, and the right -tail quantile feature is `tag::tail_quantile`. They both share the `tag::quantile` -feature and can be extracted with the `quantile()` extractor. For more implementation details, see -[classref boost::accumulators::impl::tail_quantile_impl [^tail_quantile_impl]] - -[variablelist - [[Result Type] [`` - _sample_type_ - ``]] - [[Depends On] [`count` \n `tail<_left_or_right_>`]] - [[Variants] [['none]]] - [[Initialization Parameters] [`tag::tail<_left_or_right_>::cache_size`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [`quantile_probability`]] - [[Accumulator Complexity] [O(log N), where N is the cache size]] - [[Extractor Complexity] [O(N log N), where N is the cache size]] -] - -[*Header] -[def _TAIL_QUANTILE_HPP_ [headerref boost/accumulators/statistics/tail_quantile.hpp]] - - #include <_TAIL_QUANTILE_HPP_> - -[*Example] - - // tolerance in % - double epsilon = 1; - - std::size_t n = 100000; // number of MC steps - std::size_t c = 10000; // cache size - - typedef accumulator_set > > accumulator_t_right; - typedef accumulator_set > > accumulator_t_left; - - accumulator_t_right acc0( tag::tail::cache_size = c ); - accumulator_t_right acc1( tag::tail::cache_size = c ); - accumulator_t_left acc2( tag::tail::cache_size = c ); - accumulator_t_left acc3( tag::tail::cache_size = c ); - - // two random number generators - boost::lagged_fibonacci607 rng; - boost::normal_distribution<> mean_sigma(0,1); - boost::variate_generator > normal(rng, mean_sigma); - - for (std::size_t i = 0; i < n; ++i) - { - double sample1 = rng(); - double sample2 = normal(); - acc0(sample1); - acc1(sample2); - acc2(sample1); - acc3(sample2); - } - - // check uniform distribution - BOOST_CHECK_CLOSE( quantile(acc0, quantile_probability = 0.95 ), 0.95, epsilon ); - BOOST_CHECK_CLOSE( quantile(acc0, quantile_probability = 0.975), 0.975, epsilon ); - BOOST_CHECK_CLOSE( quantile(acc0, quantile_probability = 0.99 ), 0.99, epsilon ); - BOOST_CHECK_CLOSE( quantile(acc0, quantile_probability = 0.999), 0.999, epsilon ); - BOOST_CHECK_CLOSE( quantile(acc2, quantile_probability = 0.05 ), 0.05, 2 ); - BOOST_CHECK_CLOSE( quantile(acc2, quantile_probability = 0.025), 0.025, 2 ); - BOOST_CHECK_CLOSE( quantile(acc2, quantile_probability = 0.01 ), 0.01, 3 ); - BOOST_CHECK_CLOSE( quantile(acc2, quantile_probability = 0.001), 0.001, 20 ); - - // check standard normal distribution - BOOST_CHECK_CLOSE( quantile(acc1, quantile_probability = 0.975), 1.959963, epsilon ); - BOOST_CHECK_CLOSE( quantile(acc1, quantile_probability = 0.999), 3.090232, epsilon ); - BOOST_CHECK_CLOSE( quantile(acc3, quantile_probability = 0.025), -1.959963, epsilon ); - BOOST_CHECK_CLOSE( quantile(acc3, quantile_probability = 0.001), -3.090232, epsilon ); - -[*See also] - -* [classref boost::accumulators::impl::tail_quantile_impl [^tail_quantile_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.tail [^tail]] - -[endsect] - -[section:tail_variate tail_variate] - -Tracks the covariates of largest or smallest [^N] samples. -`tag::tail_variate<_variate_type_, _variate_tag_, right>` tracks the covariate associated with -_variate_tag_ for the largest [^N], and `tag::tail_variate<_variate_type_, _variate_tag_, left>` -for the smallest. The parameter [^N] is specified with the `tag::tail<_left_or_right_>::cache_size` -initialization parameter. For implementation details, see -[classref boost::accumulators::impl::tail_variate_impl [^tail_variate_impl]]. - -Both `tag::tail_variate<_variate_type_, _variate_tag_, right>` and -`tag::tail_variate<_variate_type_, _variate_tag_, left>` satisfy the `tag::abstract_tail_variate` feature -and can be extracted with the `tail_variate()` extractor. - -[variablelist - [[Result Type] [`` - boost::iterator_range< - boost::reverse_iterator< - boost::permutation_iterator< - std::vector<_variate_type_>::const_iterator // variates - , std::vector::iterator // indices - > - > - > - ``]] - [[Depends On] [`tail<_left_or_right_>`]] - [[Variants] [`abstract_tail_variate`]] - [[Initialization Parameters] [`tag::tail<_left_or_right_>::cache_size`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(log N), where N is the cache size]] - [[Extractor Complexity] [O(N log N), where N is the cache size]] -] - -[*Header] -[def _TAIL_VARIATE_HPP_ [headerref boost/accumulators/statistics/tail_variate.hpp]] - - #include <_TAIL_VARIATE_HPP_> - -[*Example] - - accumulator_set > > acc( - tag::tail::cache_size = 4 - ); - - acc(8, covariate1 = 3); - CHECK_RANGE_EQUAL(tail(acc), {8}); - CHECK_RANGE_EQUAL(tail_variate(acc), {3}); - - acc(16, covariate1 = 1); - CHECK_RANGE_EQUAL(tail(acc), {16, 8}); - CHECK_RANGE_EQUAL(tail_variate(acc), {1, 3}); - - acc(12, covariate1 = 4); - CHECK_RANGE_EQUAL(tail(acc), {16, 12, 8}); - CHECK_RANGE_EQUAL(tail_variate(acc), {1, 4, 3}); - - acc(24, covariate1 = 5); - CHECK_RANGE_EQUAL(tail(acc), {24, 16, 12, 8}); - CHECK_RANGE_EQUAL(tail_variate(acc), {5, 1, 4, 3}); - - acc(1, covariate1 = 9); - CHECK_RANGE_EQUAL(tail(acc), {24, 16, 12, 8}); - CHECK_RANGE_EQUAL(tail_variate(acc), {5, 1, 4, 3}); - - acc(9, covariate1 = 7); - CHECK_RANGE_EQUAL(tail(acc), {24, 16, 12, 9}); - CHECK_RANGE_EQUAL(tail_variate(acc), {5, 1, 4, 7}); - -[*See also] - -* [classref boost::accumulators::impl::tail_variate_impl [^tail_variate_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.tail [^tail]] - -[endsect] - -[section:tail_variate_means tail_variate_means ['and variants]] - -Estimation of the absolute and relative tail variate means (for both left and right tails). -The absolute tail variate means has the feature -`tag::absolute_tail_variate_means<_left_or_right_, _variate_type_, _variate_tag_>` -and the relative tail variate mean has the feature -`tag::relative_tail_variate_means<_left_or_right_, _variate_type_, _variate_tag_>`. All -absolute tail variate mean features share the `tag::abstract_absolute_tail_variate_means` -feature and can be extracted with the `tail_variate_means()` extractor. All the -relative tail variate mean features share the `tag::abstract_relative_tail_variate_means` -feature and can be extracted with the `relative_tail_variate_means()` extractor. - -For more implementation details, see -[classref boost::accumulators::impl::tail_variate_means_impl [^tail_variate_means_impl]] - -[variablelist - [[Result Type] [`` - boost::iterator_range< - std::vector< - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - >::iterator - > - ``]] - [[Depends On] [`non_coherent_tail_mean<_left_or_right_>` \n - `tail_variate<_variate_type_, _variate_tag_, _left_or_right_>`]] - [[Variants] [`tag::absolute_tail_variate_means<_left_or_right_, _variate_type_, _variate_tag_>` \n - `tag::relative_tail_variate_means<_left_or_right_, _variate_type_, _variate_tag_>`]] - [[Initialization Parameters] [`tag::tail<_left_or_right_>::cache_size`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [`quantile_probability`]] - [[Accumulator Complexity] [O(log N), where N is the cache size]] - [[Extractor Complexity] [O(N log N), where N is the cache size]] -] - -[*Header] -[def _TAIL_VARIATE_MEANS_HPP_ [headerref boost/accumulators/statistics/tail_variate_means.hpp]] - - #include <_TAIL_VARIATE_MEANS_HPP_> - -[*Example] - - std::size_t c = 5; // cache size - - typedef double variate_type; - typedef std::vector variate_set_type; - - typedef accumulator_set(relative)>, tag::tail > - accumulator_t1; - - typedef accumulator_set(absolute)>, tag::tail > - accumulator_t2; - - typedef accumulator_set(relative)>, tag::tail > - accumulator_t3; - - typedef accumulator_set(absolute)>, tag::tail > - accumulator_t4; - - accumulator_t1 acc1( right_tail_cache_size = c ); - accumulator_t2 acc2( right_tail_cache_size = c ); - accumulator_t3 acc3( left_tail_cache_size = c ); - accumulator_t4 acc4( left_tail_cache_size = c ); - - variate_set_type cov1, cov2, cov3, cov4, cov5; - double c1[] = { 10., 20., 30., 40. }; // 100 - double c2[] = { 26., 4., 17., 3. }; // 50 - double c3[] = { 46., 64., 40., 50. }; // 200 - double c4[] = { 1., 3., 70., 6. }; // 80 - double c5[] = { 2., 2., 2., 14. }; // 20 - cov1.assign(c1, c1 + sizeof(c1)/sizeof(variate_type)); - cov2.assign(c2, c2 + sizeof(c2)/sizeof(variate_type)); - cov3.assign(c3, c3 + sizeof(c3)/sizeof(variate_type)); - cov4.assign(c4, c4 + sizeof(c4)/sizeof(variate_type)); - cov5.assign(c5, c5 + sizeof(c5)/sizeof(variate_type)); - - acc1(100., covariate1 = cov1); - acc1( 50., covariate1 = cov2); - acc1(200., covariate1 = cov3); - acc1( 80., covariate1 = cov4); - acc1( 20., covariate1 = cov5); - - acc2(100., covariate1 = cov1); - acc2( 50., covariate1 = cov2); - acc2(200., covariate1 = cov3); - acc2( 80., covariate1 = cov4); - acc2( 20., covariate1 = cov5); - - acc3(100., covariate1 = cov1); - acc3( 50., covariate1 = cov2); - acc3(200., covariate1 = cov3); - acc3( 80., covariate1 = cov4); - acc3( 20., covariate1 = cov5); - - acc4(100., covariate1 = cov1); - acc4( 50., covariate1 = cov2); - acc4(200., covariate1 = cov3); - acc4( 80., covariate1 = cov4); - acc4( 20., covariate1 = cov5); - - // check relative risk contributions - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.7).begin() ), 14./75. ); // (10 + 46) / 300 = 14/75 - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.7).begin() + 1), 7./25. ); // (20 + 64) / 300 = 7/25 - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.7).begin() + 2), 7./30. ); // (30 + 40) / 300 = 7/30 - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.7).begin() + 3), 3./10. ); // (40 + 50) / 300 = 3/10 - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.3).begin() ), 14./35. ); // (26 + 2) / 70 = 14/35 - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.3).begin() + 1), 3./35. ); // ( 4 + 2) / 70 = 3/35 - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.3).begin() + 2), 19./70. ); // (17 + 2) / 70 = 19/70 - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.3).begin() + 3), 17./70. ); // ( 3 + 14) / 70 = 17/70 - - // check absolute risk contributions - BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.7).begin() ), 28 ); // (10 + 46) / 2 = 28 - BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.7).begin() + 1), 42 ); // (20 + 64) / 2 = 42 - BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.7).begin() + 2), 35 ); // (30 + 40) / 2 = 35 - BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.7).begin() + 3), 45 ); // (40 + 50) / 2 = 45 - BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.3).begin() ), 14 ); // (26 + 2) / 2 = 14 - BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.3).begin() + 1), 3 ); // ( 4 + 2) / 2 = 3 - BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.3).begin() + 2),9.5 ); // (17 + 2) / 2 = 9.5 - BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.3).begin() + 3),8.5 ); // ( 3 + 14) / 2 = 8.5 - - // check relative risk contributions - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.9).begin() ), 23./100. ); // 46/200 = 23/100 - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.9).begin() + 1), 8./25. ); // 64/200 = 8/25 - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.9).begin() + 2), 1./5. ); // 40/200 = 1/5 - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.9).begin() + 3), 1./4. ); // 50/200 = 1/4 - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.1).begin() ), 1./10. ); // 2/ 20 = 1/10 - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.1).begin() + 1), 1./10. ); // 2/ 20 = 1/10 - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.1).begin() + 2), 1./10. ); // 2/ 20 = 1/10 - BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.1).begin() + 3), 7./10. ); // 14/ 20 = 7/10 - - // check absolute risk contributions - BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.9).begin() ), 46 ); // 46 - BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.9).begin() + 1), 64 ); // 64 - BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.9).begin() + 2), 40 ); // 40 - BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.9).begin() + 3), 50 ); // 50 - BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.1).begin() ), 2 ); // 2 - BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.1).begin() + 1), 2 ); // 2 - BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.1).begin() + 2), 2 ); // 2 - BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.1).begin() + 3), 14 ); // 14 - -[*See also] - -* [classref boost::accumulators::impl::tail_variate_means_impl [^tail_variate_means_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.non_coherent_tail_mean [^non_coherent_tail_mean]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.tail_variate [^tail_variate]] - -[endsect] - -[section:variance variance ['and variants]] - -Lazy or iterative calculation of the variance. The lazy calculation is associated with the `tag::lazy_variance` -feature, and the iterative calculation with the `tag::variance` feature. Both can be extracted -using the `tag::variance()` extractor. For more implementation details, see -[classref boost::accumulators::impl::lazy_variance_impl [^lazy_variance_impl]] and -[classref boost::accumulators::impl::variance_impl [^variance_impl]] - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - ``]] - [[Depends On] [`tag::lazy_variance` depends on `tag::moment<2>` and `tag::mean` \n - `tag::variance` depends on `tag::count` and `tag::immediate_mean`]] - [[Variants] [`tag::lazy_variance` (a.k.a. `tag::variance(lazy))` \n - `tag::variance` (a.k.a. `tag::variance(immediate)`)]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _VARIANCE_HPP_ [headerref boost/accumulators/statistics/variance.hpp]] - - #include <_VARIANCE_HPP_> - -[*Example] - - // lazy variance - accumulator_set > acc1; - - acc1(1); - acc1(2); - acc1(3); - acc1(4); - acc1(5); - - BOOST_CHECK_EQUAL(5u, count(acc1)); - BOOST_CHECK_CLOSE(3., mean(acc1), 1e-5); - BOOST_CHECK_CLOSE(11., accumulators::moment<2>(acc1), 1e-5); - BOOST_CHECK_CLOSE(2., variance(acc1), 1e-5); - - // immediate variance - accumulator_set > acc2; - - acc2(1); - acc2(2); - acc2(3); - acc2(4); - acc2(5); - - BOOST_CHECK_EQUAL(5u, count(acc2)); - BOOST_CHECK_CLOSE(3., mean(acc2), 1e-5); - BOOST_CHECK_CLOSE(2., variance(acc2), 1e-5); - -[*See also] - -* [classref boost::accumulators::impl::lazy_variance_impl [^lazy_variance_impl]] -* [classref boost::accumulators::impl::variance_impl [^variance_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.mean [^mean]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.moment [^moment]] - -[endsect] - -[section:weighted_covariance weighted_covariance] - -An iterative Monte Carlo estimator for the weighted covariance. The feature is specified as -`tag::weighted_covariance<_variate_type_, _variate_tag_>` and is extracted with the `weighted_variate()` -extractor. For more implementation details, see -[classref boost::accumulators::impl::weighted_covariance_impl [^weighted_covariance_impl]] - -[variablelist - [[Result Type] [`` - numeric::functional::outer_product< - numeric::functional::multiplies< - _weight_type_ - , numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - >::result_type - , numeric::functional::multiplies< - _weight_type_ - , numeric::functional::fdiv<_variate_type_, std::size_t>::result_type - >::result_type - > - ``]] - [[Depends On] [`count` \n - `sum_of_weights` \n - `weighted_mean` \n - `weighted_mean_of_variates<_variate_type_, _variate_tag_>`]] - [[Variants] [`abstract_weighted_covariance`]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [`weight` \n - `_variate_tag_`]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _WEIGHTED_COVARIANCE_HPP_ [headerref boost/accumulators/statistics/weighted_covariance.hpp]] - - #include <_WEIGHTED_COVARIANCE_HPP_> - -[*Example] - - accumulator_set >, double > acc; - - acc(1., weight = 1.1, covariate1 = 2.); - acc(1., weight = 2.2, covariate1 = 4.); - acc(2., weight = 3.3, covariate1 = 3.); - acc(6., weight = 4.4, covariate1 = 1.); - - double epsilon = 1e-6; - BOOST_CHECK_CLOSE(weighted_covariance(acc), -2.39, epsilon); - -[*See also] - -* [classref boost::accumulators::impl::weighted_covariance_impl [^weighted_covariance_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.sum [^sum]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.weighted_mean [^weighted_mean]] - -[endsect] - -[section:weighted_density weighted_density] - -The `tag::weighted_density` feature returns a histogram of the weighted sample distribution. For more -implementation details, see [classref boost::accumulators::impl::weighted_density_impl [^weighted_density_impl]]. - -[variablelist - [[Result Type] [`` - iterator_range< - std::vector< - std::pair< - numeric::functional::fdiv<_weight_type_, std::size_t>::result_type - , numeric::functional::fdiv<_weight_type_, std::size_t>::result_type - > - >::iterator - > - ``]] - [[Depends On] [`count` \n `sum_of_weights` \n `min` \n `max`]] - [[Variants] [['none]]] - [[Initialization Parameters] [`tag::weighted_density::cache_size` \n `tag::weighted_density::num_bins`]] - [[Accumulator Parameters] [`weight`]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [O(N), when N is `weighted_density::num_bins`]] -] - -[*Header] -[def _WEIGHTED_DENSITY_HPP_ [headerref boost/accumulators/statistics/weighted_density.hpp]] - - #include <_WEIGHTED_DENSITY_HPP_> - -[/ TODO add example ] - -[*See also] - -* [classref boost::accumulators::impl::weighted_density_impl [^weighted_density_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.sum [^sum]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.min [^min]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.max [^max]] - -[endsect] - -[section:weighted_extended_p_square weighted_extended_p_square] - -Multiple quantile estimation with the extended [^P^2] algorithm for weighted samples. For further -details, see [classref boost::accumulators::impl::weighted_extended_p_square_impl [^weighted_extended_p_square_impl]]. - -[variablelist - [[Result Type] [`` - boost::iterator_range< - _implementation_defined_ - > - ``]] - [[Depends On] [`count` \n `sum_of_weights`]] - [[Variants] [['none]]] - [[Initialization Parameters] [`tag::weighted_extended_p_square::probabilities`]] - [[Accumulator Parameters] [`weight`]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _WEIGHTED_EXTENDED_P_SQUARE_HPP_ [headerref boost/accumulators/statistics/weighted_extended_p_square.hpp]] - - #include <_WEIGHTED_EXTENDED_P_SQUARE_HPP_> - -[*Example] - - typedef accumulator_set, double> accumulator_t; - - // tolerance in % - double epsilon = 1; - - // some random number generators - double mu1 = -1.0; - double mu2 = 1.0; - boost::lagged_fibonacci607 rng; - boost::normal_distribution<> mean_sigma1(mu1, 1); - boost::normal_distribution<> mean_sigma2(mu2, 1); - boost::variate_generator > normal1(rng, mean_sigma1); - boost::variate_generator > normal2(rng, mean_sigma2); - - std::vector probs_uniform, probs_normal1, probs_normal2, probs_normal_exact1, probs_normal_exact2; - - double p1[] = {/*0.001,*/ 0.01, 0.1, 0.5, 0.9, 0.99, 0.999}; - probs_uniform.assign(p1, p1 + sizeof(p1) / sizeof(double)); - - double p2[] = {0.001, 0.025}; - double p3[] = {0.975, 0.999}; - probs_normal1.assign(p2, p2 + sizeof(p2) / sizeof(double)); - probs_normal2.assign(p3, p3 + sizeof(p3) / sizeof(double)); - - double p4[] = {-3.090232, -1.959963}; - double p5[] = {1.959963, 3.090232}; - probs_normal_exact1.assign(p4, p4 + sizeof(p4) / sizeof(double)); - probs_normal_exact2.assign(p5, p5 + sizeof(p5) / sizeof(double)); - - accumulator_t acc_uniform(tag::weighted_extended_p_square::probabilities = probs_uniform); - accumulator_t acc_normal1(tag::weighted_extended_p_square::probabilities = probs_normal1); - accumulator_t acc_normal2(tag::weighted_extended_p_square::probabilities = probs_normal2); - - for (std::size_t i = 0; i < 100000; ++i) - { - acc_uniform(rng(), weight = 1.); - - double sample1 = normal1(); - double sample2 = normal2(); - acc_normal1(sample1, weight = std::exp(-mu1 * (sample1 - 0.5 * mu1))); - acc_normal2(sample2, weight = std::exp(-mu2 * (sample2 - 0.5 * mu2))); - } - - // check for uniform distribution - for (std::size_t i = 0; i < probs_uniform.size(); ++i) - { - BOOST_CHECK_CLOSE(weighted_extended_p_square(acc_uniform)[i], probs_uniform[i], epsilon); - } - - // check for standard normal distribution - for (std::size_t i = 0; i < probs_normal1.size(); ++i) - { - BOOST_CHECK_CLOSE(weighted_extended_p_square(acc_normal1)[i], probs_normal_exact1[i], epsilon); - BOOST_CHECK_CLOSE(weighted_extended_p_square(acc_normal2)[i], probs_normal_exact2[i], epsilon); - } - -[*See also] - -* [classref boost::accumulators::impl::weighted_extended_p_square_impl [^weighted_extended_p_square_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.sum [^sum]] - -[endsect] - -[section:weighted_kurtosis weighted_kurtosis] - -The kurtosis of a sample distribution is defined as the ratio of the 4th central moment and the -square of the 2nd central moment (the variance) of the samples, minus 3. The term [^-3] is added -in order to ensure that the normal distribution has zero kurtosis. For more implementation -details, see [classref boost::accumulators::impl::weighted_kurtosis_impl [^weighted_kurtosis_impl]] - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv< - numeric::functional::multiplies<_sample_type_, _weight_type_>::result_type - , numeric::functional::multiplies<_sample_type_, _weight_type_>::result_type - >::result_type - ``]] - [[Depends On] [`weighted_mean` \n `weighted_moment<2>` \n `weighted_moment<3>` \n `weighted_moment<4>`]] - [[Variants] [['none]]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _WEIGHTED_KURTOSIS_HPP_ [headerref boost/accumulators/statistics/weighted_kurtosis.hpp]] - - #include <_WEIGHTED_KURTOSIS_HPP_> - -[*Example] - - accumulator_set, int > acc2; - - acc2(2, weight = 4); - acc2(7, weight = 1); - acc2(4, weight = 3); - acc2(9, weight = 1); - acc2(3, weight = 2); - - BOOST_CHECK_EQUAL( weighted_mean(acc2), 42./11. ); - BOOST_CHECK_EQUAL( accumulators::weighted_moment<2>(acc2), 212./11. ); - BOOST_CHECK_EQUAL( accumulators::weighted_moment<3>(acc2), 1350./11. ); - BOOST_CHECK_EQUAL( accumulators::weighted_moment<4>(acc2), 9956./11. ); - BOOST_CHECK_CLOSE( weighted_kurtosis(acc2), 0.58137026432, 1e-6 ); - -[*See also] - -* [classref boost::accumulators::impl::weighted_kurtosis_impl [^weighted_kurtosis_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.weighted_mean [^weighted_mean]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.weighted_moment [^weighted_moment]] - -[endsect] - -[section:weighted_mean weighted_mean ['and variants]] - -Calculates the weighted mean of samples or variates. The calculation is either -lazy (in the result extractor), or immediate (in the accumulator). The lazy implementation -is the default. For more implementation details, see -[classref boost::accumulators::impl::weighted_mean_impl [^weighted_mean_impl]] or. -[classref boost::accumulators::impl::immediate_weighted_mean_impl [^immediate_weighted_mean_impl]] - -[variablelist - [[Result Type] [For samples, `numeric::functional::fdiv::result_type, _weight_type_>::result_type` \n - For variates, `numeric::functional::fdiv::result_type, _weight_type_>::result_type`]] - [[Depends On] [`sum_of_weights` \n - The lazy mean of samples depends on `weighted_sum` \n - The lazy mean of variates depends on `weighted_sum_of_variates<>`]] - [[Variants] [`weighted_mean_of_variates<_variate_type_, _variate_tag_>` \n - `immediate_weighted_mean` \n - `immediate_weighted_mean_of_variates<_variate_type_, _variate_tag_>`]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _WEIGHTED_MEAN_HPP_ [headerref boost/accumulators/statistics/weighted_mean.hpp]] - - #include <_WEIGHTED_MEAN_HPP_> - -[*Example] - - accumulator_set< - int - , stats< - tag::weighted_mean - , tag::weighted_mean_of_variates - > - , int - > acc; - - acc(10, weight = 2, covariate1 = 7); // 20 - BOOST_CHECK_EQUAL(2, sum_of_weights(acc)); // - // - acc(6, weight = 3, covariate1 = 8); // 18 - BOOST_CHECK_EQUAL(5, sum_of_weights(acc)); // - // - acc(4, weight = 4, covariate1 = 9); // 16 - BOOST_CHECK_EQUAL(9, sum_of_weights(acc)); // - // - acc(6, weight = 5, covariate1 = 6); //+ 30 - BOOST_CHECK_EQUAL(14, sum_of_weights(acc)); // - //= 84 / 14 = 6 - - BOOST_CHECK_EQUAL(6., weighted_mean(acc)); - BOOST_CHECK_EQUAL(52./7., (accumulators::weighted_mean_of_variates(acc))); - - accumulator_set< - int - , stats< - tag::weighted_mean(immediate) - , tag::weighted_mean_of_variates(immediate) - > - , int - > acc2; - - acc2(10, weight = 2, covariate1 = 7); // 20 - BOOST_CHECK_EQUAL(2, sum_of_weights(acc2)); // - // - acc2(6, weight = 3, covariate1 = 8); // 18 - BOOST_CHECK_EQUAL(5, sum_of_weights(acc2)); // - // - acc2(4, weight = 4, covariate1 = 9); // 16 - BOOST_CHECK_EQUAL(9, sum_of_weights(acc2)); // - // - acc2(6, weight = 5, covariate1 = 6); //+ 30 - BOOST_CHECK_EQUAL(14, sum_of_weights(acc2)); // - //= 84 / 14 = 6 - - BOOST_CHECK_EQUAL(6., weighted_mean(acc2)); - BOOST_CHECK_EQUAL(52./7., (accumulators::weighted_mean_of_variates(acc2))); - -[*See also] - -* [classref boost::accumulators::impl::weighted_mean_impl [^weighted_mean_impl]] -* [classref boost::accumulators::impl::immediate_weighted_mean_impl [^immediate_weighted_mean_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.weighted_sum [^weighted_sum]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.sum [^sum]] - -[endsect] - -[section:weighted_median weighted_median ['and variants]] - -Median estimation for weighted samples based on the [^P^2] quantile estimator, the density estimator, or -the [^P^2] cumulative distribution estimator. For more implementation details, see -[classref boost::accumulators::impl::weighted_median_impl [^weighted_median_impl]], -[classref boost::accumulators::impl::with_weighted_density_median_impl [^with_weighted_density_median_impl]], -and [classref boost::accumulators::impl::with_weighted_p_square_cumulative_distribution_median_impl [^with_weighted_p_square_cumulative_distribution_median_impl]]. - -The three median accumulators all satisfy the `tag::weighted_median` feature, and can all be -extracted with the `weighted_median()` extractor. - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv<_sample_type_, std::size_t>::result_type - ``]] - [[Depends On] [`weighted_median` depends on `weighted_p_square_quantile_for_median` \n - `with_weighted_density_median` depends on `count` and `weighted_density` \n - `with_weighted_p_square_cumulative_distribution_median` depends on `weighted_p_square_cumulative_distribution`]] - [[Variants] [`with_weighted_density_median` (a.k.a. `weighted_median(with_weighted_density)`) \n - `with_weighted_p_square_cumulative_distribution_median` (a.k.a. `weighted_median(with_weighted_p_square_cumulative_distribution)`)]] - [[Initialization Parameters] [`with_weighted_density_median` requires `tag::weighted_density::cache_size` and `tag::weighted_density::num_bins` \n - `with_weighted_p_square_cumulative_distribution_median` requires `tag::weighted_p_square_cumulative_distribution::num_cells`]] - [[Accumulator Parameters] [`weight`]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [TODO]] -] - -[*Header] -[def _WEIGHTED_MEDIAN_HPP_ [headerref boost/accumulators/statistics/weighted_median.hpp]] - - #include <_WEIGHTED_MEDIAN_HPP_> - -[*Example] - - // Median estimation of normal distribution N(1,1) using samples from a narrow normal distribution N(1,0.01) - // The weights equal to the likelihood ratio of the corresponding samples - - // two random number generators - double mu = 1.; - double sigma_narrow = 0.01; - double sigma = 1.; - boost::lagged_fibonacci607 rng; - boost::normal_distribution<> mean_sigma_narrow(mu,sigma_narrow); - boost::variate_generator > normal_narrow(rng, mean_sigma_narrow); - - accumulator_set, double > acc; - accumulator_set, double > - acc_dens( tag::weighted_density::cache_size = 10000, tag::weighted_density::num_bins = 1000 ); - accumulator_set, double > - acc_cdist( tag::weighted_p_square_cumulative_distribution::num_cells = 100 ); - - for (std::size_t i=0; i<100000; ++i) - { - double sample = normal_narrow(); - acc(sample, weight = std::exp(0.5 * (sample - mu) * (sample - mu) * ( 1./sigma_narrow/sigma_narrow - 1./sigma/sigma ))); - acc_dens(sample, weight = std::exp(0.5 * (sample - mu) * (sample - mu) * ( 1./sigma_narrow/sigma_narrow - 1./sigma/sigma ))); - acc_cdist(sample, weight = std::exp(0.5 * (sample - mu) * (sample - mu) * ( 1./sigma_narrow/sigma_narrow - 1./sigma/sigma ))); - } - - BOOST_CHECK_CLOSE(1., weighted_median(acc), 1e-1); - BOOST_CHECK_CLOSE(1., weighted_median(acc_dens), 1e-1); - BOOST_CHECK_CLOSE(1., weighted_median(acc_cdist), 1e-1); - -[*See also] - -* [classref boost::accumulators::impl::weighted_median_impl [^weighted_median_impl]] -* [classref boost::accumulators::impl::with_weighted_density_median_impl [^with_weighted_density_median_impl]] -* [classref boost::accumulators::impl::with_weighted_p_square_cumulative_distribution_median_impl [^with_weighted_p_square_cumulative_distribution_median_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.weighted_p_square_quantile [^weighted_p_square_quantile]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.weighted_p_square_cumulative_distribution [^weighted_p_square_cumulative_distribution]] - -[endsect] - -[section:weighted_moment weighted_moment] - -Calculates the N-th moment of the weighted samples, which is defined as the sum of the weighted N-th -power of the samples over the sum of the weights. - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv< - numeric::functional::multiplies<_sample_type_, _weight_type_>::result_type - , weight_type - >::result_type - ``]] - [[Depends On] [`count` \n `sum_of_weights`]] - [[Variants] [['none]]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [`weight`]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _WEIGHTED_MOMENT_HPP_ [headerref boost/accumulators/statistics/weighted_moment.hpp]] - - #include <_WEIGHTED_MOMENT_HPP_> - -[*Example] - - accumulator_set >, double> acc2; - accumulator_set >, double> acc7; - - acc2(2.1, weight = 0.7); - acc2(2.7, weight = 1.4); - acc2(1.8, weight = 0.9); - - acc7(2.1, weight = 0.7); - acc7(2.7, weight = 1.4); - acc7(1.8, weight = 0.9); - - BOOST_CHECK_CLOSE(5.403, accumulators::weighted_moment<2>(acc2), 1e-5); - BOOST_CHECK_CLOSE(548.54182, accumulators::weighted_moment<7>(acc7), 1e-5); - -[*See also] - -* [classref boost::accumulators::impl::weighted_moment_impl [^weighted_moment_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.sum [^sum]] - -[endsect] - -[section:weighted_p_square_cumulative_distribution weighted_p_square_cumulative_distribution] - -Histogram calculation of the cumulative distribution with the [^P^2] algorithm for weighted samples. -For more implementation details, see -[classref boost::accumulators::impl::weighted_p_square_cumulative_distribution_impl [^weighted_p_square_cumulative_distribution_impl]] - -[variablelist - [[Result Type] [`` - iterator_range< - std::vector< - std::pair< - numeric::functional::fdiv::result_type - , numeric::functional::fdiv::result_type - > - >::iterator - > - `` - where `weighted_sample` is `numeric::functional::multiplies<_sample_type_, _weight_type_>::result_type`]] - [[Depends On] [`count` \n `sum_or_weights`]] - [[Variants] [['none]]] - [[Initialization Parameters] [`tag::weighted_p_square_cumulative_distribution::num_cells`]] - [[Accumulator Parameters] [`weight`]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [O(N) where N is `num_cells`]] -] - -[*Header] -[def _WEIGHTED_P_SQUARE_CUMULATIVE_DISTRIBUTION_HPP_ [headerref boost/accumulators/statistics/weighted_p_square_cumul_dist.hpp]] - - #include <_WEIGHTED_P_SQUARE_CUMULATIVE_DISTRIBUTION_HPP_> - -[*Example] - - // tolerance in % - double epsilon = 4; - - typedef accumulator_set, double > accumulator_t; - - accumulator_t acc_upper(tag::weighted_p_square_cumulative_distribution::num_cells = 100); - accumulator_t acc_lower(tag::weighted_p_square_cumulative_distribution::num_cells = 100); - - // two random number generators - double mu_upper = 1.0; - double mu_lower = -1.0; - boost::lagged_fibonacci607 rng; - boost::normal_distribution<> mean_sigma_upper(mu_upper,1); - boost::normal_distribution<> mean_sigma_lower(mu_lower,1); - boost::variate_generator > normal_upper(rng, mean_sigma_upper); - boost::variate_generator > normal_lower(rng, mean_sigma_lower); - - for (std::size_t i=0; i<100000; ++i) - { - double sample = normal_upper(); - acc_upper(sample, weight = std::exp(-mu_upper * (sample - 0.5 * mu_upper))); - } - - for (std::size_t i=0; i<100000; ++i) - { - double sample = normal_lower(); - acc_lower(sample, weight = std::exp(-mu_lower * (sample - 0.5 * mu_lower))); - } - - typedef iterator_range >::iterator > histogram_type; - histogram_type histogram_upper = weighted_p_square_cumulative_distribution(acc_upper); - histogram_type histogram_lower = weighted_p_square_cumulative_distribution(acc_lower); - - // Note that applying importance sampling results in a region of the distribution - // to be estimated more accurately and another region to be estimated less accurately - // than without importance sampling, i.e., with unweighted samples - - for (std::size_t i = 0; i < histogram_upper.size(); ++i) - { - // problem with small results: epsilon is relative (in percent), not absolute! - - // check upper region of distribution - if ( histogram_upper[i].second > 0.1 ) - BOOST_CHECK_CLOSE( 0.5 * (1.0 + erf( histogram_upper[i].first / sqrt(2.0) )), histogram_upper[i].second, epsilon ); - // check lower region of distribution - if ( histogram_lower[i].second < -0.1 ) - BOOST_CHECK_CLOSE( 0.5 * (1.0 + erf( histogram_lower[i].first / sqrt(2.0) )), histogram_lower[i].second, epsilon ); - } - -[*See also] - -* [classref boost::accumulators::impl::weighted_p_square_cumulative_distribution_impl [^weighted_p_square_cumulative_distribution_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.sum [^sum]] - -[endsect] - -[section:weighted_p_square_quantile weighted_p_square_quantile ['and variants]] - -Single quantile estimation with the [^P^2] algorithm. For more implementation details, see -[classref boost::accumulators::impl::weighted_p_square_quantile_impl [^weighted_p_square_quantile_impl]] - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv< - numeric::functional::multiplies<_sample_type_, _weight_type_>::result_type - , std::size_t - >::result_type - ``]] - [[Depends On] [`count` \n `sum_of_weights`]] - [[Variants] [`weighted_p_square_quantile_for_median`]] - [[Initialization Parameters] [`quantile_probability`, which defaults to `0.5`. - (Note: for `weighted_p_square_quantile_for_median`, the `quantile_probability` - parameter is ignored and is always `0.5`.)]] - [[Accumulator Parameters] [`weight`]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _WEIGHTED_P_SQUARE_QUANTILE_HPP_ [headerref boost/accumulators/statistics/weighted_p_square_quantile.hpp]] - - #include <_WEIGHTED_P_SQUARE_QUANTILE_HPP_> - -[*Example] - - typedef accumulator_set, double> accumulator_t; - - // tolerance in % - double epsilon = 1; - - // some random number generators - double mu4 = -1.0; - double mu5 = -1.0; - double mu6 = 1.0; - double mu7 = 1.0; - boost::lagged_fibonacci607 rng; - boost::normal_distribution<> mean_sigma4(mu4, 1); - boost::normal_distribution<> mean_sigma5(mu5, 1); - boost::normal_distribution<> mean_sigma6(mu6, 1); - boost::normal_distribution<> mean_sigma7(mu7, 1); - boost::variate_generator > normal4(rng, mean_sigma4); - boost::variate_generator > normal5(rng, mean_sigma5); - boost::variate_generator > normal6(rng, mean_sigma6); - boost::variate_generator > normal7(rng, mean_sigma7); - - accumulator_t acc0(quantile_probability = 0.001); - accumulator_t acc1(quantile_probability = 0.025); - accumulator_t acc2(quantile_probability = 0.975); - accumulator_t acc3(quantile_probability = 0.999); - - accumulator_t acc4(quantile_probability = 0.001); - accumulator_t acc5(quantile_probability = 0.025); - accumulator_t acc6(quantile_probability = 0.975); - accumulator_t acc7(quantile_probability = 0.999); - - - for (std::size_t i=0; i<100000; ++i) - { - double sample = rng(); - acc0(sample, weight = 1.); - acc1(sample, weight = 1.); - acc2(sample, weight = 1.); - acc3(sample, weight = 1.); - - double sample4 = normal4(); - double sample5 = normal5(); - double sample6 = normal6(); - double sample7 = normal7(); - acc4(sample4, weight = std::exp(-mu4 * (sample4 - 0.5 * mu4))); - acc5(sample5, weight = std::exp(-mu5 * (sample5 - 0.5 * mu5))); - acc6(sample6, weight = std::exp(-mu6 * (sample6 - 0.5 * mu6))); - acc7(sample7, weight = std::exp(-mu7 * (sample7 - 0.5 * mu7))); - } - - // check for uniform distribution with weight = 1 - BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc0), 0.001, 15 ); - BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc1), 0.025, 5 ); - BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc2), 0.975, epsilon ); - BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc3), 0.999, epsilon ); - - // check for shifted standard normal distribution ("importance sampling") - BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc4), -3.090232, epsilon ); - BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc5), -1.959963, epsilon ); - BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc6), 1.959963, epsilon ); - BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc7), 3.090232, epsilon ); - -[*See also] - -* [classref boost::accumulators::impl::weighted_p_square_quantile_impl [^weighted_p_square_quantile_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.sum [^sum]] - -[endsect] - -[section:weighted_peaks_over_threshold weighted_peaks_over_threshold ['and variants]] - -Weighted peaks over threshold method for weighted quantile and weighted tail mean estimation. -For more implementation details, -see [classref boost::accumulators::impl::weighted_peaks_over_threshold_impl [^weighted_peaks_over_threshold_impl]] -and [classref boost::accumulators::impl::weighted_peaks_over_threshold_prob_impl [^weighted_peaks_over_threshold_prob_impl]]. - -Both `tag::weighted_peaks_over_threshold<_left_or_right_>` and -`tag::weighted_peaks_over_threshold_prob<_left_or_right_>` satisfy the -`tag::weighted_peaks_over_threshold<_left_or_right_>` feature and can be extracted using the -`weighted_peaks_over_threshold()` extractor. - -[variablelist - [[Result Type] [`tuple` where `float_type` is - `` - numeric::functional::fdiv< - numeric::functional::multiplies<_sample_type_, _weight_type_>::result_type - , std::size_t - >::result_type - ``]] - [[Depends On] [`weighted_peaks_over_threshold<_left_or_right_>` depends on `sum_of_weights` \n - `weighted_peaks_over_threshold_prob<_left_or_right_>` depends on `sum_of_weights` and `tail_weights<_left_or_right_>`]] - [[Variants] [`weighted_peaks_over_threshold_prob`]] - [[Initialization Parameters] [ `tag::peaks_over_threshold::threshold_value` \n - `tag::peaks_over_threshold_prob::threshold_probability` \n - `tag::tail<_left_or_right_>::cache_size` ]] - [[Accumulator Parameters] [`weight`]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [TODO]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _WEIGHTED_PEAKS_OVER_THRESHOLD_HPP_ [headerref boost/accumulators/statistics/weighted_peaks_over_threshold.hpp]] - - #include <_WEIGHTED_PEAKS_OVER_THRESHOLD_HPP_> - -[/ TODO Add example] - -[*See also] - -* [classref boost::accumulators::impl::weighted_peaks_over_threshold_impl [^weighted_peaks_over_threshold_impl]] -* [classref boost::accumulators::impl::weighted_peaks_over_threshold_prob_impl [^weighted_peaks_over_threshold_prob_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.sum [^sum]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.tail [^tail]] - -[endsect] - -[section:weighted_skewness weighted_skewness] - -The skewness of a sample distribution is defined as the ratio of the 3rd central moment and the [^3/2]-th power -of the 2nd central moment (the variance) of the samples 3. The skewness estimator for weighted samples -is formally identical to the estimator for unweighted samples, except that the weighted counterparts of -all measures it depends on are to be taken. - -For implementation details, see -[classref boost::accumulators::impl::weighted_skewness_impl [^weighted_skewness_impl]]. - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv< - numeric::functional::multiplies<_sample_type_, _weight_type_>::result_type - , numeric::functional::multiplies<_sample_type_, _weight_type_>::result_type - >::result_type - ``]] - [[Depends On] [`weighted_mean` \n `weighted_moment<2>` \n `weighted_moment<3>`]] - [[Variants] [['none]]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [`weight`]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _WEIGHTED_SKEWNESS_HPP_ [headerref boost/accumulators/statistics/weighted_skewness.hpp]] - - #include <_WEIGHTED_SKEWNESS_HPP_> - -[*Example] - - accumulator_set, int > acc2; - - acc2(2, weight = 4); - acc2(7, weight = 1); - acc2(4, weight = 3); - acc2(9, weight = 1); - acc2(3, weight = 2); - - BOOST_CHECK_EQUAL( weighted_mean(acc2), 42./11. ); - BOOST_CHECK_EQUAL( accumulators::weighted_moment<2>(acc2), 212./11. ); - BOOST_CHECK_EQUAL( accumulators::weighted_moment<3>(acc2), 1350./11. ); - BOOST_CHECK_CLOSE( weighted_skewness(acc2), 1.30708406282, 1e-6 ); - -[*See also] - -* [classref boost::accumulators::impl::weighted_skewness_impl [^weighted_skewness_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.weighted_mean [^weighted_mean]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.weighted_moment [^weighted_moment]] - -[endsect] - -[section:weighted_sum weighted_sum ['and variants]] - -For summing the weighted samples or variates. All of the `tag::weighted_sum_of_variates<>` features -can be extracted with the `weighted_sum_of_variates()` extractor. Variants that implement the Kahan -summation algorithm are also provided. - -[variablelist - [[Result Type] [`numeric::functional::multiplies<_sample_type_, _weight_type_>::result_type` for summing weighted samples \n - `numeric::functional::multiplies<_variate_type_, _weight_type_>::result_type` for summing weighted variates]] - [[Depends On] [['none]]] - [[Variants] [`tag::weighted_sum` \n - `tag::weighted_sum_of_variates<_variate_type_, _variate_tag_>` \n - `tag::weighted_sum_kahan` (a.k.a. tag::weighted_sum(kahan)) \n - `tag::weighted_sum_of_variates_kahan<_variate_type_, _variate_tag_>` \n]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [`weight` \n - `_variate_tag_` for summing variates]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1). Note that the Kahan sum performs four floating-point sum - operations per accumulated value, whereas the naive sum - performs only one.]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _WEIGHTED_SUM_HPP_ [headerref boost/accumulators/statistics/weighted_sum.hpp]] -[def _WEIGHTED_SUM_KAHAN_HPP_ [headerref boost/accumulators/statistics/weighted_sum_kahan.hpp]] - - #include <_WEIGHTED_SUM_HPP_> - #include <_WEIGHTED_SUM_KAHAN_HPP_> - - -[*Example] - - accumulator_set >, int> acc; - - acc(1, weight = 2, covariate1 = 3); - BOOST_CHECK_EQUAL(2, weighted_sum(acc)); - BOOST_CHECK_EQUAL(6, weighted_sum_of_variates(acc)); - - acc(2, weight = 3, covariate1 = 6); - BOOST_CHECK_EQUAL(8, weighted_sum(acc)); - BOOST_CHECK_EQUAL(24, weighted_sum_of_variates(acc)); - - acc(4, weight = 6, covariate1 = 9); - BOOST_CHECK_EQUAL(32, weighted_sum(acc)); - BOOST_CHECK_EQUAL(78, weighted_sum_of_variates(acc)); - - // demonstrate weighted Kahan summation - accumulator_set, float > acc; - BOOST_CHECK_EQUAL(0.0f, weighted_sum_kahan(acc)); - for (size_t i = 0; i < 1e6; ++i) { - acc(1.0f, weight = 1e-6f); - } - BOOST_CHECK_EQUAL(1.0f, weighted_sum_kahan(acc)); - -[*See also] - -* [classref boost::accumulators::impl::weighted_sum_impl [^weighted_sum_impl]] -* [classref boost::accumulators::impl::weighted_sum_impl [^weighted_sum_kahan_impl]] - -[endsect] - -[section:non_coherent_weighted_tail_mean non_coherent_weighted_tail_mean] - -Estimation of the (non-coherent) weighted tail mean based on order statistics (for both left and right tails). -The left non-coherent weighted tail mean feature is `tag::non_coherent_weighted_tail_mean`, and the right -non-choherent weighted tail mean feature is `tag::non_coherent_weighted_tail_mean`. They both share the -`tag::abstract_non_coherent_tail_mean` feature with the unweighted non-coherent tail mean accumulators and can -be extracted with either the `non_coherent_tail_mean()` or the `non_coherent_weighted_tail_mean()` extractors. -For more implementation details, see -[classref boost::accumulators::impl::non_coherent_weighted_tail_mean_impl [^non_coherent_weighted_tail_mean_impl]]. - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv< - numeric::functional::multiplies<_sample_type_, _weight_type_>::result_type - , std::size_t - >::result_type - ``]] - [[Depends On] [`sum_of_weights` \n `tail_weights<_left_or_right_>`]] - [[Variants] [`abstract_non_coherent_tail_mean`]] - [[Initialization Parameters] [`tag::tail<_left_or_right_>::cache_size`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [`quantile_probability`]] - [[Accumulator Complexity] [O(log N), where N is the cache size]] - [[Extractor Complexity] [O(N log N), where N is the cache size]] -] - -[*Header] -[def _WEIGHTED_TAIL_MEAN_HPP_ [headerref boost/accumulators/statistics/weighted_tail_mean.hpp]] - - #include <_WEIGHTED_TAIL_MEAN_HPP_> - -[*Example] - - // tolerance in % - double epsilon = 1; - - std::size_t n = 100000; // number of MC steps - std::size_t c = 25000; // cache size - - accumulator_set >, double > - acc0( right_tail_cache_size = c ); - accumulator_set >, double > - acc1( left_tail_cache_size = c ); - - // random number generators - boost::lagged_fibonacci607 rng; - - for (std::size_t i = 0; i < n; ++i) - { - double smpl = std::sqrt(rng()); - acc0(smpl, weight = 1./smpl); - } - - for (std::size_t i = 0; i < n; ++i) - { - double smpl = rng(); - acc1(smpl*smpl, weight = smpl); - } - - // check uniform distribution - BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc0, quantile_probability = 0.95), 0.975, epsilon ); - BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc0, quantile_probability = 0.975), 0.9875, epsilon ); - BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc0, quantile_probability = 0.99), 0.995, epsilon ); - BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc0, quantile_probability = 0.999), 0.9995, epsilon ); - BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc1, quantile_probability = 0.05), 0.025, epsilon ); - BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc1, quantile_probability = 0.025), 0.0125, epsilon ); - BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc1, quantile_probability = 0.01), 0.005, epsilon ); - BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc1, quantile_probability = 0.001), 0.0005, 5*epsilon ); - -[*See also] - -* [classref boost::accumulators::impl::non_coherent_weighted_tail_mean_impl [^non_coherent_weighted_tail_mean_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.sum [^sum]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.tail [^tail]] - -[endsect] - -[section:weighted_tail_quantile weighted_tail_quantile] - -Tail quantile estimation based on order statistics of weighted samples (for both left -and right tails). The left weighted tail quantile feature is `tag::weighted_tail_quantile`, -and the right weighted tail quantile feature is `tag::weighted_tail_quantile`. They both -share the `tag::quantile` feature with the unweighted tail quantile accumulators and can be -extracted with either the `quantile()` or the `weighted_tail_quantile()` extractors. For more -implementation details, see -[classref boost::accumulators::impl::weighted_tail_quantile_impl [^weighted_tail_quantile_impl]] - -[variablelist - [[Result Type] [`` - _sample_type_ - ``]] - [[Depends On] [`sum_of_weights` \n `tail_weights<_left_or_right_>`]] - [[Variants] [['none]]] - [[Initialization Parameters] [`tag::tail<_left_or_right_>::cache_size`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [`quantile_probability`]] - [[Accumulator Complexity] [O(log N), where N is the cache size]] - [[Extractor Complexity] [O(N log N), where N is the cache size]] -] - -[*Header] -[def _WEIGHTED_TAIL_QUANTILE_HPP_ [headerref boost/accumulators/statistics/weighted_tail_quantile.hpp]] - - #include <_WEIGHTED_TAIL_QUANTILE_HPP_> - -[*Example] - - // tolerance in % - double epsilon = 1; - - std::size_t n = 100000; // number of MC steps - std::size_t c = 20000; // cache size - - double mu1 = 1.0; - double mu2 = -1.0; - boost::lagged_fibonacci607 rng; - boost::normal_distribution<> mean_sigma1(mu1,1); - boost::normal_distribution<> mean_sigma2(mu2,1); - boost::variate_generator > normal1(rng, mean_sigma1); - boost::variate_generator > normal2(rng, mean_sigma2); - - accumulator_set >, double> - acc1(right_tail_cache_size = c); - - accumulator_set >, double> - acc2(left_tail_cache_size = c); - - for (std::size_t i = 0; i < n; ++i) - { - double sample1 = normal1(); - double sample2 = normal2(); - acc1(sample1, weight = std::exp(-mu1 * (sample1 - 0.5 * mu1))); - acc2(sample2, weight = std::exp(-mu2 * (sample2 - 0.5 * mu2))); - } - - // check standard normal distribution - BOOST_CHECK_CLOSE( quantile(acc1, quantile_probability = 0.975), 1.959963, epsilon ); - BOOST_CHECK_CLOSE( quantile(acc1, quantile_probability = 0.999), 3.090232, epsilon ); - BOOST_CHECK_CLOSE( quantile(acc2, quantile_probability = 0.025), -1.959963, epsilon ); - BOOST_CHECK_CLOSE( quantile(acc2, quantile_probability = 0.001), -3.090232, epsilon ); - -[*See also] - -* [classref boost::accumulators::impl::weighted_tail_quantile_impl [^weighted_tail_quantile_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.sum [^sum]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.tail [^tail]] - -[endsect] - -[section:weighted_tail_variate_means weighted_tail_variate_means ['and variants]] - -Estimation of the absolute and relative weighted tail variate means (for both left and right tails) -The absolute weighted tail variate means has the feature -`tag::absolute_weighted_tail_variate_means<_left_or_right_, _variate_type_, _variate_tag_>` -and the relative weighted tail variate mean has the feature -`tag::relative_weighted_tail_variate_means<_left_or_right_, _variate_type_, _variate_tag_>`. All -absolute weighted tail variate mean features share the `tag::abstract_absolute_tail_variate_means` -feature with their unweighted variants and can be extracted with the `tail_variate_means()` and -`weighted_tail_variate_means()` extractors. All the relative weighted tail variate mean features -share the `tag::abstract_relative_tail_variate_means` feature with their unweighted variants -and can be extracted with either the `relative_tail_variate_means()` or -`relative_weighted_tail_variate_means()` extractors. - -For more implementation details, see -[classref boost::accumulators::impl::weighted_tail_variate_means_impl [^weighted_tail_variate_means_impl]] - -[variablelist - [[Result Type] [`` - boost::iterator_range< - numeric::functional::fdiv< - numeric::functional::multiplies<_variate_type_, _weight_type_>::result_type - , _weight_type_ - >::result_type::iterator - > - ``]] - [[Depends On] [`non_coherent_weighted_tail_mean<_left_or_right_>` \n - `tail_variate<_variate_type_, _variate_tag_, _left_or_right_>` \n - `tail_weights<_left_or_right_>`]] - [[Variants] [`tag::absolute_weighted_tail_variate_means<_left_or_right_, _variate_type_, _variate_tag_>` \n - `tag::relative_weighted_tail_variate_means<_left_or_right_, _variate_type_, _variate_tag_>`]] - [[Initialization Parameters] [`tag::tail<_left_or_right_>::cache_size`]] - [[Accumulator Parameters] [['none]]] - [[Extractor Parameters] [`quantile_probability`]] - [[Accumulator Complexity] [O(log N), where N is the cache size]] - [[Extractor Complexity] [O(N log N), where N is the cache size]] -] - -[*Header] -[def _WEIGHTED_TAIL_VARIATE_MEANS_HPP_ [headerref boost/accumulators/statistics/weighted_tail_variate_means.hpp]] - - #include <_WEIGHTED_TAIL_VARIATE_MEANS_HPP_> - -[*Example] - - std::size_t c = 5; // cache size - - typedef double variate_type; - typedef std::vector variate_set_type; - - accumulator_set(relative)>, double > - acc1( right_tail_cache_size = c ); - accumulator_set(absolute)>, double > - acc2( right_tail_cache_size = c ); - accumulator_set(relative)>, double > - acc3( left_tail_cache_size = c ); - accumulator_set(absolute)>, double > - acc4( left_tail_cache_size = c ); - - variate_set_type cov1, cov2, cov3, cov4, cov5; - double c1[] = { 10., 20., 30., 40. }; // 100 - double c2[] = { 26., 4., 17., 3. }; // 50 - double c3[] = { 46., 64., 40., 50. }; // 200 - double c4[] = { 1., 3., 70., 6. }; // 80 - double c5[] = { 2., 2., 2., 14. }; // 20 - cov1.assign(c1, c1 + sizeof(c1)/sizeof(variate_type)); - cov2.assign(c2, c2 + sizeof(c2)/sizeof(variate_type)); - cov3.assign(c3, c3 + sizeof(c3)/sizeof(variate_type)); - cov4.assign(c4, c4 + sizeof(c4)/sizeof(variate_type)); - cov5.assign(c5, c5 + sizeof(c5)/sizeof(variate_type)); - - acc1(100., weight = 0.8, covariate1 = cov1); - acc1( 50., weight = 0.9, covariate1 = cov2); - acc1(200., weight = 1.0, covariate1 = cov3); - acc1( 80., weight = 1.1, covariate1 = cov4); - acc1( 20., weight = 1.2, covariate1 = cov5); - - acc2(100., weight = 0.8, covariate1 = cov1); - acc2( 50., weight = 0.9, covariate1 = cov2); - acc2(200., weight = 1.0, covariate1 = cov3); - acc2( 80., weight = 1.1, covariate1 = cov4); - acc2( 20., weight = 1.2, covariate1 = cov5); - - acc3(100., weight = 0.8, covariate1 = cov1); - acc3( 50., weight = 0.9, covariate1 = cov2); - acc3(200., weight = 1.0, covariate1 = cov3); - acc3( 80., weight = 1.1, covariate1 = cov4); - acc3( 20., weight = 1.2, covariate1 = cov5); - - acc4(100., weight = 0.8, covariate1 = cov1); - acc4( 50., weight = 0.9, covariate1 = cov2); - acc4(200., weight = 1.0, covariate1 = cov3); - acc4( 80., weight = 1.1, covariate1 = cov4); - acc4( 20., weight = 1.2, covariate1 = cov5); - - // check relative risk contributions - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.7).begin() ), (0.8*10 + 1.0*46)/(0.8*100 + 1.0*200) ); - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.7).begin() + 1), (0.8*20 + 1.0*64)/(0.8*100 + 1.0*200) ); - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.7).begin() + 2), (0.8*30 + 1.0*40)/(0.8*100 + 1.0*200) ); - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.7).begin() + 3), (0.8*40 + 1.0*50)/(0.8*100 + 1.0*200) ); - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.3).begin() ), (0.9*26 + 1.2*2)/(0.9*50 + 1.2*20) ); - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.3).begin() + 1), (0.9*4 + 1.2*2)/(0.9*50 + 1.2*20) ); - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.3).begin() + 2), (0.9*17 + 1.2*2)/(0.9*50 + 1.2*20) ); - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.3).begin() + 3), (0.9*3 + 1.2*14)/(0.9*50 + 1.2*20) ); - - // check absolute risk contributions - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.7).begin() ), (0.8*10 + 1.0*46)/1.8 ); - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.7).begin() + 1), (0.8*20 + 1.0*64)/1.8 ); - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.7).begin() + 2), (0.8*30 + 1.0*40)/1.8 ); - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.7).begin() + 3), (0.8*40 + 1.0*50)/1.8 ); - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.3).begin() ), (0.9*26 + 1.2*2)/2.1 ); - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.3).begin() + 1), (0.9*4 + 1.2*2)/2.1 ); - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.3).begin() + 2), (0.9*17 + 1.2*2)/2.1 ); - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.3).begin() + 3), (0.9*3 + 1.2*14)/2.1 ); - - // check relative risk contributions - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.9).begin() ), 1.0*46/(1.0*200) ); - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.9).begin() + 1), 1.0*64/(1.0*200) ); - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.9).begin() + 2), 1.0*40/(1.0*200) ); - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.9).begin() + 3), 1.0*50/(1.0*200) ); - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.1).begin() ), 1.2*2/(1.2*20) ); - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.1).begin() + 1), 1.2*2/(1.2*20) ); - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.1).begin() + 2), 1.2*2/(1.2*20) ); - BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.1).begin() + 3), 1.2*14/(1.2*20) ); - - // check absolute risk contributions - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.9).begin() ), 1.0*46/1.0 ); - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.9).begin() + 1), 1.0*64/1.0 ); - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.9).begin() + 2), 1.0*40/1.0 ); - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.9).begin() + 3), 1.0*50/1.0 ); - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.1).begin() ), 1.2*2/1.2 ); - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.1).begin() + 1), 1.2*2/1.2 ); - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.1).begin() + 2), 1.2*2/1.2 ); - BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.1).begin() + 3), 1.2*14/1.2 ); - -[*See also] - -* [classref boost::accumulators::impl::weighted_tail_variate_means_impl [^weighted_tail_variate_means_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.non_coherent_weighted_tail_mean [^non_coherent_weighted_tail_mean]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.tail_variate [^tail_variate]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.tail [^tail]] - -[endsect] - -[section:weighted_variance weighted_variance ['and variants]] - -Lazy or iterative calculation of the weighted variance. The lazy calculation is associated with the `tag::lazy_weighted_variance` -feature, and the iterative calculation with the `tag::weighted_variance` feature. Both can be extracted -using the `tag::weighted_variance()` extractor. For more implementation details, see -[classref boost::accumulators::impl::lazy_weighted_variance_impl [^lazy_weighted_variance_impl]] and -[classref boost::accumulators::impl::weighted_variance_impl [^weighted_variance_impl]] - -[variablelist - [[Result Type] [`` - numeric::functional::fdiv< - numeric::functional::multiplies<_sample_type_, _weight_type_>::result_type - , std::size_t - >::result_type - ``]] - [[Depends On] [`tag::lazy_weighted_variance` depends on `tag::weighted_moment<2>` and `tag::weighted_mean` \n - `tag::weighted_variance` depends on `tag::count` and `tag::immediate_weighted_mean`]] - [[Variants] [`tag::lazy_weighted_variance` (a.k.a. `tag::weighted_variance(lazy))` \n - `tag::weighted_variance` (a.k.a. `tag::weighted_variance(immediate)`)]] - [[Initialization Parameters] [['none]]] - [[Accumulator Parameters] [`weight`]] - [[Extractor Parameters] [['none]]] - [[Accumulator Complexity] [O(1)]] - [[Extractor Complexity] [O(1)]] -] - -[*Header] -[def _WEIGHTED_VARIANCE_HPP_ [headerref boost/accumulators/statistics/weighted_variance.hpp]] - - #include <_WEIGHTED_VARIANCE_HPP_> - -[*Example] - - // lazy weighted_variance - accumulator_set, int> acc1; - - acc1(1, weight = 2); // 2 - acc1(2, weight = 3); // 6 - acc1(3, weight = 1); // 3 - acc1(4, weight = 4); // 16 - acc1(5, weight = 1); // 5 - - // weighted_mean = (2+6+3+16+5) / (2+3+1+4+1) = 32 / 11 = 2.9090909090909090909090909090909 - - BOOST_CHECK_EQUAL(5u, count(acc1)); - BOOST_CHECK_CLOSE(2.9090909, weighted_mean(acc1), 1e-5); - BOOST_CHECK_CLOSE(10.1818182, accumulators::weighted_moment<2>(acc1), 1e-5); - BOOST_CHECK_CLOSE(1.7190083, weighted_variance(acc1), 1e-5); - - // immediate weighted_variance - accumulator_set, int> acc2; - - acc2(1, weight = 2); - acc2(2, weight = 3); - acc2(3, weight = 1); - acc2(4, weight = 4); - acc2(5, weight = 1); - - BOOST_CHECK_EQUAL(5u, count(acc2)); - BOOST_CHECK_CLOSE(2.9090909, weighted_mean(acc2), 1e-5); - BOOST_CHECK_CLOSE(1.7190083, weighted_variance(acc2), 1e-5); - - // check lazy and immediate variance with random numbers - - // two random number generators - boost::lagged_fibonacci607 rng; - boost::normal_distribution<> mean_sigma(0,1); - boost::variate_generator > normal(rng, mean_sigma); - - accumulator_set, double > acc_lazy; - accumulator_set, double > acc_immediate; - - for (std::size_t i=0; i<10000; ++i) - { - double value = normal(); - acc_lazy(value, weight = rng()); - acc_immediate(value, weight = rng()); - } - - BOOST_CHECK_CLOSE(1., weighted_variance(acc_lazy), 1.); - BOOST_CHECK_CLOSE(1., weighted_variance(acc_immediate), 1.); - -[*See also] - -* [classref boost::accumulators::impl::lazy_weighted_variance_impl [^lazy_weighted_variance_impl]] -* [classref boost::accumulators::impl::weighted_variance_impl [^weighted_variance_impl]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.count [^count]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.weighted_mean [^weighted_mean]] -* [link accumulators.user_s_guide.the_statistical_accumulators_library.weighted_moment [^weighted_moment]] - -[endsect] - -[endsect] - -[endsect] - -[section Acknowledgements] - -Boost.Accumulators represents the efforts of many individuals. I would like to thank -Daniel Egloff of _ZKB_ for helping to conceive the library and realize its -implementation. I would also like to thank David Abrahams and Matthias Troyer for -their key contributions to the design of the library. Many thanks are due to Michael -Gauckler and Olivier Gygi, who, along with Daniel Egloff, implemented many of the -statistical accumulators. - -I would also like to thank Simon West for all his assistance maintaining -Boost.Accumulators. - -Finally, I would like to thank _ZKB_ for sponsoring the work on Boost.Accumulators -and graciously donating it to the community. - -[endsect] - -[section Reference] - -[xinclude accdoc.xml] - -[xinclude statsdoc.xml] - -[xinclude opdoc.xml] - -[endsect] diff --git a/doc/config.json b/doc/config.json new file mode 100644 index 00000000..e3d153dd --- /dev/null +++ b/doc/config.json @@ -0,0 +1,11 @@ +{ + "include_private": false, + "legacy_behavior": false, + "external_marker": "!EXTERNAL!", + "link_prefix": "ref_", + "default_namespace": "boost::accumulators", + "convenience_header": "boost/accumulators/accumulators.hpp", + "github_repo": "boostorg/accumulators", + "github_branch": "develop", + "replace_strings": { "__see_below__": "pass:q,a[__see{nbsp}below__]" } +} diff --git a/doc/docca_runner/README.md b/doc/docca_runner/README.md new file mode 100644 index 00000000..de010f5f --- /dev/null +++ b/doc/docca_runner/README.md @@ -0,0 +1,21 @@ + + +# Docca runner (Accumulators) + +Boost.Accumulators needs small Docca behavior changes for Doxygen output that stock +`tools/docca/docca.py` does not handle (header `\f$` / `\f[` formulas, Boost.Parameter +parameter XML). Those fixes live in `accumulators_docca.py`, which imports the +real Docca module and patches it before `main()`. Doxygen `` elements are +converted to Asciidoctor `stem:` markup (see `:stem: latexmath` in `pages/main.adoc`). + +`accumulators_docca.jam` defines `accumulators_docca.pyreference`, which mirrors +stock `docca.pyreference` but runs `accumulators_docca.py` for the reference +generation step. The doc `Jamfile` imports both `docca` (features, Doxygen) and +`accumulators_docca` (custom pyreference). + +When upstream Docca absorbs these fixes, drop this directory and switch the +`Jamfile` back to `docca.pyreference`. diff --git a/doc/docca_runner/accumulators_docca.jam b/doc/docca_runner/accumulators_docca.jam new file mode 100644 index 00000000..21369246 --- /dev/null +++ b/doc/docca_runner/accumulators_docca.jam @@ -0,0 +1,210 @@ +# +# Copyright (c) 2025 Dmitry Arkhipov (grisumbras@gmail.com) +# Copyright (C) 2026 Ming Yang Zhang, Leo Chen +# +# Distributed under the Boost Software License, Version 1.0. +# +# Accumulators-specific Docca pyreference driver. Reuses the stock docca module +# for Doxygen integration and config features; only generate-reference runs +# accumulators_docca.py instead of tools/docca/docca.py. +# + +import "class" : new ; +import docca ; +import doxygen ; +import errors ; +import feature ; +import modules ; +import param ; +import path ; +import project ; +import property-set ; +import targets ; +import toolset ; +import type ; +import virtual-target ; + +.here = [ path.make [ modules.binding $(__name__) ] ] ; +.here = $(.here:D) ; + +rule pyreference ( target : sources * : requirements * : default-build * + : usage-requirements * ) +{ + param.handle-named-params + sources requirements default-build usage-requirements ; + + targets.create-metatarget accumulators-docca-reference-target-class + : [ project.current ] + : $(target) + : $(sources) + : $(requirements) + : $(default-build) + : $(usage-requirements) + ; +} + +class accumulators-docca-reference-target-class : basic-target +{ + import generators ; + import path ; + import project ; + import toolset ; + import type ; + + rule __init__ ( name : project : sources * : requirements * + : default-build * : usage-requirements * ) + { + basic-target.__init__ $(name) : $(project) : $(sources) : + $(requirements) : $(default-build) : $(usage-requirements) ; + self.docca-location = [ modules.peek docca : .here ] ; + } + + rule construct ( name : sources * : property-set ) + { + local config-dir = $(name:S=) ; + config-dir = $(config-dir:B=_$(config-dir:B)-dir) ; + + local target-dir = $(config-dir) ; + + local doxydir ; + local ps ; + if $(sources) && ( ! $(sources[2-]) ) + && ( [ $(sources).type ] = DOXYGEN_XML_MULTIFILE ) + { + doxydir = $(sources[1]) ; + ps = $(property-set) ; + } + else + { + ps = [ $(property-set).add-raw + GENERATE_HTML=NO + GENERATE_XML=YES + XML_OUTPUT=$(target-dir) + ] ; + local doxyfile = [ generators.construct + $(self.project) $(target-dir)/sources.dox + : DOXYFILE + : $(ps) + : $(sources) + : top-level + ] ; + ps = [ $(property-set).add $(doxyfile[1]) ] ; + doxyfile = [ virtual-target.register $(doxyfile[2]) ] ; + + doxydir = [ generators.construct + $(self.project) $(target-dir)/stamp + : DOXYGEN_XML_MULTIFILE + : $(ps) + : $(doxyfile) + : top-level + ] ; + ps = [ $(property-set).add $(doxydir[1]) ] ; + doxydir = [ virtual-target.register $(doxydir[2]) ] ; + } + + local path = [ $(doxydir).name ] ; + local a = [ new action $(doxydir) + : docca.touch-action + : [ property-set.empty ] + ] ; + local index = [ new file-target [ path.join $(path:D) index.xml ] exact + : XML + : $(self.project) + : $(a) + ] ; + index = [ virtual-target.register $(index) ] ; + + local template = [ get-template $(ps) ] ; + local docca-config = [ get-configs $(config-dir) : $(ps) ] ; + + local action-name = accumulators_docca.generate-reference ; + local relevant = [ toolset.relevant $(action-name) ] ; + local action-sources = $(index) $(template) ; + if $(docca-config) + { + action-sources += $(docca-config) ; + } + a = [ + new action $(action-sources) + : $(action-name) + : [ $(ps).relevant $(relevant) ] + ] ; + local target = [ + new file-target $(name) exact + : [ type.type $(name) ] + : $(self.project) + : $(a) + ] ; + local path = [ path.root $(name) [ $(target).path ] ] ; + return [ property-set.create $(path:D) ] + [ virtual-target.register $(target) ] ; + } + + local rule get-template ( property-set ) + { + local template = [ $(property-set).get ] ; + if $(template[2]) + { + import errors ; + errors.user-error + "Several templates specified for docca:" $(template) ; + } + + if ! $(template) + { + template = + [ virtual-target.from-file quickbook.jinja2 + : $(self.docca-location)/include/docca + : $(self.project) + ] ; + } + + return $(template) ; + } + + local rule get-configs ( dir : property-set ) + { + local config ; + if [ $(property-set).get ] + { + local a = [ new action : docca.make-docca-config : $(property-set) ] ; + config = [ new file-target $(dir)/docca-config.json exact + : [ type.type docca-config.json ] + : $(self.project) + : $(a) + ] ; + config = [ virtual-target.register $(config) ] ; + } + + return $(config) ; + } +} + +rule partition-reference ( target : sources * : properties * ) +{ + RUNNER on $(target) = [ path.native $(.here)/accumulators_docca.py ] ; +} + +actions partition-reference bind RUNNER +{ + "$(PYTHON:E=python)" "$(RUNNER)" -i"$(>[1]:D)/_entities_framework-dir/index.xml" -o"$(<)" -c"$(>[3])" -c"$(>[4])" -T"$(>[2])" -I"$(INCLUDE)" +} + +rule generate-reference ( target : sources + : properties * ) +{ + RUNNER on $(target) = [ path.native $(.here)/accumulators_docca.py ] ; +} +actions generate-reference bind CONFIGS EXTENSIONS +{ + "$(PYTHON:E=python)" "$(RUNNER)" -i"$(>[1])" -o"$(<)" -c"$(CONFIGS)" -c"$(>[3])" -E"$(EXTENSIONS)" -T"$(>[2])" -I"$(INCLUDE)" +} + +toolset.flags accumulators_docca.generate-reference FLAGS ; +toolset.flags accumulators_docca.generate-reference INCLUDE ; +toolset.flags accumulators_docca.generate-reference CONFIGS ; +toolset.flags accumulators_docca.generate-reference EXTENSIONS ; +toolset.flags accumulators_docca.generate-reference PYTHON ; + +toolset.flags accumulators_docca.partition-reference FLAGS ; +toolset.flags accumulators_docca.partition-reference INCLUDE ; +toolset.flags accumulators_docca.partition-reference PYTHON ; diff --git a/doc/docca_runner/accumulators_docca.py b/doc/docca_runner/accumulators_docca.py new file mode 100644 index 00000000..7c38804c --- /dev/null +++ b/doc/docca_runner/accumulators_docca.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python +# +# Copyright (C) 2026 Ming Yang Zhang, Leo Chen +# +# 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) +# +# Thin wrapper around tools/docca/docca.py for Boost.Accumulators. Applies +# Accumulators-specific fixes without modifying the shared docca.py: +# - Doxygen from \\f$...\\f$ / \\f[...\\f] in header comments +# - Boost.Parameter-style parameter XML from Doxygen +# + +import os +import sys + + +def _tools_docca_path(): + here = os.path.dirname(os.path.realpath(__file__)) + boost_root = os.path.abspath(os.path.join(here, '..', '..', '..', '..')) + return os.path.join(boost_root, 'tools', 'docca', 'docca.py') + + +def _formula_raw_text(element, docca, index, allow_missing_refs=False): + if element.text: + return element.text.strip() + parts = docca.phrase_content( + element, index, allow_missing_refs=allow_missing_refs) + return ''.join(p for p in parts if isinstance(p, str)).strip() + + +def _normalize_formula(text): + display = False + if text.startswith(r'\['): + display = True + text = text[2:].lstrip() + if text.endswith(r'\]'): + text = text[:-2].rstrip() + elif text.startswith('$$'): + display = True + text = text[2:].lstrip() + if text.endswith('$$'): + text = text[:-2].rstrip() + elif text.startswith('$'): + text = text[1:].lstrip() + if text.endswith('$'): + text = text[:-1].rstrip() + return text, display + + +def _apply_patches(docca): + class Formula(docca.Phrase): + def __init__(self, latex, display=False): + super().__init__([latex]) + self.latex = latex + self.display = display + + docca.Formula = Formula + + _orig_construct_environment = docca.construct_environment + + def construct_environment(loader, config): + env = _orig_construct_environment(loader, config) + env.tests['Formula'] = lambda x: isinstance(x, Formula) + return env + + docca.construct_environment = construct_environment + + _orig_make_phrase = docca.make_phrase + + def make_phrase(element, index, allow_missing_refs=False): + if element.tag == 'formula': + text, display = _normalize_formula( + _formula_raw_text( + element, docca, index, + allow_missing_refs=allow_missing_refs)) + return Formula(text, display) + return _orig_make_phrase( + element, index, allow_missing_refs=allow_missing_refs) + + docca.make_phrase = make_phrase + + def parameter_init(self, element, parent): + self.type = docca.text_with_refs(element.find('type'), parent.index) + self.default_value = docca.text_with_refs( + element.find('defval'), parent.index) + + self.description = element.find('briefdescription') + if self.description is not None: + self.description = docca.make_blocks(self.description, parent) + else: + self.description = [] + + self.name = element.find('declname') + if self.name is not None: + self.name = self.name.text + + self.array = docca.text_with_refs(element.find('array'), parent.index) + if self.array: + if (isinstance(self.type[-1], str) + and self.type[-1].endswith('(&)')): + self.type[-1] = self.type[-1][:-3] + else: + self.array = None + + self.args = docca.text_with_refs( + element.find('argsstring'), parent.index) + if self.args: + if (isinstance(self.type[-1], str) + and isinstance(self.args[0], str) + and self.type[-1].endswith('(*') + and self.args[0].startswith(')(')): + self.type[-1] = self.type[-1][:-2] + self.args[0] = self.args[0][1:] + else: + self.args = None + + docca.Parameter.__init__ = parameter_init + + +def main(): + tools_docca = _tools_docca_path() + if not os.path.isfile(tools_docca): + sys.stderr.write( + 'accumulators_docca.py: could not find %s\n' % tools_docca) + sys.exit(1) + + sys.path.insert(0, os.path.dirname(tools_docca)) + import docca # noqa: E402 + + _apply_patches(docca) + docca.main(sys.argv, sys.stdin, sys.stdout, tools_docca) + + +if __name__ == '__main__': + main() diff --git a/doc/externals.hpp b/doc/externals.hpp new file mode 100644 index 00000000..c6d07c73 --- /dev/null +++ b/doc/externals.hpp @@ -0,0 +1,110 @@ +#pragma once + +namespace boost { + +/// !EXTERNAL! +/// +/// @see https://www.boost.org/doc/libs/latest/libs/mpl/index.html +namespace mpl +{ +template +struct vector; +template +struct map; +template +struct set; +struct true_; +struct false_; +} // namespace mpl + +/// !EXTERNAL! +/// +/// @see https://www.boost.org/doc/libs/latest/libs/parameter/index.html +namespace parameter +{ +template +struct keyword; +} // namespace parameter + +/// !EXTERNAL! +/// +/// @see https://www.boost.org/doc/libs/latest/libs/fusion/index.html +namespace fusion +{ +struct void_; +} // namespace fusion + +namespace numeric +{ +namespace functional +{ +/// !EXTERNAL! +template +struct tag; +} // namespace functional +} // namespace numeric + +namespace detail +{ +/// !EXTERNAL! +template +struct pod_singleton; +/// !EXTERNAL! +template +struct function1; +/// !EXTERNAL! +template +struct function2; +} // namespace detail + +namespace random +{ +/// !EXTERNAL! +struct lagged_fibonacci607; +/// !EXTERNAL! +template +struct normal_distribution; +/// !EXTERNAL! +template +struct variate_generator; +} // namespace random + +} // namespace boost + +namespace std { + +/// !EXTERNAL! +/// +/// @see https://en.cppreference.com/w/cpp/types/size_t +struct size_t {}; + +/// !EXTERNAL! +/// +/// @see https://en.cppreference.com/w/cpp/container/vector +template +struct vector {}; + +/// !EXTERNAL! +/// +/// @see https://en.cppreference.com/w/cpp/utility/functional +template +struct binary_function {}; + +/// !EXTERNAL! +/// +/// @see https://en.cppreference.com/w/cpp/utility/functional +template +struct unary_function {}; + +/// !EXTERNAL! +/// +/// @see https://en.cppreference.com/w/cpp/io/basic_ostream +struct ostream {}; + +/// !EXTERNAL! +/// +/// @see https://en.cppreference.com/w/cpp/algorithm/for_each +template +UnaryFunction for_each(InputIt, InputIt, UnaryFunction); + +} // namespace std diff --git a/doc/htmldir.rb b/doc/htmldir.rb new file mode 100644 index 00000000..076113aa --- /dev/null +++ b/doc/htmldir.rb @@ -0,0 +1,741 @@ +# coding: utf-8 + +require 'asciidoctor' +require 'asciidoctor/converter/html5' +require 'fileutils' +require 'pathname' + +BOOST_ACCUMULATORS_GITHUB_INCLUDE = + 'https://github.com/boostorg/accumulators/blob/develop/include/'.freeze + +module BoostAccumulatorsIncludeLinker + module_function + + # Link #include paths inside code listings. + def fix_ref_hash_links(html, doc) + return html unless html&.include?('href="#ref_') + + html.gsub(/href="#(ref_[^"]+)"/) do + refid = Regexp.last_match(1) + resolved = doc.link_to_target(refid, "##{refid}") + if resolved.start_with?('#') && resolved == "##{refid}" + Regexp.last_match(0) + else + %(href="#{resolved}") + end + end + end + + def link_includes(html) + html.gsub( + /#include\s+<(boost\/accumulators\/[\w.\/]+)>/ + ) do + path = Regexp.last_match(1) + url = "#{BOOST_ACCUMULATORS_GITHUB_INCLUDE}#{path}" + %(#include <#{path}>) + end.gsub( + /#include\s+<(boost\/accumulators\/[\w.\/]+)>/ + ) do + path = Regexp.last_match(1) + url = "#{BOOST_ACCUMULATORS_GITHUB_INCLUDE}#{path}" + %(#include <#{path}>) + end + end +end + +class Asciidoctor::AbstractBlock + attr_accessor :real_level + + def document_dirname + if @document.upper_doc && (@document.upper_doc != @document.top_doc) + base = @document.upper_doc.document_filepath() + base.delete_suffix @document.attributes['outfilesuffix'] + else + "." + end + end + + def document_filename + base = @document.id + if @document.upper_doc && (@document.upper_doc != @document.top_doc) + base = base.delete_prefix "#{document.upper_doc.id}_" + end + base + @document.attributes['outfilesuffix'] + end + + def document_filepath + suffix = @document.attributes['outfilesuffix'] + File.join(document_dirname, @document.document_filename).delete_prefix( + ".#{File::SEPARATOR}") + end + + def filepath_to other + self_dir = Pathname.new document_dirname + other_dir = Pathname.new other.document_dirname + ret = File.join( + other_dir.relative_path_from(self_dir), + other.document_filename).delete_prefix(".#{File::SEPARATOR}") + ret + end +end + +class Asciidoctor::Document + attr_accessor :parsed + attr_accessor :processed + attr_accessor :catalog + attr_accessor :child_documents + attr_accessor :top_doc + attr_accessor :upper_doc + attr_accessor :next_doc + attr_accessor :prev_doc + + alias core_init initialize + def initialize data = nil, options = {} + options[:sourcemap] = true + core_init data, options + @child_documents = [] + end + + def content # this is different from the reguar Document.content + super + end + + alias core_docinfo docinfo + def docinfo location = :head, suffix = nil + result = core_docinfo location, suffix + if (location == :footer) && (attr? 'project-gh', nil, true) + doc_id = id || @id + source = if PARTITION_SOURCE.key?(doc_id) + PARTITION_SOURCE[doc_id] + else + attr('source-location', nil, true) + end + if source + result += '' + end + end + if [:header, :footer].include?(location) + result += '' + end + result + end + + def find_child_doc(doc, id) + return doc if doc.id == id + + doc.child_documents.each do |child| + found = find_child_doc(child, id) + return found if found + end + nil + end + + def document_for_ref(refid) + return nil unless @catalog && (node = @catalog[:refs][refid]) + + doc = node + until !doc || (doc.context == :document) + doc = doc.parent + end + return doc unless doc + + if doc.id != refid + home = @top_doc || @document&.top_doc || self + found = find_child_doc(home, refid) + doc = found if found + end + doc + end + + def link_to_target(refid, target = "##{refid}") + anchor = nil + if target.start_with?('#') && target.length > 1 + anchor = target[1..-1] + end + + ref = anchor || refid + doc = document_for_ref(ref) + + if !doc || (doc.id == @id) + anchor ? "##{anchor}" : target + elsif anchor + if doc.id == @id + "##{anchor}" + elsif doc.id == anchor + @document.filepath_to doc + else + "#{@document.filepath_to doc}##{anchor}" + end + elsif "##{doc.id}" == target + @document.filepath_to doc + else + "#{@document.filepath_to doc}#{target}" + end + end + + def nav_link_html(target, role) + text = target.captioned_title + title = target.document.doctitle sanitize: true + text = %(#{text}) + link = link_to_target target.id + link = %(#{text}) + %(
  • #{link}
  • ) + end + + def spawn_child_documents + pagelevels = attr('pagelevels', 0).to_i + if pagelevels < 0 + logger.warn "attribute 'pagelevels' must be >= 0; setting to 0" + pagelevels = 0 + end + set_attribute('pagelevels', pagelevels.to_s) + + @id = File.basename( + @attributes['outfile'] , @attributes['outfilesuffix']) + register( + :refs, + [@id, + Asciidoctor::Inline.new( + parent = self, + context = :anchor, + text = doctitle, + opts = {:type => :ref, :id => @id}), + doctitle]) + + @child_documents = generate_child_docs self, pagelevels + @real_level = 0 + + if sections.empty? + attrs = @attributes.clone + @blocks << Asciidoctor::Section.new( + self, + 1, + false, + {:attributes => attrs}) + end + reindex_sections + update_source_location + + @top_doc = self + make_linear_connections + update_real_level self, 0 + + @processed = true + end + + def generate_child_docs(node, doc_pagelevels) + result = [] + node.blocks.filter! do |block| + if block.context != :section + next true + end + + node.document.playback_attributes block.attributes + pagelevels = block.attr('pagelevels', doc_pagelevels).to_i + if block.level > pagelevels || !block.id + next true + end + + result << node.document.spawn_document_from(block, doc_pagelevels) + false + end + result + end + + def spawn_document_from(node, doc_pagelevels) + pagelevels = node.attr('pagelevels', doc_pagelevels).to_i + + attrs = @attributes.clone + unless PARTITION_SOURCE.key?(node.id) + attrs.delete('source-location') + end + attrs['title'] = node.title + attrs['notitle'] = true + attrs['authors'] = nil + attrs['author'] = nil + attrs['pagelevels'] = pagelevels.to_s + doc = Asciidoctor::Document.new( + [], + {:attributes => attrs, + :doctype => self.doctype, + :header_footer => !self.attr?(:embedded), + :safe => self.safe}) + doc.id = node.id + doc.catalog = @catalog + doc.child_documents = generate_child_docs(node, pagelevels) + doc.blocks << node + doc.finalize_header({}) + reparent_blocks(node, doc) + doc.real_level = node.real_level + doc.reindex_sections + if !PARTITION_SOURCE[doc.id] + doc.update_source_location + end + doc.parsed = true + doc.processed = true + doc + end + + def update_real_level(node, real_level) + node.real_level = real_level + + if node.context == :dlist + node.find_by(context: :list_item).each do |block| + update_real_level block, real_level + 1 + end + else + node.blocks.each do |block| + update_real_level block, real_level + 1 + end + end + end + + def reparent_blocks(node, parent, real_level = node.level) + node.parent = parent + node.real_level = real_level + node.level = node.level - real_level + 1 + + if node.context == :dlist + node.find_by(context: :list_item).each do |block| + reparent_blocks(block, node, real_level + 1) + end + return + end + + node.blocks.each do |block| + reparent_blocks(block, node, real_level + 1) + if block.context == :table + block.columns.each do |col| + col.parent = col.parent + end + block.rows.body.each do |row| + row.each do |cell| + cell.parent = cell.parent + end + end + end + end + end + + def make_linear_connections + prev = self + child_documents.each do |doc| + doc.top_doc = @top_doc + doc.upper_doc = self + doc.prev_doc = prev + prev.next_doc = doc + prev = doc.make_linear_connections + end + prev + end + + PARTITION_SOURCE = { + 'accumulators_framework_reference' => + 'pages/ref/accumulators_framework_reference.adoc', + 'statistics_library_reference' => + 'pages/ref/statistics_library_reference.adoc', + 'numeric_operators_library_reference' => + 'pages/ref/numeric_operators_library_reference.adoc', + 'ref' => 'pages/reference.adoc' + }.freeze + + def update_source_location + if (first_section.attr? 'source-location', nil, true) + sl = first_section.attr('source-location') + if sl&.start_with?('include/') + set_attribute('source-location', sl) + return + end + if sl && !sl.include?('bin.v2') && + !File.basename(sl).start_with?('entities') + set_attribute('source-location', sl) + return + end + end + + if (path = PARTITION_SOURCE[@id]) + set_attribute('source-location', path) + return + end + + if !first_section.source_location + return + end + + path = Pathname.new first_section.source_location.file + if path.to_s.include?('bin.v2') || + path.basename.to_s.start_with?('entities') + return + end + + if (attr? 'project-dir', nil, true) + path = path.relative_path_from(attr 'project-dir') + end + + set_attribute('source-location', path.to_s) + end +end + +class HtmlDirConverter < Asciidoctor::Converter::Html5Converter + include Asciidoctor + include Asciidoctor::Converter + include Asciidoctor::Writer + + register_for 'htmldir' + + attr_accessor :home_doc + + # Home-page TOC shape (Boost.Accumulators chapter layout). + USER_GUIDE_NESTED = [ + ['the_accumulators_framework', + 'The Accumulators Framework'], + ['the_statistical_accumulators_library', + 'The Statistical Accumulators Library'], + ].freeze + + REFERENCE_TOC_SECTIONS = [ + ['accumulators_framework_reference', + 'Accumulators Framework Reference'], + ['statistics_library_reference', + 'Statistics Library Reference'], + ['numeric_operators_library_reference', + 'Numeric Operators Library Reference'], + ].freeze + + def find_child_doc(doc, id) + doc.find_child_doc(doc, id) + end + + def convert_outline(node, opts = {}) + home = @home_doc || node.document.top_doc + convert_accumulators_home_outline(home, node.document, opts) + end + + def convert_accumulators_home_outline(home_doc, current_doc, opts) + result = ['
      '] + + preface = home_doc.sections.find { |s| s.id == 'preface' } + preface_title = preface ? preface.title : 'Preface' + result << toc_list_item( + current_doc, + current_doc.link_to_target('preface'), + preface_title, + nil, + current_page: on_index_preface?(current_doc)) + + if (ug = find_child_doc(home_doc, 'user_s_guide')) + ug_nested = USER_GUIDE_NESTED.any? { |id, _| current_doc.id == id } + nested = USER_GUIDE_NESTED.map do |id, title| + child = find_child_doc(home_doc, id) + if child + [child, section_title(child, id, title)] + else + [nil, title, current_doc.link_to_target(id, "##{id}")] + end + end + result << toc_list_item( + current_doc, + current_doc.link_to_target(ug.id), + section_title(ug, 'user_s_guide', "User's Guide"), + nested, + current_page: current_doc.id == ug.id && !ug_nested) + end + + if (ack = find_child_doc(home_doc, 'acknowledgements')) + result << toc_list_item( + current_doc, + current_doc.link_to_target(ack.id), + section_title( + ack, 'acknowledgements', 'Acknowledgements'), + nil, + current_page: current_doc.id == ack.id) + end + + if (ref = find_child_doc(home_doc, 'ref')) + ref_base = current_doc.link_to_target(ref.id) + nested = REFERENCE_TOC_SECTIONS.map do |anchor, title| + child = find_child_doc(ref, anchor) + if child + [child, title] + else + [nil, title, + current_doc.link_to_target(anchor, "##{anchor}")] + end + end + result << toc_list_item( + current_doc, + ref_base, + section_title(ref, 'ref', 'Reference'), + nested, + current_page: current_doc.id == ref.id || + REFERENCE_TOC_SECTIONS.any? { |id, _| current_doc.id == id }) + end + + result << '
    ' + result.join LF + end + + def on_index_preface?(doc) + doc == @home_doc + end + + def section_title(doc_or_sect, id, fallback) + if doc_or_sect.respond_to?(:captioned_title) && + (t = doc_or_sect.captioned_title) + return t + end + + if doc_or_sect.respond_to?(:sections) && + !doc_or_sect.sections.empty? + return doc_or_sect.sections[0].title + end + + fallback + end + + def toc_list_item(doc, href, title, nested = nil, current_page: false) + role = current_page ? ' class="this-page"' : '' + item = %(
  • #{title}) + if nested && !nested.empty? + item << '
      ' + nested.each do |child_doc, child_title, child_href| + if child_doc + link = child_href || doc.link_to_target(child_doc.id) + label = child_title || + section_title(child_doc, child_doc.id, child_doc.id) + child_role = doc.id == child_doc.id ? + ' class="this-page"' : '' + else + link = child_href + label = child_title + child_role = '' + end + item << %(
    • #{label}
    • ) + end + item << '
    ' + end + item << '
  • ' + item + end + + def convert_document(node) + if !node.processed + @home_doc = node + node.spawn_child_documents + end + + html = super + body_id = node.id + unless html =~ /]*class="[^"]*toc2/ + html = html.sub( + %(), + %()) + html = html.sub( + 'id="toc" class="toc"', + 'id="toc" class="toc2"') + end + html + end + + def convert_outline_doc(doc, node, opts) + toclevels = ((node.first_section.attr 'toclevels') || + opts[:toclevels] || (node.document.attr 'toclevels', 2)).to_i + return unless node.real_level < toclevels + + opts[:toclevels] = toclevels + if node.first_section.id == node.id + sections = node.first_section.sections + else + sections = node.sections + end + children = sections + node.child_documents + convert_outline_ext doc, children, node.real_level + 1, opts + end + + def convert_outline_sect(doc, node, opts) + toclevels = ((node.attr 'toclevels').to_i || opts[:toclevels] || 2) + return unless node.real_level < toclevels + + opts[:toclevels] = toclevels + convert_outline_ext doc, node.sections, node.real_level + 1, opts + end + + def convert_outline_ext(doc, nodes, level, opts) + return unless !nodes.empty? + + sectnumlevels = ( + opts[:sectnumlevels] || + (nodes[0].document.attributes['sectnumlevels'] || 3).to_i) + + result = [%(
      )] + nodes.each do |node| + result << list_item_for_node(doc, node, sectnumlevels) + if node.context == :document + child_toc_level = convert_outline_doc doc, node, opts + else + child_toc_level = convert_outline_sect doc, node, opts + end + result << child_toc_level if child_toc_level + end + result << '
    ' + result.join LF + end + + def list_item_for_node(doc, node, sectnumlevels) + if node.context == :document + section = node.sections[0] + else + section = node + end + + slevel = section.real_level + signifier = nil + sectnum = nil + if !section.caption && ( + section.numbered && slevel <= sectnumlevels) + if slevel < 2 && node.document.doctype == 'book' + case section.sectname + when 'chapter' + signifier = ( + node.document.attributes['chapter-signifier']) + sectnum = section.sectnum + when 'part' + signifier = ( + node.document.attributes['part-signifier']) + sectnum = section.sectnum nil, ':' + else + sectnum = section.sectnum + end + end + end + signifier = signifier ? "#{signifier} " : '' + sectnum = sectnum ? "#{sectnum} " : '' + stitle = %(#{signifier}#{sectnum}#{section.title}) + stitle = stitle.gsub DropAnchorRx, '' if stitle.include? '#{stitle}) + end + + def convert_inline_anchor(node) + if node.type == :link + target = node.target + if target&.start_with?('#') && target.length > 1 + refid = target[1..-1] + if refid.start_with?('ref_') + resolved = node.document.link_to_target(refid, target) + if resolved != target + attrs = node.role ? %( class="#{node.role}") : '' + text = node.text || refid + return %(#{text}) + end + end + end + return super + end + + if node.type != :xref + return super + end + + if (path = node.attributes['path']) + attrs = append_link_constraint_attrs( + node, node.role ? [%( class="#{node.role}")] : []) + attrs = attrs.join + text = node.text || path + else + attrs = node.role ? %( class="#{node.role}") : '' + unless (text = node.text) + ref = (@refs ||= node.document.catalog[:refs])[ + refid = node.attributes['refid']] || + (refid.nil_or_empty? ? (top = get_root_document node) : nil) + if AbstractNode === ref + if (@resolving_xref ||= (outer = true)) && outer + if (text = ref.xreftext node.attr 'xrefstyle', nil, true) + text = text.gsub DropAnchorRx, '' if text.include? '#{text}) + end + + def write output, target + if output + output = BoostAccumulatorsIncludeLinker.link_includes(output) + output = BoostAccumulatorsIncludeLinker.fix_ref_hash_links( + output, @home_doc) + end + File.write target, output, mode: Asciidoctor::FILE_WRITE_MODE + write_children( + @home_doc, File.dirname(target), File.extname(target)) + end + + def write_children(doc, outdir, ext) + doc.child_documents.each do |child| + outfile = File.join(outdir, child.document_filepath) + + outfiledir = File.dirname(outfile) + FileUtils.mkdir_p(outfiledir) unless File.exist?(outfiledir) + + File.open(outfile, 'w') do |f| + logger.info %(Writing to '#{outfile}') + output = child.convert + output = BoostAccumulatorsIncludeLinker.link_includes(output) + output = BoostAccumulatorsIncludeLinker.fix_ref_hash_links( + output, child) + f.write(output) + end + write_children(child, outdir, ext) + end + end +end diff --git a/doc/images/caution.png b/doc/images/caution.png new file mode 100644 index 00000000..5b7809ca Binary files /dev/null and b/doc/images/caution.png differ diff --git a/doc/images/important.png b/doc/images/important.png new file mode 100644 index 00000000..12c90f60 Binary files /dev/null and b/doc/images/important.png differ diff --git a/doc/images/note.png b/doc/images/note.png new file mode 100644 index 00000000..d0c3c645 Binary files /dev/null and b/doc/images/note.png differ diff --git a/doc/images/repo-logo.png b/doc/images/repo-logo.png new file mode 100644 index 00000000..37d9ae84 Binary files /dev/null and b/doc/images/repo-logo.png differ diff --git a/doc/images/tip.png b/doc/images/tip.png new file mode 100644 index 00000000..5c4aab3b Binary files /dev/null and b/doc/images/tip.png differ diff --git a/doc/images/warning.png b/doc/images/warning.png new file mode 100644 index 00000000..1c33db8f Binary files /dev/null and b/doc/images/warning.png differ diff --git a/doc/pages/acknowledgements.adoc b/doc/pages/acknowledgements.adoc new file mode 100644 index 00000000..263a6fa8 --- /dev/null +++ b/doc/pages/acknowledgements.adoc @@ -0,0 +1,21 @@ +//// +Copyright (C) 2005, 2006 Eric Niebler +Copyright (C) 2026 Ming Yang Zhang, Leo Chen +Distributed under the Boost Software License, Version 1.0. +//// + +[[acknowledgements]] += Acknowledgements + +Boost.Accumulators represents the efforts of many individuals. I would like to thank +Daniel Egloff of {zkb} for helping to conceive the library and realize its +implementation. I would also like to thank David Abrahams and Matthias Troyer for +their key contributions to the design of the library. Many thanks are due to Michael +Gauckler and Olivier Gygi, who, along with Daniel Egloff, implemented many of the +statistical accumulators. + +I would also like to thank Simon West for all his assistance maintaining +Boost.Accumulators. + +Finally, I would like to thank {zkb} for sponsoring the work on Boost.Accumulators +and graciously donating it to the community. diff --git a/doc/pages/definitions.adoc b/doc/pages/definitions.adoc new file mode 100644 index 00000000..b339605e --- /dev/null +++ b/doc/pages/definitions.adoc @@ -0,0 +1,87 @@ +//// +Definitions (from QuickBook macros) +//// + +:note: [$images/note.png] +:alert: [$images/caution.png] +:detail: [$images/note.png] +:tip: [$images/tip.png] +:sample_type: pass:a[sample-type] +:weight_type: pass:a[weight-type] +:variate_type: pass:a[variate-type] +:variate_tag: pass:a[variate-tag] +:left_or_right: pass:a[left-or-right] +:implementation_defined: pass:a[implementation-defined] +:boost: link:http://www.boost.org[Boost] +:mpl: link:../../libs/mpl/index.html[MPL] +:mpl_lambda_expression: link:../../libs/mpl/doc/refmanual/lambda-expression.html[MPL Lambda Expression] +:mpl_metafunction_class: link:../../libs/mpl/doc/refmanual/metafunction-class.html[MPL Metafunction Class] +:parameter: link:../../libs/parameter/index.html[Boost.Parameter] +:accumulator_set: xref:ref_accumulator_set[accumulator_set<>] +:accumulator_base: xref:ref_accumulator_base[accumulator_base] +:depends_on: xref:ref_depends_on[depends_on<>] +:feature_of: xref:ref_feature_of[feature_of<>] +:as_feature: xref:ref_as_feature[as_feature<>] +:features: xref:ref_features[features<>] +:external: xref:ref_external[external<>] +:droppable: xref:ref_droppable[droppable<>] +:droppable_accumulator: xref:ref_droppable_accumulator[droppable_accumulator<>] +:extractor: xref:ref_extractor[extractor<>] +:tail: xref:ref_tag_tail[tail] +:tail_variate: xref:ref_tag_tail_variate[tail_variate<>] +:extract_result: xref:ref_extract_result[extract_result()] +:zkb: link:http://www.zkb.com[Zürcher Kantonalbank] +:count_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/count.hpp[] +:covariance_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/covariance.hpp[] +:covariate_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/variates/covariate.hpp[] +:density_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/density.hpp[] +:error_of_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/error_of.hpp[] +:error_of_mean_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/error_of_mean.hpp[] +:extended_p_square_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/extended_p_square.hpp[] +:extended_p_square_quantile_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/extended_p_square_quantile.hpp[] +:kurtosis_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/kurtosis.hpp[] +:max_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/max.hpp[] +:mean_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/mean.hpp[] +:median_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/median.hpp[] +:min_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/min.hpp[] +:moment_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/moment.hpp[] +:p_square_cumulative_distribution_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/p_square_cumul_dist.hpp[] +:p_square_quantile_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/p_square_quantile.hpp[] +:peaks_over_threshold_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/peaks_over_threshold.hpp[] +:pot_quantile_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/pot_quantile.hpp[] +:pot_tail_mean_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/pot_tail_mean.hpp[] +:rolling_count_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/rolling_count.hpp[] +:rolling_sum_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/rolling_sum.hpp[] +:rolling_mean_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/rolling_mean.hpp[] +:rolling_moment_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/rolling_moment.hpp[] +:rolling_variance_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/rolling_variance.hpp[] +:skewness_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/skewness.hpp[] +:sum_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/sum.hpp[] +:sum_kahan_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/sum_kahan.hpp[] +:tail_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/tail.hpp[] +:tail_mean_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/tail_mean.hpp[] +:tail_quantile_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/tail_quantile.hpp[] +:tail_variate_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/tail_variate.hpp[] +:tail_variate_means_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/tail_variate_means.hpp[] +:variance_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/variance.hpp[] +:weighted_covariance_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_covariance.hpp[] +:weighted_density_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_density.hpp[] +:weighted_extended_p_square_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_extended_p_square.hpp[] +:weighted_kurtosis_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_kurtosis.hpp[] +:weighted_mean_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_mean.hpp[] +:weighted_median_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_median.hpp[] +:weighted_moment_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_moment.hpp[] +:weighted_p_square_cumulative_distribution_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_p_square_cumul_dist.hpp[] +:weighted_p_square_quantile_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_p_square_quantile.hpp[] +:weighted_peaks_over_threshold_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_peaks_over_threshold.hpp[] +:weighted_skewness_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_skewness.hpp[] +:weighted_sum_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_sum.hpp[] +:weighted_sum_kahan_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_sum_kahan.hpp[] +:weighted_tail_mean_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_tail_mean.hpp[] +:weighted_tail_quantile_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_tail_quantile.hpp[] +:weighted_tail_variate_means_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_tail_variate_means.hpp[] +:weighted_variance_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/weighted_variance.hpp[] +:accumulators_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/accumulators.hpp[] +:stats_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/statistics/stats.hpp[] +:framework_accumulator_base_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/framework/accumulator_base.hpp[] +:framework_sample_hpp: link:https://github.com/boostorg/accumulators/blob/develop/include/boost/accumulators/framework/parameters/sample.hpp[] diff --git a/doc/pages/docinfo-footer.html b/doc/pages/docinfo-footer.html new file mode 100644 index 00000000..15917c17 --- /dev/null +++ b/doc/pages/docinfo-footer.html @@ -0,0 +1,16 @@ + + + diff --git a/doc/pages/docinfo.html b/doc/pages/docinfo.html new file mode 100644 index 00000000..ac65c5f0 --- /dev/null +++ b/doc/pages/docinfo.html @@ -0,0 +1,108 @@ + diff --git a/doc/pages/main.adoc b/doc/pages/main.adoc new file mode 100644 index 00000000..f806cd5b --- /dev/null +++ b/doc/pages/main.adoc @@ -0,0 +1,67 @@ +//// +Copyright (C) 2005, 2006 Eric Niebler +Copyright (C) 2026 Ming Yang Zhang, Leo Chen +Distributed under the Boost Software License, Version 1.0. +//// + += Chapter 1. Boost.Accumulators +Eric Niebler + +Copyright (C) 2005, 2006 Eric Niebler + +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or copy at +link:https://www.boost.org/LICENSE_1_0.txt[https://www.boost.org/LICENSE_1_0.txt]) + +:idprefix: +:sectanchors: +:toclevels: 2 +:toc: left +:pagelevels: 1 +:source-language: c++ +:stem: latexmath + +include::definitions.adoc[] + +[#preface,pagelevels=0] +== Preface + +[quote] +____ +++"++It is better to be approximately right than exactly wrong.++"++ + +-- _Old adage_ +____ + +=== Description + +Boost.Accumulators is both a library for incremental statistical computation as +well as an extensible framework for incremental calculation in general. The library +deals primarily with the concept of an _accumulator_, which is a primitive +computational entity that accepts data one sample at a time and maintains some +internal state. These accumulators may offload some of their computations on other +accumulators, on which they depend. Accumulators are grouped within an +_accumulator set_. Boost.Accumulators resolves the inter-dependencies +between accumulators in a set and ensures that accumulators are processed in the +proper order. + +:leveloffset: +1 + +include::user_s_guide.adoc[] + +[#the_statistical_accumulators_library,pagelevels=1] += The Statistical Accumulators Library + +include::the_statistical_accumulators_library.adoc[] + +include::acknowledgements.adoc[] + +include::reference.adoc[] + +include::ref/accumulators_framework_reference.adoc[] + +include::ref/statistics_library_reference.adoc[] + +include::ref/numeric_operators_library_reference.adoc[] + +:leveloffset: -1 diff --git a/doc/pages/ref/accumulators_framework_reference.adoc b/doc/pages/ref/accumulators_framework_reference.adoc new file mode 100644 index 00000000..cfa8ade5 --- /dev/null +++ b/doc/pages/ref/accumulators_framework_reference.adoc @@ -0,0 +1,12 @@ +//// +Copyright (C) 2005, 2006 Eric Niebler +Copyright (C) 2026 Ming Yang Zhang, Leo Chen +Distributed under the Boost Software License, Version 1.0. +//// + +:source-location: pages/ref/accumulators_framework_reference.adoc + +[#accumulators_framework_reference,pagelevels=3,toclevels=1] += Accumulators Framework Reference + +include::{entities-framework-file}[leveloffset=+1] diff --git a/doc/pages/ref/numeric_operators_library_reference.adoc b/doc/pages/ref/numeric_operators_library_reference.adoc new file mode 100644 index 00000000..69027351 --- /dev/null +++ b/doc/pages/ref/numeric_operators_library_reference.adoc @@ -0,0 +1,12 @@ +//// +Copyright (C) 2005, 2006 Eric Niebler +Copyright (C) 2026 Ming Yang Zhang, Leo Chen +Distributed under the Boost Software License, Version 1.0. +//// + +:source-location: pages/ref/numeric_operators_library_reference.adoc + +[#numeric_operators_library_reference,pagelevels=3,toclevels=1] += Numeric Operators Library Reference + +include::{entities-numeric-file}[leveloffset=+1] diff --git a/doc/pages/ref/statistics_library_reference.adoc b/doc/pages/ref/statistics_library_reference.adoc new file mode 100644 index 00000000..1cc4bea7 --- /dev/null +++ b/doc/pages/ref/statistics_library_reference.adoc @@ -0,0 +1,12 @@ +//// +Copyright (C) 2005, 2006 Eric Niebler +Copyright (C) 2026 Ming Yang Zhang, Leo Chen +Distributed under the Boost Software License, Version 1.0. +//// + +:source-location: pages/ref/statistics_library_reference.adoc + +[#statistics_library_reference,pagelevels=3,toclevels=1] += Statistics Library Reference + +include::{entities-statistics-file}[leveloffset=+1] diff --git a/doc/pages/reference.adoc b/doc/pages/reference.adoc new file mode 100644 index 00000000..415f1dda --- /dev/null +++ b/doc/pages/reference.adoc @@ -0,0 +1,12 @@ +//// +Copyright (C) 2005, 2006 Eric Niebler +Copyright (C) 2026 Ming Yang Zhang, Leo Chen +Distributed under the Boost Software License, Version 1.0. +//// + +[#ref,pagelevels=3,toclevels=1] += Reference + +* <> +* <> +* <> diff --git a/doc/pages/the_statistical_accumulators_library.adoc b/doc/pages/the_statistical_accumulators_library.adoc new file mode 100644 index 00000000..feb291c2 --- /dev/null +++ b/doc/pages/the_statistical_accumulators_library.adoc @@ -0,0 +1,4012 @@ +//// +Copyright (C) 2005, 2006 Eric Niebler +Copyright (C) 2026 Ming Yang Zhang, Leo Chen +Distributed under the Boost Software License, Version 1.0. +//// +The Statistical Accumulators Library defines accumulators for incremental statistical +computations. It is built on top of <>. + +[[count]] +== count + +The `count` feature is a simple counter that tracks the +number of samples pushed into the accumulator set. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +std::size_t +---- + +[dlist] +Depends On:: +none + +Variants:: +none + +Initialization Parameters:: +none + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set > acc; +acc(0); +acc(0); +acc(0); +assert(3 == count(acc)); +---- + +*See also* + +* xref:ref_impl_count_impl[count_impl] + +[[covariance]] +== covariance + +The `covariance` feature is an iterative Monte Carlo estimator for the covariance. +It is specified as `tag::covariance<{variate_type}, {variate_tag}>`. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::outer_product< + numeric::functional::fdiv<{sample_type}, std::size_t>::result_type + , numeric::functional::fdiv<{variate_type}, std::size_t>::result_type +>::result_type +---- + +[dlist] +Depends On:: +`count` + +`mean` + +`mean_of_variates<{variate_type}, {variate_tag}>` + +Variants:: +`abstract_covariance` + +Initialization Parameters:: +none + +Accumulator Parameters:: +{variate_tag} + +Extractor Parameters:: +none + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +O(1) + +*Headers* + +[source,c++] +---- +#include +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set > > acc; +acc(1., covariate1 = 2.); +acc(1., covariate1 = 4.); +acc(2., covariate1 = 3.); +acc(6., covariate1 = 1.); +assert(covariance(acc) == -1.75); +---- + +*See also* + +* xref:ref_impl_covariance_impl[covariance_impl] +* <> +* <> + +[[density]] +== density + +The `tag::density` feature returns a histogram of the sample distribution. For more +implementation details, see xref:ref_impl_density_impl[density_impl]. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +iterator_range< + std::vector< + std::pair< + numeric::functional::fdiv<{sample_type}, std::size_t>::result_type + , numeric::functional::fdiv<{sample_type}, std::size_t>::result_type + > + >::iterator +> +---- + +[dlist] +Depends On:: +`count` + +`min` + +`max` + +Variants:: +none + +Initialization Parameters:: +`density::cache_size` + +`density::num_bins` + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +O(N), when N is `density::num_bins` + +*Header* + +[source,c++] +---- +#include +---- + +*Note* + +Results from the `density` accumulator can only be extracted after the number of +samples meets or exceeds the cache size. + +*See also* + +* xref:ref_impl_density_impl[density_impl] +* <> +* <> +* <> + +[[error_of_mean]] +== error_of + +The `error_of` feature calculates the error of the mean feature. It is equal to +`sqrt(variance / (count - 1))`. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, std::size_t>::result_type +---- + +[dlist] +Depends On:: +`count` + +`variance` + +Variants:: +`error_of` + +Initialization Parameters:: +none + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set > > acc; +acc(1.1); +acc(1.2); +acc(1.3); +assert(0.057735 == error_of(acc)); +---- + +*See also* + +* xref:ref_impl_error_of_mean_impl[error_of_mean_impl] +* <> +* <> + +[[extended_p_square]] +== extended_p_square + +Multiple quantile estimation with the extended `P^2` algorithm. For further +details, see xref:ref_impl_extended_p_square_impl[extended_p_square_impl]. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +boost::iterator_range< + {implementation_defined} +> +---- + +[dlist] +Depends On:: +`count` + +Variants:: +none + +Initialization Parameters:: +`tag::extended_p_square::probabilities` + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +boost::array probs = {0.001,0.01,0.1,0.25,0.5,0.75,0.9,0.99,0.999}; +accumulator_set > + acc(tag::extended_p_square::probabilities = probs); + +boost::lagged_fibonacci607 rng; // a random number generator +for (int i=0; i<10000; ++i) + acc(rng()); + +BOOST_CHECK_CLOSE(extended_p_square(acc)[0], probs[0], 25); +BOOST_CHECK_CLOSE(extended_p_square(acc)[1], probs[1], 10); +BOOST_CHECK_CLOSE(extended_p_square(acc)[2], probs[2], 5); + +for (std::size_t i=3; i < probs.size(); ++i) +{ + BOOST_CHECK_CLOSE(extended_p_square(acc)[i], probs[i], 2); +} +---- + +*See also* + +* xref:ref_impl_extended_p_square_impl[extended_p_square_impl] +* <> + +[[extended_p_square_quantile]] +== extended_p_square_quantile _and variants_ + +Quantile estimation using the extended `P^2` algorithm for weighted and unweighted samples. +By default, the calculation is linear and unweighted, but quadratic and weighted variants +are also provided. For further implementation details, see +xref:ref_impl_extended_p_square_quantile_impl[extended_p_square_quantile_impl]. + +All the variants share the `tag::quantile` feature and can be extracted using the `quantile()` +extractor. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, std::size_t>::result_type +---- + +[dlist] +Depends On:: +weighted variants depend on `weighted_extended_p_square` + +unweighted variants depend on `extended_p_square` + +Variants:: +`extended_p_square_quantile_quadratic` + +`weighted_extended_p_square_quantile` + +`weighted_extended_p_square_quantile_quadratic` + +Initialization Parameters:: +`tag::extended_p_square::probabilities` + +Accumulator Parameters:: +`weight` for the weighted variants + +Extractor Parameters:: +`quantile_probability` + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +O(N) where N is the count of probabilities. + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +typedef accumulator_set > + accumulator_t; +typedef accumulator_set, double > + accumulator_t_weighted; +typedef accumulator_set > + accumulator_t_quadratic; +typedef accumulator_set, double > + accumulator_t_weighted_quadratic; + +// tolerance +double epsilon = 1; + +// a random number generator +boost::lagged_fibonacci607 rng; + +boost::array probs = { 0.990, 0.991, 0.992, 0.993, 0.994, + 0.995, 0.996, 0.997, 0.998, 0.999 }; +accumulator_t acc(extended_p_square_probabilities = probs); +accumulator_t_weighted acc_weighted(extended_p_square_probabilities = probs); +accumulator_t_quadratic acc2(extended_p_square_probabilities = probs); +accumulator_t_weighted_quadratic acc_weighted2(extended_p_square_probabilities = probs); + +for (int i=0; i<10000; ++i) +{ + double sample = rng(); + acc(sample); + acc2(sample); + acc_weighted(sample, weight = 1.); + acc_weighted2(sample, weight = 1.); +} + +for (std::size_t i = 0; i < probs.size() - 1; ++i) +{ + BOOST_CHECK_CLOSE( + quantile(acc, quantile_probability = 0.99025 + i*0.001) + , 0.99025 + i*0.001 + , epsilon + ); + BOOST_CHECK_CLOSE( + quantile(acc2, quantile_probability = 0.99025 + i*0.001) + , 0.99025 + i*0.001 + , epsilon + ); + BOOST_CHECK_CLOSE( + quantile(acc_weighted, quantile_probability = 0.99025 + i*0.001) + , 0.99025 + i*0.001 + , epsilon + ); + BOOST_CHECK_CLOSE( + quantile(acc_weighted2, quantile_probability = 0.99025 + i*0.001) + , 0.99025 + i*0.001 + , epsilon + ); +} +---- + +*See also* + +* xref:ref_impl_extended_p_square_quantile_impl[extended_p_square_quantile_impl] +* <> +* <> + +[[kurtosis]] +== kurtosis + +The kurtosis of a sample distribution is defined as the ratio of the 4th central moment and the +square of the 2nd central moment (the variance) of the samples, minus 3. The term `-3` is added +in order to ensure that the normal distribution has zero kurtosis. For more implementation +details, see xref:ref_impl_kurtosis_impl[kurtosis_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, {sample_type}>::result_type +---- + +[dlist] +Depends On:: +`mean` + +`moment<2>` + +`moment<3>` + +`moment<4>` + +Variants:: +none + +Initialization Parameters:: +none + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set > acc; + +acc(2); +acc(7); +acc(4); +acc(9); +acc(3); + +BOOST_CHECK_EQUAL( mean(acc), 5 ); +BOOST_CHECK_EQUAL( accumulators::moment<2>(acc), 159./5. ); +BOOST_CHECK_EQUAL( accumulators::moment<3>(acc), 1171./5. ); +BOOST_CHECK_EQUAL( accumulators::moment<4>(acc), 1863 ); +BOOST_CHECK_CLOSE( kurtosis(acc), -1.39965397924, 1e-6 ); +---- + +*See also* + +* xref:ref_impl_kurtosis_impl[kurtosis_impl] +* <> +* <> + +[[max]] +== max + +Calculates the maximum value of all the samples. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +{sample_type} +---- + +[dlist] +Depends On:: +none + +Variants:: +none + +Initialization Parameters:: +none + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set > acc; + +acc(1); +BOOST_CHECK_EQUAL(1, (max)(acc)); + +acc(0); +BOOST_CHECK_EQUAL(1, (max)(acc)); + +acc(2); +BOOST_CHECK_EQUAL(2, (max)(acc)); +---- + +*See also* + +* xref:ref_impl_max_impl[max_impl] + +[[mean]] +== mean _and variants_ + +Calculates the mean of samples, weights or variates. The calculation is either +lazy (in the result extractor), or immediate (in the accumulator). The lazy implementation +is the default. For more implementation details, see +xref:ref_impl_mean_impl[mean_impl] or. +xref:ref_impl_immediate_mean_impl[immediate_mean_impl] + +** +[source,cpp,subs="+attributes"] +---- +---- + +[dlist] +Result Type:: +For samples, `numeric::functional::fdiv<{sample_type}, std::size_t>::result_type` + +For weights, `numeric::functional::fdiv<{weight_type}, std::size_t>::result_type` + +For variates, `numeric::functional::fdiv<{variate_type}, std::size_t>::result_type` + + +Depends On:: +`count` + +The lazy mean of samples depends on `sum` + +The lazy mean of weights depends on `sum_of_weights` + +The lazy mean of variates depends on `sum_of_variates<>` + +Variants:: +`mean_of_weights` + +`mean_of_variates<{variate_type}, {variate_tag}>` + +`immediate_mean` + +`immediate_mean_of_weights` + +`immediate_mean_of_variates<{variate_type}, {variate_tag}>` + +Initialization Parameters:: +none + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set< + int + , stats< + tag::mean + , tag::mean_of_weights + , tag::mean_of_variates + > + , int +> acc; + +acc(1, weight = 2, covariate1 = 3); +BOOST_CHECK_CLOSE(1., mean(acc), 1e-5); +BOOST_CHECK_EQUAL(1u, count(acc)); +BOOST_CHECK_EQUAL(2, sum(acc)); +BOOST_CHECK_CLOSE(2., mean_of_weights(acc), 1e-5); +BOOST_CHECK_CLOSE(3., (accumulators::mean_of_variates(acc)), 1e-5); + +acc(0, weight = 4, covariate1 = 4); +BOOST_CHECK_CLOSE(0.33333333333333333, mean(acc), 1e-5); +BOOST_CHECK_EQUAL(2u, count(acc)); +BOOST_CHECK_EQUAL(2, sum(acc)); +BOOST_CHECK_CLOSE(3., mean_of_weights(acc), 1e-5); +BOOST_CHECK_CLOSE(3.5, (accumulators::mean_of_variates(acc)), 1e-5); + +acc(2, weight = 9, covariate1 = 8); +BOOST_CHECK_CLOSE(1.33333333333333333, mean(acc), 1e-5); +BOOST_CHECK_EQUAL(3u, count(acc)); +BOOST_CHECK_EQUAL(20, sum(acc)); +BOOST_CHECK_CLOSE(5., mean_of_weights(acc), 1e-5); +BOOST_CHECK_CLOSE(5., (accumulators::mean_of_variates(acc)), 1e-5); + +accumulator_set< + int + , stats< + tag::mean(immediate) + , tag::mean_of_weights(immediate) + , tag::mean_of_variates(immediate) + > + , int +> acc2; + +acc2(1, weight = 2, covariate1 = 3); +BOOST_CHECK_CLOSE(1., mean(acc2), 1e-5); +BOOST_CHECK_EQUAL(1u, count(acc2)); +BOOST_CHECK_CLOSE(2., mean_of_weights(acc2), 1e-5); +BOOST_CHECK_CLOSE(3., (accumulators::mean_of_variates(acc2)), 1e-5); + +acc2(0, weight = 4, covariate1 = 4); +BOOST_CHECK_CLOSE(0.33333333333333333, mean(acc2), 1e-5); +BOOST_CHECK_EQUAL(2u, count(acc2)); +BOOST_CHECK_CLOSE(3., mean_of_weights(acc2), 1e-5); +BOOST_CHECK_CLOSE(3.5, (accumulators::mean_of_variates(acc2)), 1e-5); + +acc2(2, weight = 9, covariate1 = 8); +BOOST_CHECK_CLOSE(1.33333333333333333, mean(acc2), 1e-5); +BOOST_CHECK_EQUAL(3u, count(acc2)); +BOOST_CHECK_CLOSE(5., mean_of_weights(acc2), 1e-5); +BOOST_CHECK_CLOSE(5., (accumulators::mean_of_variates(acc2)), 1e-5); +---- + +*See also* + +* xref:ref_impl_mean_impl[mean_impl] +* xref:ref_impl_immediate_mean_impl[immediate_mean_impl] +* <> +* <> + +[[median]] +== median _and variants_ + +Median estimation based on the `P^2` quantile estimator, the density estimator, or +the `P^2` cumulative distribution estimator. For more implementation details, see +xref:ref_impl_median_impl[median_impl], +xref:ref_impl_with_density_median_impl[with_density_median_impl], +and xref:ref_impl_with_p_square_cumulative_distribution_median_impl[with_p_square_cumulative_distribution_median_impl]. + +The three median accumulators all satisfy the `tag::median` feature, and can all be +extracted with the `median()` extractor. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, std::size_t>::result_type +---- + +[dlist] +Depends On:: +`median` depends on `p_square_quantile_for_median` + +`with_density_median` depends on `count` and `density` + +`with_p_square_cumulative_distribution_median` depends on `p_square_cumulative_distribution` + +Variants:: +`with_density_median` + +`with_p_square_cumulative_distribution_median` + +Initialization Parameters:: +`with_density_median` requires `tag::density::cache_size` and `tag::density::num_bins` + +`with_p_square_cumulative_distribution_median` requires `tag::p_square_cumulative_distribution::num_cells` + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +TODO + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +// two random number generators +double mu = 1.; +boost::lagged_fibonacci607 rng; +boost::normal_distribution<> mean_sigma(mu,1); +boost::variate_generator > + normal(rng, mean_sigma); + +accumulator_set > acc; +accumulator_set > + acc_dens( density_cache_size = 10000, density_num_bins = 1000 ); +accumulator_set > + acc_cdist( p_square_cumulative_distribution_num_cells = 100 ); + +for (std::size_t i=0; i<100000; ++i) +{ + double sample = normal(); + acc(sample); + acc_dens(sample); + acc_cdist(sample); +} + +BOOST_CHECK_CLOSE(1., median(acc), 1.); +BOOST_CHECK_CLOSE(1., median(acc_dens), 1.); +BOOST_CHECK_CLOSE(1., median(acc_cdist), 3.); +---- + +*See also* + +* xref:ref_impl_median_impl[median_impl] +* xref:ref_impl_with_density_median_impl[with_density_median_impl] +* xref:ref_impl_with_p_square_cumulative_distribution_median_impl[with_p_square_cumulative_distribution_median_impl] +* <> +* <> +* <> + +[[min]] +== min + +Calculates the minimum value of all the samples. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +{sample_type} +---- + +[dlist] +Depends On:: +none + +Variants:: +none + +Initialization Parameters:: +none + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set > acc; + +acc(1); +BOOST_CHECK_EQUAL(1, (min)(acc)); + +acc(0); +BOOST_CHECK_EQUAL(0, (min)(acc)); + +acc(2); +BOOST_CHECK_EQUAL(0, (min)(acc)); +---- + +*See also* + +* xref:ref_impl_min_impl[min_impl] + +[[moment]] +== moment + +Calculates the N-th moment of the samples, which is defined as the sum of the N-th power of the +samples over the count of samples. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, std::size_t>::result_type +---- + +[dlist] +Depends On:: +`count` + +Variants:: +none + +Initialization Parameters:: +none + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set > > acc1; + +acc1(2); // 4 +acc1(4); // 16 +acc1(5); // + 25 + // = 45 / 3 = 15 + +BOOST_CHECK_CLOSE(15., accumulators::moment<2>(acc1), 1e-5); + +accumulator_set > > acc2; + +acc2(2); // 32 +acc2(3); // 243 +acc2(4); // 1024 +acc2(5); // + 3125 + // = 4424 / 4 = 1106 + +BOOST_CHECK_CLOSE(1106., accumulators::moment<5>(acc2), 1e-5); +---- + +*See also* + +* xref:ref_impl_moment_impl[moment_impl] +* <> + +[[p_square_cumulative_distribution]] +== p_square_cumulative_distribution + +Histogram calculation of the cumulative distribution with the `P^2` algorithm. +For more implementation details, see +xref:ref_impl_p_square_cumulative_distribution_impl[p_square_cumulative_distribution_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +iterator_range< + std::vector< + std::pair< + numeric::functional::fdiv<{sample_type}, std::size_t>::result_type + , numeric::functional::fdiv<{sample_type}, std::size_t>::result_type + > + >::iterator +> +---- + +[dlist] +Depends On:: +`count` + +Variants:: +none + +Initialization Parameters:: +`tag::p_square_cumulative_distribution::num_cells` + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +O(N) where N is `num_cells` + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +// tolerance in % +double epsilon = 3; + +typedef accumulator_set > accumulator_t; + +accumulator_t acc(tag::p_square_cumulative_distribution::num_cells = 100); + +// two random number generators +boost::lagged_fibonacci607 rng; +boost::normal_distribution<> mean_sigma(0,1); +boost::variate_generator > normal(rng, mean_sigma); + +for (std::size_t i=0; i<100000; ++i) +{ + acc(normal()); +} + +typedef iterator_range >::iterator > histogram_type; +histogram_type histogram = p_square_cumulative_distribution(acc); + +for (std::size_t i = 0; i < histogram.size(); ++i) +{ + // problem with small results: epsilon is relative (in percent), not absolute! + if ( histogram[i].second > 0.001 ) + BOOST_CHECK_CLOSE( 0.5 * (1.0 + erf( histogram[i].first / sqrt(2.0) )), histogram[i].second, epsilon ); +} +---- + +*See also* + +* xref:ref_impl_p_square_cumulative_distribution_impl[p_square_cumulative_distribution_impl] +* <> + +[[p_square_quantile]] +== p_square_quantile _and variants_ + +Single quantile estimation with the `P^2` algorithm. For more implementation details, see +xref:ref_impl_p_square_quantile_impl[p_square_quantile_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, std::size_t>::result_type +---- + +[dlist] +Depends On:: +`count` + +Variants:: +`p_square_quantile_for_median` + +Initialization Parameters:: +`quantile_probability`, which defaults to `0.5`. (Note: for `p_square_quantile_for_median`, the `quantile_probability` parameter is ignored and is always `0.5`.) + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +typedef accumulator_set > accumulator_t; + +// tolerance in % +double epsilon = 1; + +// a random number generator +boost::lagged_fibonacci607 rng; + +accumulator_t acc0(quantile_probability = 0.001); +accumulator_t acc1(quantile_probability = 0.01 ); +accumulator_t acc2(quantile_probability = 0.1 ); +accumulator_t acc3(quantile_probability = 0.25 ); +accumulator_t acc4(quantile_probability = 0.5 ); +accumulator_t acc5(quantile_probability = 0.75 ); +accumulator_t acc6(quantile_probability = 0.9 ); +accumulator_t acc7(quantile_probability = 0.99 ); +accumulator_t acc8(quantile_probability = 0.999); + +for (int i=0; i<100000; ++i) +{ + double sample = rng(); + acc0(sample); + acc1(sample); + acc2(sample); + acc3(sample); + acc4(sample); + acc5(sample); + acc6(sample); + acc7(sample); + acc8(sample); +} + +BOOST_CHECK_CLOSE( p_square_quantile(acc0), 0.001, 15*epsilon ); +BOOST_CHECK_CLOSE( p_square_quantile(acc1), 0.01 , 5*epsilon ); +BOOST_CHECK_CLOSE( p_square_quantile(acc2), 0.1 , epsilon ); +BOOST_CHECK_CLOSE( p_square_quantile(acc3), 0.25 , epsilon ); +BOOST_CHECK_CLOSE( p_square_quantile(acc4), 0.5 , epsilon ); +BOOST_CHECK_CLOSE( p_square_quantile(acc5), 0.75 , epsilon ); +BOOST_CHECK_CLOSE( p_square_quantile(acc6), 0.9 , epsilon ); +BOOST_CHECK_CLOSE( p_square_quantile(acc7), 0.99 , epsilon ); +BOOST_CHECK_CLOSE( p_square_quantile(acc8), 0.999, epsilon ); +---- + +*See also* + +* xref:ref_impl_p_square_quantile_impl[p_square_quantile_impl] +* <> + +[[peaks_over_threshold]] +== peaks_over_threshold _and variants_ + +Peaks Over Threshold method for quantile and tail mean estimation. For implementation +details, see xref:ref_impl_peaks_over_threshold_impl[peaks_over_threshold_impl] +and xref:ref_impl_peaks_over_threshold_prob_impl[peaks_over_threshold_prob_impl]. + +Both `tag::peaks_over_threshold` and `tag::peaks_over_threshold_prob<>` satisfy the `tag::abstract_peaks_over_threshold` +feature, and can be extracted with the `peaks_over_threshold()` extractor. The result is a 3-tuple representing +the fit parameters `u_bar`, `beta_bar` and `xi_hat`. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +boost::tuple< + numeric::functional::fdiv<{sample_type}, std::size_t>::result_type // u_bar + , numeric::functional::fdiv<{sample_type}, std::size_t>::result_type // beta_bar + , numeric::functional::fdiv<{sample_type}, std::size_t>::result_type // xi_hat +> +---- + +[dlist] +Depends On:: +`count` + +In addition, `tag::peaks_over_threshold_prob<>` depends on `tail<{left_or_right}>` + +Variants:: +`peaks_over_threshold_prob<{left_or_right}>` + +Initialization Parameters:: +`tag::peaks_over_threshold::threshold_value` + +`tag::peaks_over_threshold_prob::threshold_probability` + +`tag::tail<{left_or_right}>::cache_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +TODO + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +See example for <>. + +*See also* + +* xref:ref_impl_peaks_over_threshold_impl[peaks_over_threshold_impl] +* xref:ref_impl_peaks_over_threshold_prob_impl[peaks_over_threshold_prob_impl] +* <> +* <> +* <> +* <> + +[[pot_quantile]] +== pot_quantile _and variants_ + +Quantile estimation based on Peaks over Threshold method (for both left and right tails). For +implementation details, see xref:ref_impl_pot_quantile_impl[pot_quantile_impl]. + +Both `tag::pot_quantile<{left_or_right}>` and `tag::pot_quantile_prob<{left_or_right}>` satisfy the +`tag::quantile` feature and can be extracted using the `quantile()` extractor. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, std::size_t>::result_type +---- + +[dlist] +Depends On:: +`pot_quantile<{left_or_right}>` depends on `peaks_over_threshold<{left_or_right}>` + +`pot_quantile_prob<{left_or_right}>` depends on `peaks_over_threshold_prob<{left_or_right}>` + +Variants:: +`pot_quantile_prob<{left_or_right}>` + +Initialization Parameters:: +`tag::peaks_over_threshold::threshold_value` + +`tag::peaks_over_threshold_prob::threshold_probability` + +`tag::tail<{left_or_right}>::cache_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +`quantile_probability` + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +TODO + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +// tolerance in % +double epsilon = 1.; + +double alpha = 0.999; +double threshold_probability = 0.99; +double threshold = 3.; + +// two random number generators +boost::lagged_fibonacci607 rng; +boost::normal_distribution<> mean_sigma(0,1); +boost::exponential_distribution<> lambda(1); +boost::variate_generator > normal(rng, mean_sigma); +boost::variate_generator > exponential(rng, lambda); + +accumulator_set(with_threshold_value)> > acc1( + tag::peaks_over_threshold::threshold_value = threshold +); +accumulator_set(with_threshold_probability)> > acc2( + tag::tail::cache_size = 2000 + , tag::peaks_over_threshold_prob::threshold_probability = threshold_probability +); + +threshold_probability = 0.995; +threshold = 5.; + +accumulator_set(with_threshold_value)> > acc3( + tag::peaks_over_threshold::threshold_value = threshold +); +accumulator_set(with_threshold_probability)> > acc4( + tag::tail::cache_size = 2000 + , tag::peaks_over_threshold_prob::threshold_probability = threshold_probability +); + +for (std::size_t i = 0; i < 100000; ++i) +{ + double sample = normal(); + acc1(sample); + acc2(sample); +} + +for (std::size_t i = 0; i < 100000; ++i) +{ + double sample = exponential(); + acc3(sample); + acc4(sample); +} + +BOOST_CHECK_CLOSE( quantile(acc1, quantile_probability = alpha), 3.090232, epsilon ); +BOOST_CHECK_CLOSE( quantile(acc2, quantile_probability = alpha), 3.090232, epsilon ); + +BOOST_CHECK_CLOSE( quantile(acc3, quantile_probability = alpha), 6.908, epsilon ); +BOOST_CHECK_CLOSE( quantile(acc4, quantile_probability = alpha), 6.908, epsilon ); +---- + +*See also* + +* xref:ref_impl_pot_quantile_impl[pot_quantile_impl] +* <> + +[[pot_tail_mean]] +== pot_tail_mean + +Estimation of the (coherent) tail mean based on the peaks over threshold method (for both left and right tails). +For implementation details, see xref:ref_impl_pot_tail_mean_impl[pot_tail_mean_impl]. + +Both `tag::pot_tail_mean<{left_or_right}>` and `tag::pot_tail_mean_prob<{left_or_right}>` satisfy the +`tag::tail_mean` feature and can be extracted using the `tail_mean()` extractor. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, std::size_t>::result_type +---- + +[dlist] +Depends On:: +`pot_tail_mean<{left_or_right}>` depends on `peaks_over_threshold<{left_or_right}>` and `pot_quantile<{left_or_right}>` + +`pot_tail_mean_prob<{left_or_right}>` depends on `peaks_over_threshold_prob<{left_or_right}>` and `pot_quantile_prob<{left_or_right}>` + +Variants:: +`pot_tail_mean_prob<{left_or_right}>` + +Initialization Parameters:: +`tag::peaks_over_threshold::threshold_value` + +`tag::peaks_over_threshold_prob::threshold_probability` + +`tag::tail<{left_or_right}>::cache_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +`quantile_probability` + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +TODO + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +// TODO +---- + +*See also* + +* xref:ref_impl_pot_tail_mean_impl[pot_tail_mean_impl] +* <> +* <> + +[[rolling_count]] +== rolling_count + +The rolling count is the current number of elements in the rolling window. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +std::size_t +---- + +[dlist] +Depends On:: +`rolling_window_plus1` + +Variants:: +none + +Initialization Parameters:: +`tag::rolling_window::window_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set > acc(tag::rolling_window::window_size = 3); + +BOOST_CHECK_EQUAL(0u, rolling_count(acc)); + +BOOST_CHECK_EQUAL(1u, rolling_count(acc)); + +acc(1); +BOOST_CHECK_EQUAL(2u, rolling_count(acc)); + +acc(1); +BOOST_CHECK_EQUAL(3u, rolling_count(acc)); + +acc(1); +BOOST_CHECK_EQUAL(3u, rolling_count(acc)); + +acc(1); +BOOST_CHECK_EQUAL(3u, rolling_count(acc)); +---- + +*See also* + +* xref:ref_impl_rolling_count_impl[rolling_count_impl] + +[[rolling_sum]] +== rolling_sum + +The rolling sum is the sum of the last /N/ samples. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +{sample_type} +---- + +[dlist] +Depends On:: +`rolling_window_plus1` + +Variants:: +none + +Initialization Parameters:: +`tag::rolling_window::window_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set > acc(tag::rolling_window::window_size = 3); + +BOOST_CHECK_EQUAL(0, rolling_sum(acc)); + +acc(1); +BOOST_CHECK_EQUAL(1, rolling_sum(acc)); + +acc(2); +BOOST_CHECK_EQUAL(3, rolling_sum(acc)); + +acc(3); +BOOST_CHECK_EQUAL(6, rolling_sum(acc)); + +acc(4); +BOOST_CHECK_EQUAL(9, rolling_sum(acc)); + +acc(5); +BOOST_CHECK_EQUAL(12, rolling_sum(acc)); +---- + +*See also* + +* xref:ref_impl_rolling_sum_impl[rolling_sum_impl] + +[[rolling_mean]] +== rolling_mean + +The rolling mean is the mean over the last /N/ samples. It is computed by dividing +the rolling sum by the rolling count. + +Lazy or iterative calculation of the mean over the last /N/ samples. The lazy calculation is associated with the `tag::lazy_rolling_mean` +feature, and the iterative calculation (which is the default) with the `tag::immediate_rolling_mean` feature. Both can be extracted +using the `tag::rolling_mean()` extractor. For more implementation details, see +xref:ref_impl_lazy_rolling_mean_impl[lazy_rolling_mean_impl] and +xref:ref_impl_immediate_rolling_mean_impl[immediate_rolling_mean_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, std::size_t>::result_type +---- + +[dlist] +Depends On:: +`lazy_rolling_mean` depends on `rolling_sum` and `rolling_count` + +`immediate_rolling_mean` depends on `rolling_count` + +Variants:: +`lazy_rolling_mean` (a.k.a. `rolling_mean(lazy))` + +`immediate_rolling_mean` (a.k.a. `rolling_mean(immediate)`) + +Initialization Parameters:: +`tag::rolling_window::window_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set > acc(tag::rolling_window::window_size = 5); + +acc(1); +acc(2); +acc(3); + +BOOST_CHECK_CLOSE( rolling_mean(acc), 2.0, 1e-6 ); + +acc(4); +acc(5); +acc(6); +acc(7); + +BOOST_CHECK_CLOSE( rolling_mean(acc), 5.0, 1e-6 ); +---- + +*See also* + +* xref:ref_impl_lazy_rolling_mean_impl[lazy_rolling_mean_impl] +* xref:ref_impl_immediate_rolling_mean_impl[immediate_rolling_mean_impl] +* <> +* <> + +[[rolling_moment]] +== rolling_moment + +rolling_moment calculates the _M_-th moment of the samples, which is defined as the sum of the /M/-th power of the samples over the count of samples, over the last /N/ samples. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, std::size_t>::result_type +---- + +[dlist] +Depends On:: +none + +Variants:: +none + +Initialization Parameters:: +`tag::rolling_window::window_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set > > acc(tag::rolling_window::window_size = 3); + +acc(2); +acc(4); + +BOOST_CHECK_CLOSE( rolling_moment<2>(acc), (4.0 + 16.0)/2, 1e-5 ); + +acc(5); +acc(6); + +BOOST_CHECK_CLOSE( rolling_moment<2>(acc), (16.0 + 25.0 + 36.0)/3, 1e-5 ); +---- + +*See also* + +* xref:ref_impl_rolling_moment_impl[rolling_moment_impl] + +[[rolling_variance]] +== rolling_variance + +Lazy or iterative calculation of the variance over the last /N/ samples. The lazy calculation is associated with the `tag::lazy_rolling_variance` +feature, and the iterative calculation with the `tag::immediate_rolling_variance` feature. Both can be extracted using the `tag::rolling_variance()` extractor. +For more implementation details, see +xref:ref_impl_lazy_rolling_variance_impl[lazy_rolling_variance_impl] and +xref:ref_impl_immediate_rolling_variance_impl[immediate_rolling_variance_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, std::size_t>::result_type +---- + +[dlist] +Depends On:: +`lazy_rolling_variance` depends on `rolling_moment<2>`, `rolling_count` and `rolling_mean` + +`immediate_rolling_variance` depends on `rolling_count` and `immediate_rolling_mean` + +Variants:: +`lazy_rolling_variance` (a.k.a. `rolling_variance(lazy))` + +`immediate_rolling_variance` (a.k.a. `rolling_variance(immediate)`) + +Initialization Parameters:: +`tag::rolling_window::window_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set > acc(tag::rolling_window::window_size = 4); + +acc(1.2); + +BOOST_CHECK_CLOSE( rolling_variance(acc), 0.0, 1e-10 ); // variance is not defined for a single sample + +acc(2.3); +acc(3.4); + +BOOST_CHECK_CLOSE( rolling_variance(acc), 1.21, 1e-10 ); // variance over samples 1-3 + +acc(4.5); +acc(0.4); +acc(2.2); +acc(7.1); + +BOOST_CHECK_CLOSE( rolling_variance(acc), 8.41666666666667, 1e-10 ); // variance over samples 4-7 +---- + +*See also* + +* xref:ref_impl_lazy_rolling_variance_impl[lazy_rolling_variance_impl] +* xref:ref_impl_immediate_rolling_variance_impl[immediate_rolling_variance_impl] +* <> +* <> +* <> +* <> + +[[skewness]] +== skewness + +The skewness of a sample distribution is defined as the ratio of the 3rd central moment and the `3/2`-th power +of the 2nd central moment (the variance) of the samples 3. For implementation details, see +xref:ref_impl_skewness_impl[skewness_impl]. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, {sample_type}>::result_type +---- + +[dlist] +Depends On:: +`mean` + +`moment<2>` + +`moment<3>` + +Variants:: +none + +Initialization Parameters:: +none + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set > acc2; + +acc2(2); +acc2(7); +acc2(4); +acc2(9); +acc2(3); + +BOOST_CHECK_EQUAL( mean(acc2), 5 ); +BOOST_CHECK_EQUAL( accumulators::moment<2>(acc2), 159./5. ); +BOOST_CHECK_EQUAL( accumulators::moment<3>(acc2), 1171./5. ); +BOOST_CHECK_CLOSE( skewness(acc2), 0.406040288214, 1e-6 ); +---- + +*See also* + +* xref:ref_impl_skewness_impl[skewness_impl] +* <> +* <> + +[[sum]] +== sum _and variants_ + +For summing the samples, weights or variates. The default implementation uses the standard sum operation, +but variants using the Kahan summation algorithm are also provided. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +{sample_type} for summing samples +{weight_type} for summing weights +{variate_type} for summing variates +---- + +[dlist] +Depends On:: +none + +Variants:: +`tag::sum` + +`tag::sum_of_weights` + +`tag::sum_of_variates<{variate_type}, {variate_tag}>` + +`tag::sum_kahan` (a.k.a. `tag::sum(kahan)`) + +`tag::sum_of_weights_kahan` (a.k.a. `tag::sum_of_weights(kahan)`) + +`tag::sum_of_variates_kahan<{variate_type}, {variate_tag}>` + + +Initialization Parameters:: +none + +Accumulator Parameters:: +`weight` for summing weights + +`{variate_tag}` for summing variates + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1). Note that the Kahan sum performs four floating-point sum operations per accumulated value, whereas the naive sum performs only one. + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set< + int + , stats< + tag::sum + , tag::sum_of_weights + , tag::sum_of_variates + > + , int +> acc; + +acc(1, weight = 2, covariate1 = 3); +BOOST_CHECK_EQUAL(2, sum(acc)); // weighted sample = 1 * 2 +BOOST_CHECK_EQUAL(2, sum_of_weights(acc)); +BOOST_CHECK_EQUAL(3, sum_of_variates(acc)); + +acc(2, weight = 4, covariate1 = 6); +BOOST_CHECK_EQUAL(10, sum(acc)); // weighted sample = 2 * 4 +BOOST_CHECK_EQUAL(6, sum_of_weights(acc)); +BOOST_CHECK_EQUAL(9, sum_of_variates(acc)); + +acc(3, weight = 6, covariate1 = 9); +BOOST_CHECK_EQUAL(28, sum(acc)); // weighted sample = 3 * 6 +BOOST_CHECK_EQUAL(12, sum_of_weights(acc)); +BOOST_CHECK_EQUAL(18, sum_of_variates(acc)); + +// demonstrate Kahan summation +accumulator_set > acc; +BOOST_CHECK_EQUAL(0.0f, sum_kahan(acc)); +for (size_t i = 0; i < 1e6; ++i) { + acc(1e-6f); +} +BOOST_CHECK_EQUAL(1.0f, sum_kahan(acc)); +---- + +*See also* + +* xref:ref_impl_sum_impl[sum_impl] +* xref:ref_impl_sum_kahan_impl[sum_kahan_impl] + +[[tail]] +== tail + +Tracks the largest or smallest `N` values. `tag::tail` tracks the largest `N`, +and `tag::tail` tracks the smallest. The parameter `N` is specified with the +`tag::tail<{left_or_right}>::cache_size` initialization parameter. For implementation details, see +xref:ref_impl_tail_impl[tail_impl]. + +Both `tag::tail` and `tag::tail` satisfy the `tag::abstract_tail` feature and +can be extracted with the `tail()` extractor. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +boost::iterator_range< + boost::reverse_iterator< + boost::permutation_iterator< + std::vector<{sample_type}>::const_iterator // samples + , std::vector::iterator // indices + > + > +> +---- + +[dlist] +Depends On:: +none + +Variants:: +`abstract_tail` + +Initialization Parameters:: +`tag::tail<{left_or_right}>::cache_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(log N), where N is the cache size + +Extractor Complexity:: +O(N log N), where N is the cache size + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +See the Example for <>. + +*See also* + +* xref:ref_impl_tail_impl[tail_impl] +* <> + +[[coherent_tail_mean]] +== coherent_tail_mean + +Estimation of the coherent tail mean based on order statistics (for both left and right tails). +The left coherent tail mean feature is `tag::coherent_tail_mean`, and the right coherent +tail mean feature is `tag::coherent_tail_mean`. They both share the `tag::tail_mean` feature +and can be extracted with the `tail_mean()` extractor. For more implementation details, see +xref:ref_impl_coherent_tail_mean_impl[coherent_tail_mean_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, std::size_t>::result_type +---- + +[dlist] +Depends On:: +`count` + +`quantile` + +`non_coherent_tail_mean<{left_or_right}>` + +Variants:: +none + +Initialization Parameters:: +`tag::tail<{left_or_right}>::cache_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +`quantile_probability` + +Accumulator Complexity:: +O(log N), where N is the cache size + +Extractor Complexity:: +O(N log N), where N is the cache size + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +See the example for +<>. + +*See also* + +* xref:ref_impl_coherent_tail_mean_impl[coherent_tail_mean_impl] +* <> +* <> +* <> +* <> +* <> + +[[non_coherent_tail_mean]] +== non_coherent_tail_mean + +Estimation of the (non-coherent) tail mean based on order statistics (for both left and right tails). +The left non-coherent tail mean feature is `tag::non_coherent_tail_mean`, and the right non-choherent +tail mean feature is `tag::non_coherent_tail_mean`. They both share the `tag::abstract_non_coherent_tail_mean` +feature and can be extracted with the `non_coherent_tail_mean()` extractor. For more implementation details, see +xref:ref_impl_non_coherent_tail_mean_impl[non_coherent_tail_mean_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, std::size_t>::result_type +---- + +[dlist] +Depends On:: +`count` + +`tail<{left_or_right}>` + +Variants:: +`abstract_non_coherent_tail_mean` + +Initialization Parameters:: +`tag::tail<{left_or_right}>::cache_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +`quantile_probability` + +Accumulator Complexity:: +O(log N), where N is the cache size + +Extractor Complexity:: +O(N log N), where N is the cache size + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +// tolerance in % +double epsilon = 1; + +std::size_t n = 100000; // number of MC steps +std::size_t c = 10000; // cache size + +typedef accumulator_set, tag::tail_quantile > > accumulator_t_right1; +typedef accumulator_set, tag::tail_quantile > > accumulator_t_left1; +typedef accumulator_set, tag::tail_quantile > > accumulator_t_right2; +typedef accumulator_set, tag::tail_quantile > > accumulator_t_left2; + +accumulator_t_right1 acc0( right_tail_cache_size = c ); +accumulator_t_left1 acc1( left_tail_cache_size = c ); +accumulator_t_right2 acc2( right_tail_cache_size = c ); +accumulator_t_left2 acc3( left_tail_cache_size = c ); + +// a random number generator +boost::lagged_fibonacci607 rng; + +for (std::size_t i = 0; i < n; ++i) +{ + double sample = rng(); + acc0(sample); + acc1(sample); + acc2(sample); + acc3(sample); +} + +// check uniform distribution +BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc0, quantile_probability = 0.95), 0.975, epsilon ); +BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc0, quantile_probability = 0.975), 0.9875, epsilon ); +BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc0, quantile_probability = 0.99), 0.995, epsilon ); +BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc0, quantile_probability = 0.999), 0.9995, epsilon ); +BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc1, quantile_probability = 0.05), 0.025, epsilon ); +BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc1, quantile_probability = 0.025), 0.0125, epsilon ); +BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc1, quantile_probability = 0.01), 0.005, 5 ); +BOOST_CHECK_CLOSE( non_coherent_tail_mean(acc1, quantile_probability = 0.001), 0.0005, 10 ); +BOOST_CHECK_CLOSE( tail_mean(acc2, quantile_probability = 0.95), 0.975, epsilon ); +BOOST_CHECK_CLOSE( tail_mean(acc2, quantile_probability = 0.975), 0.9875, epsilon ); +BOOST_CHECK_CLOSE( tail_mean(acc2, quantile_probability = 0.99), 0.995, epsilon ); +BOOST_CHECK_CLOSE( tail_mean(acc2, quantile_probability = 0.999), 0.9995, epsilon ); +BOOST_CHECK_CLOSE( tail_mean(acc3, quantile_probability = 0.05), 0.025, epsilon ); +BOOST_CHECK_CLOSE( tail_mean(acc3, quantile_probability = 0.025), 0.0125, epsilon ); +BOOST_CHECK_CLOSE( tail_mean(acc3, quantile_probability = 0.01), 0.005, 5 ); +BOOST_CHECK_CLOSE( tail_mean(acc3, quantile_probability = 0.001), 0.0005, 10 ); +---- + +*See also* + +* xref:ref_impl_non_coherent_tail_mean_impl[non_coherent_tail_mean_impl] +* <> +* <> + +[[tail_quantile]] +== tail_quantile + +Tail quantile estimation based on order statistics (for both left and right tails). +The left tail quantile feature is `tag::tail_quantile`, and the right +tail quantile feature is `tag::tail_quantile`. They both share the `tag::quantile` +feature and can be extracted with the `quantile()` extractor. For more implementation details, see +xref:ref_impl_tail_quantile_impl[tail_quantile_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +{sample_type} +---- + +[dlist] +Depends On:: +`count` + +`tail<{left_or_right}>` + +Variants:: +none + +Initialization Parameters:: +`tag::tail<{left_or_right}>::cache_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +`quantile_probability` + +Accumulator Complexity:: +O(log N), where N is the cache size + +Extractor Complexity:: +O(N log N), where N is the cache size + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +// tolerance in % +double epsilon = 1; + +std::size_t n = 100000; // number of MC steps +std::size_t c = 10000; // cache size + +typedef accumulator_set > > accumulator_t_right; +typedef accumulator_set > > accumulator_t_left; + +accumulator_t_right acc0( tag::tail::cache_size = c ); +accumulator_t_right acc1( tag::tail::cache_size = c ); +accumulator_t_left acc2( tag::tail::cache_size = c ); +accumulator_t_left acc3( tag::tail::cache_size = c ); + +// two random number generators +boost::lagged_fibonacci607 rng; +boost::normal_distribution<> mean_sigma(0,1); +boost::variate_generator > normal(rng, mean_sigma); + +for (std::size_t i = 0; i < n; ++i) +{ + double sample1 = rng(); + double sample2 = normal(); + acc0(sample1); + acc1(sample2); + acc2(sample1); + acc3(sample2); +} + +// check uniform distribution +BOOST_CHECK_CLOSE( quantile(acc0, quantile_probability = 0.95 ), 0.95, epsilon ); +BOOST_CHECK_CLOSE( quantile(acc0, quantile_probability = 0.975), 0.975, epsilon ); +BOOST_CHECK_CLOSE( quantile(acc0, quantile_probability = 0.99 ), 0.99, epsilon ); +BOOST_CHECK_CLOSE( quantile(acc0, quantile_probability = 0.999), 0.999, epsilon ); +BOOST_CHECK_CLOSE( quantile(acc2, quantile_probability = 0.05 ), 0.05, 2 ); +BOOST_CHECK_CLOSE( quantile(acc2, quantile_probability = 0.025), 0.025, 2 ); +BOOST_CHECK_CLOSE( quantile(acc2, quantile_probability = 0.01 ), 0.01, 3 ); +BOOST_CHECK_CLOSE( quantile(acc2, quantile_probability = 0.001), 0.001, 20 ); + +// check standard normal distribution +BOOST_CHECK_CLOSE( quantile(acc1, quantile_probability = 0.975), 1.959963, epsilon ); +BOOST_CHECK_CLOSE( quantile(acc1, quantile_probability = 0.999), 3.090232, epsilon ); +BOOST_CHECK_CLOSE( quantile(acc3, quantile_probability = 0.025), -1.959963, epsilon ); +BOOST_CHECK_CLOSE( quantile(acc3, quantile_probability = 0.001), -3.090232, epsilon ); +---- + +*See also* + +* xref:ref_impl_tail_quantile_impl[tail_quantile_impl] +* <> +* <> + +[[tail_variate]] +== tail_variate + +Tracks the covariates of largest or smallest `N` samples. +`tag::tail_variate<{variate_type}, {variate_tag}, right>` tracks the covariate associated with +{variate_tag} for the largest `N`, and `tag::tail_variate<{variate_type}, {variate_tag}, left>` +for the smallest. The parameter `N` is specified with the `tag::tail<{left_or_right}>::cache_size` +initialization parameter. For implementation details, see +xref:ref_impl_tail_variate_impl[tail_variate_impl]. + +Both `tag::tail_variate<{variate_type}, {variate_tag}, right>` and +`tag::tail_variate<{variate_type}, {variate_tag}, left>` satisfy the `tag::abstract_tail_variate` feature +and can be extracted with the `tail_variate()` extractor. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +boost::iterator_range< + boost::reverse_iterator< + boost::permutation_iterator< + std::vector<{variate_type}>::const_iterator // variates + , std::vector::iterator // indices + > + > +> +---- + +[dlist] +Depends On:: +`tail<{left_or_right}>` + +Variants:: +`abstract_tail_variate` + +Initialization Parameters:: +`tag::tail<{left_or_right}>::cache_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(log N), where N is the cache size + +Extractor Complexity:: +O(N log N), where N is the cache size + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set > > acc( + tag::tail::cache_size = 4 +); + +acc(8, covariate1 = 3); +CHECK_RANGE_EQUAL(tail(acc), {8}); +CHECK_RANGE_EQUAL(tail_variate(acc), {3}); + +acc(16, covariate1 = 1); +CHECK_RANGE_EQUAL(tail(acc), {16, 8}); +CHECK_RANGE_EQUAL(tail_variate(acc), {1, 3}); + +acc(12, covariate1 = 4); +CHECK_RANGE_EQUAL(tail(acc), {16, 12, 8}); +CHECK_RANGE_EQUAL(tail_variate(acc), {1, 4, 3}); + +acc(24, covariate1 = 5); +CHECK_RANGE_EQUAL(tail(acc), {24, 16, 12, 8}); +CHECK_RANGE_EQUAL(tail_variate(acc), {5, 1, 4, 3}); + +acc(1, covariate1 = 9); +CHECK_RANGE_EQUAL(tail(acc), {24, 16, 12, 8}); +CHECK_RANGE_EQUAL(tail_variate(acc), {5, 1, 4, 3}); + +acc(9, covariate1 = 7); +CHECK_RANGE_EQUAL(tail(acc), {24, 16, 12, 9}); +CHECK_RANGE_EQUAL(tail_variate(acc), {5, 1, 4, 7}); +---- + +*See also* + +* xref:ref_impl_tail_variate_impl[tail_variate_impl] +* <> + +[[tail_variate_means]] +== tail_variate_means and variants + +Estimation of the absolute and relative tail variate means (for both left and right tails). +The absolute tail variate means has the feature +`tag::absolute_tail_variate_means<{left_or_right}, {variate_type}, {variate_tag}>` +and the relative tail variate mean has the feature +`tag::relative_tail_variate_means<{left_or_right}, {variate_type}, {variate_tag}>`. All +absolute tail variate mean features share the `tag::abstract_absolute_tail_variate_means` +feature and can be extracted with the `tail_variate_means()` extractor. All the +relative tail variate mean features share the `tag::abstract_relative_tail_variate_means` +feature and can be extracted with the `relative_tail_variate_means()` extractor. + +For more implementation details, see +xref:ref_impl_tail_variate_means_impl[tail_variate_means_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +boost::iterator_range< std::vector< numeric::functional::fdiv<{sample_type}, std::size_t>::result_type >::iterator > +---- + +[dlist] +Depends On:: +`non_coherent_tail_mean<{left_or_right}>` + +`tail_variate<{variate_type}, {variate_tag}, {left_or_right}>` + +Variants:: +`tag::absolute_tail_variate_means<{left_or_right}, {variate_type}, {variate_tag}>` + +`tag::relative_tail_variate_means<{left_or_right}, {variate_type}, {variate_tag}>` + +Initialization Parameters:: +`tag::tail<{left_or_right}>::cache_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +`quantile_probability` + +Accumulator Complexity:: +O(log N), where N is the cache size + +Extractor Complexity:: +O(N log N), where N is the cache size + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +std::size_t c = 5; // cache size + +typedef double variate_type; +typedef std::vector variate_set_type; + +typedef accumulator_set(relative)>, tag::tail > +accumulator_t1; + +typedef accumulator_set(absolute)>, tag::tail > +accumulator_t2; + +typedef accumulator_set(relative)>, tag::tail > +accumulator_t3; + +typedef accumulator_set(absolute)>, tag::tail > +accumulator_t4; + +accumulator_t1 acc1( right_tail_cache_size = c ); +accumulator_t2 acc2( right_tail_cache_size = c ); +accumulator_t3 acc3( left_tail_cache_size = c ); +accumulator_t4 acc4( left_tail_cache_size = c ); + +variate_set_type cov1, cov2, cov3, cov4, cov5; +double c1[] = { 10., 20., 30., 40. }; // 100 +double c2[] = { 26., 4., 17., 3. }; // 50 +double c3[] = { 46., 64., 40., 50. }; // 200 +double c4[] = { 1., 3., 70., 6. }; // 80 +double c5[] = { 2., 2., 2., 14. }; // 20 +cov1.assign(c1, c1 + sizeof(c1)/sizeof(variate_type)); +cov2.assign(c2, c2 + sizeof(c2)/sizeof(variate_type)); +cov3.assign(c3, c3 + sizeof(c3)/sizeof(variate_type)); +cov4.assign(c4, c4 + sizeof(c4)/sizeof(variate_type)); +cov5.assign(c5, c5 + sizeof(c5)/sizeof(variate_type)); + +acc1(100., covariate1 = cov1); +acc1( 50., covariate1 = cov2); +acc1(200., covariate1 = cov3); +acc1( 80., covariate1 = cov4); +acc1( 20., covariate1 = cov5); + +acc2(100., covariate1 = cov1); +acc2( 50., covariate1 = cov2); +acc2(200., covariate1 = cov3); +acc2( 80., covariate1 = cov4); +acc2( 20., covariate1 = cov5); + +acc3(100., covariate1 = cov1); +acc3( 50., covariate1 = cov2); +acc3(200., covariate1 = cov3); +acc3( 80., covariate1 = cov4); +acc3( 20., covariate1 = cov5); + +acc4(100., covariate1 = cov1); +acc4( 50., covariate1 = cov2); +acc4(200., covariate1 = cov3); +acc4( 80., covariate1 = cov4); +acc4( 20., covariate1 = cov5); + +// check relative risk contributions +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.7).begin() ), 14./75. ); // (10 + 46) / 300 = 14/75 +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.7).begin() + 1), 7./25. ); // (20 + 64) / 300 = 7/25 +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.7).begin() + 2), 7./30. ); // (30 + 40) / 300 = 7/30 +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.7).begin() + 3), 3./10. ); // (40 + 50) / 300 = 3/10 +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.3).begin() ), 14./35. ); // (26 + 2) / 70 = 14/35 +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.3).begin() + 1), 3./35. ); // ( 4 + 2) / 70 = 3/35 +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.3).begin() + 2), 19./70. ); // (17 + 2) / 70 = 19/70 +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.3).begin() + 3), 17./70. ); // ( 3 + 14) / 70 = 17/70 + +// check absolute risk contributions +BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.7).begin() ), 28 ); // (10 + 46) / 2 = 28 +BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.7).begin() + 1), 42 ); // (20 + 64) / 2 = 42 +BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.7).begin() + 2), 35 ); // (30 + 40) / 2 = 35 +BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.7).begin() + 3), 45 ); // (40 + 50) / 2 = 45 +BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.3).begin() ), 14 ); // (26 + 2) / 2 = 14 +BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.3).begin() + 1), 3 ); // ( 4 + 2) / 2 = 3 +BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.3).begin() + 2),9.5 ); // (17 + 2) / 2 = 9.5 +BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.3).begin() + 3),8.5 ); // ( 3 + 14) / 2 = 8.5 + +// check relative risk contributions +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.9).begin() ), 23./100. ); // 46/200 = 23/100 +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.9).begin() + 1), 8./25. ); // 64/200 = 8/25 +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.9).begin() + 2), 1./5. ); // 40/200 = 1/5 +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc1, quantile_probability = 0.9).begin() + 3), 1./4. ); // 50/200 = 1/4 +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.1).begin() ), 1./10. ); // 2/ 20 = 1/10 +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.1).begin() + 1), 1./10. ); // 2/ 20 = 1/10 +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.1).begin() + 2), 1./10. ); // 2/ 20 = 1/10 +BOOST_CHECK_EQUAL( *(relative_tail_variate_means(acc3, quantile_probability = 0.1).begin() + 3), 7./10. ); // 14/ 20 = 7/10 + +// check absolute risk contributions +BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.9).begin() ), 46 ); // 46 +BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.9).begin() + 1), 64 ); // 64 +BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.9).begin() + 2), 40 ); // 40 +BOOST_CHECK_EQUAL( *(tail_variate_means(acc2, quantile_probability = 0.9).begin() + 3), 50 ); // 50 +BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.1).begin() ), 2 ); // 2 +BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.1).begin() + 1), 2 ); // 2 +BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.1).begin() + 2), 2 ); // 2 +BOOST_CHECK_EQUAL( *(tail_variate_means(acc4, quantile_probability = 0.1).begin() + 3), 14 ); // 14 +---- + +*See also* + +* xref:ref_impl_tail_variate_means_impl[tail_variate_means_impl] +* <> +* <> + +[[variance]] +== variance _and variants_ + +Lazy or iterative calculation of the variance. The lazy calculation is associated with the `tag::lazy_variance` +feature, and the iterative calculation with the `tag::variance` feature. Both can be extracted +using the `tag::variance()` extractor. For more implementation details, see +xref:ref_impl_lazy_variance_impl[lazy_variance_impl] and +xref:ref_impl_variance_impl[variance_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, std::size_t>::result_type +---- + +[dlist] +Depends On:: +`tag::lazy_variance` depends on `tag::moment<2>` and `tag::mean` + +`tag::variance` depends on `tag::count` and `tag::immediate_mean` + +Variants:: +`tag::lazy_variance` (a.k.a. `tag::variance(lazy))` + +`tag::variance` (a.k.a. `tag::variance(immediate)`) + +Initialization Parameters:: +none + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +// lazy variance +accumulator_set > acc1; + +acc1(1); +acc1(2); +acc1(3); +acc1(4); +acc1(5); + +BOOST_CHECK_EQUAL(5u, count(acc1)); +BOOST_CHECK_CLOSE(3., mean(acc1), 1e-5); +BOOST_CHECK_CLOSE(11., accumulators::moment<2>(acc1), 1e-5); +BOOST_CHECK_CLOSE(2., variance(acc1), 1e-5); + +// immediate variance +accumulator_set > acc2; + +acc2(1); +acc2(2); +acc2(3); +acc2(4); +acc2(5); + +BOOST_CHECK_EQUAL(5u, count(acc2)); +BOOST_CHECK_CLOSE(3., mean(acc2), 1e-5); +BOOST_CHECK_CLOSE(2., variance(acc2), 1e-5); +---- + +*See also* + +* xref:ref_impl_lazy_variance_impl[lazy_variance_impl] +* xref:ref_impl_variance_impl[variance_impl] +* <> +* <> +* <> + +[[weighted_covariance]] +== weighted_covariance + +An iterative Monte Carlo estimator for the weighted covariance. The feature is specified as +`tag::weighted_covariance<{variate_type}, {variate_tag}>` and is extracted with the `weighted_variate()` +extractor. For more implementation details, see +xref:ref_impl_weighted_covariance_impl[weighted_covariance_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::outer_product< + numeric::functional::multiplies< + {weight_type} + , numeric::functional::fdiv<{sample_type}, std::size_t>::result_type + >::result_type + , numeric::functional::multiplies< + {weight_type} + , numeric::functional::fdiv<{variate_type}, std::size_t>::result_type + >::result_type +> +---- + +[dlist] +Depends On:: +`count` + +`sum_of_weights` + +`weighted_mean` + +`weighted_mean_of_variates<{variate_type}, {variate_tag}>` + +Variants:: +`abstract_weighted_covariance` + +Initialization Parameters:: +none + +Accumulator Parameters:: +`weight` + +`{variate_tag}` + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set >, double > acc; +---- + +[source,c++] +---- +acc(1., weight = 1.1, covariate1 = 2.); +acc(1., weight = 2.2, covariate1 = 4.); +acc(2., weight = 3.3, covariate1 = 3.); +acc(6., weight = 4.4, covariate1 = 1.); + +double epsilon = 1e-6; +BOOST_CHECK_CLOSE(weighted_covariance(acc), -2.39, epsilon); +---- + +*See also* + +* xref:ref_impl_weighted_covariance_impl[weighted_covariance_impl] +* <> +* <> +* <> + +[[weighted_density]] +== weighted_density + +The `tag::weighted_density` feature returns a histogram of the weighted sample distribution. For more +implementation details, see xref:ref_impl_weighted_density_impl[weighted_density_impl]. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +iterator_range< + std::vector< + std::pair< + numeric::functional::fdiv<{weight_type}, std::size_t>::result_type + , numeric::functional::fdiv<{weight_type}, std::size_t>::result_type + > + >::iterator +> +---- + +[dlist] +Depends On:: +`count` + +`sum_of_weights` + +`min` + +`max` + +Variants:: +none + +Initialization Parameters:: +`tag::weighted_density::cache_size` + +`tag::weighted_density::num_bins` + +Accumulator Parameters:: +`weight` + +Extractor Parameters:: +none + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +O(N), when N is `weighted_density::num_bins` + +*Header* + +[source,c++] +---- +#include +---- + +*See also* + +* xref:ref_impl_weighted_density_impl[weighted_density_impl] +* <> +* <> +* <> +* <> + +[[weighted_extended_p_square]] +== weighted_extended_p_square + +Multiple quantile estimation with the extended `P^2` algorithm for weighted samples. For further +details, see xref:ref_impl_weighted_extended_p_square_impl[weighted_extended_p_square_impl]. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +boost::iterator_range< {implementation_defined} > +---- + +[dlist] +Depends On:: +`count` + +`sum_of_weights` + +Variants:: +none + +Initialization Parameters:: +`tag::weighted_extended_p_square::probabilities` + +Accumulator Parameters:: +`weight` + +Extractor Parameters:: +none + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +typedef accumulator_set, double> accumulator_t; + +// tolerance in % +double epsilon = 1; + +// some random number generators +double mu1 = -1.0; +double mu2 = 1.0; +boost::lagged_fibonacci607 rng; +boost::normal_distribution<> mean_sigma1(mu1, 1); +boost::normal_distribution<> mean_sigma2(mu2, 1); +boost::variate_generator > normal1(rng, mean_sigma1); +boost::variate_generator > normal2(rng, mean_sigma2); + +std::vector probs_uniform, probs_normal1, probs_normal2, probs_normal_exact1, probs_normal_exact2; + +double p1[] = {/*0.001,*/ 0.01, 0.1, 0.5, 0.9, 0.99, 0.999}; +probs_uniform.assign(p1, p1 + sizeof(p1) / sizeof(double)); + +double p2[] = {0.001, 0.025}; +double p3[] = {0.975, 0.999}; +probs_normal1.assign(p2, p2 + sizeof(p2) / sizeof(double)); +probs_normal2.assign(p3, p3 + sizeof(p3) / sizeof(double)); + +double p4[] = {-3.090232, -1.959963}; +double p5[] = {1.959963, 3.090232}; +probs_normal_exact1.assign(p4, p4 + sizeof(p4) / sizeof(double)); +probs_normal_exact2.assign(p5, p5 + sizeof(p5) / sizeof(double)); + +accumulator_t acc_uniform(tag::weighted_extended_p_square::probabilities = probs_uniform); +accumulator_t acc_normal1(tag::weighted_extended_p_square::probabilities = probs_normal1); +accumulator_t acc_normal2(tag::weighted_extended_p_square::probabilities = probs_normal2); + +for (std::size_t i = 0; i < 100000; ++i) +{ + acc_uniform(rng(), weight = 1.); + + double sample1 = normal1(); + double sample2 = normal2(); + acc_normal1(sample1, weight = std::exp(-mu1 * (sample1 - 0.5 * mu1))); + acc_normal2(sample2, weight = std::exp(-mu2 * (sample2 - 0.5 * mu2))); +} + +// check for uniform distribution +for (std::size_t i = 0; i < probs_uniform.size(); ++i) +{ + BOOST_CHECK_CLOSE(weighted_extended_p_square(acc_uniform)[i], probs_uniform[i], epsilon); +} + +// check for standard normal distribution +for (std::size_t i = 0; i < probs_normal1.size(); ++i) +{ + BOOST_CHECK_CLOSE(weighted_extended_p_square(acc_normal1)[i], probs_normal_exact1[i], epsilon); + BOOST_CHECK_CLOSE(weighted_extended_p_square(acc_normal2)[i], probs_normal_exact2[i], epsilon); +} +---- + +*See also* + +* xref:ref_impl_weighted_extended_p_square_impl[weighted_extended_p_square_impl] +* <> +* <> + +[[weighted_kurtosis]] +== weighted_kurtosis + +The kurtosis of a sample distribution is defined as the ratio of the 4th central moment and the +square of the 2nd central moment (the variance) of the samples, minus 3. The term `-3` is added +in order to ensure that the normal distribution has zero kurtosis. For more implementation +details, see xref:ref_impl_weighted_kurtosis_impl[weighted_kurtosis_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv< + numeric::functional::multiplies<{sample_type}, {weight_type}>::result_type + , numeric::functional::multiplies<{sample_type}, {weight_type}>::result_type +>::result_type +---- + +[dlist] +Depends On:: +`weighted_mean` + +`weighted_moment<2>` + +`weighted_moment<3>` + +`weighted_moment<4>` + +Variants:: +none + +Initialization Parameters:: +none + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set, int > acc2; + +acc2(2, weight = 4); +acc2(7, weight = 1); +acc2(4, weight = 3); +acc2(9, weight = 1); +acc2(3, weight = 2); + +BOOST_CHECK_EQUAL( weighted_mean(acc2), 42./11. ); +BOOST_CHECK_EQUAL( accumulators::weighted_moment<2>(acc2), 212./11. ); +BOOST_CHECK_EQUAL( accumulators::weighted_moment<3>(acc2), 1350./11. ); +BOOST_CHECK_EQUAL( accumulators::weighted_moment<4>(acc2), 9956./11. ); +BOOST_CHECK_CLOSE( weighted_kurtosis(acc2), 0.58137026432, 1e-6 ); +---- + +*See also* + +* xref:ref_impl_weighted_kurtosis_impl[weighted_kurtosis_impl] +* <> +* <> + +[[weighted_mean]] +== weighted_mean _and variants_ + +Calculates the weighted mean of samples or variates. The calculation is either +lazy (in the result extractor), or immediate (in the accumulator). The lazy implementation +is the default. For more implementation details, see +xref:ref_impl_weighted_mean_impl[weighted_mean_impl] or. +xref:ref_impl_immediate_weighted_mean_impl[immediate_weighted_mean_impl] + + + +[dlist] +Result Type:: +For samples, `numeric::functional::fdiv::result_type, {weight_type}>::result_type` +For variates, `numeric::functional::fdiv::result_type, {weight_type}>::result_type` + + +Depends On:: +`sum_of_weights` + +The lazy mean of samples depends on `weighted_sum` + +The lazy mean of variates depends on `weighted_sum_of_variates<>` + +Variants:: +`weighted_mean_of_variates<{variate_type}, {variate_tag}>` + +`immediate_weighted_mean` + +`immediate_weighted_mean_of_variates<{variate_type}, {variate_tag}>` + +Initialization Parameters:: +none + +Accumulator Parameters:: +none + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set< + int + , stats< + tag::weighted_mean + , tag::weighted_mean_of_variates + > + , int +> acc; + +acc(10, weight = 2, covariate1 = 7); // 20 +BOOST_CHECK_EQUAL(2, sum_of_weights(acc)); // + // +acc(6, weight = 3, covariate1 = 8); // 18 +BOOST_CHECK_EQUAL(5, sum_of_weights(acc)); // + // +acc(4, weight = 4, covariate1 = 9); // 16 +BOOST_CHECK_EQUAL(9, sum_of_weights(acc)); // + // +acc(6, weight = 5, covariate1 = 6); //+ 30 +BOOST_CHECK_EQUAL(14, sum_of_weights(acc)); // + //= 84 / 14 = 6 + +BOOST_CHECK_EQUAL(6., weighted_mean(acc)); +BOOST_CHECK_EQUAL(52./7., (accumulators::weighted_mean_of_variates(acc))); + +accumulator_set< + int + , stats< + tag::weighted_mean(immediate) + , tag::weighted_mean_of_variates(immediate) + > + , int +> acc2; + +acc2(10, weight = 2, covariate1 = 7); // 20 +BOOST_CHECK_EQUAL(2, sum_of_weights(acc2)); // + // +acc2(6, weight = 3, covariate1 = 8); // 18 +BOOST_CHECK_EQUAL(5, sum_of_weights(acc2)); // + // +acc2(4, weight = 4, covariate1 = 9); // 16 +BOOST_CHECK_EQUAL(9, sum_of_weights(acc2)); // + // +acc2(6, weight = 5, covariate1 = 6); //+ 30 +BOOST_CHECK_EQUAL(14, sum_of_weights(acc2)); // + //= 84 / 14 = 6 + +BOOST_CHECK_EQUAL(6., weighted_mean(acc2)); +BOOST_CHECK_EQUAL(52./7., (accumulators::weighted_mean_of_variates(acc2))); +---- + +*See also* + +* xref:ref_impl_weighted_mean_impl[weighted_mean_impl] +* xref:ref_impl_immediate_weighted_mean_impl[immediate_weighted_mean_impl] +* <> +* <> + +[[weighted_median]] +== weighted_median _and variants_ + +Median estimation for weighted samples based on the `P^2` quantile estimator, the density estimator, or +the `P^2` cumulative distribution estimator. For more implementation details, see +xref:ref_impl_weighted_median_impl[weighted_median_impl], +xref:ref_impl_with_density_weighted_median_impl[with_weighted_density_median_impl], +and xref:ref_impl_with_p_square_cumulative_distribution_weighted_median_impl[with_weighted_p_square_cumulative_distribution_median_impl]. + +The three median accumulators all satisfy the `tag::weighted_median` feature, and can all be +extracted with the `weighted_median()` extractor. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv<{sample_type}, std::size_t>::result_type +---- + +[dlist] +Depends On:: +`weighted_median` depends on `weighted_p_square_quantile_for_median` + +`with_weighted_density_median` depends on `count` and `weighted_density` + +`with_weighted_p_square_cumulative_distribution_median` depends on `weighted_p_square_cumulative_distribution` + +Variants:: +`with_weighted_density_median` (a.k.a. `weighted_median(with_weighted_density)`) + +`with_weighted_p_square_cumulative_distribution_median` (a.k.a. `weighted_median(with_weighted_p_square_cumulative_distribution)`) + +Initialization Parameters:: +`with_weighted_density_median` requires `tag::weighted_density::cache_size` and `tag::weighted_density::num_bins` + +`with_weighted_p_square_cumulative_distribution_median` requires `tag::weighted_p_square_cumulative_distribution::num_cells` + +Accumulator Parameters:: +`weight` + +Extractor Parameters:: +none + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +TODO + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +// Median estimation of normal distribution N(1,1) using samples from a narrow normal distribution N(1,0.01) +// The weights equal to the likelihood ratio of the corresponding samples + +// two random number generators +double mu = 1.; +double sigma_narrow = 0.01; +double sigma = 1.; +boost::lagged_fibonacci607 rng; +boost::normal_distribution<> mean_sigma_narrow(mu,sigma_narrow); +boost::variate_generator > normal_narrow(rng, mean_sigma_narrow); + +accumulator_set, double > acc; +accumulator_set, double > + acc_dens( tag::weighted_density::cache_size = 10000, tag::weighted_density::num_bins = 1000 ); +accumulator_set, double > + acc_cdist( tag::weighted_p_square_cumulative_distribution::num_cells = 100 ); + +for (std::size_t i=0; i<100000; ++i) +{ + double sample = normal_narrow(); + acc(sample, weight = std::exp(0.5 * (sample - mu) * (sample - mu) * ( 1./sigma_narrow/sigma_narrow - 1./sigma/sigma ))); + acc_dens(sample, weight = std::exp(0.5 * (sample - mu) * (sample - mu) * ( 1./sigma_narrow/sigma_narrow - 1./sigma/sigma ))); + acc_cdist(sample, weight = std::exp(0.5 * (sample - mu) * (sample - mu) * ( 1./sigma_narrow/sigma_narrow - 1./sigma/sigma ))); +} + +BOOST_CHECK_CLOSE(1., weighted_median(acc), 1e-1); +BOOST_CHECK_CLOSE(1., weighted_median(acc_dens), 1e-1); +BOOST_CHECK_CLOSE(1., weighted_median(acc_cdist), 1e-1); +---- + +*See also* + +* xref:ref_impl_weighted_median_impl[weighted_median_impl] +* xref:ref_impl_with_density_weighted_median_impl[with_weighted_density_median_impl] +* xref:ref_impl_with_p_square_cumulative_distribution_weighted_median_impl[with_weighted_p_square_cumulative_distribution_median_impl] +* <> +* <> +* <> + +[[weighted_moment]] +== weighted_moment + +Calculates the N-th moment of the weighted samples, which is defined as the sum of the weighted N-th +power of the samples over the sum of the weights. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv< + numeric::functional::multiplies<{sample_type}, {weight_type}>::result_type + , weight_type +>::result_type +---- + +[dlist] +Depends On:: +`count` + +`sum_of_weights` + +Variants:: +none + +Initialization Parameters:: +none + +Accumulator Parameters:: +`weight` + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set >, double> acc2; +accumulator_set >, double> acc7; + +acc2(2.1, weight = 0.7); +acc2(2.7, weight = 1.4); +acc2(1.8, weight = 0.9); + +acc7(2.1, weight = 0.7); +acc7(2.7, weight = 1.4); +acc7(1.8, weight = 0.9); + +BOOST_CHECK_CLOSE(5.403, accumulators::weighted_moment<2>(acc2), 1e-5); +BOOST_CHECK_CLOSE(548.54182, accumulators::weighted_moment<7>(acc7), 1e-5); +---- + +*See also* + +* xref:ref_impl_weighted_moment_impl[weighted_moment_impl] +* <> +* <> + +[[weighted_p_square_cumulative_distribution]] +== weighted_p_square_cumulative_distribution + +Histogram calculation of the cumulative distribution with the `P^2` algorithm for weighted samples. +For more implementation details, see +xref:ref_impl_weighted_p_square_cumulative_distribution_impl[weighted_p_square_cumulative_distribution_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +iterator_range< + std::vector< + std::pair< + numeric::functional::fdiv::result_type + , numeric::functional::fdiv::result_type + > + >::iterator +> +---- +where `weighted_sample is numeric::functional::multiplies<{sample_type}, {weight_type}>::result_type` + +[dlist] +Depends On:: +`count` + +`sum_or_weights` + +Variants:: +none + +Initialization Parameters:: +`tag::weighted_p_square_cumulative_distribution::num_cells` + +Accumulator Parameters:: +`weight` + +Extractor Parameters:: +none + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +O(N) where N is `num_cells` + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +// tolerance in % +double epsilon = 4; + +typedef accumulator_set, double > accumulator_t; + +accumulator_t acc_upper(tag::weighted_p_square_cumulative_distribution::num_cells = 100); +accumulator_t acc_lower(tag::weighted_p_square_cumulative_distribution::num_cells = 100); + +// two random number generators +double mu_upper = 1.0; +double mu_lower = -1.0; +boost::lagged_fibonacci607 rng; +boost::normal_distribution<> mean_sigma_upper(mu_upper,1); +boost::normal_distribution<> mean_sigma_lower(mu_lower,1); +boost::variate_generator > normal_upper(rng, mean_sigma_upper); +boost::variate_generator > normal_lower(rng, mean_sigma_lower); + +for (std::size_t i=0; i<100000; ++i) +{ + double sample = normal_upper(); + acc_upper(sample, weight = std::exp(-mu_upper * (sample - 0.5 * mu_upper))); +} + +for (std::size_t i=0; i<100000; ++i) +{ + double sample = normal_lower(); + acc_lower(sample, weight = std::exp(-mu_lower * (sample - 0.5 * mu_lower))); +} + +typedef iterator_range >::iterator > histogram_type; +histogram_type histogram_upper = weighted_p_square_cumulative_distribution(acc_upper); +histogram_type histogram_lower = weighted_p_square_cumulative_distribution(acc_lower); + +// Note that applying importance sampling results in a region of the distribution +// to be estimated more accurately and another region to be estimated less accurately +// than without importance sampling, i.e., with unweighted samples + +for (std::size_t i = 0; i < histogram_upper.size(); ++i) +{ + // problem with small results: epsilon is relative (in percent), not absolute! + + // check upper region of distribution + if ( histogram_upper[i].second > 0.1 ) + BOOST_CHECK_CLOSE( 0.5 * (1.0 + erf( histogram_upper[i].first / sqrt(2.0) )), histogram_upper[i].second, epsilon ); + // check lower region of distribution + if ( histogram_lower[i].second < -0.1 ) + BOOST_CHECK_CLOSE( 0.5 * (1.0 + erf( histogram_lower[i].first / sqrt(2.0) )), histogram_lower[i].second, epsilon ); +} +---- + +*See also* + +* xref:ref_impl_weighted_p_square_cumulative_distribution_impl[weighted_p_square_cumulative_distribution_impl] +* <> +* <> + +[[weighted_p_square_quantile]] +== weighted_p_square_quantile _and variants_ + +Single quantile estimation with the `P^2` algorithm. For more implementation details, see +xref:ref_impl_weighted_p_square_quantile_impl[weighted_p_square_quantile_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv< numeric::functional::multiplies<{sample_type}, {weight_type}>::result_type , std::size_t >::result_type +---- + +[dlist] +Depends On:: +`count` + +`sum_of_weights` + +Variants:: +`weighted_p_square_quantile_for_median` + +Initialization Parameters:: +`quantile_probability`, which defaults to `0.5`. (Note: for `weighted_p_square_quantile_for_median`, the `quantile_probability` parameter is ignored and is always `0.5`.) + +Accumulator Parameters:: +`weight` + +Extractor Parameters:: +none + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +typedef accumulator_set, double> accumulator_t; + +// tolerance in % +double epsilon = 1; + +// some random number generators +double mu4 = -1.0; +double mu5 = -1.0; +double mu6 = 1.0; +double mu7 = 1.0; +boost::lagged_fibonacci607 rng; +boost::normal_distribution<> mean_sigma4(mu4, 1); +boost::normal_distribution<> mean_sigma5(mu5, 1); +boost::normal_distribution<> mean_sigma6(mu6, 1); +boost::normal_distribution<> mean_sigma7(mu7, 1); +boost::variate_generator > normal4(rng, mean_sigma4); +boost::variate_generator > normal5(rng, mean_sigma5); +boost::variate_generator > normal6(rng, mean_sigma6); +boost::variate_generator > normal7(rng, mean_sigma7); + +accumulator_t acc0(quantile_probability = 0.001); +accumulator_t acc1(quantile_probability = 0.025); +accumulator_t acc2(quantile_probability = 0.975); +accumulator_t acc3(quantile_probability = 0.999); + +accumulator_t acc4(quantile_probability = 0.001); +accumulator_t acc5(quantile_probability = 0.025); +accumulator_t acc6(quantile_probability = 0.975); +accumulator_t acc7(quantile_probability = 0.999); + + +for (std::size_t i=0; i<100000; ++i) +{ + double sample = rng(); + acc0(sample, weight = 1.); + acc1(sample, weight = 1.); + acc2(sample, weight = 1.); + acc3(sample, weight = 1.); + + double sample4 = normal4(); + double sample5 = normal5(); + double sample6 = normal6(); + double sample7 = normal7(); + acc4(sample4, weight = std::exp(-mu4 * (sample4 - 0.5 * mu4))); + acc5(sample5, weight = std::exp(-mu5 * (sample5 - 0.5 * mu5))); + acc6(sample6, weight = std::exp(-mu6 * (sample6 - 0.5 * mu6))); + acc7(sample7, weight = std::exp(-mu7 * (sample7 - 0.5 * mu7))); +} + +// check for uniform distribution with weight = 1 +BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc0), 0.001, 15 ); +BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc1), 0.025, 5 ); +BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc2), 0.975, epsilon ); +BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc3), 0.999, epsilon ); + +// check for shifted standard normal distribution ("importance sampling") +BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc4), -3.090232, epsilon ); +BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc5), -1.959963, epsilon ); +BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc6), 1.959963, epsilon ); +BOOST_CHECK_CLOSE( weighted_p_square_quantile(acc7), 3.090232, epsilon ); +---- + +*See also* + +* xref:ref_impl_weighted_p_square_quantile_impl[weighted_p_square_quantile_impl] +* <> +* <> + +[[weighted_peaks_over_threshold]] +== weighted_peaks_over_threshold _and variants_ + +Weighted peaks over threshold method for weighted quantile and weighted tail mean estimation. +For more implementation details, +see xref:ref_impl_weighted_peaks_over_threshold_impl[weighted_peaks_over_threshold_impl] +and xref:ref_impl_weighted_peaks_over_threshold_prob_impl[weighted_peaks_over_threshold_prob_impl]. + +Both `tag::weighted_peaks_over_threshold<{left_or_right}>` and +`tag::weighted_peaks_over_threshold_prob<{left_or_right}>` satisfy the +`tag::weighted_peaks_over_threshold<{left_or_right}>` feature and can be extracted using the +`weighted_peaks_over_threshold()` extractor. + +*Result Type* +`tuple` where `float_type` is +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv< + numeric::functional::multiplies<{sample_type}, {weight_type}>::result_type + , std::size_t +>::result_type +---- + +[dlist] +Depends On:: +`weighted_peaks_over_threshold<{left_or_right}>` depends on `sum_of_weights` + +`weighted_peaks_over_threshold_prob<{left_or_right}>` depends on `sum_of_weights` and `tail_weights<{left_or_right}>` + +Variants:: +`weighted_peaks_over_threshold_prob` + +Initialization Parameters:: +`tag::peaks_over_threshold::threshold_value` + +`tag::peaks_over_threshold_prob::threshold_probability` + +`tag::tail<{left_or_right}>::cache_size` + +Accumulator Parameters:: +`weight` + +Extractor Parameters:: +none + +Accumulator Complexity:: +TODO + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*See also* + +* xref:ref_impl_weighted_peaks_over_threshold_impl[weighted_peaks_over_threshold_impl] +* xref:ref_impl_weighted_peaks_over_threshold_prob_impl[weighted_peaks_over_threshold_prob_impl] +* <> +* <> + +[[weighted_skewness]] +== weighted_skewness + +The skewness of a sample distribution is defined as the ratio of the 3rd central moment and the `3/2`-th power +of the 2nd central moment (the variance) of the samples 3. The skewness estimator for weighted samples +is formally identical to the estimator for unweighted samples, except that the weighted counterparts of +all measures it depends on are to be taken. + +For implementation details, see +xref:ref_impl_weighted_skewness_impl[weighted_skewness_impl]. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv< + numeric::functional::multiplies<{sample_type}, {weight_type}>::result_type + , numeric::functional::multiplies<{sample_type}, {weight_type}>::result_type +>::result_type +---- + +[dlist] +Depends On:: +`weighted_mean` + +`weighted_moment<2>` + +`weighted_moment<3>` + +Variants:: +none + +Initialization Parameters:: +none + +Accumulator Parameters:: +`weight` + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set, int > acc2; + +acc2(2, weight = 4); +acc2(7, weight = 1); +acc2(4, weight = 3); +acc2(9, weight = 1); +acc2(3, weight = 2); + +BOOST_CHECK_EQUAL( weighted_mean(acc2), 42./11. ); +BOOST_CHECK_EQUAL( accumulators::weighted_moment<2>(acc2), 212./11. ); +BOOST_CHECK_EQUAL( accumulators::weighted_moment<3>(acc2), 1350./11. ); +BOOST_CHECK_CLOSE( weighted_skewness(acc2), 1.30708406282, 1e-6 ); +---- + +*See also* + +* xref:ref_impl_weighted_skewness_impl[weighted_skewness_impl] +* <> +* <> + +[[weighted_sum]] +== weighted_sum _and variants_ + +For summing the weighted samples or variates. All of the `tag::weighted_sum_of_variates<>` features +can be extracted with the `weighted_sum_of_variates()` extractor. Variants that implement the Kahan +summation algorithm are also provided. + + +[dlist] +Result Type:: +`numeric::functional::multiplies<{sample_type}, {weight_type}>::result_type` for summing weighted samples + +`numeric::functional::multiplies<{variate_type}, {weight_type}>::result_type` for summing weighted variates + +Depends On:: +none + +Variants:: +`tag::weighted_sum` + +`tag::weighted_sum_of_variates<{variate_type}, {variate_tag}>` + +`tag::weighted_sum_kahan` (a.k.a. tag::weighted_sum(kahan)) + +`tag::weighted_sum_of_variates_kahan<{variate_type}, {variate_tag}>` + + +Initialization Parameters:: +none + +Accumulator Parameters:: +`weight` + +`{variate_tag}` for summing variates + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1). Note that the Kahan sum performs four floating-point sum operations per accumulated value, whereas the naive sum performs only one. + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +#include +---- + +*Example* + +[source,c++] +---- +accumulator_set >, int> acc; + +acc(1, weight = 2, covariate1 = 3); +BOOST_CHECK_EQUAL(2, weighted_sum(acc)); +BOOST_CHECK_EQUAL(6, weighted_sum_of_variates(acc)); + +acc(2, weight = 3, covariate1 = 6); +BOOST_CHECK_EQUAL(8, weighted_sum(acc)); +BOOST_CHECK_EQUAL(24, weighted_sum_of_variates(acc)); + +acc(4, weight = 6, covariate1 = 9); +BOOST_CHECK_EQUAL(32, weighted_sum(acc)); +BOOST_CHECK_EQUAL(78, weighted_sum_of_variates(acc)); + +// demonstrate weighted Kahan summation +accumulator_set, float > acc; +BOOST_CHECK_EQUAL(0.0f, weighted_sum_kahan(acc)); +for (size_t i = 0; i < 1e6; ++i) { + acc(1.0f, weight = 1e-6f); +} +BOOST_CHECK_EQUAL(1.0f, weighted_sum_kahan(acc)); +---- + +*See also* + +* xref:ref_impl_weighted_sum_impl[weighted_sum_impl] +* xref:ref_impl_weighted_sum_kahan_impl[weighted_sum_kahan_impl] + +[[non_coherent_weighted_tail_mean]] +== non_coherent_weighted_tail_mean + +Estimation of the (non-coherent) weighted tail mean based on order statistics (for both left and right tails). +The left non-coherent weighted tail mean feature is `tag::non_coherent_weighted_tail_mean`, and the right +non-choherent weighted tail mean feature is `tag::non_coherent_weighted_tail_mean`. They both share the +`tag::abstract_non_coherent_tail_mean` feature with the unweighted non-coherent tail mean accumulators and can +be extracted with either the `non_coherent_tail_mean()` or the `non_coherent_weighted_tail_mean()` extractors. +For more implementation details, see +xref:ref_impl_non_coherent_weighted_tail_mean_impl[non_coherent_weighted_tail_mean_impl]. + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv< + numeric::functional::multiplies<{sample_type}, {weight_type}>::result_type + , std::size_t +>::result_type +---- + +[dlist] +Depends On:: +`sum_of_weights` + +`tail_weights<{left_or_right}>` + +Variants:: +`abstract_non_coherent_tail_mean` + +Initialization Parameters:: +`tag::tail<{left_or_right}>::cache_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +`quantile_probability` + +Accumulator Complexity:: +O(log N), where N is the cache size + +Extractor Complexity:: +O(N log N), where N is the cache size + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +// tolerance in % +double epsilon = 1; + +std::size_t n = 100000; // number of MC steps +std::size_t c = 25000; // cache size + +accumulator_set >, double > + acc0( right_tail_cache_size = c ); +accumulator_set >, double > + acc1( left_tail_cache_size = c ); + +// random number generators +boost::lagged_fibonacci607 rng; + +for (std::size_t i = 0; i < n; ++i) +{ + double smpl = std::sqrt(rng()); + acc0(smpl, weight = 1./smpl); +} + +for (std::size_t i = 0; i < n; ++i) +{ + double smpl = rng(); + acc1(smpl*smpl, weight = smpl); +} + +// check uniform distribution +BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc0, quantile_probability = 0.95), 0.975, epsilon ); +BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc0, quantile_probability = 0.975), 0.9875, epsilon ); +BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc0, quantile_probability = 0.99), 0.995, epsilon ); +BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc0, quantile_probability = 0.999), 0.9995, epsilon ); +BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc1, quantile_probability = 0.05), 0.025, epsilon ); +BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc1, quantile_probability = 0.025), 0.0125, epsilon ); +BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc1, quantile_probability = 0.01), 0.005, epsilon ); +BOOST_CHECK_CLOSE( non_coherent_weighted_tail_mean(acc1, quantile_probability = 0.001), 0.0005, 5*epsilon ); +---- + +*See also* + +* xref:ref_impl_non_coherent_weighted_tail_mean_impl[non_coherent_weighted_tail_mean_impl] +* <> +* <> + +[[weighted_tail_quantile]] +== weighted_tail_quantile + +Tail quantile estimation based on order statistics of weighted samples (for both left +and right tails). The left weighted tail quantile feature is `tag::weighted_tail_quantile`, +and the right weighted tail quantile feature is `tag::weighted_tail_quantile`. They both +share the `tag::quantile` feature with the unweighted tail quantile accumulators and can be +extracted with either the `quantile()` or the `weighted_tail_quantile()` extractors. For more +implementation details, see +xref:ref_impl_weighted_tail_quantile_impl[weighted_tail_quantile_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +{sample_type} +---- + +[dlist] +Depends On:: +`sum_of_weights` + +`tail_weights<{left_or_right}>` + +Variants:: +none + +Initialization Parameters:: +`tag::tail<{left_or_right}>::cache_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +`quantile_probability` + +Accumulator Complexity:: +O(log N), where N is the cache size + +Extractor Complexity:: +O(N log N), where N is the cache size + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +// tolerance in % +double epsilon = 1; + +std::size_t n = 100000; // number of MC steps +std::size_t c = 20000; // cache size + +double mu1 = 1.0; +double mu2 = -1.0; +boost::lagged_fibonacci607 rng; +boost::normal_distribution<> mean_sigma1(mu1,1); +boost::normal_distribution<> mean_sigma2(mu2,1); +boost::variate_generator > normal1(rng, mean_sigma1); +boost::variate_generator > normal2(rng, mean_sigma2); + +accumulator_set >, double> + acc1(right_tail_cache_size = c); + +accumulator_set >, double> + acc2(left_tail_cache_size = c); + +for (std::size_t i = 0; i < n; ++i) +{ + double sample1 = normal1(); + double sample2 = normal2(); + acc1(sample1, weight = std::exp(-mu1 * (sample1 - 0.5 * mu1))); + acc2(sample2, weight = std::exp(-mu2 * (sample2 - 0.5 * mu2))); +} + +// check standard normal distribution +BOOST_CHECK_CLOSE( quantile(acc1, quantile_probability = 0.975), 1.959963, epsilon ); +BOOST_CHECK_CLOSE( quantile(acc1, quantile_probability = 0.999), 3.090232, epsilon ); +BOOST_CHECK_CLOSE( quantile(acc2, quantile_probability = 0.025), -1.959963, epsilon ); +BOOST_CHECK_CLOSE( quantile(acc2, quantile_probability = 0.001), -3.090232, epsilon ); +---- + +*See also* + +* xref:ref_impl_weighted_tail_quantile_impl[weighted_tail_quantile_impl] +* <> +* <> + +[[weighted_tail_variate_means]] +== weighted_tail_variate_means _and variants_ + +Estimation of the absolute and relative weighted tail variate means (for both left and right tails) +The absolute weighted tail variate means has the feature +`tag::absolute_weighted_tail_variate_means<{left_or_right}, {variate_type}, {variate_tag}>` +and the relative weighted tail variate mean has the feature +`tag::relative_weighted_tail_variate_means<{left_or_right}, {variate_type}, {variate_tag}>`. All +absolute weighted tail variate mean features share the `tag::abstract_absolute_tail_variate_means` +feature with their unweighted variants and can be extracted with the `tail_variate_means()` and +`weighted_tail_variate_means()` extractors. All the relative weighted tail variate mean features +share the `tag::abstract_relative_tail_variate_means` feature with their unweighted variants +and can be extracted with either the `relative_tail_variate_means()` or +`relative_weighted_tail_variate_means()` extractors. + +For more implementation details, see +xref:ref_impl_weighted_tail_variate_means_impl[weighted_tail_variate_means_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +boost::iterator_range< + numeric::functional::fdiv< + numeric::functional::multiplies<{variate_type}, {weight_type}>::result_type + , {weight_type} + >::result_type::iterator +> +---- + +[dlist] +Depends On:: +`non_coherent_weighted_tail_mean<{left_or_right}>` + +`tail_variate<{variate_type}, {variate_tag}, {left_or_right}>` + +`tail_weights<{left_or_right}>` + +Variants:: +`tag::absolute_weighted_tail_variate_means<{left_or_right}, {variate_type}, {variate_tag}>` + +`tag::relative_weighted_tail_variate_means<{left_or_right}, {variate_type}, {variate_tag}>` + +Initialization Parameters:: +`tag::tail<{left_or_right}>::cache_size` + +Accumulator Parameters:: +none + +Extractor Parameters:: +`quantile_probability` + +Accumulator Complexity:: +O(log N), where N is the cache size + +Extractor Complexity:: +O(N log N), where N is the cache size + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +std::size_t c = 5; // cache size + +typedef double variate_type; +typedef std::vector variate_set_type; + +accumulator_set(relative)>, double > + acc1( right_tail_cache_size = c ); +accumulator_set(absolute)>, double > + acc2( right_tail_cache_size = c ); +accumulator_set(relative)>, double > + acc3( left_tail_cache_size = c ); +accumulator_set(absolute)>, double > + acc4( left_tail_cache_size = c ); + +variate_set_type cov1, cov2, cov3, cov4, cov5; +double c1[] = { 10., 20., 30., 40. }; // 100 +double c2[] = { 26., 4., 17., 3. }; // 50 +double c3[] = { 46., 64., 40., 50. }; // 200 +double c4[] = { 1., 3., 70., 6. }; // 80 +double c5[] = { 2., 2., 2., 14. }; // 20 +cov1.assign(c1, c1 + sizeof(c1)/sizeof(variate_type)); +cov2.assign(c2, c2 + sizeof(c2)/sizeof(variate_type)); +cov3.assign(c3, c3 + sizeof(c3)/sizeof(variate_type)); +cov4.assign(c4, c4 + sizeof(c4)/sizeof(variate_type)); +cov5.assign(c5, c5 + sizeof(c5)/sizeof(variate_type)); + +acc1(100., weight = 0.8, covariate1 = cov1); +acc1( 50., weight = 0.9, covariate1 = cov2); +acc1(200., weight = 1.0, covariate1 = cov3); +acc1( 80., weight = 1.1, covariate1 = cov4); +acc1( 20., weight = 1.2, covariate1 = cov5); + +acc2(100., weight = 0.8, covariate1 = cov1); +acc2( 50., weight = 0.9, covariate1 = cov2); +acc2(200., weight = 1.0, covariate1 = cov3); +acc2( 80., weight = 1.1, covariate1 = cov4); +acc2( 20., weight = 1.2, covariate1 = cov5); + +acc3(100., weight = 0.8, covariate1 = cov1); +acc3( 50., weight = 0.9, covariate1 = cov2); +acc3(200., weight = 1.0, covariate1 = cov3); +acc3( 80., weight = 1.1, covariate1 = cov4); +acc3( 20., weight = 1.2, covariate1 = cov5); + +acc4(100., weight = 0.8, covariate1 = cov1); +acc4( 50., weight = 0.9, covariate1 = cov2); +acc4(200., weight = 1.0, covariate1 = cov3); +acc4( 80., weight = 1.1, covariate1 = cov4); +acc4( 20., weight = 1.2, covariate1 = cov5); + +// check relative risk contributions +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.7).begin() ), (0.8*10 + 1.0*46)/(0.8*100 + 1.0*200) ); +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.7).begin() + 1), (0.8*20 + 1.0*64)/(0.8*100 + 1.0*200) ); +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.7).begin() + 2), (0.8*30 + 1.0*40)/(0.8*100 + 1.0*200) ); +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.7).begin() + 3), (0.8*40 + 1.0*50)/(0.8*100 + 1.0*200) ); +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.3).begin() ), (0.9*26 + 1.2*2)/(0.9*50 + 1.2*20) ); +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.3).begin() + 1), (0.9*4 + 1.2*2)/(0.9*50 + 1.2*20) ); +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.3).begin() + 2), (0.9*17 + 1.2*2)/(0.9*50 + 1.2*20) ); +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.3).begin() + 3), (0.9*3 + 1.2*14)/(0.9*50 + 1.2*20) ); + +// check absolute risk contributions +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.7).begin() ), (0.8*10 + 1.0*46)/1.8 ); +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.7).begin() + 1), (0.8*20 + 1.0*64)/1.8 ); +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.7).begin() + 2), (0.8*30 + 1.0*40)/1.8 ); +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.7).begin() + 3), (0.8*40 + 1.0*50)/1.8 ); +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.3).begin() ), (0.9*26 + 1.2*2)/2.1 ); +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.3).begin() + 1), (0.9*4 + 1.2*2)/2.1 ); +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.3).begin() + 2), (0.9*17 + 1.2*2)/2.1 ); +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.3).begin() + 3), (0.9*3 + 1.2*14)/2.1 ); + +// check relative risk contributions +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.9).begin() ), 1.0*46/(1.0*200) ); +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.9).begin() + 1), 1.0*64/(1.0*200) ); +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.9).begin() + 2), 1.0*40/(1.0*200) ); +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc1, quantile_probability = 0.9).begin() + 3), 1.0*50/(1.0*200) ); +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.1).begin() ), 1.2*2/(1.2*20) ); +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.1).begin() + 1), 1.2*2/(1.2*20) ); +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.1).begin() + 2), 1.2*2/(1.2*20) ); +BOOST_CHECK_EQUAL( *(relative_weighted_tail_variate_means(acc3, quantile_probability = 0.1).begin() + 3), 1.2*14/(1.2*20) ); + +// check absolute risk contributions +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.9).begin() ), 1.0*46/1.0 ); +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.9).begin() + 1), 1.0*64/1.0 ); +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.9).begin() + 2), 1.0*40/1.0 ); +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc2, quantile_probability = 0.9).begin() + 3), 1.0*50/1.0 ); +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.1).begin() ), 1.2*2/1.2 ); +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.1).begin() + 1), 1.2*2/1.2 ); +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.1).begin() + 2), 1.2*2/1.2 ); +BOOST_CHECK_EQUAL( *(weighted_tail_variate_means(acc4, quantile_probability = 0.1).begin() + 3), 1.2*14/1.2 ); +---- + +*See also* + +* xref:ref_impl_weighted_tail_variate_means_impl[weighted_tail_variate_means_impl] +* <> +* <> +* <> + +[[weighted_variance]] +== weighted_variance and variants + +Lazy or iterative calculation of the weighted variance. The lazy calculation is associated with the `tag::lazy_weighted_variance` +feature, and the iterative calculation with the `tag::weighted_variance` feature. Both can be extracted +using the `tag::weighted_variance()` extractor. For more implementation details, see +xref:ref_impl_lazy_weighted_variance_impl[lazy_weighted_variance_impl] and +xref:ref_impl_weighted_variance_impl[weighted_variance_impl] + +*Result Type* +[source,cpp,subs="+attributes"] +---- +numeric::functional::fdiv< + numeric::functional::multiplies<{sample_type}, {weight_type}>::result_type + , std::size_t +>::result_type +---- + +[dlist] +Depends On:: +`tag::lazy_weighted_variance` depends on `tag::weighted_moment<2>` and `tag::weighted_mean` + +`tag::weighted_variance` depends on `tag::count` and `tag::immediate_weighted_mean` + +Variants:: +`tag::lazy_weighted_variance` (a.k.a. `tag::weighted_variance(lazy))` + +`tag::weighted_variance` (a.k.a. `tag::weighted_variance(immediate)`) + +Initialization Parameters:: +none + +Accumulator Parameters:: +`weight` + +Extractor Parameters:: +none + +Accumulator Complexity:: +O(1) + +Extractor Complexity:: +O(1) + +*Header* + +[source,c++] +---- +#include +---- + +*Example* + +[source,c++] +---- +// lazy weighted_variance +accumulator_set, int> acc1; + +acc1(1, weight = 2); // 2 +acc1(2, weight = 3); // 6 +acc1(3, weight = 1); // 3 +acc1(4, weight = 4); // 16 +acc1(5, weight = 1); // 5 + +// weighted_mean = (2+6+3+16+5) / (2+3+1+4+1) = 32 / 11 = 2.9090909090909090909090909090909 + +BOOST_CHECK_EQUAL(5u, count(acc1)); +BOOST_CHECK_CLOSE(2.9090909, weighted_mean(acc1), 1e-5); +BOOST_CHECK_CLOSE(10.1818182, accumulators::weighted_moment<2>(acc1), 1e-5); +BOOST_CHECK_CLOSE(1.7190083, weighted_variance(acc1), 1e-5); + +// immediate weighted_variance +accumulator_set, int> acc2; + +acc2(1, weight = 2); +acc2(2, weight = 3); +acc2(3, weight = 1); +acc2(4, weight = 4); +acc2(5, weight = 1); + +BOOST_CHECK_EQUAL(5u, count(acc2)); +BOOST_CHECK_CLOSE(2.9090909, weighted_mean(acc2), 1e-5); +BOOST_CHECK_CLOSE(1.7190083, weighted_variance(acc2), 1e-5); + +// check lazy and immediate variance with random numbers + +// two random number generators +boost::lagged_fibonacci607 rng; +boost::normal_distribution<> mean_sigma(0,1); +boost::variate_generator > normal(rng, mean_sigma); + +accumulator_set, double > acc_lazy; +accumulator_set, double > acc_immediate; + +for (std::size_t i=0; i<10000; ++i) +{ + double value = normal(); + acc_lazy(value, weight = rng()); + acc_immediate(value, weight = rng()); +} + +BOOST_CHECK_CLOSE(1., weighted_variance(acc_lazy), 1.); +BOOST_CHECK_CLOSE(1., weighted_variance(acc_immediate), 1.); +---- + +*See also* + +* xref:ref_impl_lazy_weighted_variance_impl[lazy_weighted_variance_impl] +* xref:ref_impl_weighted_variance_impl[weighted_variance_impl] +* <> +* <> +* <> diff --git a/doc/pages/user_s_guide.adoc b/doc/pages/user_s_guide.adoc new file mode 100644 index 00000000..0af8fa92 --- /dev/null +++ b/doc/pages/user_s_guide.adoc @@ -0,0 +1,1130 @@ +//// +Copyright (C) 2005, 2006 Eric Niebler +Copyright (C) 2026 Ming Yang Zhang, Leo Chen +Distributed under the Boost Software License, Version 1.0. +//// +[[user_s_guide]] += User's Guide + +This section describes how to use the Boost.Accumulators framework to create new +accumulators and how to use the existing statistical accumulators to perform incremental +statistical computation. For detailed information regarding specific components in +Boost.Accumulators, check the <> section. + +[[hello_world]] +== Hello, World! + + +Below is a complete example of how to use the Accumulators Framework and the +Statistical Accumulators to perform an incremental statistical calculation. It +calculates the mean and 2nd moment of a sequence of doubles. + +[source,c++] +---- +#include +#include +#include +#include +#include +using namespace boost::accumulators; + +int main() +{ + // Define an accumulator set for calculating the mean and the + // 2nd moment ... + accumulator_set > > acc; + + // push in some data ... + acc(1.2); + acc(2.3); + acc(3.4); + acc(4.5); + + // Display the results ... + std::cout << "Mean: " << mean(acc) << std::endl; + std::cout << "Moment: " << moment<2>(acc) << std::endl; + + return 0; +} +---- + + +This program displays the following: + +[source,c++] +---- +Mean: 2.85 +Moment: 9.635 +---- + +[[the_accumulators_framework]] +== The Accumulators Framework + +The Accumulators Framework is framework for performing incremental calculations. Usage +of the framework follows the following pattern: + +* Users build a computational object, called an _{accumulator_set}_, by selecting + the computations in which they are interested, or authoring their own computational + primitives which fit within the framework. +* Users push data into the {accumulator_set} object one sample at a time. +* The {accumulator_set} computes the requested quantities in the most efficient method + possible, resolving dependencies between requested calculations, possibly caching + intermediate results. + +The Accumulators Framework defines the utilities needed for defining primitive +computational elements, called accumulators. It also provides the {accumulator_set} +type, described above. + +[[terminology]] +== Terminology + + +The following terms are used in the rest of the documentation. + +[dlist] +Sample:: +A datum that is pushed into an {accumulator_set}. The type of the sample is the +_sample type_. + +Weight:: +An optional scalar value passed along with the sample specifying the weight of the +sample. Conceptually, each sample is multiplied with its weight. The type of the +weight is the _weight type_. + +Feature:: +An abstract primitive computational entity. When defining an {accumulator_set}, users +specify the features in which they are interested, and the {accumulator_set} figures +out which _accumulators_ would best provide those features. Features may depend on +other features. If they do, the accumulator set figures out which accumulators to add +to satisfy the dependencies. + +Accumulator:: +A concrete primitive computational entity. An accumulator is a concrete implementation +of a feature. It satisfies exactly one abstract feature. Several different +accumulators may provide the same feature, but may represent different implementation +strategies. + +Accumulator Set:: +A collection of accumulators. An accumulator set is specified with a sample type and a +list of features. The accumulator set uses this information to generate an ordered set +of accumulators depending on the feature dependency graph. An accumulator set accepts +samples one datum at a time, propagating them to each accumulator in order. At any +point, results can be extracted from the accumulator set. + + +[[overview]] +== Overview + + +Here is a list of the important types and functions in the Accumulator Framework and +a brief description of each. + +.Accumulators Toolbox +|=== +|Tool |Description + +|{accumulator_set} +|This is the most important type in the Accumulators Framework. It is a collection of +accumulators. A datum pushed into an {accumulator_set} is forwarded to each +accumulator, in an order determined by the dependency relationships between the +accumulators. Computational results can be extracted from an accumulator at any time. + +|{depends_on} +|Used to specify which other features a feature depends on. + +|{feature_of} +|Trait used to tell the Accumulators Framework that, for the purpose of feature-based +dependency resolution, one feature should be treated the same as another. + +|{as_feature} +|Used to create an alias for a feature. For example, if there are two features, +`fast_X` and `accurate_X`, they can be mapped to `X(fast)` and `X(accurate)` with +{as_feature}. This is just syntactic sugar. + +|{features} +|An {mpl} sequence. We can use {features} as the second template parameter when +declaring an {accumulator_set}. + +|{external} +|Used when declaring an {accumulator_set}. If the weight type is specified with +{external}, then the weight accumulators are assumed to reside in a separate +accumulator set which will be passed in with a named parameter. + +|{extractor} +|A class template useful for creating an extractor function object. It is +parameterized on a feature, and it has member functions for extracting from an +{accumulator_set} the result corresponding to that feature. +|=== + +[[using_accumulator_set_]] +=== Using `accumulator_set<>` + +Our tour of the {accumulator_set} class template begins with the forward declaration: + +[source,c++] +---- +template< typename Sample, typename Features, typename Weight = void > +struct accumulator_set; +---- + + +The template parameters have the following meaning: + +[dlist] +Sample:: +The type of the data that will be accumulated. + +Features:: +An {mpl} sequence of features to be calculated. + +Weight:: +The type of the (optional) weight paramter. + +For example, the following line declares an {accumulator_set} that will accept +a sequence of doubles one at a time and calculate the min and mean: + +[source,c++] +---- +accumulator_set< double, features< tag::min, tag::mean > > acc; +---- + + +Notice that we use the {features} template to specify a list of features to be calculated. +{features} is an MPL sequence of features. + +[NOTE] +==== +{features} is a synonym of `mpl::vector<>`. In fact, we could use `mpl::vector<>` or any +MPL sequence if we prefer, and the meaning would be the same. +==== + +Once we have defined an {accumulator_set}, we can then push data into it, and it will +calculate the quantities you requested, as shown below. + +[source,c++] +---- +// push some data into the accumulator_set ... +acc(1.2); +acc(2.3); +acc(3.4); +---- + +Since {accumulator_set} defines its accumulate function to be the function call operator, +we might be tempted to use an {accumulator_set} as a UnaryFunction to a standard algorithm +such as `std::for_each`. That's fine as long as we keep in mind that the standard +algorithms take UnaryFunction objects by value, which involves making a copy of the +{accumulator_set} object. Consider the following: + +[source,c++] +---- +// The data for which we wish to calculate statistical properties: +std::vector< double > data( /* stuff */ ); + +// The accumulator set which will calculate the properties for us: +accumulator_set< double, features< tag::min, tag::mean > > acc; + +// Use std::for_each to accumulate the statistical properties: +acc = std::for_each( data.begin(), data.end(), acc ); +---- + +Notice how we must assign the return value of `std::for_each` back to the +{accumulator_set}. This works, but some accumulators are not cheap to copy. For example, +the {tail} and {tail_variate} accumulators must store a `std::vector<>`, so copying these +accumulators involves a dynamic allocation. We might be better off in this case passing +the accumulator by reference, with the help of `boost::bind()` and `boost::ref()`. See +below: + +[source,c++] +---- +// The data for which we wish to calculate statistical properties: +std::vector< double > data( /* stuff */ ); + +// The accumulator set which will calculate the properties for us: +accumulator_set< double, features< tag::tail > > acc( + tag::tail::cache_size = 4 ); + +// Use std::for_each to accumulate the statistical properties: +std::for_each( data.begin(), data.end(), bind( ref(acc), _1 ) ); +---- + +Notice now that we don't care about the return value of `std::for_each()` anymore because +`std::for_each()` is modifying `acc` directly. + +[NOTE] +==== +To use `boost::bind()` and `boost::ref()`, you must `#include ` and +`` +==== + +[[extracting_results]] +=== Extracting Results + +Once we have declared an {accumulator_set} and pushed data into it, we need to be able +to extract results from it. For each feature we can add to an {accumulator_set}, there +is a corresponding extractor for fetching its result. Usually, the extractor has the +same name as the feature, but in a different namespace. For example, if we accumulate +the `tag::min` and `tag::max` features, we can extract the results with the `min` and `max` +extractors, as follows: + +[source,c++] +---- +// Calculate the minimum and maximum for a sequence of integers. +accumulator_set< int, features< tag::min, tag::max > > acc; +acc( 2 ); +acc( -1 ); +acc( 1 ); +---- + + +[source,c++] +---- +// This displays "(-1, 2)" +std::cout << '(' << min( acc ) << ", " << max( acc ) << ")\n"; +---- + + +The extractors are all declared in the `boost::accumulators::extract` namespace, but they +are brought into the `boost::accumulators` namespace with a `using` declaration. + +[TIP] +==== +On the Windows platform, `min` and `max` are preprocessor macros defined in `WinDef.h`. +To use the `min` and `max` extractors, you should either compile with `NOMINMAX` defined, or +you should invoke the extractors like: `(min)( acc )` and `(max)( acc )`. The parentheses +keep the macro from being invoked. +==== + +Another way to extract a result from an {accumulator_set} is with the +`extract_result()` function. This can be more convenient if there isn't an extractor +object handy for a certain feature. The line above which displays results could +equally be written as: + +[source,c++] +---- +// This displays "(-1, 2)" +std::cout << '(' << extract_result< tag::min >( acc ) + << ", " << extract_result< tag::max >( acc ) << ")\n"; +---- + + +Finally, we can define our own extractor using the {extractor} class template. For +instance, another way to avoid the `min` / `max` macro business would be to define +extractors with names that don't conflict with the macros, like this: + +[source,c++] +---- +extractor< tag::min > min_; +extractor< tag::min > max_; + +// This displays "(-1, 2)" +std::cout << '(' << min_( acc ) << ", " << max_( acc ) << ")\n"; +---- + +[[passing_optional_parameters]] +=== Passing Optional Parameters + +Some accumulators need initialization parameters. In addition, perhaps some auxiliary +information needs to be passed into the {accumulator_set} along with each sample. +Boost.Accumulators handles these cases with named parameters from the {parameter} +library. + +For example, consider the {tail} and {tail_variate} features. {tail} keeps +an ordered list of the largest `N` samples, where `N` can be specified at +construction time. Also, the {tail_variate} feature, which depends on {tail}, keeps +track of some data that is covariate with the `N` samples tracked by {tail}. The +code below shows how this all works, and is described in more detail below. + +[source,c++] +---- +// Define a feature for tracking covariate data +typedef tag::tail_variate< int, tag::covariate1, left > my_tail_variate_tag; + +// This will calculate the left tail and my_tail_variate_tag for N == 2 +// using the tag::tail::cache_size named parameter +accumulator_set< double, features< my_tail_variate_tag > > acc( + tag::tail::cache_size = 2 ); + +// push in some samples and some covariates by using +// the covariate1 named parameter +acc( 1.2, covariate1 = 12 ); +acc( 2.3, covariate1 = -23 ); +acc( 3.4, covariate1 = 34 ); +acc( 4.5, covariate1 = -45 ); + +// Define an extractor for the my_tail_variate_tag feature +extractor< my_tail_variate_tag > my_tail_variate; + +// Write the tail statistic to std::cout. This will print "4.5, 3.4, " +std::ostream_iterator< double > dout( std::cout, ", " ); +std::copy( tail( acc ).begin(), tail( acc ).end(), dout ); + +// Write the tail_variate statistic to std::cout. This will print "-45, 34, " +std::ostream_iterator< int > iout( std::cout, ", " ); +std::copy( my_tail_variate( acc ).begin(), my_tail_variate( acc ).end(), iout ); +---- + + +There are several things to note about the code above. First, notice that we didn't have +to request that the {tail} feature be calculated. That is implicit because the {tail_variate} +feature depends on the {tail} feature. Next, notice how the `acc` object +is initialized: `acc( tag::tail::cache_size = 2 )`. Here, `cache_size` is a named parameter. +It is used to tell the {tail} and {tail_variate} accumulators how many samples and +covariates to store. Conceptually, every construction parameter is made available to +every accumulator in an accumulator set. + +We also use a named parameter to pass covariate data into the accumulator set along with +the samples. As with the constructor parameters, all parameters to the accumulate function +are made available to all the accumulators in the set. In this case, only the accumulator +for the `my_tail_variate` feature would be interested in the value of the `covariate1` named +parameter. + +We can make one final observation about the example above. Since {tail} and {tail_variate} +are multi-valued features, the result we extract for them is represented as an iterator +range. That is why we can say `tail( acc ).begin()` and `tail( acc ).end()`. + +Even the extractors can accept named parameters. In a bit, we'll see a situation where that +is useful. + +[[weighted_samples]] +=== Weighted Samples + +Some accumulators, statistical accumulators in particular, deal with data that are +weighted. Each sample pushed into the accumulator has an associated weight, by which +the sample is conceptually multiplied. The Statistical Accumulators Library provides an +assortment of these weighted statistical accumulators. And many unweighted statistical +accumulators have weighted variants. For instance, the weighted variant of the `sum` +accumulator is called `weighted_sum`, and is calculated by accumulating all the +samples multiplied by their weights. + +To declare an {accumulator_set} that accepts weighted samples, you must specify the +type of the weight parameter as the 3rd template parameter, as follows: + +[source,c++] +---- +// 3rd template parameter 'int' means this is a weighted +// accumulator set where the weights have type 'int' +accumulator_set< int, features< tag::sum >, int > acc; +---- + + +When you specify a weight, all the accumulators in the set are replaced with +their weighted equivalents. For example, the above {accumulator_set} declaration +is equivalent to the following: + +[source,c++] +---- +// Since we specified a weight, tag::sum becomes tag::weighted_sum +accumulator_set< int, features< tag::weighted_sum >, int > acc; +---- + + +When passing samples to the accumulator set, you must also specify the +weight of each sample. You can do that with the `weight` named parameter, +as follows: + +[source,c++] +---- +acc(1, weight = 2); // 1 * 2 +acc(2, weight = 4); // 2 * 4 +acc(3, weight = 6); // + 3 * 6 + // ------- + // = 28 +---- + + +You can then extract the result with the `sum()` extractor, as follows: + +[source,c++] +---- +// This prints "28" +std::cout << sum(acc) << std::endl; +---- + + +[NOTE] +==== +When working with weighted statistical accumulators from the Statistical Accumulators +Library, be sure to include the appropriate header. For instance, `weighted_sum` is +defined in {weighted_sum_hpp}. +==== + +[[numeric_operators_sub_library]] +=== Numeric Operators Sub-Library + +This section describes the function objects in the `boost::numeric` namespace, which +is a sub-library that provides function objects and meta-functions corresponding +to the infix operators in C++. + +In the `boost::numeric::operators` namespace are additional operator overloads for +some useful operations not provided by the standard library, such as multiplication +of a `std::complex<>` with a scalar. + +In the `boost::numeric::functional` namespace are function object equivalents of +the infix operators. These function object types are heterogeneous, and so are more +general than the standard ones found in the `` header. They use the +Boost.Typeof library to deduce the return types of the infix expressions they +evaluate. In addition, they look within the `boost::numeric::operators` namespace +to consider any additional overloads that might be defined there. + +In the `boost::numeric` namespace are global polymorphic function objects +corresponding to the function object types defined in the `boost::numeric::functional` +namespace. For example, `boost::numeric::plus(a, b)` is equivalent to +`boost::numeric::functional::plus()(a, b)`, and both are equivalent to +`using namespace boost::numeric::operators; a + b;`. + +The Numeric Operators Sub-Library also gives several ways to sub-class and +a way to sub-class and specialize operations. One way uses tag dispatching on +the types of the operands. The other way is based on the compile-time +properties of the operands. + +[[extending_the_accumulators_framework]] +=== Extending the Accumulators Framework + +This section describes how to extend the Accumulators Framework by defining new accumulators, features and extractors. Also covered are how to control the dependency resolution of features within an accumulator set. + +[[defining_a_new_accumulator]] +==== _Defining a New Accumulator_ + +All new accumulators must satisfy the <>. Below is a +sample class that satisfies the accumulator concept, which simply sums +the values of all samples passed into it. + +[source,c++] +---- +#include +#include + +namespace boost { // Putting your accumulators in the +namespace accumulators { // impl namespace has some +namespace impl { // advantages. See below. + +template +struct sum_accumulator // All accumulators should inherit from + : accumulator_base // accumulator_base. +{ + typedef Sample result_type; // The type returned by result() below. + + template // The constructor takes an argument pack. + sum_accumulator(Args const & args) + : sum(args[sample | Sample()]) // Maybe there is an initial value in the + { // argument pack. ('sample' is defined in + } // sample.hpp, included above.) + + template // The accumulate function is the function + void operator ()(Args const & args) // call operator, and it also accepts an + { // argument pack. + this->sum += args[sample]; + } + + result_type result(dont_care) const // The result function will also be passed + { // an argument pack, but we don't use it here, + return this->sum; // so we use "dont_care" as the argument type. + } +private: + Sample sum; +}; + +}}} +---- + + +Much of the above should be pretty self-explanatory, except for the use of argument packs +which may be confusing if you have never used the {parameter} library before. An argument +pack is a cluster of values, each of which can be accessed with a key. So `args[sample]` +extracts from the pack the value associated with the `sample` key. And the cryptic +`args[sample | Sample()]` evaluates to the value associated with the `sample` key if it +exists, or a default-constructed `Sample` if it doesn't. + +The example above demonstrates the most common attributes of an accumulator. There are +other optional member functions that have special meaning. In particular: + +*Optional Accumulator Member Functions* + +[dlist] +`on_drop(Args)`:: +Defines an action to be taken when this accumulator is dropped. See the section on +<>. + +[[accessing_other_accumulators_in_the_set]] +==== Accessing Other Accumulators in the Set + + +Some accumulators depend on other accumulators within the same accumulator set. In those +cases, it is necessary to be able to access those other accumulators. To make this possible, +the {accumulator_set} passes a reference to itself when invoking the member functions of +its contained accumulators. It can be accessed by using the special `accumulator` key with +the argument pack. Consider how we might implement `mean_accumulator`: + +[source,c++] +---- +// Mean == (Sum / Count) +template +struct mean_accumulator : accumulator_base +{ + typedef Sample result_type; + mean_accumulator(dont_care) {} + + template + result_type result(Args const &args) const + { + return sum(args[accumulator]) / count(args[accumulator]); + } +}; +---- + + +`mean` depends on the `sum` and `count` accumulators. (We'll see in the next section how +to specify these dependencies.) The result of the mean accumulator is merely the result of +the sum accumulator divided by the result of the count accumulator. Consider how we write +that: `sum(args[accumulator]) / count(args[accumulator])`. The expression `args[accumulator]` +evaluates to a reference to the {accumulator_set} that contains this `mean_accumulator`. It +also contains the `sum` and `count` accumulators, and we can access their results with the +extractors defined for those features: `sum` and `count`. + +[NOTE] +==== +Accumulators that inherit from {accumulator_base} get an empty `operator ()`, so accumulators +like `mean_accumulator` above need not define one. +==== + +All the member functions that accept an argument pack have access to the enclosing +{accumulator_set} via the `accumulator` key, including the constructor. The accumulators +within the set are constructed in an order determined by their interdependencies. As a +result, it is safe for an accumulator to access one on which it depends during construction. + +[[infix_notation_and_the_numeric_operators_sub_libra]] +==== Infix Notation and the Numeric Operators Sub-Library + + +Although not necessary, it can be a good idea to put your accumulator implementations in +the `boost::accumulators::impl` namespace. This namespace pulls in any operators defined +in the `boost::numeric::operators` namespace with a using directive. The Numeric Operators +Sub-Library defines some additional overloads that will make your accumulators work with +all sorts of data types. + +Consider `mean_accumulator` defined above. It divides the sum of the samples by the count. +The type of the count is `std::size_t`. What if the sample type doesn't define division by +`std::size_t`? That's the case for `std::complex<>`. You might think that if the sample type +is `std::complex<>`, the code would not work, but in fact it does. That's because +Numeric Operators Sub-Library defines an overloaded `operator/` for `std::complex<>` +and `std::size_t`. This operator is defined in the `boost::numeric::operators` namespace and +will be found within the `boost::accumulators::impl` namespace. That's why it's a good idea +to put your accumulators there. + +[[droppable_accumulators]] +==== Droppable Accumulators + + +The term "droppable" refers to an accumulator that can be removed from the {accumulator_set}. +You can request that an accumulator be made droppable by using the {droppable} class template. + +[source,c++] +---- +// calculate sum and count, make sum droppable: +accumulator_set< double, features< tag::count, droppable > > acc; + +// add some data +acc(3.0); +acc(2.0); + +// drop the sum (sum is 5 here) +acc.drop(); + +// add more data +acc(1.0); + +// This will display "3" and "5" +std::cout << count(acc) << ' ' << sum(acc); +---- + + +Any accumulators that get added to an accumulator set in order to satisfy +dependencies on droppable accumulators are themselves droppable. Consider +the following accumulator: + +[source,c++] +---- +// Sum is not droppable. Mean is droppable. Count, brought in to +// satisfy mean's dependencies, is implicitly droppable, too. +accumulator_set< double, features< tag::sum, droppable > > acc; +---- + + +`mean` depends on `sum` and `count`. Since `mean` is droppable, so too is `count`. +However, we have explicitly requested that `sum` be not droppable, so it isn't. Had +we left `tag::sum` out of the above declaration, the `sum` accumulator would have +been implicitly droppable. + +A droppable accumulator is reference counted, and is only really dropped after all the +accumulators that depend on it have been dropped. This can lead to some surprising +behavior in some situations. +[source,c++] +---- + +// calculate sum and mean, make mean droppable. +accumulator_set< double, features< tag::sum, droppable > > acc; + +// add some data +acc(1.0); +acc(2.0); + +// drop the mean. mean's reference count +// drops to 0, so it's really dropped. So +// too, count's reference count drops to 0 +// and is really dropped. +acc.drop(); + +// add more data. Sum continues to accumulate! +acc(3.0); + +// This will display "6 2 3" +std::cout << sum(acc) << ' ' + << count(acc) << ' ' + << mean(acc); +---- + + +Note that at the point at which `mean` is dropped, `sum` is 3, `count` is 2, and +therefore `mean` is 1.5. But since `sum` continues to accumulate even after `mean` +has been dropped, the value of `mean` continues to change. If you want to remember +the value of `mean` at the point it is dropped, you should save its value into +a local variable. + +The following rules more precisely specify how droppable and non-droppable +accumulators behave within an accumulator set. + +* There are two types of accumulators: droppable and non-droppable. + The default is non-droppable. +* For any feature `X`, both `X` and `droppable` satisfy the `X` dependency. +* If feature `X` depends on `Y` and `Z`, then `droppable` depends on + `droppable` and `droppable`. +* All accumulators have `add_ref()` and `drop()` member functions. +* For non-droppable accumulators, `drop()` is a no-op, and `add_ref()` + invokes `add_ref()` on all accumulators corresponding to the features + upon which the current accumulator depends. +* Droppable accumulators have a reference count and define `add_ref()` + and `drop()` to manipulate the reference count. +* For droppable accumulators, `add_ref()` increments the accumulator's + reference count, and also `add_ref()`'s the accumulators corresponding + to the features upon which the current accumulator depends. +* For droppable accumulators, `drop()` decrements the accumulator's + reference count, and also `drop()`'s the accumulators corresponding to + the features upon which the current accumulator depends. +* The accumulator_set constructor walks the list of *user-specified* + features and `add_ref()`'s the accumulator that corresponds to each of + them. (Note: that means that an accumulator that is not user-specified + but in the set merely to satisfy a dependency will be dropped as soon + as all its dependencies have been dropped. Ones that have been user + specified are not dropped until their dependencies have been + dropped *and* the user has explicitly dropped the accumulator.) +* Droppable accumulators check their reference count in their + accumulate member function. If the reference count is 0, the function + is a no-op. +* Users are not allowed to drop a feature that is not user-specified and + marked as droppable. + +And as an optimization: + +* If the user specifies the non-droppable feature `X`, which depends on `Y` + and `Z`, then the accumulators for `Y` and `Z` can be safely made + non-droppable, as well as any accumulators on which they depend. + +[[defining_a_new_feature]] +==== _Defining a New Feature_ + +Once we have implemented an accumulator, we must define a feature for it so +that users can specify the feature when declaring an {accumulator_set}. We +typically put the features into a nested namespace, so that later we can +define an extractor of the same name. All features must satisfy the +<>. Using {depends_on} makes satisfying the concept simple. +Below is an example of a feature definition. + +[source,c++] +---- +namespace boost { namespace accumulators { namespace tag { + +struct mean // Features should inherit from + : depends_on< count, sum > // depends_on<> to specify dependencies +{ + // Define a nested typedef called 'impl' that specifies which + // accumulator implements this feature. + typedef accumulators::impl::mean_accumulator< mpl::_1 > impl; +}; + +}}} +---- + + +The only two things we must do to define the `mean` feature is to specify the +dependencies with {depends_on} and define the nested `impl` typedef. Even features +that have no dependencies should inherit from {depends_on}. The nested `impl` type +must be an {mpl_lambda_expression}. The result of +`mpl::apply< impl, {sample_type}, {weight_type} >::type` must be +be the type of the accumulator that implements this feature. The use of {mpl} +placeholders like `mpl::_1` make it especially easy to make a template such +as `mean_accumulator<>` an {mpl_lambda_expression}. Here, `mpl::_1` will be +replaced with the sample type. Had we used `mpl::_2`, it would have been replaced +with the weight type. + +What about accumulator types that are not templates? If you have a `foo_accumulator` +which is a plain struct and not a template, you could turn it into an +{mpl_lambda_expression} using `mpl::always<>`, like this: + +[source,c++] +---- +// An MPL lambda expression that always evaluates to +// foo_accumulator: +typedef mpl::always< foo_accumulator > impl; +---- + + +If you are ever unsure, or if you are not comfortable with MPL lambda expressions, +you could always define `impl` explicitly: + +[source,c++] +---- +// Same as 'typedef mpl::always< foo_accumulator > impl;' +struct impl +{ + template< typename Sample, typename Weight > + struct apply + { + typedef foo_accumulator type; + }; +}; +---- + + +Here, `impl` is a binary {mpl_metafunction_class}, which is a kind of +{mpl_lambda_expression}. The nested +`apply<>` template is part of the metafunction class protocol and tells MPL how +to build the accumulator type given the sample and weight types. + +All features must also provide a nested `is_weight_accumulator` typedef. It must +be either `mpl::true_` or `mpl::false_`. {depends_on} provides a default of +`mpl::false_` for all features that inherit from it, but that can be overridden +(or hidden, technically speaking) in the derived type. When the feature represents +an accumulation of information about the weights instead of the samples, we +can mark this feature as such with `typedef mpl::true_ is_weight_accumulator;`. +The weight accumulators are made external if the weight type is specified using +the {external} template. + +[[defining_a_new_extractor]] +==== _Defining a New Extractor_ + +Now that we have an accumulator and a feature, the only thing lacking is a way +to get results from the accumulator set. The Accumulators Framework provides the +{extractor} class template to make it simple to define an extractor for your +feature. Here's an extractor for the `mean` feature we defined above: + +[source,c++] +---- +namespace boost { +namespace accumulators { // By convention, we put extractors +namespace extract { // in the 'extract' namespace + +extractor< tag::mean > const mean = {}; // Simply define our extractor with + // our feature tag, like this. +} +using extract::mean; // Pull the extractor into the + // enclosing namespace. +}} +---- + + +Once defined, the `mean` extractor can be used to extract the result of the +`tag::mean` feature from an {accumulator_set}. + +Parameterized features complicate this simple picture. Consider the `moment` +feature, for calculating the `N`-th moment, where `N` is specified as +a template parameter: + +[source,c++] +---- +// An accumulator set for calculating the N-th moment, for N == 2 ... +accumulator_set< double, features< tag::moment<2> > > acc; + +// ... add some data ... + +// Display the 2nd moment ... +std::cout << "2nd moment is " << accumulators::moment<2>(acc) << std::endl; +---- + + +In the expression `accumulators::moment<2>(acc)`, what is `moment`? It cannot be an object -- +the syntax of C++ will not allow it. Clearly, if we want to provide this syntax, +we must make `moment` a function template. Here's what the definition of the +`moment` extractor looks like: + +[source,c++] +---- +namespace boost { +namespace accumulators { // By convention, we put extractors +namespace extract { // in the 'extract' namespace + +template +typename mpl::apply >::type::result_type +moment(AccumulatorSet const &acc) +{ + return extract_result >(acc); +} + +} +using extract::moment; // Pull the extractor into the + // enclosing namespace. +}} +---- + + +The return type deserves some explanation. Every {accumulator_set} type +is actually a unary {mpl_metafunction_class}. When you `mpl::apply<>` an +{accumulator_set} and +a feature, the result is the type of the accumulator within the set that +implements that feature. And every accumulator provides a nested `result_type` +typedef that tells what its return type is. The extractor simply delegates +its work to the {extract_result} function. + +[[controlling_dependencies]] +==== _Controlling Dependencies_ + +The feature-based dependency resolution of the Accumulators Framework is +designed to allow multiple different implementation strategies for each +feature. For instance, two different accumulators may calculate the same +quantity with different rounding modes, or using different algorithms with +different size/speed tradeoffs. Other accumulators that depend on that +quantity shouldn't care how it's calculated. The Accumulators Framework +handles this by allowing several different accumulators satisfy the same +feature. + +*Aliasing feature dependencies with `feature_of<>`* + +Imagine that you would like to implement the hypothetical _fubar_ statistic, +and that you know two ways to calculate fubar on a bunch of samples: an +accurate but slow calculation and an approximate but fast calculation. You +might opt to make the accurate calculation the default, so you implement +two accumulators and call them `impl::fubar_impl` and `impl::fast_fubar_impl`. +You would also define the `tag::fubar` and `tag::fast_fubar` features as described +<>. +Now, you would like to inform the Accumulators Framework that these two features +are the same from the point of view of dependency resolution. You can do that +with {feature_of}, as follows: + +[source,c++] +---- +namespace boost { namespace accumulators +{ + // For the purposes of feature-based dependency resolution, + // fast_fubar provides the same feature as fubar + template<> + struct feature_of + : feature_of + { + }; +}} +---- + + +The above code instructs the Accumulators Framework that, if another accumulator +in the set depends on the `tag::fubar` feature, the `tag::fast_fubar` feature +is an acceptable substitute. + +*Registering feature variants with `as_feature<>`* + +You may have noticed that some feature variants in the Accumulators Framework can be +specified with a nicer syntax. For instance, instead of `tag::mean` and `tag::immediate_mean` +you can specify them with `tag::mean(lazy)` and `tag::mean(immediate)` respectively. +These are merely aliases, but the syntax makes the relationship between the two clearer. +You can create these feature aliases with the {as_feature} trait. Given the fubar example +above, you might decide to alias `tag::fubar(accurate)` with `tag::fubar` and +`tag::fubar(fast)` with `tag::fast_fubar`. You would do that as follows: + +[source,c++] +---- +namespace boost { namespace accumulators +{ + struct fast {}; // OK to leave these tags empty + struct accurate {}; + + template<> + struct as_feature + { + typedef tag::fubar type; + }; + + template<> + struct as_feature + { + typedef tag::fast_fubar type; + }; +}} +---- + + +Once you have done this, users of your fubar accumulator can request the `tag::fubar(fast)` +and `tag::fubar(accurate)` features when defining their `accumulator_set`s and get the correct +accumulator. + +[[operators_ex]] +==== _Specializing Numeric Operators_ + +This section describes how to adapt third-party numeric types to work with the Accumulator +Framework. + +Rather than relying on the built-in operators, the Accumulators Framework relies on functions +and operator overloads defined in the +<> for many of its numeric +operations. This is so that it +is possible to assign non-standard meanings to arithmetic operations. For instance, when +calculating an average by dividing two integers, the standard integer division behavior +would be mathematically incorrect for most statistical quantities. So rather than use `x / y`, +the Accumulators Framework uses `numeric::fdiv(x, y)`, which does floating-point division +even if both `x` and `y` are integers. + +Another example where the Numeric Operators Sub-Library is useful is when a type does not +define the operator overloads required to use it for some statistical calculations. For instance, +`std::vector<>` does not overload any arithmetic operators, yet it may be useful to use +`std::vector<>` as a sample or variate type. The Numeric Operators Sub-Library +defines the necessary operator overloads in the `boost::numeric::operators` namespace, +which is brought into scope by the Accumulators Framework with a using directive. + +*Numeric Function Objects and Tag Dispatching* + +How are the numeric function object defined by the Numeric Operators Sub-Library made +to work with types such as `std::vector<>`? The free functions in the `boost::numeric` namespace +are implemented in terms of the function objects in the `boost::numeric::functional` namespace, +so to make `boost::numeric::fdiv()` do something sensible with a `std::vector<>`, for instance, +we'll need to partially specialize the `boost::numeric::functional::fdiv<>` function object. + +The functional objects make use of a technique known as +link:http://www.boost.org/community/generic_programming.html#tag_dispatching[tag dispatching] to +select the proper implementation for the given operands. It works as follows: + +[source,c++] +---- +namespace boost { namespace numeric { namespace functional +{ + // Metafunction for looking up the tag associated with + // a given numeric type T. + template + struct tag + { + // by default, all types have void as a tag type + typedef void type; + }; + + // Forward declaration looks up the tag types of each operand + template< + typename Left + , typename Right + , typename LeftTag = typename tag::type + , typename RightTag = typename tag::type + > + struct fdiv; +}}} + +---- + +If you have some user-defined type `MyDouble` for which you would like to customize the behavior +of `numeric::fdiv()`, you would specialize `numeric::functional::fdiv<>` by +first defining a tag type, as shown below: + +[source,c++] +---- +namespace boost { namespace numeric { namespace functional +{ + // Tag type for MyDouble + struct MyDoubleTag {}; + + // Specialize tag<> for MyDouble. + // This only needs to be done once. + template<> + struct tag + { + typedef MyDoubleTag type; + }; + + // Specify how to divide a MyDouble by an integral count + template + struct fdiv + { + // Define the type of the result + typedef ... result_type; + + result_type operator()(Left & left, Right & right) const + { + return ...; + } + }; +}}} + +---- + +Once you have done this, `numeric::fdiv()` will use your specialization +of `numeric::functional::fdiv<>` when the first argument is a `MyDouble` +object. All of the function objects in the Numeric Operators Sub-Library can +be customized in a similar fashion. + +[[concepts]] +==== Concepts + +[[accumulator_concept]] +===== Accumulator Concept + + +In the following table, `Acc` is the type of an accumulator, `acc` and `acc2` are objects of type +`Acc`, and `args` is the name of an argument pack from the {parameter} library. + +.Accumulator Requirements +|=== +|Expression |Return type |Assertion / Note / Pre- / Post-condition + +|`Acc::result_type` +|_implementation defined_ +|The type returned by `Acc::result()`. + +|`Acc acc(args)` +|none +|Construct from an argument pack. + +|`Acc acc(acc2)` +|none +|Post: `acc.result(args)` is equivalent to `acc2.result(args)`. + +|`acc(args)` +|_unspecified_ +| + +|`acc.on_drop(args)` +|_unspecified_ +| + +|`acc.result(args)` +|`Acc::result_type` +| +|=== + + +[[feature_concept]] +===== Feature Concept + + +In the following table, `F` is the type of a feature and `S` is some scalar type. + +.Feature Requirements +|=== +|Expression |Return type |Assertion / Note / Pre- / Post-condition + +|`F::dependencies` +|_unspecified_ +|An MPL sequence of other features on which `F` depends. + +|`F::is_weight_accumulator` +|`mpl::true_` or `mpl::false_` +|`mpl::true_` if the accumulator for this feature should be made external when the +weight type for the accumulator set is `external`, `mpl::false_` otherwise. + +|`F::impl` +|_unspecified_ +|An {mpl_lambda_expression} that returns the type of the accumulator that implements +this feature when passed a sample type and a weight type. +|=== diff --git a/doc/reference.adoc.jinja2 b/doc/reference.adoc.jinja2 new file mode 100644 index 00000000..c8f033d4 --- /dev/null +++ b/doc/reference.adoc.jinja2 @@ -0,0 +1,1354 @@ +{%- macro write_entity(entity) -%} + {% if entity.access != Access.private or Config.include_private -%} + {%- if entity is Namespace -%} + {{ write_namespace(entity) }} + {%- elif entity is Type -%} + {{ write_type(entity) }} + {%- elif entity is OverloadSet -%} + {{ write_overload_set(entity) }} + {%- elif entity is Variable -%} + {{ write_variable(entity) }} + {%- endif -%} + {%- endif -%} +{%- endmacro -%} + + +{%- macro write_namespace(entity) -%} + {%- for m in entity.members.values() | select("Type") | sort -%} + {{ write_type(m) }} + {%- endfor -%} + + {%- for m in entity.members.values() | select("OverloadSet") | sort -%} + {{ write_overload_set(m) }} + {%- endfor -%} + + {%- for m in entity.members.values() | select("Variable") | sort -%} + {{ write_variable(m) }} + {%- endfor -%} +{%- endmacro -%} + + +{%- macro write_type(entity) %} +{% call(segment) section(entity) %} +{%- if segment == "summary" -%} + +{%- if entity is Scope -%} +{#- public members -#} +{{ simple_summary_table( + entity.members.values() + | select("Type") + | selectattr("access", "eq", Access.public), + "Types") }} +{{ function_summary_table( + entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.public) + | selectattr("kind", "eq", FunctionKind.nonstatic), + "Member Functions") }} {#- -#} +{{ function_summary_table( + entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.public) + | selectattr("kind", "eq", FunctionKind.static), + "Static Member Functions") }} +{{ simple_summary_table( + entity.members.values() + | select("Variable") + | selectattr("access", "eq", Access.public) + | rejectattr("is_static"), + "Data Members") }} +{{ simple_summary_table( + entity.members.values() + | select("Variable") + | selectattr("access", "eq", Access.public) + | selectattr("is_static") + | reject("in", entity.objects), + "Static Data Members") }} +{{ function_summary_table( + entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.public) + | selectattr("kind", "eq", FunctionKind.friend), + "Friends") }} +{{ function_summary_table( + entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.public) + | selectattr("kind", "eq", FunctionKind.free), + "Related Non-member Functions") }} +{#- protected members -#} +{{ simple_summary_table( + entity.members.values() + | select("Type") + | selectattr("access", "eq", Access.protected), + "Protected Types") }} {#- -#} +{{ function_summary_table( + entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.protected) + | selectattr("kind", "eq", FunctionKind.nonstatic), + "Protected Member Functions") }} {#- -#} +{{ function_summary_table( + entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.protected) + | selectattr("kind", "eq", FunctionKind.static), + "Protected Static Member Functions") }} {#- -#} +{{ simple_summary_table( + entity.members.values() + | select("Variable") + | selectattr("access", "eq", Access.protected) + | rejectattr("is_static"), + "Protected Data Members") }} {#- -#} +{{ simple_summary_table( + entity.members.values() + | select("Variable") + | selectattr("access", "eq", Access.protected) + | selectattr("is_static") + | reject("in", entity.objects), + "Protected Static Members") }} {#- -#} +{#- private members -#} +{%- if Config.get("include_private") %} +{{ simple_summary_table( + entity.members.values() + | select("Type") + | selectattr("access", "eq", Access.private), + "Private Types") }} {#- -#} +{{ function_summary_table( + entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.private) + | selectattr("kind", "eq", FunctionKind.nonetatic), + "Private Member Functions") }} {#- -#} +{{ function_summary_table( + entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.private) + | selectattr("kind", "eq", FunctionKind.static), + "Private Static Member Functions") }} {#- -#} +{{ simple_summary_table( + entity.members.values() + | select("Variable") + | selectattr("access", "eq", Access.private) + | rejectattr("is_static"), + "Private Data Members") }} {#- -#} +{{ simple_summary_table( + entity.members.values() + | select("Variable") + | selectattr("access", "eq", Access.private) + | selectattr("is_static") + | reject("in", entity.objects), + "Private Static Members") }} {#- -#} +{%- endif -%} +{%- endif -%} + +{% if entity is Enum -%} +{%- call(member) summary_table(entity.objects, "Values") -%} + |``{{ code_escape(member.name) }}`` + |{{ description(member.brief) | trim }} +{%- endcall -%} +{%- else -%} +{{ simple_summary_table(entity.objects, "Values") }} +{%- endif -%} + +{%- elif segment == "members" -%} + +{%- if entity is Scope -%} +{#- public member subsections #} +:leveloffset: +1 + +{% for member in entity.members.values() + | select("Type") + | selectattr("access", "eq", Access.public) -%} +{{ write_entity(member) }} +{% endfor %} +{%- for member in entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.public) + | selectattr("kind", "eq", FunctionKind.nonstatic) -%} +{{ write_entity(member) }} +{% endfor %} +{%- for member in entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.public) + | selectattr("kind", "eq", FunctionKind.static) -%} +{{ write_entity(member) }} +{% endfor %} +{%- for member in entity.members.values() + | select("Variable") + | selectattr("access", "eq", Access.public) + | rejectattr("is_static") -%} +{{ write_entity(member) }} +{% endfor %} +{%- for member in entity.members.values() + | select("Variable") + | selectattr("access", "eq", Access.public) + | selectattr("is_static") + | reject("in", entity.objects) -%} +{{ write_entity(member) }} +{% endfor %} +{%- for member in entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.public) + | selectattr("kind", "eq", FunctionKind.friend) -%} +{{ write_entity(member) }} +{% endfor %} +{%- for member in entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.public) + | selectattr("kind", "eq", FunctionKind.free) -%} +{{ write_entity(member) }} +{% endfor %} +{#- protected member subsections -#} +{%- for member in entity.members.values() + | select("Type") + | selectattr("access", "eq", Access.protected) -%} +{{ write_entity(member) }} +{% endfor %} +{%- for member in entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.protected) + | selectattr("kind", "eq", FunctionKind.nonstatic) -%} +{{ write_entity(member) }} +{% endfor %} +{%- for member in entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.protected) + | selectattr("kind", "eq", FunctionKind.static) -%} +{{ write_entity(member) }} +{% endfor %} +{%- for member in entity.members.values() + | select("Variable") + | selectattr("access", "eq", Access.protected) + | rejectattr("is_static") -%} +{{ write_entity(member) }} +{% endfor %} +{%- for member in entity.members.values() + | select("Variable") + | selectattr("access", "eq", Access.protected) + | selectattr("is_static") + | reject("in", entity.objects) -%} +{{ write_entity(member) }} +{% endfor %} +{#- private members -#} +{%- if Config.get("include_private") %} +{%- for member in entity.members.values() + | select("Type") + | selectattr("access", "eq", Access.private) -%} +{{ write_entity(member) }} +{% endfor %} +{%- for member in entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.private) + | selectattr("kind", "eq", FunctionKind.nonstatic) -%} +{{ write_entity(member) }} +{% endfor %} +{%- for member in entity.members.values() + | select("OverloadSet") + | selectattr("access", "eq", Access.private) + | selectattr("kind", "eq", FunctionKind.static) -%} +{{ write_entity(member) }} +{% endfor %} +{%- for member in entity.members.values() + | select("Variable") + | selectattr("access", "eq", Access.private) + | rejectattr("is_static") -%} +{{ write_entity(member) }} +{% endfor %} +{%- for member in entity.members.values() + | select("Variable") + | selectattr("access", "eq", Access.private) + | selectattr("is_static") + | reject("in", entity.objects) -%} +{{ write_entity(member) }} +{% endfor %} +{% endif -%} + +:leveloffset: -1 +{%- endif -%} + +{%- endif -%} + +{% endcall %} +{% endmacro -%} + + +{%- macro write_overload_set(oset) -%} +[id={{ anchor(oset[0]) }} +{%- if oset.location -%} + ,source-location="include/{{oset.location.file}}" +{%- endif -%} +] += ``{{ abridged_fqn(oset[0]) }}`` +{{ description(oset[0].brief) }} + +{{ heading("Synopsis") }} +{% if oset.location and (oset.scope is Namespace or oset.is_friend) -%} + Defined in header {{ source_header(oset.location.file) }}. +{%- endif %} + +[source,c++,subs="+attributes"] +---- +{{ overload_set_declaration(oset) }} +---- + +{% if oset[0].description -%} + {{ oset_description(oset, title="Description") }} +{%- endif %} + +{% if Config.get("convenience_header") + and oset.location + and (oset.scope is Namespace + or (oset.kind in (FunctionKind.free, FunctionKind.friend))) -%} +Convenience header {{ source_header(Config.convenience_header) }} +{%- endif %} + +{% endmacro -%} + + +{%- macro write_variable(entity) -%} +{%- call(segment) section(entity) %}{% endcall -%} +{%- endmacro -%} + + +{%- macro section(entity) %} +[id={{ anchor(entity) }} +{%- if entity.location -%} + ,source-location="include/{{entity.location.file}}" +{%- endif -%} +] += ``{{ abridged_fqn(entity) }}`` +{{ description(entity.brief) }} + +{{ heading("Synopsis") }} +{% if entity.location + and (entity.scope is Namespace + or (entity is Function and entity.is_friend)) -%} + Defined in header {{ source_header(entity.location.file) }}. +{%- endif %} + +[source,c++,subs="+attributes"] +---- +{{ entity_declaration(entity) }} +---- + +{{ caller("summary") }} + +{% if entity.description -%} + {{ description(entity.description, title="Description") }} +{%- endif %} + +{% if entity.location + and (entity.scope is Namespace + or (entity is Function + and entity.kind in (FunctionKind.free, FunctionKind.friend))) -%} +Convenience header {{ source_header(Config.convenience_header) }}. +{%- endif %} +{{ caller("members") }} +{% endmacro -%} + + +{% macro description(parts, nesting=1, title=None) -%} +{%- for part in parts -%} +{%- if loop.first and title + and part is not Section and part is not ParameterList + -%} +{{ heading(title) }} +{% endif -%} + +{%- if part is Paragraph -%} + {%- if (part | length) == 1 and part[0] is Formula and part[0].display -%} +{{ formula_block(part[0]) }} + {%- else -%} + {{ phrase(part) }}{{ "\n\n" }} + {%- endif -%} +{%- elif part is List -%} +{{ itemised(part, nesting) }} +{%- elif part is Section -%} +{{ subsection(part) }} +{%- elif part is CodeBlock %} +[source] +---- +{% for line in part -%} +{{line}} +{% endfor -%} +---- +{% elif part is ParameterList -%} +{{ parameter_list(part) }} +{% elif part is Table -%} +{{ table(part) }} +{%- else -%} +{{ part.unhandled_type() }} +{%- endif -%} +{%- endfor -%} +{%- endmacro -%} + + +{%- macro oset_description(oset, nesting=1, title=None) -%} +{%- set ns = namespace(done_parameters=False) -%} +{%- for part in oset[0].description -%} +{%- if loop.first and title + and part is not Section and part is not ParameterList + -%} +{{ heading(title) }} +{% endif -%} + + +{%- if part is Paragraph -%} + {%- if (part | length) == 1 and part[0] is Formula and part[0].display -%} +{{ formula_block(part[0]) }} + {%- else -%} + {{ phrase(part) }}{{ "\n\n" }} + {%- endif -%} +{%- elif part is List -%} +{{ itemised(part, nesting) }} +{%- elif part is Section -%} + {%- if part.kind == "see" -%} + {%- if not ns.done_parameters -%} + {%- set ns.done_parameters = true -%} + {{ oset_all_parameter_lists(oset) }} + {%- endif -%} + {%- endif -%} + {%- if not part.kind == "return" %}{{ subsection(part) }}{% endif -%} +{%- elif part is CodeBlock %} +[source] +---- +{% for line in part -%} +{{line}} +{% endfor -%} +---- +{% elif part is ParameterList -%} +{%- if not ns.done_parameters -%} +{%- set ns.done_parameters = true -%} +{{ oset_all_parameter_lists(oset) }} +{%- endif -%} +{%- elif part is Table -%} +{{ table(part) }} +{%- else -%} +{{ part.unhandled_type() }} +{%- endif -%} +{%- endfor -%} +{%- if not ns.done_parameters -%} + {{ oset_all_parameter_lists(oset) }} +{%- endif -%} +{%- endmacro -%} + + +{%- macro oset_all_parameter_lists(oset) -%} +{%- for kind in [ + ParameterList.TemplateParameters, + ParameterList.ReturnValues, + ParameterList.Parameters, + ParameterList.Exceptions] -%} +{{ oset_parameter_list(oset, kind) }} +{% endfor -%} +{%- endmacro -%} + + +{%- macro itemised(lst, nesting) -%} + {%- for item in lst -%} + {%- for mark in range(0, nesting) -%} + {%- if lst.is_ordered -%} + . + {%- else -%} + * + {%- endif %} + {%- endfor %} {{ description(item, nesting + 1) }} + {%- endfor -%} +{%- endmacro -%} + + +{%- macro subsection(sub) -%} +{%- if sub.kind in ["note", "warning", "attention"] -%} +{{ admonition(sub) }} +{% else -%} +{{ heading("") }} +{%- if sub.title %}{{ phrase(sub.title) }} +{%- elif sub.kind -%} + {%- if sub.kind == "see" %}See Also + {%- elif sub.kind == "return" %}Return Value + {%- elif sub.kind == "author" %}Author + {%- elif sub.kind == "authors" %}Authors + {%- elif sub.kind == "version" %}Version + {%- elif sub.kind == "since" %}Since + {%- elif sub.kind == "date" %}Date + {%- elif sub.kind == "pre" %}Preconditions + {%- elif sub.kind == "post" %}Postconditions + {%- elif sub.kind == "copyright" %}Copyright + {%- elif sub.kind == "invariant" %}Invariants + {%- elif sub.kind == "remark" %}Remarks + {%- elif sub.kind == "par" %}Paragraph + {%- elif sub.kind == "rcs"%}RCS + {%- else %}Unknown + {%- endif -%} +{%- endif %} +{{ description(sub) }} +{%- endif -%} +{%- endmacro -%} + + +{%- macro admonition(sub) -%} +[ +{%- if sub.kind == "warning" %}WARNING +{%- elif sub.kind == "note" %}NOTE +{%- elif sub.kind == "attention" %}IMPORTANT +{%- else %}{{ sub.kind.upper() }} +{%- endif -%} +] +==== +{{ description(sub) }} +==== +{% endmacro -%} + + +{%- macro table(part) -%} +{% if part.caption %}.{{ phrase(part.caption) }}{% endif %} +|=== +{%- for row in part %} +{% for cell in row -%} + a|{{ description(cell) }} +{%- endfor %} +{% endfor %} +|=== +{% endmacro -%} + + +{%- macro parameter_list(part) -%} +{%- set ns = namespace(title="", col="") -%} +{%- if part.kind == ParameterList.Parameters -%} + {%- set ns.title = "Parameters" -%} + {%- set ns.col1 = "Name" -%} + {%- set ns.col2 = "Description" -%} +{%- elif part.kind == ParameterList.TemplateParameters -%} + {%- set ns.title = "Template Parameters" -%} + {%- set ns.col1 = "Type" -%} + {%- set ns.col2 = "Description" -%} +{%- elif part.kind == ParameterList.Exceptions -%} + {%- set ns.title = "Exceptions" -%} + {%- set ns.col1 = "Type" -%} + {%- set ns.col2 = "Thrown On" -%} +{%- elif part.kind == ParameterList.ReturnValues -%} + {%- set ns.title = "Return Values" -%} + {%- set ns.col1 = "Type" -%} + {%- set ns.col2 = "Description" -%} +{%- endif -%} +{% call(param_block) summary_table(part, ns.title, cols=[ns.col1, ns.col2]) -%} +{%- set sep = joiner(", ") -%} +| +{%- for item in param_block -%} +{{ sep() }}`` +{%- if item.type %}{{ phrase(item.type) }} {% endif -%} +{{ phrase(item.name) }}`` +{%- endfor %} +|{{ description(param_block.description) }} +{% endcall -%} +{%- endmacro -%} + + +{%- macro oset_parameter_list(oset, kind) -%} +{%- set ns = namespace(title="", col="") -%} +{%- if kind == ParameterList.Parameters -%} + {%- set ns.title = "Parameters" -%} + {%- set ns.col1 = "Name" -%} + {%- set ns.col2 = "Description" -%} + {%- set ns.duplicates = False -%} +{%- elif kind == ParameterList.TemplateParameters -%} + {%- set ns.title = "Template Parameters" -%} + {%- set ns.col1 = "Type" -%} + {%- set ns.col2 = "Description" -%} + {%- set ns.duplicates = False -%} +{%- elif kind == ParameterList.Exceptions -%} + {%- set ns.title = "Exceptions" -%} + {%- set ns.col1 = "Type" -%} + {%- set ns.col2 = "Thrown On" -%} + {%- set ns.duplicates = True -%} +{%- elif kind == ParameterList.ReturnValues -%} + {%- set ns.title = "Return Values" -%} + {%- set ns.col1 = "Type" -%} + {%- set ns.col2 = "Description" -%} + {%- set ns.duplicates = True -%} +{%- endif -%} + +{%- set params = [] -%} +{%- for func in oset -%} + {%- for part in func.description -%} + {%- if part is ParameterList and part.kind == kind -%} + {%- for param in part -%} + {%- set name = param | map(attribute="name") + | map(attribute="text") | join -%} + {%- set type = param | map(attribute="type") + | map(attribute="text") | join -%} + {%- set names = params | map("map", attribute="name") + | map("map", attribute="text") | map("join") -%} + {%- set types = params | map("map", attribute="type") + | map("map", attribute="text") | map("join") -%} + {%- if ns.duplicates or (name not in names) or (type not in types) -%} + {%- set ___ = params.append(param) -%} + {%- endif -%} + {%- endfor -%} + {%- endif -%} + {%- endfor -%} +{%- endfor -%} + +{%- if kind == ParameterList.ReturnValues -%} +{%- set ns.did_return_values = False -%} +{%- for func in oset -%} + {%- for part in func.description -%} + {%- if not ns.did_return_values + and part is Section + and part.kind == "return" -%} + {%- set ns.did_return_values = True -%} + {{ subsection(part) }} + {%- endif -%} + {%- endfor -%} +{%- endfor -%} +{%- endif -%} + +{% call(param_block) summary_table(params, ns.title, cols=[ns.col1, ns.col2]) -%} +{%- set sep = joiner(", ") -%} +| +{%- for item in param_block -%} +{{ sep() }}`` +{%- if item.type %}{{ phrase(item.type,in_code="line") }} {% endif -%} +{{ phrase(item.name,in_code="line") }}`` +{%- endfor %} +|{{ description(param_block.description) }} +{% endcall -%} +{%- endmacro -%} + + +{%- macro phrase(para, in_code=False, in_link=False) -%} +{%- for part in para -%}{{ phrase_part(part, in_code=in_code, in_link=False) }}{%- endfor -%} +{%- endmacro -%} + + +{% macro formula_block(formula) %} +[stem] +++++ +{{ formula.latex }} +++++ + +{% endmacro %} + + +{%- macro phrase_part(part, in_code=False, in_link=False) -%} + {%- if part is string -%} + {{ text_helper(part, in_code=in_code, in_link=False) }} + {%- elif part is EmDash -%} + -- + {%- elif part is EnDash -%} + {{ part.text }} + {%- elif part is Formula -%} + {%- if part.display -%} +{{ formula_block(part) }}{{ "\n" }} + {%- else -%} +stem:[{{ part.latex }}] + {%- endif -%} + {%- elif part is Monospaced -%} + ``{{ phrase(part, in_code="line", in_link=in_link) }}`` + {%- elif part is Emphasised -%} + __{{ phrase(part, in_code=in_code, in_link=in_link) }}__ + {%- elif part is Strong -%} + **{{ phrase(part, in_code=in_code, in_link=in_link) }}** + {%- elif part is EntityRef -%} + {%- if in_code == "block" -%} + {{ abridged_fqn(part.entity) }} + {%- else -%} + {%- set is_external = Config.get("external_marker") + and (part.entity.brief | map(attribute="text") | join | trim) + == Config.get("external_marker") -%} + {%- if is_external -%} + link: + {%- for part in part.entity.description -%} + {%- if part is Section and part.kind == Section.See -%} + {{ part | map(attribute="text") | join | trim }} + {%- endif -%} + {%- endfor -%} + [ + {%- if in_code -%} + {{ abridged_fqn(part.entity) }} + {%- else -%} + ``{{ phrase(part, in_code="line", in_link=True) }}`` + {%- endif -%} + ] + {%- else -%} + link:#++{{ link(part.entity) }}++[ + {%- if in_code -%} + {{ abridged_fqn(part.entity) }} + {%- else -%} + ``{{ phrase(part, in_code="line", in_link=True) }}`` + {%- endif -%} + ] + {%- endif -%} + {%- endif -%} + {%- elif part is UrlLink -%} + link:pass:a[{{ escape(part.url) }}][{{ phrase(part, in_code=in_code, in_link=True) }}] + {%- elif part is Linebreak -%}{{ "\n\n" }} + {%- elif part is Phrase -%} + {{ phrase(part, in_code=in_code, in_link=in_link) }} + {%- else -%} + {{ part.unhandled_type() }} + {%- endif -%} +{%- endmacro -%} + + +{%- macro link(entity) -%} + {%- if entity is Enumerator -%} + {{ link(entity.enum) }} + {%- else -%} + {{ anchor(entity) }} + {%- endif -%} +{%- endmacro -%} + + +{%- macro anchor(entity) -%} + {%- set ns = namespace(path=entity.path) -%} + {%- if entity.fully_qualified_name.startswith(Config.default_namespace) -%} + {%- set ns.path = ns.path[2:] -%} + {%- endif -%} + {{ Config.link_prefix }} + {%- set sep = joiner("_") -%} + {%- for segment in ns.path -%} + {{ sep() }}{{ sanitize_path_segment(segment.name) }} + {%- endfor -%} + {%- if entity.scope and not entity.scope is Namespace -%} + {%- if (entity is Function or entity is OverloadSet) and entity.is_friend -%}_fr{%- endif -%} + {%- if (entity is Function or entity is OverloadSet) and entity.is_free -%}_fe{%- endif -%} + {%- endif -%} +{%- endmacro -%} + + +{%- macro sanitize_path_segment(segment) -%} + {{ segment.replace("[", "__lb_") + .replace("]", "_rb_") + .replace("(", "_lp_") + .replace(")", "_rp_") + .replace("<=>", "_spshp_") + .replace("operator>", "operator__gt_") + .replace("operator~", "operator_bnot_") + .replace("->", "__arrow_") + .replace("=", "_eq_") + .replace("!", "__not_") + .replace("+", "_plus_") + .replace("-", "_minus_") + .replace("&", "_and_") + .replace("|", "_or_") + .replace("^", "_xor_") + .replace("*", "__star_") + .replace("/", "_slash_") + .replace("%", "_mod_") + .replace("<", "_lt_") + .replace(">", "_gt_") + .replace("~", "_dtor_") + .replace(",", "_comma_") + .replace("::", "_") + .replace(":", "_") + .replace(" ", "_") }} +{%- endmacro -%} + + +{%- macro abridged_fqn(entity) -%} + {%- set ns = namespace(scope=entity.scope) -%} + {%- if entity is Function + and (entity.is_free or entity.is_friend) + and entity.scope + and entity.scope is not Namespace -%} {#- friend or related -#} + {%- set ns.scope = ns.scope.scope -%} + {%- endif -%} + {%- set s = ns.scope.fully_qualified_name + '::' + entity.name -%} + + {%- set prefix = Config.default_namespace + "::" -%} + {%- if s.startswith(prefix) -%} + {{ code_escape(s[prefix | length:]) }} + {%- else -%} + {{ code_escape(s) }} + {%- endif -%} +{%- endmacro -%} + + +{%- macro entity_declaration(entity) -%} +{{ template_parameters(entity) }} +{%- if entity is Variable -%} +{%- set sp = joiner(" ") -%} +{%- if entity.is_static %}{{ sp() }}static{% endif -%} +{%- if entity.is_constexpr %}{{ sp() }}constexpr{% endif %} +{%- if sp() %} +{% endif -%} +{{ phrase(entity.type, in_code="block") }} +{%- if entity.args %}(*{% else %} {% endif -%} +{%- endif -%} +{%- if entity is Type %}{{ entity.declarator }} {% endif -%} +{{ entity.name }} +{%- if entity is Variable and entity.args -%} +){{ phrase(entity.args, in_code="block") }} +{%- endif -%} +{%- if entity is Class -%} +{%- set ns = namespace(sep=':') -%} +{% for entry in entity.bases %} + {%- if entry.access != Access.private or Config.include_private %} + {{ ns.sep }} {{ entry.access }} {% set ns.sep = ',' -%} + {%- if entry.is_virtual %}virtual {% endif -%} + {{ phrase(entry.base, in_code="block") }} + {%- endif -%} +{%- endfor -%} +{%- endif -%} +{%- if entity is Enum and entity.underlying_type %} + : {{ phrase(entity.underlying_type, in_code="block") }} +{%- endif -%} +{%- if entity is TypeAlias %} = {{ phrase(entity.aliased, in_code="block") }}{% endif -%} +{%- if entity is Variable and entity.value %} {{ phrase(entity.value, in_code="block") }}{% endif -%} +; +{%- endmacro -%} + + +{%- macro overload_set_declaration(oset) -%} +{%- set sep = joiner("\n") -%} +{% for func in oset -%} +{{ sep() }}{{ function_declaration(func) }} +{%- if (oset | length) > 1 %} // <{{ loop.index }}>{% endif %} +{% endfor -%} +{% endmacro -%} + + +{%- macro function_declaration(entity) -%} +{{ template_parameters(entity) }} +{%- set sp = joiner(" ") -%} +{%- if entity.is_explicit %}{{ sp() }}explicit{% endif -%} +{%- if entity.is_static %}{{ sp() }}static{% endif -%} +{%- if entity.is_constexpr %}{{ sp() }}constexpr{% endif %} +{%- set ret = phrase(entity.return_type, in_code="block") -%} +{%- if ret %}{{ sp() }}{{ ret }}{% endif -%} +{%- if sp() %} +{% endif -%} +{{ block_code_escape(entity.name) }}( +{%- for param in entity.parameters %} + {{ phrase(param.type, in_code="block") }} + {%- if param.array %} (&{% endif -%} + {%- if param.name -%} + {%- if not param.array %} {% endif -%} + {{ param.name }} + {%- endif -%} + {%- if param.array %}) {{ phrase(param.array, in_code="block") }}{% endif -%} + {%- if param.default_value %} = {{ phrase(param.default_value, in_code="block") }}{% endif -%} + + {%- if not loop.last %},{% endif -%} +{%- endfor -%} +) +{%- if entity.refqual or entity.is_const -%} + {{ " " }} + {%- if entity.is_const %}const{% endif -%} + {%- if "lvalue" == entity.refqual %}& + {%- elif "rvalue" == entity.refqual %}&& + {%- endif -%} +{%- endif -%} +{%- if entity.is_noexcept and not entity.is_destructor %} noexcept +{%- if entity.noexcept_condition -%} + ({{ entity.noexcept_condition }}) +{%- endif -%} +{%- endif -%} +{%- if not entity.is_noexcept and entity.is_destructor %} noexcept(false){% endif -%} +{%- if entity.is_deleted %} = delete +{%- elif entity.is_defaulted and Config.get("show_defaulted") %} = default +{%- endif -%} +; +{%- endmacro %} + + +{%- macro template_parameters(entity) -%} +{%- if entity.template_parameters or entity.is_specialization -%}template<{%- endif -%} +{%- for tparam in entity.template_parameters %} + {{ phrase(tparam.type, in_code="block") }} + {%- if tparam.array %} (&{% endif -%} + {%- if tparam.name -%} + {%- if not tparam.array %} {% endif -%} + {{ phrase_part(tparam.name, in_code="block") }} + {%- endif -%} + {%- if tparam.array %}) {{ phrase(tparam.array, in_code="block") }}{% endif -%} + {%- if tparam.default_value %} = {{ phrase(tparam.default_value, in_code="block") }}{% endif -%} + +{%- if loop.last -%} +> +{% else -%} +, +{%- endif -%} + +{%- else -%} +{%- if entity.is_specialization -%} +> +{% endif -%} +{%- endfor %} +{%- endmacro -%} + + +{%- macro simple_summary_table(sequence, title) -%} +{%- call(member) summary_table(sequence | sort, title) -%} +|link:#++{{ link(member) }}++[``{{ code_escape(member.name) }}``] +|{{ description(member.brief) | trim }} +{%- endcall -%} +{%- endmacro -%} + + +{%- macro function_summary_table(sequence, title) -%} +{%- call(member) summary_table( + sequence | sort, title, cols=["Name", "Description"]) -%} + |link:#++{{ link(member) }}++[``{{ code_escape(member.name) }}``] + {%- if member.is_constructor %}{nbsp}[.silver]##[constructor]##{% endif -%} + {%- if member.is_destructor %}{nbsp}[.silver]##[destructor]##{% endif -%} + |{{ description(member[0].brief) | trim }} +{% endcall -%} +{%- endmacro -%} + + + +{%- macro summary_table(sequence, title, cols=["Name", "Description"], frame="all") -%} +{%- for row in sequence -%} +{% if loop.first -%} +{{ heading(title) }} +|=== +{% for col in cols %}|{{col}}{% endfor %} + +{% endif -%} + {{ caller(row) }} +{% if loop.last %} +|=== +{% endif %} +{%- endfor -%} +{%- endmacro -%} + + +{% macro heading(title) -%} +[discrete] +=== {{ escape(title) }} +{%- endmacro -%} + + +{%- macro source_header(path) -%} +link:https://github.com/{{ Config.get("github_repo", "boostorg/accumulators") }}/blob/{{ Config.get("github_branch", "develop") }}/include/{{ path }}[<{{ path }}>] +{%- endmacro -%} + + +{%- macro text_helper(s, in_code=False, in_link=False) -%} + {%- if s -%} + {%- set replacements=Config.get("replace_strings", {}) if in_code else {} -%} + + {%- set ns = namespace(s=s) -%} + {%- if in_code -%} + {%- set ns.s = re.sub("\\s+", " ", ns.s, re.U) -%} + {%- if ns.s.endswith(" &") -%} + {%- set ns.s = ns.s[:-2] + "&" -%} + {%- elif ns.s.endswith(" *") -%} + {%- set ns.s = ns.s[:-2] + "*" -%} + {%- elif ns.s.endswith(" &&") -%} + {%- set ns.s = ns.s[:-3] + "&&" -%} + {%- elif ns.s.endswith(" &...") -%} + {%- set ns.s = ns.s[:-5] + "&..." -%} + {%- elif ns.s.endswith(" *...") -%} + {%- set ns.s = ns.s[:-5] + "*..." -%} + {%- elif ns.s.endswith(" &&...") -%} + {%- set ns.s = ns.s[:-6] + "&&..." -%} + {%- endif -%} + {%- else -%} + {%- set ns.s = s -%} + {%- endif -%} + {%- for src, tgt in replacements.items() -%} + {%- set ns.s = re.sub(src, tgt, ns.s, flags=re.U) -%} + {%- endfor -%} + {%- if in_code == "block" -%} + {{ block_code_escape(ns.s) }} + {%- elif in_code == "line" -%} + {{ code_escape(ns.s, in_link=in_link) }} + {%- else -%} + {{ escape(prevent_spurious_list_items(ns.s)) }} + {%- endif -%} + {%- else -%} + {{ s }} + {%- endif -%} +{%- endmacro -%} + + +{%- macro escape(s) -%} +{{ s.replace("++", "{pp}") }} +{%- endmacro -%} + + +{# LaTeX subscripts/superscripts use {n}, {left}, etc.; escape for AsciiDoc. #} +{%- macro asciidoc_escape_braces(s) -%} +{{- s.replace('\\', '\\\\').replace('{', '\\{').replace('}', '\\}') -}} +{%- endmacro -%} + + +{# "K. Author" at line start is parsed as an ordered list; break that pattern. #} +{%- macro prevent_spurious_list_items(s) -%} +{%- set lines = s.split('\n') -%} +{%- set ns = namespace(out=[]) -%} +{%- for line in lines -%} +{%- if line|length >= 3 and line[1] == '.' and line[2] == ' ' + and line[0].isupper() -%} +{%- set _ = ns.out.append('{empty}' + line) -%} +{%- else -%} +{%- set _ = ns.out.append(line) -%} +{%- endif -%} +{%- endfor -%} +{{ ns.out | join('\n') }} +{%- endmacro -%} + + +{%- macro block_code_escape(s) -%} +{{ asciidoc_escape_braces(s) }} +{%- endmacro -%} + + +{%- macro code_escape(s, in_link=False) -%} +{{ asciidoc_escape_braces(s).replace("<=", "++<=++") + .replace("<", "++<++") + .replace(">", "++>++") + .replace("->", "++->++") + .replace("]", "\\\\]" if in_link else "]") + .replace("...", "++...++") }} +{%- endmacro -%} + + +{%- macro member_reference_group(member) -%} +{%- set loc = member.location.file if member.location else '' -%} +{%- if member.fully_qualified_name and member.fully_qualified_name.startswith('boost::numeric') -%} +numeric +{%- elif '/numeric/' in loc -%} +numeric +{%- elif '/statistics' in loc -%} +statistics +{%- else -%} +framework +{%- endif -%} +{%- endmacro -%} + + +{%- macro entity_ref_partition_dir(entity) -%} +{#- Index links target the partition being generated, not header path. -#} +{%- set partition = Config.get('partition', '') | trim -%} +{%- if partition == 'framework' -%} +accumulators_framework_reference +{%- elif partition == 'statistics' -%} +statistics_library_reference +{%- else -%} +numeric_operators_library_reference +{%- endif -%} +{%- endmacro -%} + + +{%- macro entity_ref_relative_path(entity) -%} +{{ entity_ref_partition_dir(entity) }}/{{ anchor(entity) }}.html +{%- endmacro -%} + + +{%- macro write_numeric_namespace_members(entity) -%} +{%- for member in entity.members.values() | sort -%} + {%- if member is Namespace -%} + {%- if member.name != 'detail' -%} + {{ write_entity(member) }} + {%- endif -%} + {%- else -%} + {{ write_entity(member) }} + {%- endif -%} +{%- endfor -%} +{%- endmacro -%} + + +{%- macro write_numeric_operators_reference() -%} +{%- for entity in entities.values() -%} + {%- if entity is Namespace and entity.fully_qualified_name == 'boost::numeric' -%} + {{ write_numeric_namespace_members(entity) }} + {%- endif -%} +{%- endfor -%} +{%- endmacro -%} + + +{%- macro write_namespace_members(entity, group) -%} +{%- for member in entity.members.values() | sort -%} + {%- if member_reference_group(member) == group -%} + {{ write_entity(member) }} + {%- endif -%} +{%- endfor -%} +{%- endmacro -%} + + +{%- macro index_entry_link(entity) -%} +link:++{{ entity_ref_relative_path(entity) }}++[`{{ abridged_fqn(entity) }}`] +{%- endmacro -%} + + +{%- macro index_column(title, members) -%} +{%- if title -%} +a|**{{ title }}** + +{% for member in members | sort(attribute='fully_qualified_name') %} +* {{ index_entry_link(member) }} +{% endfor %} + +{%- else -%} +a| + +{%- endif -%} + +{%- endmacro -%} + + +{%- macro index_column_spanned(span, title, members) -%} +{{ span }}+a|**{{ title }}** + +{% for member in members | sort(attribute='fully_qualified_name') %} +* {{ index_entry_link(member) }} +{% endfor %} + +{%- endmacro -%} + + +{%- macro write_dynamic_index_table(title, column_specs, single_colspan=3) -%} + {%- set active = namespace(columns=[]) -%} + {%- for spec in column_specs -%} + {%- if spec[1] | length > 0 -%} + {%- set _ = active.columns.append(spec) -%} + {%- endif -%} + {%- endfor -%} + {%- set n = active.columns | length -%} + {%- if n == 0 -%} + + {%- elif n == 1 -%} +[cols={{ single_colspan }}*a,autowidth] +|=== +{{ single_colspan }}+|{{ title }} + +{{ index_column_spanned(single_colspan, active.columns[0][0], active.columns[0][1]) }} +|=== + + {%- else -%} +[cols={{ n }}*a,autowidth] +|=== +{{ n }}+|{{ title }} + +{% for spec in active.columns %} +{{ index_column(spec[0], spec[1]) }} +{% endfor %} +|=== + + {%- endif -%} +{%- endmacro -%} + + +{%- macro is_public_namespace_member(member) -%} + {{- member.access == Access.public + and member.scope is Namespace + and not member is Namespace -}} +{%- endmacro -%} + + +{%- macro framework_index_kind(member) -%} + {%- if not is_public_namespace_member(member) -%} + skip + {%- elif member.name.endswith('_concept') -%} + concept + {%- elif member is OverloadSet -%} + function + {%- elif member is Type -%} + {%- if member.name.startswith('detail') -%} + skip + {%- elif member.name in [ + 'as_feature', 'as_weighted_feature', 'depends_on', 'dont_care', + 'droppable', 'external', 'feature_of', 'features', 'with_cached_result' + ] -%} + metafunction + {%- elif member is Struct + and (member.members.values() + | selectattr('name', 'eq', 'type') + | selectattr('access', 'eq', Access.public) + | list) -%} + metafunction + {%- else -%} + class + {%- endif -%} + {%- else -%} + skip + {%- endif -%} +{%- endmacro -%} + + +{%- macro statistics_index_kind(member) -%} + {%- if not is_public_namespace_member(member) -%} + skip + {%- elif member.scope.name == 'tag' and member is Type -%} + tag + {%- elif member.scope.name == 'impl' and member is Type and member.name.endswith('_impl') -%} + accumulator + {%- elif member.scope.fully_qualified_name == Config.default_namespace + and (member is OverloadSet or member is Variable + or (member is Type and not member.name.startswith('detail'))) -%} + modifier + {%- else -%} + skip + {%- endif -%} +{%- endmacro -%} + + +{%- macro numeric_index_kind(member) -%} + {%- if not is_public_namespace_member(member) -%} + skip + {%- elif member is Type -%} + class + {%- elif member is OverloadSet -%} + function + {%- elif member is Variable -%} + variable + {%- else -%} + skip + {%- endif -%} +{%- endmacro -%} + + +{%- macro index_add_member(ns, kind, member, layout='default') -%} + {%- if layout == 'numeric' -%} + {%- if kind == 'class' -%} + {%- set _ = ns.col1.append(member) -%} + {%- elif kind == 'function' -%} + {%- set _ = ns.col2.append(member) -%} + {%- elif kind == 'variable' -%} + {%- set _ = ns.col3.append(member) -%} + {%- endif -%} + {%- elif kind in ('class', 'tag') -%} + {%- set _ = ns.col1.append(member) -%} + {%- elif kind in ('concept', 'accumulator') -%} + {%- set _ = ns.col2.append(member) -%} + {%- elif kind in ('metafunction', 'modifier') -%} + {%- set _ = ns.col3.append(member) -%} + {%- elif kind == 'function' -%} + {%- set _ = ns.col4.append(member) -%} + {%- elif kind == 'variable' -%} + {%- set _ = ns.col3.append(member) -%} + {%- endif -%} +{%- endmacro -%} + + +{%- macro member_index_kind(member, group) -%} + {%- if group == 'framework' -%} + {{ framework_index_kind(member) }} + {%- elif group == 'statistics' -%} + {{ statistics_index_kind(member) }} + {%- elif group == 'numeric' -%} + {{ numeric_index_kind(member) }} + {%- else -%} + skip + {%- endif -%} +{%- endmacro -%} + + +{%- macro write_index_partition_table(title, anchor, col_titles, entity, group) -%} + {%- set cols = namespace(col1=[], col2=[], col3=[], col4=[]) -%} + {%- if entity -%} + {%- for member in entity.members.values() | sort -%} + {%- if member_reference_group(member) != group -%} + {%- elif member is Namespace and member.name != 'detail' -%} + {%- for sub in member.members.values() | sort -%} + {%- set kind = member_index_kind(sub, group) | trim -%} + {%- if kind != 'skip' -%} + {{ index_add_member(cols, kind, sub) }} + {%- endif -%} + {%- endfor -%} + {%- else -%} + {%- set kind = member_index_kind(member, group) | trim -%} + {%- if kind != 'skip' -%} + {{ index_add_member(cols, kind, member) }} + {%- endif -%} + {%- endif -%} + {%- endfor -%} + {%- endif -%} +{{ write_dynamic_index_table(title, [ + (col_titles[0], cols.col1), + (col_titles[1], cols.col2), + (col_titles[2], cols.col3), + (col_titles[3], cols.col4), +]) }} + +{%- endmacro -%} + + +{%- macro write_numeric_index_table() -%} + {%- set cols = namespace(col1=[], col2=[], col3=[], col4=[]) -%} + {%- for numeric in entities.values() -%} + {%- if numeric is Namespace + and numeric.fully_qualified_name == 'boost::numeric' -%} + {%- for member in numeric.members.values() | sort -%} + {%- if member is Namespace and member.name != 'detail' -%} + {%- for sub in member.members.values() | sort -%} + {%- set kind = numeric_index_kind(sub) -%} + {%- if kind != 'skip' -%} + {{ index_add_member(cols, kind, sub, 'numeric') }} + {%- endif -%} + {%- endfor -%} + {%- else -%} + {%- set kind = numeric_index_kind(member) -%} + {%- if kind != 'skip' -%} + {{ index_add_member(cols, kind, member, 'numeric') }} + {%- endif -%} + {%- endif -%} + {%- endfor -%} + {%- endif -%} + {%- endfor -%} +[cols=3*a,autowidth] +|=== +3+|Numeric Operators + +{{ index_column('Classes', cols.col1) }} +{{ index_column('Functions', cols.col2) }} +{{ index_column('Variables', cols.col3) }} +|=== + +{%- endmacro -%} + + +{%- macro write_framework_partition(entity) -%} +{{ write_index_partition_table( + 'Accumulators Framework', + 'accumulators_framework_reference', + ['Classes', 'Concepts', 'Metafunctions', 'Functions'], + entity, 'framework') }} + +{{ write_namespace_members(entity, 'framework') }} +{%- endmacro -%} + + +{%- macro write_statistics_partition(entity) -%} +{{ write_index_partition_table( + 'Statistics Library', + 'statistics_library_reference', + ['Tags', 'Accumulators', 'Modifiers', ''], + entity, 'statistics') }} + +{{ write_namespace_members(entity, 'statistics') }} +{%- endmacro -%} + + +{%- macro write_numeric_partition() -%} +{{ write_numeric_index_table() }} + +{{ write_numeric_operators_reference() }} +{%- endmacro -%} + + +{% set partition = Config.get('partition', '') | trim -%} +{% if partition == 'numeric' -%} +{{ write_numeric_partition() }} +{% else -%} +{% for entity in entities.values() -%} + {% if entity is not Namespace -%} + {% continue %} + {%- endif -%} + {% if Config.get("default_namespace") + and entity.fully_qualified_name != Config.default_namespace -%} + {% continue %} + {%- endif -%} + + {% if partition == 'framework' -%} +{{ write_framework_partition(entity) }} + {% elif partition == 'statistics' -%} +{{ write_statistics_partition(entity) }} + {% endif -%} +{%- endfor %} +{% endif -%}