vSMC
vSMC: Scalable Monte Carlo
threefry.hpp
Go to the documentation of this file.
1 //============================================================================
2 // vSMC/include/vsmc/rng/threefry.hpp
3 //----------------------------------------------------------------------------
4 // vSMC: Scalable Monte Carlo
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013,2014, 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_THREEFRY_HPP
33 #define VSMC_RNG_THREEFRY_HPP
34 
36 
37 #define VSMC_STATIC_ASSERT_RNG_THREEFRY_RESULT_TYPE(ResultType) \
38  VSMC_STATIC_ASSERT( \
39  (cxx11::is_same<ResultType, uint32_t>::value || \
40  cxx11::is_same<ResultType, uint64_t>::value), \
41  USE_ThreefryEngine_WITH_INTEGER_TYPE_OTHER_THAN_uint32_t_OR_uint64_t)
42 
43 #define VSMC_STATIC_ASSERT_RNG_THREEFRY_SIZE(K) \
44  VSMC_STATIC_ASSERT((K == 2 || K == 4), \
45  USE_ThreefryEngine_WITH_SIZE_OTHER_THAN_2_OR_4)
46 
47 #define VSMC_STATIC_ASSERT_RNG_THREEFRY \
48  VSMC_STATIC_ASSERT_RNG_THREEFRY_RESULT_TYPE(ResultType); \
49  VSMC_STATIC_ASSERT_RNG_THREEFRY_SIZE(K);
50 
51 #define VSMC_DEFINE_RNG_THREEFRY_ROTATE_CONSTANT(T, K, N, I, val) \
52  template <> struct ThreefryRotateConstantValue < T, K, N, I > : \
53  public cxx11::integral_constant< unsigned, val > {};
54 
57 #ifndef VSMC_RNG_THREEFRY_ROUNDS
58 #define VSMC_RNG_THREEFRY_ROUNDS 20
59 #endif
60 
61 namespace vsmc {
62 
63 namespace internal {
64 
65 template <typename> struct ThreefryKSConstantValue;
66 
67 template <> struct ThreefryKSConstantValue<uint32_t> :
68  public cxx11::integral_constant<uint32_t,
69  UINT32_C(0x1BD11BDA)> {};
70 
71 template <> struct ThreefryKSConstantValue<uint64_t> :
72  public cxx11::integral_constant<uint64_t,
73  UINT64_C(0x1BD11BDAA9FC1A22)> {};
74 
75 template <typename, std::size_t, std::size_t, std::size_t>
77 
86 
95 
104 
113 
122 
131 
132 template <typename ResultType, unsigned N> struct ThreefryRotateImpl;
133 
134 template <unsigned N>
135 struct ThreefryRotateImpl<uint32_t, N>
136 {static uint32_t eval (uint32_t x) {return x << N | x >> (32 - N);}};
137 
138 template <unsigned N>
139 struct ThreefryRotateImpl<uint64_t, N>
140 {static uint64_t eval (uint64_t x) {return x << N | x >> (64 - N);}};
141 
142 template <typename ResultType, std::size_t K, std::size_t N, bool = (N > 0)>
143 struct ThreefryRotate {static void eval (Array<ResultType, K> &) {}};
144 
145 template <typename ResultType, std::size_t N>
146 struct ThreefryRotate<ResultType, 2, N, true>
147 {
148  static void eval (Array<ResultType, 2> &state)
149  {
150  state[Position<0>()] += state[Position<1>()];
151  state[Position<1>()] =
153  ResultType, 2, r_, 0>::value>::eval(state[Position<1>()]);
154  state[Position<1>()] ^= state[Position<0>()];
155  }
156 
157  private :
158 
159  static VSMC_CONSTEXPR const unsigned r_ = (N - 1) % 8;
160 }; // struct ThreefryRotate
161 
162 template <typename ResultType, std::size_t N>
163 struct ThreefryRotate<ResultType, 4, N, true>
164 {
165  static void eval (Array<ResultType, 4> &state)
166  {
167  state[Position<0>()] += state[Position<i0_>()];
168  state[Position<i0_>()] =
170  ResultType, 4, r_, 0>::value>::eval(state[Position<i0_>()]);
171  state[Position<i0_>()] ^= state[Position<0>()];
172 
173  state[Position<2>()] += state[Position<i2_>()];
174  state[Position<i2_>()] =
176  ResultType, 4, r_, 1>::value>::eval(state[Position<i2_>()]);
177  state[Position<i2_>()] ^= state[Position<2>()];
178  }
179 
180  private :
181 
182  static VSMC_CONSTEXPR const std::size_t i0_ = N % 2 ? 1 : 3;
183  static VSMC_CONSTEXPR const std::size_t i2_ = N % 2 ? 3 : 1;
184  static VSMC_CONSTEXPR const unsigned r_ = (N - 1) % 8;
185 }; // struct ThreefryRotate
186 
187 template <typename ResultType, std::size_t K, std::size_t N,
188  bool = (N % 4 == 0)>
190 {
191  static void eval (Array<ResultType, K> &,
192  const Array<ResultType, K + 1> &) {}
193 }; // struct ThreefryInsertKey
194 
195 template <typename ResultType, std::size_t N>
197 {
198  static void eval (Array<ResultType, 2> &state,
199  const Array<ResultType, 3> &par)
200  {
201  state[Position<0>()] += par[Position<i0_>()];
202  state[Position<1>()] += par[Position<i1_>()];
203  state[Position<1>()] += inc_;
204  }
205 
206  private :
207 
208  static VSMC_CONSTEXPR const std::size_t inc_ = N / 4;
209  static VSMC_CONSTEXPR const std::size_t i0_ = (inc_ + 0) % 3;
210  static VSMC_CONSTEXPR const std::size_t i1_ = (inc_ + 1) % 3;
211 }; // struct ThreefryInsertKey
212 
213 template <typename ResultType, std::size_t N>
215 {
216  static void eval (Array<ResultType, 4> &state,
217  const Array<ResultType, 5> &par)
218  {
219  state[Position<0>()] += par[Position<i0_>()];
220  state[Position<1>()] += par[Position<i1_>()];
221  state[Position<2>()] += par[Position<i2_>()];
222  state[Position<3>()] += par[Position<i3_>()];
223  state[Position<3>()] += inc_;
224  }
225 
226  private :
227 
228  static VSMC_CONSTEXPR const std::size_t inc_ = N / 4;
229  static VSMC_CONSTEXPR const std::size_t i0_ = (inc_ + 0) % 5;
230  static VSMC_CONSTEXPR const std::size_t i1_ = (inc_ + 1) % 5;
231  static VSMC_CONSTEXPR const std::size_t i2_ = (inc_ + 2) % 5;
232  static VSMC_CONSTEXPR const std::size_t i3_ = (inc_ + 3) % 5;
233 }; // struct ThreefryInsertKey
234 
235 } // namespace vsmc::internal
236 
263 template <typename ResultType, std::size_t K,
264  std::size_t Rounds = VSMC_RNG_THREEFRY_ROUNDS>
266 {
267  public :
268 
269  typedef ResultType result_type;
273 
274  private :
275 
276  typedef Counter<ctr_type> counter;
277 
278  public :
279 
280  explicit ThreefryEngine (result_type s = 0) : index_(K)
281  {
283  seed(s);
284  }
285 
286  template <typename SeedSeq>
287  explicit ThreefryEngine (SeedSeq &seq,
288  typename cxx11::enable_if<internal::is_seed_seq<SeedSeq,
289  result_type, key_type, ThreefryEngine<ResultType, K, Rounds>
290  >::value>::type * = VSMC_NULLPTR) : index_(K)
291  {
293  seed(seq);
294  }
295 
296  ThreefryEngine (const key_type &k) : index_(K)
297  {
299  seed(k);
300  }
301 
302  void seed (result_type s)
303  {
304  counter::reset(ctr_);
305  key_type k;
306  k.fill(0);
307  k.front() = s;
308  init_par(k);
309  index_ = K;
310  }
311 
312  template <typename SeedSeq>
313  void seed (SeedSeq &seq,
314  typename cxx11::enable_if<internal::is_seed_seq<SeedSeq,
315  result_type, key_type, ThreefryEngine<ResultType, K, Rounds>
316  >::value>::type * = VSMC_NULLPTR)
317  {
318  counter::reset(ctr_);
319  key_type k;
320  seq.generate(k.begin(), k.end());
321  init_par(k);
322  index_ = K;
323  }
324 
325  void seed (const key_type &k)
326  {
327  counter::reset(ctr_);
328  init_par(k);
329  index_ = K;
330  }
331 
332  ctr_type ctr () const {return ctr_;}
333 
334  key_type key () const
335  {
336  key_type k;
337  for (std::size_t i = 0; i != K; ++i)
338  k[i] = par_[i];
339 
340  return k;
341  }
342 
343  void ctr (const ctr_type &c)
344  {
345  counter::set(ctr_, c);
346  index_ = K;
347  }
348 
349  void key (const key_type &k)
350  {
351  init_par(k);
352  index_ = K;
353  }
354 
355  result_type operator() ()
356  {
357  if (index_ == K) {
358  counter::increment(ctr_);
359  generate_buffer(ctr_, buffer_);
360  index_ = 0;
361  }
362 
363  return buffer_[index_++];
364  }
365 
368  buffer_type operator() (const ctr_type &c) const
369  {
370  buffer_type buf;
371  generate_buffer(c, buf);
372 
373  return buf;
374  }
375 
378  void operator() (const ctr_type &c, buffer_type &buf) const
379  {generate_buffer(c, buf);}
380 
381  void discard (result_type nskip)
382  {
383  std::size_t n = static_cast<std::size_t>(nskip);
384  if (index_ + n <= K) {
385  index_ += n;
386  return;
387  }
388 
389  n -= K - index_;
390  if (n <= K) {
391  index_ = K;
392  operator()();
393  index_ = n;
394  return;
395  }
396 
397  counter::increment(ctr_, static_cast<result_type>(n / K));
398  index_ = K;
399  operator()();
400  index_ = n % K;
401  }
402 
403  static VSMC_CONSTEXPR const result_type _Min = 0;
404  static VSMC_CONSTEXPR const result_type _Max = static_cast<result_type>(
405  ~(static_cast<result_type>(0)));
406 
407  static VSMC_CONSTEXPR result_type min VSMC_MNE () {return _Min;}
408  static VSMC_CONSTEXPR result_type max VSMC_MNE () {return _Max;}
409 
410  friend inline bool operator== (
413  {
414  return
415  eng1.index_ == eng2.index_ &&
416  eng1.ctr_ == eng2.ctr_ &&
417  eng1.par_ == eng2.par_;
418  }
419 
420  friend inline bool operator!= (
423  {return !(eng1 == eng2);}
424 
425  template <typename CharT, typename Traits>
426  friend inline std::basic_ostream<CharT, Traits> &operator<< (
427  std::basic_ostream<CharT, Traits> &os,
429  {
430  if (!os.good())
431  return os;
432 
433  os << eng.ctr_ << ' ';
434  os << eng.par_ << ' ';
435  os << eng.buffer_ << ' ';
436  os << eng.index_;
437 
438  return os;
439  }
440 
441  template <typename CharT, typename Traits>
442  friend inline std::basic_istream<CharT, Traits> &operator>> (
443  std::basic_istream<CharT, Traits> &is,
445  {
446  if (!is.good())
447  return is;
448 
450  is >> std::ws >> eng_tmp.ctr_;
451  is >> std::ws >> eng_tmp.par_;
452  is >> std::ws >> eng_tmp.buffer_;
453  is >> std::ws >> eng_tmp.index_;
454 
455  if (is.good()) {
456 #if VSMC_HAS_CXX11_RVALUE_REFERENCES
457  eng = cxx11::move(eng_tmp);
458 #else
459  eng = eng_tmp;
460 #endif
461  }
462 
463  return is;
464  }
465 
466  private :
467 
468  ctr_type ctr_;
470  buffer_type buffer_;
471  std::size_t index_;
472 
473  void generate_buffer (const ctr_type &c, buffer_type &buf) const
474  {
475  buf = c;
476  generate_buffer<0>(buf, cxx11::true_type());
477  }
478 
479  template <std::size_t>
480  void generate_buffer (buffer_type &, cxx11::false_type) const {}
481 
482  template <std::size_t N>
483  void generate_buffer (buffer_type &buf, cxx11::true_type) const
484  {
487  generate_buffer<N + 1>(buf,
488  cxx11::integral_constant<bool, N < Rounds>());
489  }
490 
491  void init_par (const key_type &key)
492  {
493  par_.back() = internal::ThreefryKSConstantValue<ResultType>::value;
494  par_xor<0>(key, cxx11::integral_constant<bool, 0 < K>());
495  }
496 
497  template <std::size_t>
498  void par_xor (const key_type &, cxx11::false_type) {}
499 
500  template <std::size_t N>
501  void par_xor (const key_type &key, cxx11::true_type)
502  {
503  par_[Position<N>()] = key[Position<N>()];
504  par_.back() ^= key[Position<N>()];
505  par_xor<N + 1>(key, cxx11::integral_constant<bool, N + 1 < K>());
506  }
507 }; // class ThreefryEngine
508 
512 
516 
520 
524 
528 
532 
533 } // namespace vsmc
534 
535 #endif // VSMC_RNG_THREEFRY_HPP
Definition: adapter.hpp:37
void key(const key_type &k)
Definition: threefry.hpp:349
Array< ResultType, K > buffer_type
Definition: threefry.hpp:270
#define VSMC_RNG_THREEFRY_ROUNDS
ThreefryEngine default rounds.
Definition: threefry.hpp:58
void ctr(const ctr_type &c)
Definition: threefry.hpp:343
#define VSMC_CONSTEXPR
constexpr
Definition: defines.hpp:55
Threefry RNG engine reimplemented.
Definition: threefry.hpp:265
#define VSMC_DEFINE_RNG_THREEFRY_ROTATE_CONSTANT(T, K, N, I, val)
Definition: threefry.hpp:51
friend bool operator==(const ThreefryEngine< ResultType, K, Rounds > &eng1, const ThreefryEngine< ResultType, K, Rounds > &eng2)
Definition: threefry.hpp:410
ThreefryEngine(result_type s=0)
Definition: threefry.hpp:280
iterator begin()
Definition: array.hpp:131
static constexpr const result_type _Min
Definition: threefry.hpp:403
void discard(result_type nskip)
Definition: threefry.hpp:381
Threefry4x64 Threefry_64
The default 64-bits Threefry engine.
Definition: threefry.hpp:531
ThreefryEngine< uint32_t, 4 > Threefry4x32
Threefry4x32 RNG engine reimplemented.
Definition: threefry.hpp:515
friend bool operator!=(const ThreefryEngine< ResultType, K, Rounds > &eng1, const ThreefryEngine< ResultType, K, Rounds > &eng2)
Definition: threefry.hpp:420
reference front()
Definition: array.hpp:119
static void eval(Array< ResultType, K > &)
Definition: threefry.hpp:143
Array< ResultType, K > key_type
Definition: threefry.hpp:272
static void eval(Array< ResultType, 4 > &state, const Array< ResultType, 5 > &par)
Definition: threefry.hpp:216
ThreefryEngine(SeedSeq &seq, typename cxx11::enable_if< internal::is_seed_seq< SeedSeq, result_type, key_type, ThreefryEngine< ResultType, K, Rounds > >::value >::type *=nullptr)
Definition: threefry.hpp:287
result_type operator()()
Definition: threefry.hpp:355
ThreefryEngine< uint64_t, 4 > Threefry4x64
Threefry4x64 RNG engine reimplemented.
Definition: threefry.hpp:523
reference back()
Definition: array.hpp:123
ThreefryEngine< uint64_t, 2 > Threefry2x64
Threefry2x64 RNG engine reimplemented.
Definition: threefry.hpp:519
integral_constant< bool, false > false_type
Function template argument used for position.
Definition: defines.hpp:126
Threefry4x32 Threefry
The default 32-bits Threefry engine.
Definition: threefry.hpp:527
#define VSMC_MNE
Avoid MSVC stupid behavior: MNE = Macro No Expansion.
Definition: defines.hpp:38
static constexpr const result_type _Max
Definition: threefry.hpp:404
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const ThreefryEngine< ResultType, K, Rounds > &eng)
Definition: threefry.hpp:426
#define VSMC_STATIC_ASSERT_RNG_THREEFRY
Definition: threefry.hpp:47
ResultType result_type
Definition: threefry.hpp:269
ThreefryEngine< uint32_t, 2 > Threefry2x32
Threefry2x32 RNG engine reimplemented.
Definition: threefry.hpp:511
static constexpr result_type min()
Definition: threefry.hpp:407
remove_reference< T >::type && move(T &&t) noexcept
static void eval(Array< ResultType, K > &, const Array< ResultType, K+1 > &)
Definition: threefry.hpp:191
static void eval(Array< ResultType, 2 > &state)
Definition: threefry.hpp:148
static void eval(Array< ResultType, 4 > &state)
Definition: threefry.hpp:165
#define VSMC_NULLPTR
nullptr
Definition: defines.hpp:79
integral_constant< bool, true > true_type
ThreefryEngine(const key_type &k)
Definition: threefry.hpp:296
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, ThreefryEngine< ResultType, K, Rounds > &eng)
Definition: threefry.hpp:442
void fill(const T &value)
Definition: array.hpp:166
ctr_type ctr() const
Definition: threefry.hpp:332
void seed(result_type s)
Definition: threefry.hpp:302
key_type key() const
Definition: threefry.hpp:334
static void eval(Array< ResultType, 2 > &state, const Array< ResultType, 3 > &par)
Definition: threefry.hpp:198
void seed(const key_type &k)
Definition: threefry.hpp:325
Array< ResultType, K > ctr_type
Definition: threefry.hpp:271
iterator end()
Definition: array.hpp:133
void seed(SeedSeq &seq, typename cxx11::enable_if< internal::is_seed_seq< SeedSeq, result_type, key_type, ThreefryEngine< ResultType, K, Rounds > >::value >::type *=nullptr)
Definition: threefry.hpp:313
static constexpr result_type max()
Definition: threefry.hpp:408