1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // tail_mean.hpp |
3 | // |
4 | // Copyright 2006 Daniel Egloff, Olivier Gygi. Distributed under the Boost |
5 | // Software License, Version 1.0. (See accompanying file |
6 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
7 | |
8 | #ifndef BOOST_ACCUMULATORS_STATISTICS_TAIL_MEAN_HPP_DE_01_01_2006 |
9 | #define BOOST_ACCUMULATORS_STATISTICS_TAIL_MEAN_HPP_DE_01_01_2006 |
10 | |
11 | #include <numeric> |
12 | #include <vector> |
13 | #include <limits> |
14 | #include <functional> |
15 | #include <sstream> |
16 | #include <stdexcept> |
17 | #include <boost/throw_exception.hpp> |
18 | #include <boost/parameter/keyword.hpp> |
19 | #include <boost/mpl/placeholders.hpp> |
20 | #include <boost/type_traits/is_same.hpp> |
21 | #include <boost/accumulators/framework/accumulator_base.hpp> |
22 | #include <boost/accumulators/framework/extractor.hpp> |
23 | #include <boost/accumulators/numeric/functional.hpp> |
24 | #include <boost/accumulators/framework/parameters/sample.hpp> |
25 | #include <boost/accumulators/statistics_fwd.hpp> |
26 | #include <boost/accumulators/statistics/count.hpp> |
27 | #include <boost/accumulators/statistics/tail.hpp> |
28 | #include <boost/accumulators/statistics/tail_quantile.hpp> |
29 | #include <boost/accumulators/statistics/parameters/quantile_probability.hpp> |
30 | |
31 | #ifdef _MSC_VER |
32 | # pragma warning(push) |
33 | # pragma warning(disable: 4127) // conditional expression is constant |
34 | #endif |
35 | |
36 | namespace boost { namespace accumulators |
37 | { |
38 | |
39 | namespace impl |
40 | { |
41 | |
42 | /////////////////////////////////////////////////////////////////////////////// |
43 | // coherent_tail_mean_impl |
44 | // |
45 | /** |
46 | @brief Estimation of the coherent tail mean based on order statistics (for both left and right tails) |
47 | |
48 | The coherent tail mean \f$\widehat{CTM}_{n,\alpha}(X)\f$ is equal to the non-coherent tail mean \f$\widehat{NCTM}_{n,\alpha}(X)\f$ |
49 | plus a correction term that ensures coherence in case of non-continuous distributions. |
50 | |
51 | \f[ |
52 | \widehat{CTM}_{n,\alpha}^{\mathrm{right}}(X) = \widehat{NCTM}_{n,\alpha}^{\mathrm{right}}(X) + |
53 | \frac{1}{\lceil n(1-\alpha)\rceil}\hat{q}_{n,\alpha}(X)\left(1 - \alpha - \frac{1}{n}\lceil n(1-\alpha)\rceil \right) |
54 | \f] |
55 | |
56 | \f[ |
57 | \widehat{CTM}_{n,\alpha}^{\mathrm{left}}(X) = \widehat{NCTM}_{n,\alpha}^{\mathrm{left}}(X) + |
58 | \frac{1}{\lceil n\alpha\rceil}\hat{q}_{n,\alpha}(X)\left(\alpha - \frac{1}{n}\lceil n\alpha\rceil \right) |
59 | \f] |
60 | */ |
61 | template<typename Sample, typename LeftRight> |
62 | struct coherent_tail_mean_impl |
63 | : accumulator_base |
64 | { |
65 | typedef typename numeric::functional::fdiv<Sample, std::size_t>::result_type float_type; |
66 | // for boost::result_of |
67 | typedef float_type result_type; |
68 | |
69 | coherent_tail_mean_impl(dont_care) {} |
70 | |
71 | template<typename Args> |
72 | result_type result(Args const &args) const |
73 | { |
74 | std::size_t cnt = count(args); |
75 | |
76 | std::size_t n = static_cast<std::size_t>( |
77 | std::ceil( |
78 | cnt * ( ( is_same<LeftRight, left>::value ) ? args[quantile_probability] : 1. - args[quantile_probability] ) |
79 | ) |
80 | ); |
81 | |
82 | extractor<tag::non_coherent_tail_mean<LeftRight> > const some_non_coherent_tail_mean = {}; |
83 | |
84 | return some_non_coherent_tail_mean(args) |
85 | + numeric::fdiv(quantile(args), n) |
86 | * ( |
87 | ( is_same<LeftRight, left>::value ) ? args[quantile_probability] : 1. - args[quantile_probability] |
88 | - numeric::fdiv(n, count(args)) |
89 | ); |
90 | } |
91 | |
92 | // serialization is done by accumulators it depends on |
93 | template<class Archive> |
94 | void serialize(Archive & ar, const unsigned int file_version) {} |
95 | }; |
96 | |
97 | /////////////////////////////////////////////////////////////////////////////// |
98 | // non_coherent_tail_mean_impl |
99 | // |
100 | /** |
101 | @brief Estimation of the (non-coherent) tail mean based on order statistics (for both left and right tails) |
102 | |
103 | An estimation of the non-coherent tail mean \f$\widehat{NCTM}_{n,\alpha}(X)\f$ is given by the mean of the |
104 | \f$\lceil n\alpha\rceil\f$ smallest samples (left tail) or the mean of the \f$\lceil n(1-\alpha)\rceil\f$ |
105 | largest samples (right tail), \f$n\f$ being the total number of samples and \f$\alpha\f$ the quantile level: |
106 | |
107 | \f[ |
108 | \widehat{NCTM}_{n,\alpha}^{\mathrm{right}}(X) = \frac{1}{\lceil n(1-\alpha)\rceil} \sum_{i=\lceil \alpha n \rceil}^n X_{i:n} |
109 | \f] |
110 | |
111 | \f[ |
112 | \widehat{NCTM}_{n,\alpha}^{\mathrm{left}}(X) = \frac{1}{\lceil n\alpha\rceil} \sum_{i=1}^{\lceil \alpha n \rceil} X_{i:n} |
113 | \f] |
114 | |
115 | It thus requires the caching of at least the \f$\lceil n\alpha\rceil\f$ smallest or the \f$\lceil n(1-\alpha)\rceil\f$ |
116 | largest samples. |
117 | |
118 | @param quantile_probability |
119 | */ |
120 | template<typename Sample, typename LeftRight> |
121 | struct non_coherent_tail_mean_impl |
122 | : accumulator_base |
123 | { |
124 | typedef typename numeric::functional::fdiv<Sample, std::size_t>::result_type float_type; |
125 | // for boost::result_of |
126 | typedef float_type result_type; |
127 | |
128 | non_coherent_tail_mean_impl(dont_care) {} |
129 | |
130 | template<typename Args> |
131 | result_type result(Args const &args) const |
132 | { |
133 | std::size_t cnt = count(args); |
134 | |
135 | std::size_t n = static_cast<std::size_t>( |
136 | std::ceil( |
137 | cnt * ( ( is_same<LeftRight, left>::value ) ? args[quantile_probability] : 1. - args[quantile_probability] ) |
138 | ) |
139 | ); |
140 | |
141 | // If n is in a valid range, return result, otherwise return NaN or throw exception |
142 | if (n <= static_cast<std::size_t>(tail(args).size())) |
143 | return numeric::fdiv( |
144 | std::accumulate( |
145 | tail(args).begin() |
146 | , tail(args).begin() + n |
147 | , Sample(0) |
148 | ) |
149 | , n |
150 | ); |
151 | else |
152 | { |
153 | if (std::numeric_limits<result_type>::has_quiet_NaN) |
154 | { |
155 | return std::numeric_limits<result_type>::quiet_NaN(); |
156 | } |
157 | else |
158 | { |
159 | std::ostringstream msg; |
160 | msg << "index n = " << n << " is not in valid range [0, " << tail(args).size() << ")" ; |
161 | boost::throw_exception(e: std::runtime_error(msg.str())); |
162 | return Sample(0); |
163 | } |
164 | } |
165 | } |
166 | |
167 | // serialization is done by accumulators it depends on |
168 | template<class Archive> |
169 | void serialize(Archive & ar, const unsigned int file_version) {} |
170 | }; |
171 | |
172 | } // namespace impl |
173 | |
174 | |
175 | /////////////////////////////////////////////////////////////////////////////// |
176 | // tag::coherent_tail_mean<> |
177 | // tag::non_coherent_tail_mean<> |
178 | // |
179 | namespace tag |
180 | { |
181 | template<typename LeftRight> |
182 | struct coherent_tail_mean |
183 | : depends_on<count, quantile, non_coherent_tail_mean<LeftRight> > |
184 | { |
185 | typedef accumulators::impl::coherent_tail_mean_impl<mpl::_1, LeftRight> impl; |
186 | }; |
187 | |
188 | template<typename LeftRight> |
189 | struct non_coherent_tail_mean |
190 | : depends_on<count, tail<LeftRight> > |
191 | { |
192 | typedef accumulators::impl::non_coherent_tail_mean_impl<mpl::_1, LeftRight> impl; |
193 | }; |
194 | |
195 | struct abstract_non_coherent_tail_mean |
196 | : depends_on<> |
197 | { |
198 | }; |
199 | } |
200 | |
201 | /////////////////////////////////////////////////////////////////////////////// |
202 | // extract::non_coherent_tail_mean; |
203 | // extract::coherent_tail_mean; |
204 | // |
205 | namespace extract |
206 | { |
207 | extractor<tag::abstract_non_coherent_tail_mean> const = {}; |
208 | extractor<tag::tail_mean> const = {}; |
209 | |
210 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(non_coherent_tail_mean) |
211 | BOOST_ACCUMULATORS_IGNORE_GLOBAL(coherent_tail_mean) |
212 | } |
213 | |
214 | using extract::non_coherent_tail_mean; |
215 | using extract::coherent_tail_mean; |
216 | |
217 | // for the purposes of feature-based dependency resolution, |
218 | // coherent_tail_mean<LeftRight> provides the same feature as tail_mean |
219 | template<typename LeftRight> |
220 | struct feature_of<tag::coherent_tail_mean<LeftRight> > |
221 | : feature_of<tag::tail_mean> |
222 | { |
223 | }; |
224 | |
225 | template<typename LeftRight> |
226 | struct feature_of<tag::non_coherent_tail_mean<LeftRight> > |
227 | : feature_of<tag::abstract_non_coherent_tail_mean> |
228 | { |
229 | }; |
230 | |
231 | // So that non_coherent_tail_mean can be automatically substituted |
232 | // with weighted_non_coherent_tail_mean when the weight parameter is non-void. |
233 | template<typename LeftRight> |
234 | struct as_weighted_feature<tag::non_coherent_tail_mean<LeftRight> > |
235 | { |
236 | typedef tag::non_coherent_weighted_tail_mean<LeftRight> type; |
237 | }; |
238 | |
239 | template<typename LeftRight> |
240 | struct feature_of<tag::non_coherent_weighted_tail_mean<LeftRight> > |
241 | : feature_of<tag::non_coherent_tail_mean<LeftRight> > |
242 | {}; |
243 | |
244 | // NOTE that non_coherent_tail_mean cannot be feature-grouped with tail_mean, |
245 | // which is the base feature for coherent tail means, since (at least for |
246 | // non-continuous distributions) non_coherent_tail_mean is a different measure! |
247 | |
248 | }} // namespace boost::accumulators |
249 | |
250 | #ifdef _MSC_VER |
251 | # pragma warning(pop) |
252 | #endif |
253 | |
254 | #endif |
255 | |