tail.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // tail.hpp
  3. //
  4. // Copyright 2005 Eric Niebler, Michael Gauckler. 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. #ifndef BOOST_ACCUMULATORS_STATISTICS_TAIL_HPP_EAN_28_10_2005
  8. #define BOOST_ACCUMULATORS_STATISTICS_TAIL_HPP_EAN_28_10_2005
  9. #include <vector>
  10. #include <functional>
  11. #include <boost/assert.hpp>
  12. #include <boost/range.hpp>
  13. #include <boost/mpl/if.hpp>
  14. #include <boost/mpl/or.hpp>
  15. #include <boost/mpl/placeholders.hpp>
  16. #include <boost/parameter/keyword.hpp>
  17. #include <boost/iterator/reverse_iterator.hpp>
  18. #include <boost/iterator/permutation_iterator.hpp>
  19. #include <boost/accumulators/accumulators_fwd.hpp>
  20. #include <boost/accumulators/framework/accumulator_base.hpp>
  21. #include <boost/accumulators/framework/extractor.hpp>
  22. #include <boost/accumulators/numeric/functional.hpp>
  23. #include <boost/accumulators/framework/parameters/sample.hpp>
  24. #include <boost/accumulators/framework/depends_on.hpp>
  25. #include <boost/accumulators/statistics_fwd.hpp>
  26. namespace boost { namespace accumulators
  27. {
  28. ///////////////////////////////////////////////////////////////////////////////
  29. // cache_size named parameters
  30. BOOST_PARAMETER_NESTED_KEYWORD(tag, right_tail_cache_size, cache_size)
  31. BOOST_PARAMETER_NESTED_KEYWORD(tag, left_tail_cache_size, cache_size)
  32. BOOST_ACCUMULATORS_IGNORE_GLOBAL(right_tail_cache_size)
  33. BOOST_ACCUMULATORS_IGNORE_GLOBAL(left_tail_cache_size)
  34. namespace detail
  35. {
  36. ///////////////////////////////////////////////////////////////////////////////
  37. // tail_range
  38. /// INTERNAL ONLY
  39. ///
  40. template<typename ElementIterator, typename IndexIterator>
  41. struct tail_range
  42. {
  43. typedef boost::iterator_range<
  44. boost::reverse_iterator<boost::permutation_iterator<ElementIterator, IndexIterator> >
  45. > type;
  46. };
  47. ///////////////////////////////////////////////////////////////////////////////
  48. // make_tail_range
  49. /// INTERNAL ONLY
  50. ///
  51. template<typename ElementIterator, typename IndexIterator>
  52. typename tail_range<ElementIterator, IndexIterator>::type
  53. make_tail_range(ElementIterator elem_begin, IndexIterator index_begin, IndexIterator index_end)
  54. {
  55. return boost::make_iterator_range(
  56. boost::make_reverse_iterator(
  57. boost::make_permutation_iterator(elem_begin, index_end)
  58. )
  59. , boost::make_reverse_iterator(
  60. boost::make_permutation_iterator(elem_begin, index_begin)
  61. )
  62. );
  63. }
  64. ///////////////////////////////////////////////////////////////////////////////
  65. // stat_assign_visitor
  66. /// INTERNAL ONLY
  67. ///
  68. template<typename Args>
  69. struct stat_assign_visitor
  70. {
  71. stat_assign_visitor(Args const &a, std::size_t i)
  72. : args(a)
  73. , index(i)
  74. {
  75. }
  76. template<typename Stat>
  77. void operator ()(Stat &stat) const
  78. {
  79. stat.assign(this->args, this->index);
  80. }
  81. private:
  82. stat_assign_visitor &operator =(stat_assign_visitor const &);
  83. Args const &args;
  84. std::size_t index;
  85. };
  86. ///////////////////////////////////////////////////////////////////////////////
  87. // stat_assign
  88. /// INTERNAL ONLY
  89. ///
  90. template<typename Args>
  91. inline stat_assign_visitor<Args> const stat_assign(Args const &args, std::size_t index)
  92. {
  93. return stat_assign_visitor<Args>(args, index);
  94. }
  95. ///////////////////////////////////////////////////////////////////////////////
  96. // is_tail_variate_feature
  97. /// INTERNAL ONLY
  98. ///
  99. template<typename Stat, typename LeftRight>
  100. struct is_tail_variate_feature
  101. : mpl::false_
  102. {
  103. };
  104. /// INTERNAL ONLY
  105. ///
  106. template<typename VariateType, typename VariateTag, typename LeftRight>
  107. struct is_tail_variate_feature<tag::tail_variate<VariateType, VariateTag, LeftRight>, LeftRight>
  108. : mpl::true_
  109. {
  110. };
  111. /// INTERNAL ONLY
  112. ///
  113. template<typename LeftRight>
  114. struct is_tail_variate_feature<tag::tail_weights<LeftRight>, LeftRight>
  115. : mpl::true_
  116. {
  117. };
  118. } // namespace detail
  119. namespace impl
  120. {
  121. ///////////////////////////////////////////////////////////////////////////////
  122. // tail_impl
  123. template<typename Sample, typename LeftRight>
  124. struct tail_impl
  125. : accumulator_base
  126. {
  127. // LeftRight must be either right or left
  128. BOOST_MPL_ASSERT((
  129. mpl::or_<is_same<LeftRight, right>, is_same<LeftRight, left> >
  130. ));
  131. typedef
  132. typename mpl::if_<
  133. is_same<LeftRight, right>
  134. , numeric::functional::greater<Sample const, Sample const>
  135. , numeric::functional::less<Sample const, Sample const>
  136. >::type
  137. predicate_type;
  138. // for boost::result_of
  139. typedef typename detail::tail_range<
  140. typename std::vector<Sample>::const_iterator
  141. , std::vector<std::size_t>::iterator
  142. >::type result_type;
  143. template<typename Args>
  144. tail_impl(Args const &args)
  145. : is_sorted(false)
  146. , indices()
  147. , samples(args[tag::tail<LeftRight>::cache_size], args[sample | Sample()])
  148. {
  149. this->indices.reserve(this->samples.size());
  150. }
  151. tail_impl(tail_impl const &that)
  152. : is_sorted(that.is_sorted)
  153. , indices(that.indices)
  154. , samples(that.samples)
  155. {
  156. this->indices.reserve(this->samples.size());
  157. }
  158. // This just stores the heap and the samples.
  159. // In operator()() below, if we are adding a new sample
  160. // to the sample cache, we force all the
  161. // tail_variates to update also. (It's not
  162. // good enough to wait for the accumulator_set to do it
  163. // for us because then information about whether a sample
  164. // was stored and where is lost, and would need to be
  165. // queried at runtime, which would be slow.) This is
  166. // implemented as a filtered visitation over the stats,
  167. // which we can access because args[accumulator] gives us
  168. // all the stats.
  169. template<typename Args>
  170. void operator ()(Args const &args)
  171. {
  172. if(this->indices.size() < this->samples.size())
  173. {
  174. this->indices.push_back(this->indices.size());
  175. this->assign(args, this->indices.back());
  176. }
  177. else if(predicate_type()(args[sample], this->samples[this->indices[0]]))
  178. {
  179. std::pop_heap(this->indices.begin(), this->indices.end(), indirect_cmp(this->samples));
  180. this->assign(args, this->indices.back());
  181. }
  182. }
  183. result_type result(dont_care) const
  184. {
  185. if(!this->is_sorted)
  186. {
  187. // Must use the same predicate here as in push_heap/pop_heap above.
  188. std::sort_heap(this->indices.begin(), this->indices.end(), indirect_cmp(this->samples));
  189. // sort_heap puts elements in reverse order. Calling std::reverse
  190. // turns the sorted sequence back into a valid heap.
  191. std::reverse(this->indices.begin(), this->indices.end());
  192. this->is_sorted = true;
  193. }
  194. return detail::make_tail_range(
  195. this->samples.begin()
  196. , this->indices.begin()
  197. , this->indices.end()
  198. );
  199. }
  200. private:
  201. struct is_tail_variate
  202. {
  203. template<typename T>
  204. struct apply
  205. : detail::is_tail_variate_feature<
  206. typename detail::feature_tag<T>::type
  207. , LeftRight
  208. >
  209. {};
  210. };
  211. template<typename Args>
  212. void assign(Args const &args, std::size_t index)
  213. {
  214. BOOST_ASSERT(index < this->samples.size());
  215. this->samples[index] = args[sample];
  216. std::push_heap(this->indices.begin(), this->indices.end(), indirect_cmp(this->samples));
  217. this->is_sorted = false;
  218. // Tell the tail variates to store their values also
  219. args[accumulator].template visit_if<is_tail_variate>(detail::stat_assign(args, index));
  220. }
  221. ///////////////////////////////////////////////////////////////////////////////
  222. //
  223. struct indirect_cmp
  224. {
  225. typedef std::size_t first_argument_type;
  226. typedef std::size_t second_argument_type;
  227. typedef bool result_type;
  228. indirect_cmp(std::vector<Sample> const &s)
  229. : samples(s)
  230. {
  231. }
  232. bool operator ()(std::size_t left, std::size_t right) const
  233. {
  234. return predicate_type()(this->samples[left], this->samples[right]);
  235. }
  236. private:
  237. indirect_cmp &operator =(indirect_cmp const &);
  238. std::vector<Sample> const &samples;
  239. };
  240. public:
  241. // make this accumulator serializeable
  242. template<class Archive>
  243. void serialize(Archive & ar, const unsigned int file_version)
  244. {
  245. ar & is_sorted;
  246. ar & indices;
  247. ar & samples;
  248. }
  249. private:
  250. mutable bool is_sorted;
  251. mutable std::vector<std::size_t> indices;
  252. std::vector<Sample> samples;
  253. };
  254. } // namespace impl
  255. // TODO The templatized tag::tail below should inherit from the correct named parameter.
  256. // The following lines provide a workaround, but there must be a better way of doing this.
  257. template<typename T>
  258. struct tail_cache_size_named_arg
  259. {
  260. };
  261. template<>
  262. struct tail_cache_size_named_arg<left>
  263. : tag::left_tail_cache_size
  264. {
  265. };
  266. template<>
  267. struct tail_cache_size_named_arg<right>
  268. : tag::right_tail_cache_size
  269. {
  270. };
  271. ///////////////////////////////////////////////////////////////////////////////
  272. // tag::tail<>
  273. //
  274. namespace tag
  275. {
  276. template<typename LeftRight>
  277. struct tail
  278. : depends_on<>
  279. , tail_cache_size_named_arg<LeftRight>
  280. {
  281. /// INTERNAL ONLY
  282. ///
  283. typedef accumulators::impl::tail_impl<mpl::_1, LeftRight> impl;
  284. #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
  285. /// tag::tail<LeftRight>::cache_size named parameter
  286. static boost::parameter::keyword<tail_cache_size_named_arg<LeftRight> > const cache_size;
  287. #endif
  288. };
  289. struct abstract_tail
  290. : depends_on<>
  291. {
  292. };
  293. }
  294. ///////////////////////////////////////////////////////////////////////////////
  295. // extract::tail
  296. //
  297. namespace extract
  298. {
  299. extractor<tag::abstract_tail> const tail = {};
  300. BOOST_ACCUMULATORS_IGNORE_GLOBAL(tail)
  301. }
  302. using extract::tail;
  303. template<typename LeftRight>
  304. struct feature_of<tag::tail<LeftRight> >
  305. : feature_of<tag::abstract_tail>
  306. {
  307. };
  308. }} // namespace boost::accumulators
  309. #endif