vSMC  v3.0.0
Scalable Monte Carlo
counter.hpp
Go to the documentation of this file.
1 //============================================================================
2 // vSMC/include/vsmc/rng/counter.hpp
3 //----------------------------------------------------------------------------
4 // vSMC: Scalable Monte Carlo
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2016, Yan Zhou
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //============================================================================
31 
32 #ifndef VSMC_RNG_COUNTER_HPP
33 #define VSMC_RNG_COUNTER_HPP
34 
36 
37 namespace vsmc
38 {
39 
40 namespace internal
41 {
42 
43 template <std::size_t, typename T, std::size_t K>
44 inline void increment_single(std::array<T, K> &, std::false_type)
45 {
46 }
47 
48 template <std::size_t N, typename T, std::size_t K>
49 inline void increment_single(std::array<T, K> &ctr, std::true_type)
50 {
51  if (++std::get<N>(ctr) != 0)
52  return;
53 
54  increment_single<N + 1>(ctr, std::integral_constant<bool, N + 1 < K>());
55 }
56 
57 } // namespace vsmc::internal
58 
61 template <typename T, std::size_t K>
62 inline void increment(std::array<T, K> &ctr)
63 {
64  internal::increment_single<0>(ctr, std::true_type());
65 }
66 
69 template <typename T, std::size_t K, T NSkip>
70 inline void increment(std::array<T, K> &ctr, std::integral_constant<T, NSkip>)
71 {
72  if (ctr.front() < std::numeric_limits<T>::max() - NSkip) {
73  ctr.front() += NSkip;
74  } else {
75  ctr.front() += NSkip;
76  internal::increment_single<1>(
77  ctr, std::integral_constant<bool, 1 < K>());
78  }
79 }
80 
83 template <typename T, std::size_t K>
84 inline void increment(std::array<T, K> &ctr, T nskip)
85 {
86  if (ctr.front() < std::numeric_limits<T>::max() - nskip) {
87  ctr.front() += nskip;
88  } else {
89  ctr.front() += nskip;
90  internal::increment_single<1>(
91  ctr, std::integral_constant<bool, 1 < K>());
92  }
93 }
94 
95 namespace internal
96 {
97 
98 template <std::size_t, typename T, std::size_t K, std::size_t Blocks>
99 inline void increment_block_set(const std::array<T, K> &,
100  std::array<std::array<T, K>, Blocks> &, std::false_type)
101 {
102 }
103 
104 template <std::size_t B, typename T, std::size_t K, std::size_t Blocks>
105 inline void increment_block_set(const std::array<T, K> &ctr,
106  std::array<std::array<T, K>, Blocks> &ctr_block, std::true_type)
107 {
108  std::get<B>(ctr_block) = ctr;
109  increment_block_set<B + 1>(
110  ctr, ctr_block, std::integral_constant<bool, B + 1 < Blocks>());
111 }
112 
113 template <std::size_t, typename T, std::size_t K, std::size_t Blocks>
114 inline void increment_block(std::array<T, K> &,
115  std::array<std::array<T, K>, Blocks> &, std::false_type)
116 {
117 }
118 
119 template <std::size_t B, typename T, std::size_t K, std::size_t Blocks>
120 inline void increment_block(std::array<T, K> &ctr,
121  std::array<std::array<T, K>, Blocks> &ctr_block, std::true_type)
122 {
123  increment(std::get<B>(ctr_block), std::integral_constant<T, B + 1>());
124  increment_block<B + 1>(
125  ctr, ctr_block, std::integral_constant<bool, B + 1 < Blocks>());
126 }
127 
128 template <std::size_t, typename T, std::size_t K, std::size_t Blocks>
129 inline void increment_block_safe(std::array<T, K> &,
130  std::array<std::array<T, K>, Blocks> &, std::false_type)
131 {
132 }
133 
134 template <std::size_t B, typename T, std::size_t K, std::size_t Blocks>
135 inline void increment_block_safe(std::array<T, K> &ctr,
136  std::array<std::array<T, K>, Blocks> &ctr_block, std::true_type)
137 {
138  std::get<B>(ctr_block).front() += B + 1;
139  increment_block_safe<B + 1>(
140  ctr, ctr_block, std::integral_constant<bool, B + 1 < Blocks>());
141 }
142 
143 } // namespace vsmc::internal
144 
148 template <typename T, std::size_t K, std::size_t Blocks>
149 inline void increment(
150  std::array<T, K> &ctr, std::array<std::array<T, K>, Blocks> &ctr_block)
151 {
152  internal::increment_block_set<0>(
153  ctr, ctr_block, std::integral_constant<bool, 0 < Blocks>());
154  if (ctr.front() < std::numeric_limits<T>::max() - static_cast<T>(Blocks)) {
155  internal::increment_block_safe<0>(
156  ctr, ctr_block, std::integral_constant<bool, 0 < Blocks>());
157  } else {
158  internal::increment_block<0>(
159  ctr, ctr_block, std::integral_constant<bool, 0 < Blocks>());
160  }
161  ctr = ctr_block.back();
162 }
163 
186 template <typename ResultType, typename Generator>
188 {
189  static_assert(std::is_unsigned<ResultType>::value,
190  "**CounterEngine** USED WITH ResultType OTHER THAN UNSIGNED INTGER "
191  "TYPES");
192 
193  static_assert(Generator::size() % sizeof(ResultType) == 0,
194  "**CounterEngine** USED WITH Generator::size() NOT DIVISIBLE BY "
195  "sizeof(ResultType)");
196 
197  public:
198  using result_type = ResultType;
199  using generator_type = Generator;
200  using ctr_type = typename generator_type::ctr_type;
201  using key_type = typename generator_type::key_type;
202  using skip_type = typename ctr_type::value_type;
203 
204  explicit CounterEngine(result_type s = 1) : index_(M_) { seed(s); }
205 
206  template <typename SeedSeq>
207  explicit CounterEngine(SeedSeq &seq,
208  typename std::enable_if<internal::is_seed_seq<SeedSeq, ResultType,
210  nullptr)
211  : index_(M_)
212  {
213  seed(seq);
214  }
215 
216  explicit CounterEngine(const key_type &k) : index_(M_) { seed(k); }
217 
219  {
220  key_type key;
221  std::memset(key.data(), 0, sizeof(key_type));
222  std::memcpy(key.data(), &s, std::min(sizeof(s), sizeof(key)));
223  reset(key);
224  }
225 
226  template <typename SeedSeq>
227  void seed(
228  SeedSeq &seq, typename std::enable_if<internal::is_seed_seq<SeedSeq,
229  ResultType, key_type>::value>::type * = nullptr)
230  {
231  key_type key;
232  std::array<unsigned, sizeof(key) / sizeof(unsigned) + 1> s;
233  seq.generator(s.begin(), s.end());
234  std::memcpy(key.data(), s.data(), std::min(sizeof(s), sizeof(key)));
235  reset(key);
236  }
237 
238  void seed(const key_type &key) { reset(key); }
239 
240  void key(const key_type &k) { reset(k); }
241 
242  void ctr(const ctr_type &c)
243  {
244  ctr_ = c;
245  index_ = M_;
246  }
247 
249  {
250  if (index_ == M_) {
251  generator_(ctr_, buffer_);
252  index_ = 0;
253  }
254 
255  return buffer_[static_cast<std::size_t>(index_++)];
256  }
257 
258  void operator()(std::size_t n, result_type *r)
259  {
260  const std::size_t remain = static_cast<std::size_t>(M_ - index_);
261 
262  if (n < remain) {
263  std::copy_n(buffer_.data() + index_, n, r);
264  index_ += static_cast<unsigned>(n);
265  return;
266  }
267 
268  std::copy_n(buffer_.data() + index_, remain, r);
269  r += remain;
270  n -= remain;
271  index_ = M_;
272 
273  const std::size_t m = n / M_;
274  generator_(ctr_, m, reinterpret_cast<buffer_type *>(r));
275  r += m * M_;
276  n -= m * M_;
277 
278  generator_(ctr_, buffer_);
279  std::copy_n(buffer_.data(), n, r);
280  index_ = static_cast<unsigned>(n);
281  }
282 
284  std::size_t discard()
285  {
286  const std::size_t remain = static_cast<std::size_t>(M_ - index_);
287  index_ = M_;
288 
289  return remain;
290  }
291 
292  void discard(skip_type nskip)
293  {
294  if (nskip == 0)
295  return;
296 
297  const skip_type remain = static_cast<skip_type>(M_ - index_);
298  if (nskip <= remain) {
299  index_ += static_cast<unsigned>(nskip);
300  return;
301  }
302  nskip -= remain;
303  index_ = M_;
304 
305  skip_type M = static_cast<skip_type>(M_);
306  std::size_t buf_size = sizeof(buffer_type);
307  std::size_t ctr_size = sizeof(ctr_type);
308  skip_type rate = static_cast<skip_type>(buf_size / ctr_size);
309  increment(ctr_, nskip / M * rate);
310  generator_(ctr_, buffer_);
311  index_ = static_cast<unsigned>(nskip % M);
312  }
313 
314  static constexpr result_type min()
315  {
316  return std::numeric_limits<result_type>::min();
317  }
318 
319  static constexpr result_type max()
320  {
321  return std::numeric_limits<result_type>::max();
322  }
323 
329  {
330  if (eng1.buffer_ != eng2.buffer_)
331  return false;
332  if (eng1.ctr_ != eng2.ctr_)
333  return false;
334  if (eng1.generator_ != eng2.generator_)
335  return false;
336  if (eng1.index_ != eng2.index_)
337  return false;
338  return true;
339  }
340 
346  {
347  return !(eng1 == eng2);
348  }
349 
350  template <typename CharT, typename Traits>
351  friend std::basic_ostream<CharT, Traits> &operator<<(
352  std::basic_ostream<CharT, Traits> &os,
354  {
355  if (!os)
356  return os;
357 
358  os << eng.buffer_ << ' ';
359  os << eng.ctr_ << ' ';
360  os << eng.generator_ << ' ';
361  os << eng.index_;
362 
363  return os;
364  }
365 
366  template <typename CharT, typename Traits>
367  friend std::basic_istream<CharT, Traits> &operator>>(
368  std::basic_istream<CharT, Traits> &is,
370  {
371  if (!is)
372  return is;
373 
375  is >> std::ws >> eng_tmp.buffer_;
376  is >> std::ws >> eng_tmp.ctr_;
377  is >> std::ws >> eng_tmp.generator_;
378  is >> std::ws >> eng_tmp.index_;
379 
380  if (is)
381  eng = std::move(eng_tmp);
382 
383  return is;
384  }
385 
386  private:
387  static constexpr unsigned M_ = Generator::size() / sizeof(ResultType);
388 
389  using buffer_type = std::array<ResultType, M_>;
390 
391  buffer_type buffer_;
392  ctr_type ctr_;
393  generator_type generator_;
394  unsigned index_;
395 
396  void reset(const key_type key)
397  {
398  ctr_.fill(0);
399  generator_.reset(key);
400  index_ = M_;
401  }
402 }; // class CounterEngine
403 
404 template <typename ResultType, typename Generator>
405 inline void rand(
406  CounterEngine<ResultType, Generator> &rng, std::size_t n, ResultType *r)
407 {
408  rng(n, r);
409 }
410 
411 } // namespace vsmc
412 
413 #endif // VSMC_RNG_COUNTER_HPP
Definition: monitor.hpp:48
void ctr(const ctr_type &c)
Definition: counter.hpp:242
void seed(SeedSeq &seq, typename std::enable_if< internal::is_seed_seq< SeedSeq, ResultType, key_type >::value >::type *=nullptr)
Definition: counter.hpp:227
result_type operator()()
Definition: counter.hpp:248
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const CounterEngine< ResultType, Generator > &eng)
Definition: counter.hpp:351
void increment(std::array< T, K > &ctr)
Increment a counter by one.
Definition: counter.hpp:62
typename generator_type::key_type key_type
Definition: counter.hpp:201
void key(const key_type &k)
Definition: counter.hpp:240
CounterEngine(SeedSeq &seq, typename std::enable_if< internal::is_seed_seq< SeedSeq, ResultType, key_type, CounterEngine< ResultType, Generator >>::value >::type *=nullptr)
Definition: counter.hpp:207
void increment_block(std::array< T, K > &, std::array< std::array< T, K >, Blocks > &, std::false_type)
Definition: counter.hpp:114
Counter based RNG engine.
Definition: counter.hpp:187
static constexpr result_type max()
Definition: counter.hpp:319
void operator()(std::size_t n, result_type *r)
Definition: counter.hpp:258
Generator generator_type
Definition: counter.hpp:199
CounterEngine(result_type s=1)
Definition: counter.hpp:204
void increment_block_set(const std::array< T, K > &, std::array< std::array< T, K >, Blocks > &, std::false_type)
Definition: counter.hpp:99
static constexpr result_type min()
Definition: counter.hpp:314
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, CounterEngine< ResultType, Generator > &eng)
Definition: counter.hpp:367
std::size_t discard()
Discard the buffer.
Definition: counter.hpp:284
friend bool operator!=(const CounterEngine< ResultType, Generator > &eng1, const CounterEngine< ResultType, Generator > &eng2)
eng1 != eng2 is a necessary condition for subsequent call of operator() output different results...
Definition: counter.hpp:344
friend bool operator==(const CounterEngine< ResultType, Generator > &eng1, const CounterEngine< ResultType, Generator > &eng2)
eng1 == eng2 is a sufficent condition for subsequent call of operator() output the same results...
Definition: counter.hpp:327
typename ctr_type::value_type skip_type
Definition: counter.hpp:202
CounterEngine(const key_type &k)
Definition: counter.hpp:216
void discard(skip_type nskip)
Definition: counter.hpp:292
void seed(result_type s)
Definition: counter.hpp:218
void seed(const key_type &key)
Definition: counter.hpp:238
typename generator_type::ctr_type ctr_type
Definition: counter.hpp:200
void rand(RNGType &rng, ArcsineDistribution< RealType > &dist, std::size_t N, RealType *r)
ResultType result_type
Definition: counter.hpp:198
void increment_block_safe(std::array< T, K > &, std::array< std::array< T, K >, Blocks > &, std::false_type)
Definition: counter.hpp:129
void increment_single(std::array< T, K > &, std::false_type)
Definition: counter.hpp:44