1 ///////////////////////////////////////////////////////////////////////////////
2 // weighted_tail_variate_means.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_WEIGHTED_TAIL_VARIATE_MEANS_HPP_DE_01_01_2006
9 #define BOOST_ACCUMULATORS_STATISTICS_WEIGHTED_TAIL_VARIATE_MEANS_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/numeric/functional.hpp>
22 #include <boost/accumulators/framework/accumulator_base.hpp>
23 #include <boost/accumulators/framework/extractor.hpp>
24 #include <boost/accumulators/framework/parameters/sample.hpp>
25 #include <boost/accumulators/statistics_fwd.hpp>
26 #include <boost/accumulators/statistics/tail.hpp>
27 #include <boost/accumulators/statistics/tail_variate.hpp>
28 #include <boost/accumulators/statistics/tail_variate_means.hpp>
29 #include <boost/accumulators/statistics/weighted_tail_mean.hpp>
30 #include <boost/accumulators/statistics/parameters/quantile_probability.hpp>
31 
32 #ifdef _MSC_VER
33 # pragma warning(push)
34 # pragma warning(disable: 4127) // conditional expression is constant
35 #endif
36 
37 namespace boost
38 {
39     // for _BinaryOperatrion2 in std::inner_product below
40     // multiplies two values and promotes the result to double
41     namespace numeric { namespace functional
42     {
43         ///////////////////////////////////////////////////////////////////////////////
44         // numeric::functional::multiply_and_promote_to_double
45         template<typename T, typename U>
46         struct multiply_and_promote_to_double
47           : multiplies<T, double const>
48         {
49         };
50     }}
51 }
52 
53 namespace boost { namespace accumulators
54 {
55 
56 namespace impl
57 {
58     /**
59         @brief Estimation of the absolute and relative weighted tail variate means (for both left and right tails)
60 
61         For all \f$j\f$-th variates associated to the
62 
63         \f[
64             \lambda = \inf\left\{ l \left| \frac{1}{\bar{w}_n}\sum_{i=1}^{l} w_i \geq \alpha \right. \right\}
65         \f]
66 
67         smallest samples (left tail) or the weighted mean of the
68 
69         \f[
70             n + 1 - \rho = n + 1 - \sup\left\{ r \left| \frac{1}{\bar{w}_n}\sum_{i=r}^{n} w_i \geq (1 - \alpha) \right. \right\}
71         \f]
72 
73         largest samples (right tail), the absolute weighted tail means \f$\widehat{ATM}_{n,\alpha}(X, j)\f$
74         are computed and returned as an iterator range. Alternatively, the relative weighted tail means
75         \f$\widehat{RTM}_{n,\alpha}(X, j)\f$ are returned, which are the absolute weighted tail means
76         normalized with the weighted (non-coherent) sample tail mean \f$\widehat{NCTM}_{n,\alpha}(X)\f$.
77 
78         \f[
79             \widehat{ATM}_{n,\alpha}^{\mathrm{right}}(X, j) =
80                 \frac{1}{\sum_{i=\rho}^n w_i}
81                 \sum_{i=\rho}^n w_i \xi_{j,i}
82         \f]
83 
84         \f[
85             \widehat{ATM}_{n,\alpha}^{\mathrm{left}}(X, j) =
86                 \frac{1}{\sum_{i=1}^{\lambda}}
87                 \sum_{i=1}^{\lambda} w_i \xi_{j,i}
88         \f]
89 
90         \f[
91             \widehat{RTM}_{n,\alpha}^{\mathrm{right}}(X, j) =
92                 \frac{\sum_{i=\rho}^n w_i \xi_{j,i}}
93             {\sum_{i=\rho}^n w_i \widehat{NCTM}_{n,\alpha}^{\mathrm{right}}(X)}
94         \f]
95 
96         \f[
97             \widehat{RTM}_{n,\alpha}^{\mathrm{left}}(X, j) =
98                 \frac{\sum_{i=1}^{\lambda} w_i \xi_{j,i}}
99             {\sum_{i=1}^{\lambda} w_i \widehat{NCTM}_{n,\alpha}^{\mathrm{left}}(X)}
100         \f]
101     */
102 
103     ///////////////////////////////////////////////////////////////////////////////
104     // weighted_tail_variate_means_impl
105     //  by default: absolute weighted_tail_variate_means
106     template<typename Sample, typename Weight, typename Impl, typename LeftRight, typename VariateType>
107     struct weighted_tail_variate_means_impl
108       : accumulator_base
109     {
110         typedef typename numeric::functional::fdiv<Weight, Weight>::result_type float_type;
111         typedef typename numeric::functional::fdiv<typename numeric::functional::multiplies<VariateType, Weight>::result_type, Weight>::result_type array_type;
112         // for boost::result_of
113         typedef iterator_range<typename array_type::iterator> result_type;
114 
weighted_tail_variate_means_implboost::accumulators::impl::weighted_tail_variate_means_impl115         weighted_tail_variate_means_impl(dont_care) {}
116 
117         template<typename Args>
resultboost::accumulators::impl::weighted_tail_variate_means_impl118         result_type result(Args const &args) const
119         {
120             float_type threshold = sum_of_weights(args)
121                              * ( ( is_same<LeftRight, left>::value ) ? args[quantile_probability] : 1. - args[quantile_probability] );
122 
123             std::size_t n = 0;
124             Weight sum = Weight(0);
125 
126             while (sum < threshold)
127             {
128                 if (n < static_cast<std::size_t>(tail_weights(args).size()))
129                 {
130                     sum += *(tail_weights(args).begin() + n);
131                     n++;
132                 }
133                 else
134                 {
135                     if (std::numeric_limits<float_type>::has_quiet_NaN)
136                     {
137                         std::fill(
138                             this->tail_means_.begin()
139                           , this->tail_means_.end()
140                           , std::numeric_limits<float_type>::quiet_NaN()
141                         );
142                     }
143                     else
144                     {
145                         std::ostringstream msg;
146                         msg << "index n = " << n << " is not in valid range [0, " << tail(args).size() << ")";
147                         boost::throw_exception(std::runtime_error(msg.str()));
148                     }
149                 }
150             }
151 
152             std::size_t num_variates = tail_variate(args).begin()->size();
153 
154             this->tail_means_.clear();
155             this->tail_means_.resize(num_variates, Sample(0));
156 
157             this->tail_means_ = std::inner_product(
158                 tail_variate(args).begin()
159               , tail_variate(args).begin() + n
160               , tail_weights(args).begin()
161               , this->tail_means_
162               , numeric::functional::plus<array_type const, array_type const>()
163               , numeric::functional::multiply_and_promote_to_double<VariateType const, Weight const>()
164             );
165 
166             float_type factor = sum * ( (is_same<Impl, relative>::value) ? non_coherent_weighted_tail_mean(args) : 1. );
167 
168             std::transform(
169                 this->tail_means_.begin()
170               , this->tail_means_.end()
171               , this->tail_means_.begin()
172 #ifdef BOOST_NO_CXX98_BINDERS
173               , std::bind(numeric::functional::divides<typename array_type::value_type const, float_type const>(), std::placeholders::_1, factor)
174 #else
175               , std::bind2nd(numeric::functional::divides<typename array_type::value_type const, float_type const>(), factor)
176 #endif
177             );
178 
179             return make_iterator_range(this->tail_means_);
180         }
181 
182         // make this accumulator serializeable
183         template<class Archive>
serializeboost::accumulators::impl::weighted_tail_variate_means_impl184         void serialize(Archive & ar, const unsigned int file_version)
185         {
186             ar & tail_means_;
187         }
188 
189     private:
190 
191         mutable array_type tail_means_;
192 
193     };
194 
195 } // namespace impl
196 
197 ///////////////////////////////////////////////////////////////////////////////
198 // tag::absolute_weighted_tail_variate_means
199 // tag::relative_weighted_tail_variate_means
200 //
201 namespace tag
202 {
203     template<typename LeftRight, typename VariateType, typename VariateTag>
204     struct absolute_weighted_tail_variate_means
205       : depends_on<non_coherent_weighted_tail_mean<LeftRight>, tail_variate<VariateType, VariateTag, LeftRight>, tail_weights<LeftRight> >
206     {
207         typedef accumulators::impl::weighted_tail_variate_means_impl<mpl::_1, mpl::_2, absolute, LeftRight, VariateType> impl;
208     };
209     template<typename LeftRight, typename VariateType, typename VariateTag>
210     struct relative_weighted_tail_variate_means
211       : depends_on<non_coherent_weighted_tail_mean<LeftRight>, tail_variate<VariateType, VariateTag, LeftRight>, tail_weights<LeftRight> >
212     {
213         typedef accumulators::impl::weighted_tail_variate_means_impl<mpl::_1, mpl::_2, relative, LeftRight, VariateType> impl;
214     };
215 }
216 
217 ///////////////////////////////////////////////////////////////////////////////
218 // extract::weighted_tail_variate_means
219 // extract::relative_weighted_tail_variate_means
220 //
221 namespace extract
222 {
223     extractor<tag::abstract_absolute_tail_variate_means> const weighted_tail_variate_means = {};
224     extractor<tag::abstract_relative_tail_variate_means> const relative_weighted_tail_variate_means = {};
225 
226     BOOST_ACCUMULATORS_IGNORE_GLOBAL(weighted_tail_variate_means)
227     BOOST_ACCUMULATORS_IGNORE_GLOBAL(relative_weighted_tail_variate_means)
228 }
229 
230 using extract::weighted_tail_variate_means;
231 using extract::relative_weighted_tail_variate_means;
232 
233 // weighted_tail_variate_means<LeftRight, VariateType, VariateTag>(absolute) -> absolute_weighted_tail_variate_means<LeftRight, VariateType, VariateTag>
234 template<typename LeftRight, typename VariateType, typename VariateTag>
235 struct as_feature<tag::weighted_tail_variate_means<LeftRight, VariateType, VariateTag>(absolute)>
236 {
237     typedef tag::absolute_weighted_tail_variate_means<LeftRight, VariateType, VariateTag> type;
238 };
239 
240 // weighted_tail_variate_means<LeftRight, VariateType, VariateTag>(relative) -> relative_weighted_tail_variate_means<LeftRight, VariateType, VariateTag>
241 template<typename LeftRight, typename VariateType, typename VariateTag>
242 struct as_feature<tag::weighted_tail_variate_means<LeftRight, VariateType, VariateTag>(relative)>
243 {
244     typedef tag::relative_weighted_tail_variate_means<LeftRight, VariateType, VariateTag> type;
245 };
246 
247 }} // namespace boost::accumulators
248 
249 #ifdef _MSC_VER
250 # pragma warning(pop)
251 #endif
252 
253 #endif
254