File indexing completed on 2025-01-18 09:28:21
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_ACCUMULATORS_STATISTICS_TAIL_HPP_EAN_28_10_2005
0009 #define BOOST_ACCUMULATORS_STATISTICS_TAIL_HPP_EAN_28_10_2005
0010
0011 #include <vector>
0012 #include <functional>
0013 #include <boost/assert.hpp>
0014 #include <boost/range.hpp>
0015 #include <boost/mpl/if.hpp>
0016 #include <boost/mpl/or.hpp>
0017 #include <boost/mpl/placeholders.hpp>
0018 #include <boost/parameter/keyword.hpp>
0019 #include <boost/iterator/reverse_iterator.hpp>
0020 #include <boost/iterator/permutation_iterator.hpp>
0021 #include <boost/accumulators/accumulators_fwd.hpp>
0022 #include <boost/accumulators/framework/accumulator_base.hpp>
0023 #include <boost/accumulators/framework/extractor.hpp>
0024 #include <boost/accumulators/numeric/functional.hpp>
0025 #include <boost/accumulators/framework/parameters/sample.hpp>
0026 #include <boost/accumulators/framework/depends_on.hpp>
0027 #include <boost/accumulators/statistics_fwd.hpp>
0028
0029 namespace boost { namespace accumulators
0030 {
0031
0032
0033 BOOST_PARAMETER_NESTED_KEYWORD(tag, right_tail_cache_size, cache_size)
0034 BOOST_PARAMETER_NESTED_KEYWORD(tag, left_tail_cache_size, cache_size)
0035
0036 BOOST_ACCUMULATORS_IGNORE_GLOBAL(right_tail_cache_size)
0037 BOOST_ACCUMULATORS_IGNORE_GLOBAL(left_tail_cache_size)
0038
0039 namespace detail
0040 {
0041
0042
0043
0044
0045 template<typename ElementIterator, typename IndexIterator>
0046 struct tail_range
0047 {
0048 typedef boost::iterator_range<
0049 boost::reverse_iterator<boost::permutation_iterator<ElementIterator, IndexIterator> >
0050 > type;
0051 };
0052
0053
0054
0055
0056
0057 template<typename ElementIterator, typename IndexIterator>
0058 typename tail_range<ElementIterator, IndexIterator>::type
0059 make_tail_range(ElementIterator elem_begin, IndexIterator index_begin, IndexIterator index_end)
0060 {
0061 return boost::make_iterator_range(
0062 boost::make_reverse_iterator(
0063 boost::make_permutation_iterator(elem_begin, index_end)
0064 )
0065 , boost::make_reverse_iterator(
0066 boost::make_permutation_iterator(elem_begin, index_begin)
0067 )
0068 );
0069 }
0070
0071
0072
0073
0074
0075 template<typename Args>
0076 struct stat_assign_visitor
0077 {
0078 stat_assign_visitor(Args const &a, std::size_t i)
0079 : args(a)
0080 , index(i)
0081 {
0082 }
0083
0084 template<typename Stat>
0085 void operator ()(Stat &stat) const
0086 {
0087 stat.assign(this->args, this->index);
0088 }
0089
0090 private:
0091 BOOST_DELETED_FUNCTION(stat_assign_visitor &operator =(stat_assign_visitor const &))
0092 Args const &args;
0093 std::size_t index;
0094 };
0095
0096
0097
0098
0099
0100 template<typename Args>
0101 inline stat_assign_visitor<Args> const stat_assign(Args const &args, std::size_t index)
0102 {
0103 return stat_assign_visitor<Args>(args, index);
0104 }
0105
0106
0107
0108
0109
0110 template<typename Stat, typename LeftRight>
0111 struct is_tail_variate_feature
0112 : mpl::false_
0113 {
0114 };
0115
0116
0117
0118 template<typename VariateType, typename VariateTag, typename LeftRight>
0119 struct is_tail_variate_feature<tag::tail_variate<VariateType, VariateTag, LeftRight>, LeftRight>
0120 : mpl::true_
0121 {
0122 };
0123
0124
0125
0126 template<typename LeftRight>
0127 struct is_tail_variate_feature<tag::tail_weights<LeftRight>, LeftRight>
0128 : mpl::true_
0129 {
0130 };
0131
0132 }
0133
0134 namespace impl
0135 {
0136
0137
0138 template<typename Sample, typename LeftRight>
0139 struct tail_impl
0140 : accumulator_base
0141 {
0142
0143 BOOST_MPL_ASSERT((
0144 mpl::or_<is_same<LeftRight, right>, is_same<LeftRight, left> >
0145 ));
0146
0147 typedef
0148 typename mpl::if_<
0149 is_same<LeftRight, right>
0150 , numeric::functional::greater<Sample const, Sample const>
0151 , numeric::functional::less<Sample const, Sample const>
0152 >::type
0153 predicate_type;
0154
0155
0156 typedef typename detail::tail_range<
0157 typename std::vector<Sample>::const_iterator
0158 , std::vector<std::size_t>::iterator
0159 >::type result_type;
0160
0161 template<typename Args>
0162 tail_impl(Args const &args)
0163 : is_sorted(false)
0164 , indices()
0165 , samples(args[tag::tail<LeftRight>::cache_size], args[sample | Sample()])
0166 {
0167 this->indices.reserve(this->samples.size());
0168 }
0169
0170 tail_impl(tail_impl const &that)
0171 : is_sorted(that.is_sorted)
0172 , indices(that.indices)
0173 , samples(that.samples)
0174 {
0175 this->indices.reserve(this->samples.size());
0176 }
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190 template<typename Args>
0191 void operator ()(Args const &args)
0192 {
0193 if(this->indices.size() < this->samples.size())
0194 {
0195 this->indices.push_back(this->indices.size());
0196 this->assign(args, this->indices.back());
0197 }
0198 else if(predicate_type()(args[sample], this->samples[this->indices[0]]))
0199 {
0200 std::pop_heap(this->indices.begin(), this->indices.end(), indirect_cmp(this->samples));
0201 this->assign(args, this->indices.back());
0202 }
0203 }
0204
0205 result_type result(dont_care) const
0206 {
0207 if(!this->is_sorted)
0208 {
0209
0210 std::sort_heap(this->indices.begin(), this->indices.end(), indirect_cmp(this->samples));
0211
0212
0213 std::reverse(this->indices.begin(), this->indices.end());
0214 this->is_sorted = true;
0215 }
0216
0217 return detail::make_tail_range(
0218 this->samples.begin()
0219 , this->indices.begin()
0220 , this->indices.end()
0221 );
0222 }
0223
0224 private:
0225
0226 struct is_tail_variate
0227 {
0228 template<typename T>
0229 struct apply
0230 : detail::is_tail_variate_feature<
0231 typename detail::feature_tag<T>::type
0232 , LeftRight
0233 >
0234 {};
0235 };
0236
0237 template<typename Args>
0238 void assign(Args const &args, std::size_t index)
0239 {
0240 BOOST_ASSERT(index < this->samples.size());
0241 this->samples[index] = args[sample];
0242 std::push_heap(this->indices.begin(), this->indices.end(), indirect_cmp(this->samples));
0243 this->is_sorted = false;
0244
0245 args[accumulator].template visit_if<is_tail_variate>(detail::stat_assign(args, index));
0246 }
0247
0248
0249
0250 struct indirect_cmp
0251 {
0252 typedef std::size_t first_argument_type;
0253 typedef std::size_t second_argument_type;
0254 typedef bool result_type;
0255
0256 indirect_cmp(std::vector<Sample> const &s)
0257 : samples(s)
0258 {
0259 }
0260
0261 bool operator ()(std::size_t left, std::size_t right) const
0262 {
0263 return predicate_type()(this->samples[left], this->samples[right]);
0264 }
0265
0266 private:
0267 BOOST_DELETED_FUNCTION(indirect_cmp &operator =(indirect_cmp const &))
0268 std::vector<Sample> const &samples;
0269 };
0270
0271 public:
0272
0273 template<class Archive>
0274 void serialize(Archive & ar, const unsigned int file_version)
0275 {
0276 ar & is_sorted;
0277 ar & indices;
0278 ar & samples;
0279 }
0280
0281 private:
0282 mutable bool is_sorted;
0283 mutable std::vector<std::size_t> indices;
0284 std::vector<Sample> samples;
0285 };
0286
0287 }
0288
0289
0290
0291 template<typename T>
0292 struct tail_cache_size_named_arg
0293 {
0294 };
0295 template<>
0296 struct tail_cache_size_named_arg<left>
0297 : tag::left_tail_cache_size
0298 {
0299 };
0300 template<>
0301 struct tail_cache_size_named_arg<right>
0302 : tag::right_tail_cache_size
0303 {
0304 };
0305
0306
0307
0308
0309 namespace tag
0310 {
0311 template<typename LeftRight>
0312 struct tail
0313 : depends_on<>
0314 , tail_cache_size_named_arg<LeftRight>
0315 {
0316
0317
0318 typedef accumulators::impl::tail_impl<mpl::_1, LeftRight> impl;
0319
0320 #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
0321
0322 static boost::parameter::keyword<tail_cache_size_named_arg<LeftRight> > const cache_size;
0323 #endif
0324 };
0325
0326 struct abstract_tail
0327 : depends_on<>
0328 {
0329 };
0330 }
0331
0332
0333
0334
0335 namespace extract
0336 {
0337 extractor<tag::abstract_tail> const tail = {};
0338
0339 BOOST_ACCUMULATORS_IGNORE_GLOBAL(tail)
0340 }
0341
0342 using extract::tail;
0343
0344 template<typename LeftRight>
0345 struct feature_of<tag::tail<LeftRight> >
0346 : feature_of<tag::abstract_tail>
0347 {
0348 };
0349
0350 }}
0351
0352 #endif