annotate DEPENDENCIES/generic/include/boost/accumulators/statistics/extended_p_square.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 ///////////////////////////////////////////////////////////////////////////////
Chris@16 2 // extended_p_square.hpp
Chris@16 3 //
Chris@16 4 // Copyright 2005 Daniel Egloff. Distributed under the Boost
Chris@16 5 // Software License, Version 1.0. (See accompanying file
Chris@16 6 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Chris@16 7
Chris@16 8 #ifndef BOOST_ACCUMULATORS_STATISTICS_EXTENDED_SINGLE_HPP_DE_01_01_2006
Chris@16 9 #define BOOST_ACCUMULATORS_STATISTICS_EXTENDED_SINGLE_HPP_DE_01_01_2006
Chris@16 10
Chris@16 11 #include <vector>
Chris@16 12 #include <functional>
Chris@16 13 #include <boost/range/begin.hpp>
Chris@16 14 #include <boost/range/end.hpp>
Chris@16 15 #include <boost/range/iterator_range.hpp>
Chris@16 16 #include <boost/iterator/transform_iterator.hpp>
Chris@16 17 #include <boost/iterator/counting_iterator.hpp>
Chris@16 18 #include <boost/iterator/permutation_iterator.hpp>
Chris@16 19 #include <boost/parameter/keyword.hpp>
Chris@16 20 #include <boost/mpl/placeholders.hpp>
Chris@16 21 #include <boost/accumulators/accumulators_fwd.hpp>
Chris@16 22 #include <boost/accumulators/framework/extractor.hpp>
Chris@16 23 #include <boost/accumulators/numeric/functional.hpp>
Chris@16 24 #include <boost/accumulators/framework/parameters/sample.hpp>
Chris@16 25 #include <boost/accumulators/framework/depends_on.hpp>
Chris@16 26 #include <boost/accumulators/statistics_fwd.hpp>
Chris@16 27 #include <boost/accumulators/statistics/count.hpp>
Chris@16 28 #include <boost/accumulators/statistics/times2_iterator.hpp>
Chris@16 29
Chris@16 30 namespace boost { namespace accumulators
Chris@16 31 {
Chris@16 32 ///////////////////////////////////////////////////////////////////////////////
Chris@16 33 // probabilities named parameter
Chris@16 34 //
Chris@16 35 BOOST_PARAMETER_NESTED_KEYWORD(tag, extended_p_square_probabilities, probabilities)
Chris@16 36
Chris@16 37 BOOST_ACCUMULATORS_IGNORE_GLOBAL(extended_p_square_probabilities)
Chris@16 38
Chris@16 39 namespace impl
Chris@16 40 {
Chris@16 41 ///////////////////////////////////////////////////////////////////////////////
Chris@16 42 // extended_p_square_impl
Chris@16 43 // multiple quantile estimation
Chris@16 44 /**
Chris@16 45 @brief Multiple quantile estimation with the extended \f$P^2\f$ algorithm
Chris@16 46
Chris@16 47 Extended \f$P^2\f$ algorithm for estimation of several quantiles without storing samples.
Chris@16 48 Assume that \f$m\f$ quantiles \f$\xi_{p_1}, \ldots, \xi_{p_m}\f$ are to be estimated.
Chris@16 49 Instead of storing the whole sample cumulative distribution, the algorithm maintains only
Chris@16 50 \f$m+2\f$ principal markers and \f$m+1\f$ middle markers, whose positions are updated
Chris@16 51 with each sample and whose heights are adjusted (if necessary) using a piecewise-parablic
Chris@16 52 formula. The heights of these central markers are the current estimates of the quantiles
Chris@16 53 and returned as an iterator range.
Chris@16 54
Chris@16 55 For further details, see
Chris@16 56
Chris@16 57 K. E. E. Raatikainen, Simultaneous estimation of several quantiles, Simulation, Volume 49,
Chris@16 58 Number 4 (October), 1986, p. 159-164.
Chris@16 59
Chris@16 60 The extended \f$ P^2 \f$ algorithm generalizes the \f$ P^2 \f$ algorithm of
Chris@16 61
Chris@16 62 R. Jain and I. Chlamtac, The P^2 algorithm for dynamic calculation of quantiles and
Chris@16 63 histograms without storing observations, Communications of the ACM,
Chris@16 64 Volume 28 (October), Number 10, 1985, p. 1076-1085.
Chris@16 65
Chris@16 66 @param extended_p_square_probabilities A vector of quantile probabilities.
Chris@16 67 */
Chris@16 68 template<typename Sample>
Chris@16 69 struct extended_p_square_impl
Chris@16 70 : accumulator_base
Chris@16 71 {
Chris@16 72 typedef typename numeric::functional::fdiv<Sample, std::size_t>::result_type float_type;
Chris@16 73 typedef std::vector<float_type> array_type;
Chris@16 74 // for boost::result_of
Chris@16 75 typedef iterator_range<
Chris@16 76 detail::lvalue_index_iterator<
Chris@16 77 permutation_iterator<
Chris@16 78 typename array_type::const_iterator
Chris@16 79 , detail::times2_iterator
Chris@16 80 >
Chris@16 81 >
Chris@16 82 > result_type;
Chris@16 83
Chris@16 84 template<typename Args>
Chris@16 85 extended_p_square_impl(Args const &args)
Chris@16 86 : probabilities(
Chris@16 87 boost::begin(args[extended_p_square_probabilities])
Chris@16 88 , boost::end(args[extended_p_square_probabilities])
Chris@16 89 )
Chris@16 90 , heights(2 * probabilities.size() + 3)
Chris@16 91 , actual_positions(heights.size())
Chris@16 92 , desired_positions(heights.size())
Chris@16 93 , positions_increments(heights.size())
Chris@16 94 {
Chris@16 95 std::size_t num_quantiles = this->probabilities.size();
Chris@16 96 std::size_t num_markers = this->heights.size();
Chris@16 97
Chris@16 98 for(std::size_t i = 0; i < num_markers; ++i)
Chris@16 99 {
Chris@16 100 this->actual_positions[i] = i + 1;
Chris@16 101 }
Chris@16 102
Chris@16 103 this->positions_increments[0] = 0.;
Chris@16 104 this->positions_increments[num_markers - 1] = 1.;
Chris@16 105
Chris@16 106 for(std::size_t i = 0; i < num_quantiles; ++i)
Chris@16 107 {
Chris@16 108 this->positions_increments[2 * i + 2] = probabilities[i];
Chris@16 109 }
Chris@16 110
Chris@16 111 for(std::size_t i = 0; i <= num_quantiles; ++i)
Chris@16 112 {
Chris@16 113 this->positions_increments[2 * i + 1] =
Chris@16 114 0.5 * (this->positions_increments[2 * i] + this->positions_increments[2 * i + 2]);
Chris@16 115 }
Chris@16 116
Chris@16 117 for(std::size_t i = 0; i < num_markers; ++i)
Chris@16 118 {
Chris@16 119 this->desired_positions[i] = 1. + 2. * (num_quantiles + 1.) * this->positions_increments[i];
Chris@16 120 }
Chris@16 121 }
Chris@16 122
Chris@16 123 template<typename Args>
Chris@16 124 void operator ()(Args const &args)
Chris@16 125 {
Chris@16 126 std::size_t cnt = count(args);
Chris@16 127
Chris@16 128 // m+2 principal markers and m+1 middle markers
Chris@16 129 std::size_t num_markers = 2 * this->probabilities.size() + 3;
Chris@16 130
Chris@16 131 // first accumulate num_markers samples
Chris@16 132 if(cnt <= num_markers)
Chris@16 133 {
Chris@16 134 this->heights[cnt - 1] = args[sample];
Chris@16 135
Chris@16 136 // complete the initialization of heights by sorting
Chris@16 137 if(cnt == num_markers)
Chris@16 138 {
Chris@16 139 std::sort(this->heights.begin(), this->heights.end());
Chris@16 140 }
Chris@16 141 }
Chris@16 142 else
Chris@16 143 {
Chris@16 144 std::size_t sample_cell = 1;
Chris@16 145
Chris@16 146 // find cell k = sample_cell such that heights[k-1] <= sample < heights[k]
Chris@16 147 if(args[sample] < this->heights[0])
Chris@16 148 {
Chris@16 149 this->heights[0] = args[sample];
Chris@16 150 sample_cell = 1;
Chris@16 151 }
Chris@16 152 else if(args[sample] >= this->heights[num_markers - 1])
Chris@16 153 {
Chris@16 154 this->heights[num_markers - 1] = args[sample];
Chris@16 155 sample_cell = num_markers - 1;
Chris@16 156 }
Chris@16 157 else
Chris@16 158 {
Chris@16 159 typedef typename array_type::iterator iterator;
Chris@16 160 iterator it = std::upper_bound(
Chris@16 161 this->heights.begin()
Chris@16 162 , this->heights.end()
Chris@16 163 , args[sample]
Chris@16 164 );
Chris@16 165
Chris@16 166 sample_cell = std::distance(this->heights.begin(), it);
Chris@16 167 }
Chris@16 168
Chris@16 169 // update actual positions of all markers above sample_cell index
Chris@16 170 for(std::size_t i = sample_cell; i < num_markers; ++i)
Chris@16 171 {
Chris@16 172 ++this->actual_positions[i];
Chris@16 173 }
Chris@16 174
Chris@16 175 // update desired positions of all markers
Chris@16 176 for(std::size_t i = 0; i < num_markers; ++i)
Chris@16 177 {
Chris@16 178 this->desired_positions[i] += this->positions_increments[i];
Chris@16 179 }
Chris@16 180
Chris@16 181 // adjust heights and actual positions of markers 1 to num_markers-2 if necessary
Chris@16 182 for(std::size_t i = 1; i <= num_markers - 2; ++i)
Chris@16 183 {
Chris@16 184 // offset to desired position
Chris@16 185 float_type d = this->desired_positions[i] - this->actual_positions[i];
Chris@16 186
Chris@16 187 // offset to next position
Chris@16 188 float_type dp = this->actual_positions[i+1] - this->actual_positions[i];
Chris@16 189
Chris@16 190 // offset to previous position
Chris@16 191 float_type dm = this->actual_positions[i-1] - this->actual_positions[i];
Chris@16 192
Chris@16 193 // height ds
Chris@16 194 float_type hp = (this->heights[i+1] - this->heights[i]) / dp;
Chris@16 195 float_type hm = (this->heights[i-1] - this->heights[i]) / dm;
Chris@16 196
Chris@16 197 if((d >= 1 && dp > 1) || (d <= -1 && dm < -1))
Chris@16 198 {
Chris@16 199 short sign_d = static_cast<short>(d / std::abs(d));
Chris@16 200
Chris@16 201 float_type h = this->heights[i] + sign_d / (dp - dm) * ((sign_d - dm)*hp
Chris@16 202 + (dp - sign_d) * hm);
Chris@16 203
Chris@16 204 // try adjusting heights[i] using p-squared formula
Chris@16 205 if(this->heights[i - 1] < h && h < this->heights[i + 1])
Chris@16 206 {
Chris@16 207 this->heights[i] = h;
Chris@16 208 }
Chris@16 209 else
Chris@16 210 {
Chris@16 211 // use linear formula
Chris@16 212 if(d > 0)
Chris@16 213 {
Chris@16 214 this->heights[i] += hp;
Chris@16 215 }
Chris@16 216 if(d < 0)
Chris@16 217 {
Chris@16 218 this->heights[i] -= hm;
Chris@16 219 }
Chris@16 220 }
Chris@16 221 this->actual_positions[i] += sign_d;
Chris@16 222 }
Chris@16 223 }
Chris@16 224 }
Chris@16 225 }
Chris@16 226
Chris@16 227 result_type result(dont_care) const
Chris@16 228 {
Chris@16 229 // for i in [1,probabilities.size()], return heights[i * 2]
Chris@16 230 detail::times2_iterator idx_begin = detail::make_times2_iterator(1);
Chris@16 231 detail::times2_iterator idx_end = detail::make_times2_iterator(this->probabilities.size() + 1);
Chris@16 232
Chris@16 233 return result_type(
Chris@16 234 make_permutation_iterator(this->heights.begin(), idx_begin)
Chris@16 235 , make_permutation_iterator(this->heights.begin(), idx_end)
Chris@16 236 );
Chris@16 237 }
Chris@16 238
Chris@16 239 private:
Chris@16 240 array_type probabilities; // the quantile probabilities
Chris@16 241 array_type heights; // q_i
Chris@16 242 array_type actual_positions; // n_i
Chris@16 243 array_type desired_positions; // d_i
Chris@16 244 array_type positions_increments; // f_i
Chris@16 245 };
Chris@16 246
Chris@16 247 } // namespace impl
Chris@16 248
Chris@16 249 ///////////////////////////////////////////////////////////////////////////////
Chris@16 250 // tag::extended_p_square
Chris@16 251 //
Chris@16 252 namespace tag
Chris@16 253 {
Chris@16 254 struct extended_p_square
Chris@16 255 : depends_on<count>
Chris@16 256 , extended_p_square_probabilities
Chris@16 257 {
Chris@16 258 typedef accumulators::impl::extended_p_square_impl<mpl::_1> impl;
Chris@16 259
Chris@16 260 #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
Chris@16 261 /// tag::extended_p_square::probabilities named parameter
Chris@16 262 static boost::parameter::keyword<tag::probabilities> const probabilities;
Chris@16 263 #endif
Chris@16 264 };
Chris@16 265 }
Chris@16 266
Chris@16 267 ///////////////////////////////////////////////////////////////////////////////
Chris@16 268 // extract::extended_p_square
Chris@16 269 //
Chris@16 270 namespace extract
Chris@16 271 {
Chris@16 272 extractor<tag::extended_p_square> const extended_p_square = {};
Chris@16 273
Chris@16 274 BOOST_ACCUMULATORS_IGNORE_GLOBAL(extended_p_square)
Chris@16 275 }
Chris@16 276
Chris@16 277 using extract::extended_p_square;
Chris@16 278
Chris@16 279 // So that extended_p_square can be automatically substituted with
Chris@16 280 // weighted_extended_p_square when the weight parameter is non-void
Chris@16 281 template<>
Chris@16 282 struct as_weighted_feature<tag::extended_p_square>
Chris@16 283 {
Chris@16 284 typedef tag::weighted_extended_p_square type;
Chris@16 285 };
Chris@16 286
Chris@16 287 template<>
Chris@16 288 struct feature_of<tag::weighted_extended_p_square>
Chris@16 289 : feature_of<tag::extended_p_square>
Chris@16 290 {
Chris@16 291 };
Chris@16 292
Chris@16 293 }} // namespace boost::accumulators
Chris@16 294
Chris@16 295 #endif