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