trsl logo
is_picked_systematic.hpp
Go to the documentation of this file.
1 // (C) Copyright Renaud Detry 2007-2011.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5 
8 #ifndef TRSL_IS_PICKED_SYSTEMATIC_HPP
9 #define TRSL_IS_PICKED_SYSTEMATIC_HPP
10 
11 #include <trsl/common.hpp>
12 #include <trsl/weight_accessor.hpp>
13 
14 #include <algorithm>
15 #include <functional>
16 #include <utility>
17 #include <cstdlib> // rand & random
18 #include <limits>
19 #include <cassert>
20 #include <boost/static_assert.hpp>
21 
23 namespace trsl {
24 
73  template<
74  typename ElementType,
75  typename WeightType = double,
76  typename WeightAccessor = mp_weight_accessor<WeightType, ElementType>
78  {
79  private:
80  BOOST_STATIC_ASSERT((std::numeric_limits<WeightType>::is_integer == false));
81  public:
82  typedef ElementType element_type;
83  typedef WeightType weight_type;
84  typedef WeightAccessor weight_accessor_type;
85 
93  sampleSize_(0),
94  populationWeight_(0)
95  {
96  initialize( 0 );
97  }
98 
124  is_picked_systematic(size_t sampleSize,
125  WeightType populationWeight,
126  WeightAccessor const& wac = WeightAccessor()) :
127  wac_(wac), sampleSize_(sampleSize),
128  populationWeight_(populationWeight)
129  {
130  initialize( rand_gen::uniform_01<WeightType>() );
131  }
132 
164  is_picked_systematic(size_t sampleSize,
165  WeightType populationWeight,
166  WeightType uniform01,
167  WeightAccessor const& wac = WeightAccessor()) :
168  wac_(wac), sampleSize_(sampleSize),
169  populationWeight_(populationWeight)
170  {
171  initialize(uniform01);
172  }
173 
181  bool operator()(const ElementType & e)
182  {
183  if (sampleSize_ == 0) return false;
184 
185 #ifdef TRSL_USE_SYSTEMATIC_INTUITIVE_ALGORITHM
186  // This algorithm is the intuitive implementation of
187  // systematic sampling, where one pictures a wheel with
188  // N_SAMPLE spokes and distributes the population around the
189  // wheel as segments of tire of length proportional to their
190  // weight; the spokes point to picked elements.
191  WeightType arrow = k_*step_;
192  assert(cumulative_ <= arrow);
193  if (arrow < cumulative_ + wac_(e))
194  {
195  k_++;
196  return true;
197  }
198  cumulative_ += wac_(e);
199  return false;
200 #else
201  // This algorithm is a massaged version of the intuitive
202  // algorithm. Both algorithms are conceptually identical, but
203  // this version is faster.
204  assert(position_ >= 0);
205  if (position_ < wac_(e))
206  {
207  position_ += step_;
208  return true;
209  }
210  position_ -= wac_(e);
211  return false;
212 #endif
213  }
214 
226  bool is_first_pick(const ElementType & e) const
227  {
228  if (wac_(e) <= step_) return true;
229 #ifdef TRSL_USE_SYSTEMATIC_INTUITIVE_ALGORITHM
230  return k_*step_ - cumulative_ < 2*step_;
231 #else
232  return position_ < 2*step_;
233 #endif
234  }
235 
244  {
245  if (sampleSize_ != p.sampleSize_ ||
246  populationWeight_ != p.populationWeight_) return false;
247 
248 #ifdef TRSL_USE_SYSTEMATIC_INTUITIVE_ALGORITHM
249  if (cumulative_ != p.cumulative_ ||
250  k_ != p.k_) return false;
251 #else
252  if (position_ != p.position_) return false;
253 #endif
254 
255  return true;
256  }
257 
258  private:
259  void initialize(WeightType randomReal)
260  {
261  // If one could rely on
262  //
263  // (x!=0.0)/0.0 == inf (with the sign of x)
264  //
265  // and on
266  //
267  // 0.0 * inf == NaN,
268  //
269  // neither of these throwing exceptions, then the following
270  // block could be avoided, and the case sampleSize_ == 0 would
271  // be implicitly handled by inf/NaN arithmetic.
272  //
273  // However, it would be necessary to maintain two different
274  // implementations depending on
275  // std::numeric_limits<double>::is_iec559, and even then I'm
276  // not sure if inf/NaN arithmetic is reliable.
277  if (sampleSize_ != 0)
278  step_ = populationWeight_ / sampleSize_;
279  else
280  // A semantically correct value for step_ would be inf, but
281  // we don't want to get into has_infinity trouble...
282  // When sampleSize_==0, step_ should be considered undefined.
283  step_ = 0;
284 
285  WeightType randomWeight = randomReal * step_;
286 #ifdef TRSL_USE_SYSTEMATIC_INTUITIVE_ALGORITHM
287  cumulative_ = -randomWeight;
288  k_ = 0;
289 #else
290  position_ = randomWeight;
291 #endif
292  }
293 
294  private:
295  WeightAccessor wac_;
296  size_t sampleSize_;
297  WeightType populationWeight_;
298  WeightType step_;
299 
300 #ifdef TRSL_USE_SYSTEMATIC_INTUITIVE_ALGORITHM
301  WeightType cumulative_;
302  size_t k_;
303 #else
304  WeightType position_;
305 #endif
306  };
307 
320  template<class Iterator>
321  bool is_first_pick(const Iterator& i)
322  {
323  return i.predicate().is_first_pick(*i);
324  }
325 
326 }
327 
328 #endif // include guard
common.hpp
trsl::is_picked_systematic::is_picked_systematic
is_picked_systematic(size_t sampleSize, WeightType populationWeight, WeightAccessor const &wac=WeightAccessor())
Construction with system-provided random number.
Definition: is_picked_systematic.hpp:124
trsl::is_first_pick
bool is_first_pick(const Iterator &i)
Return whether *i has been picked already.
Definition: is_picked_systematic.hpp:321
trsl
Public namespace.
Definition: common.hpp:29
trsl::is_picked_systematic::operator==
bool operator==(const is_picked_systematic< ElementType, WeightType, WeightAccessor > &p) const
Returns whether two predicates are at the same sampling advancement.
Definition: is_picked_systematic.hpp:243
trsl::is_picked_systematic::operator()
bool operator()(const ElementType &e)
Decides whether e should be picked or not (used by persistent_filter_iterator).
Definition: is_picked_systematic.hpp:181
trsl::is_picked_systematic
Functor to use with persistent_filter_iterator for systematic sampling of a range.
Definition: is_picked_systematic.hpp:77
trsl::is_picked_systematic::is_first_pick
bool is_first_pick(const ElementType &e) const
Return whether e has been picked already.
Definition: is_picked_systematic.hpp:226
trsl::is_picked_systematic::is_picked_systematic
is_picked_systematic(size_t sampleSize, WeightType populationWeight, WeightType uniform01, WeightAccessor const &wac=WeightAccessor())
Construction with user-provided random number.
Definition: is_picked_systematic.hpp:164
weight_accessor.hpp
trsl::is_picked_systematic::is_picked_systematic
is_picked_systematic()
Default constructor, shoud not be used explicitely.
Definition: is_picked_systematic.hpp:92
© Copyright 2007-2011 Renaud Detry.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at www.boost.org/LICENSE_1_0.txt.)
Revised Wed Jan 8 2020 14:43:31.