1 ///////////////////////////////////////////////////////////////////////////////
2 // extended_p_square_quantile.hpp
4 // Copyright 2005 Daniel Egloff. 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)
8 #ifndef BOOST_ACCUMULATORS_STATISTICS_EXTENDED_SINGLE_QUANTILE_HPP_DE_01_01_2006
9 #define BOOST_ACCUMULATORS_STATISTICS_EXTENDED_SINGLE_QUANTILE_HPP_DE_01_01_2006
13 #include <boost/range/begin.hpp>
14 #include <boost/range/end.hpp>
15 #include <boost/range/iterator_range.hpp>
16 #include <boost/iterator/transform_iterator.hpp>
17 #include <boost/iterator/counting_iterator.hpp>
18 #include <boost/iterator/permutation_iterator.hpp>
19 #include <boost/parameter/keyword.hpp>
20 #include <boost/mpl/placeholders.hpp>
21 #include <boost/type_traits/is_same.hpp>
22 #include <boost/accumulators/framework/accumulator_base.hpp>
23 #include <boost/accumulators/framework/extractor.hpp>
24 #include <boost/accumulators/numeric/functional.hpp>
25 #include <boost/accumulators/framework/parameters/sample.hpp>
26 #include <boost/accumulators/framework/depends_on.hpp>
27 #include <boost/accumulators/statistics_fwd.hpp>
28 #include <boost/accumulators/statistics/count.hpp>
29 #include <boost/accumulators/statistics/parameters/quantile_probability.hpp>
30 #include <boost/accumulators/statistics/extended_p_square.hpp>
31 #include <boost/accumulators/statistics/weighted_extended_p_square.hpp>
32 #include <boost/accumulators/statistics/times2_iterator.hpp>
35 # pragma warning(push)
36 # pragma warning(disable: 4127) // conditional expression is constant
39 namespace boost
{ namespace accumulators
44 ///////////////////////////////////////////////////////////////////////////////
45 // extended_p_square_quantile_impl
46 // single quantile estimation
48 @brief Quantile estimation using the extended \f$P^2\f$ algorithm for weighted and unweighted samples
50 Uses the quantile estimates calculated by the extended \f$P^2\f$ algorithm to compute
51 intermediate quantile estimates by means of quadratic interpolation.
53 @param quantile_probability The probability of the quantile to be estimated.
55 template<typename Sample
, typename Impl1
, typename Impl2
> // Impl1: weighted/unweighted // Impl2: linear/quadratic
56 struct extended_p_square_quantile_impl
59 typedef typename
numeric::functional::average
<Sample
, std::size_t>::result_type float_type
;
60 typedef std::vector
<float_type
> array_type
;
61 typedef iterator_range
<
62 detail::lvalue_index_iterator
<
64 typename
array_type::const_iterator
65 , detail::times2_iterator
69 // for boost::result_of
70 typedef float_type result_type
;
72 template<typename Args
>
73 extended_p_square_quantile_impl(Args
const &args
)
75 boost::begin(args
[extended_p_square_probabilities
])
76 , boost::end(args
[extended_p_square_probabilities
])
81 template<typename Args
>
82 result_type
result(Args
const &args
) const
86 is_same
<Impl1
, weighted
>
87 , tag::weighted_extended_p_square
88 , tag::extended_p_square
90 extended_p_square_tag
;
92 extractor
<extended_p_square_tag
> const some_extended_p_square
= {};
94 array_type
heights(some_extended_p_square(args
).size());
95 std::copy(some_extended_p_square(args
).begin(), some_extended_p_square(args
).end(), heights
.begin());
97 this->probability
= args
[quantile_probability
];
99 typename
array_type::const_iterator iter_probs
= std::lower_bound(this->probabilities
.begin(), this->probabilities
.end(), this->probability
);
100 std::size_t dist
= std::distance(this->probabilities
.begin(), iter_probs
);
101 typename
array_type::const_iterator iter_heights
= heights
.begin() + dist
;
103 // If this->probability is not in a valid range return NaN or throw exception
104 if (this->probability
< *this->probabilities
.begin() || this->probability
> *(this->probabilities
.end() - 1))
106 if (std::numeric_limits
<result_type
>::has_quiet_NaN
)
108 return std::numeric_limits
<result_type
>::quiet_NaN();
112 std::ostringstream msg
;
113 msg
<< "probability = " << this->probability
<< " is not in valid range (";
114 msg
<< *this->probabilities
.begin() << ", " << *(this->probabilities
.end() - 1) << ")";
115 boost::throw_exception(std::runtime_error(msg
.str()));
121 if (*iter_probs
== this->probability
)
123 return heights
[dist
];
129 if (is_same
<Impl2
, linear
>::value
)
131 /////////////////////////////////////////////////////////////////////////////////
132 // LINEAR INTERPOLATION
134 float_type p1
= *iter_probs
;
135 float_type p0
= *(iter_probs
- 1);
136 float_type h1
= *iter_heights
;
137 float_type h0
= *(iter_heights
- 1);
139 float_type a
= numeric::average(h1
- h0
, p1
- p0
);
140 float_type b
= h1
- p1
* a
;
142 result
= a
* this->probability
+ b
;
146 /////////////////////////////////////////////////////////////////////////////////
147 // QUADRATIC INTERPOLATION
149 float_type p0
, p1
, p2
;
150 float_type h0
, h1
, h2
;
152 if ( (dist
== 1 || *iter_probs
- this->probability
<= this->probability
- *(iter_probs
- 1) ) && dist
!= this->probabilities
.size() - 1 )
154 p0
= *(iter_probs
- 1);
156 p2
= *(iter_probs
+ 1);
157 h0
= *(iter_heights
- 1);
159 h2
= *(iter_heights
+ 1);
163 p0
= *(iter_probs
- 2);
164 p1
= *(iter_probs
- 1);
166 h0
= *(iter_heights
- 2);
167 h1
= *(iter_heights
- 1);
171 float_type hp21
= numeric::average(h2
- h1
, p2
- p1
);
172 float_type hp10
= numeric::average(h1
- h0
, p1
- p0
);
173 float_type p21
= numeric::average(p2
* p2
- p1
* p1
, p2
- p1
);
174 float_type p10
= numeric::average(p1
* p1
- p0
* p0
, p1
- p0
);
176 float_type a
= numeric::average(hp21
- hp10
, p21
- p10
);
177 float_type b
= hp21
- a
* p21
;
178 float_type c
= h2
- a
* p2
* p2
- b
* p2
;
180 result
= a
* this->probability
* this-> probability
+ b
* this->probability
+ c
;
189 array_type probabilities
;
190 mutable float_type probability
;
196 ///////////////////////////////////////////////////////////////////////////////
197 // tag::extended_p_square_quantile
201 struct extended_p_square_quantile
202 : depends_on
<extended_p_square
>
204 typedef accumulators::impl::extended_p_square_quantile_impl
<mpl::_1
, unweighted
, linear
> impl
;
206 struct extended_p_square_quantile_quadratic
207 : depends_on
<extended_p_square
>
209 typedef accumulators::impl::extended_p_square_quantile_impl
<mpl::_1
, unweighted
, quadratic
> impl
;
211 struct weighted_extended_p_square_quantile
212 : depends_on
<weighted_extended_p_square
>
214 typedef accumulators::impl::extended_p_square_quantile_impl
<mpl::_1
, weighted
, linear
> impl
;
216 struct weighted_extended_p_square_quantile_quadratic
217 : depends_on
<weighted_extended_p_square
>
219 typedef accumulators::impl::extended_p_square_quantile_impl
<mpl::_1
, weighted
, quadratic
> impl
;
223 ///////////////////////////////////////////////////////////////////////////////
224 // extract::extended_p_square_quantile
225 // extract::weighted_extended_p_square_quantile
229 extractor
<tag::extended_p_square_quantile
> const extended_p_square_quantile
= {};
230 extractor
<tag::extended_p_square_quantile_quadratic
> const extended_p_square_quantile_quadratic
= {};
231 extractor
<tag::weighted_extended_p_square_quantile
> const weighted_extended_p_square_quantile
= {};
232 extractor
<tag::weighted_extended_p_square_quantile_quadratic
> const weighted_extended_p_square_quantile_quadratic
= {};
235 using extract::extended_p_square_quantile
;
236 using extract::extended_p_square_quantile_quadratic
;
237 using extract::weighted_extended_p_square_quantile
;
238 using extract::weighted_extended_p_square_quantile_quadratic
;
240 // extended_p_square_quantile(linear) -> extended_p_square_quantile
242 struct as_feature
<tag::extended_p_square_quantile(linear
)>
244 typedef tag::extended_p_square_quantile type
;
247 // extended_p_square_quantile(quadratic) -> extended_p_square_quantile_quadratic
249 struct as_feature
<tag::extended_p_square_quantile(quadratic
)>
251 typedef tag::extended_p_square_quantile_quadratic type
;
254 // weighted_extended_p_square_quantile(linear) -> weighted_extended_p_square_quantile
256 struct as_feature
<tag::weighted_extended_p_square_quantile(linear
)>
258 typedef tag::weighted_extended_p_square_quantile type
;
261 // weighted_extended_p_square_quantile(quadratic) -> weighted_extended_p_square_quantile_quadratic
263 struct as_feature
<tag::weighted_extended_p_square_quantile(quadratic
)>
265 typedef tag::weighted_extended_p_square_quantile_quadratic type
;
268 // for the purposes of feature-based dependency resolution,
269 // extended_p_square_quantile and weighted_extended_p_square_quantile
270 // provide the same feature as quantile
272 struct feature_of
<tag::extended_p_square_quantile
>
273 : feature_of
<tag::quantile
>
277 struct feature_of
<tag::extended_p_square_quantile_quadratic
>
278 : feature_of
<tag::quantile
>
281 // So that extended_p_square_quantile can be automatically substituted with
282 // weighted_extended_p_square_quantile when the weight parameter is non-void
284 struct as_weighted_feature
<tag::extended_p_square_quantile
>
286 typedef tag::weighted_extended_p_square_quantile type
;
290 struct feature_of
<tag::weighted_extended_p_square_quantile
>
291 : feature_of
<tag::extended_p_square_quantile
>
295 // So that extended_p_square_quantile_quadratic can be automatically substituted with
296 // weighted_extended_p_square_quantile_quadratic when the weight parameter is non-void
298 struct as_weighted_feature
<tag::extended_p_square_quantile_quadratic
>
300 typedef tag::weighted_extended_p_square_quantile_quadratic type
;
303 struct feature_of
<tag::weighted_extended_p_square_quantile_quadratic
>
304 : feature_of
<tag::extended_p_square_quantile_quadratic
>
308 }} // namespace boost::accumulators
311 # pragma warning(pop)