libUTL++
randutils.hpp
1 /*
2  * Random-Number Utilities (randutil)
3  * Addresses common issues with C++11 random number generation.
4  * Makes good seeding easier, and makes using RNGs easy while retaining
5  * all the power.
6  *
7  * The MIT License (MIT)
8  *
9  * Copyright (c) 2015 Melissa E. O'Neill
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE.
28  */
29 
30 #ifndef RANDUTILS_HPP
31 #define RANDUTILS_HPP 1
32 
33 /*
34  * This header includes three class templates that can help make C++11
35  * random number generation easier to use.
36  *
37  * randutils::seed_seq_fe
38  *
39  * Fixed-Entropy Seed sequence
40  *
41  * Provides a replacement for std::seed_seq that avoids problems with bias,
42  * performs better in empirical statistical tests, and executes faster in
43  * normal-sized use cases.
44  *
45  * In normal use, it's accessed via one of the following type aliases
46  *
47  * randutils::seed_seq_fe128
48  * randutils::seed_seq_fe256
49  *
50  * It's discussed in detail at
51  * http://www.pcg-random.org/posts/developing-a-seed_seq-alternative.html
52  * and the motivation for its creation (what's wrong with std::seed_seq) here
53  * http://www.pcg-random.org/posts/cpp-seeding-surprises.html
54  *
55  *
56  * randutils::auto_seeded
57  *
58  * Extends a seed sequence class with a nondeterministic default constructor.
59  * Uses a variety of local sources of entropy to portably initialize any
60  * seed sequence to a good default state.
61  *
62  * In normal use, it's accessed via one of the following type aliases, which
63  * use seed_seq_fe128 and seed_seq_fe256 above.
64  *
65  * randutils::auto_seed_128
66  * randutils::auto_seed_256
67  *
68  * It's discussed in detail at
69  * http://www.pcg-random.org/posts/simple-portable-cpp-seed-entropy.html
70  * and its motivation (why you can't just use std::random_device) here
71  * http://www.pcg-random.org/posts/cpps-random_device.html
72  *
73  *
74  * randutils::random_generator
75  *
76  * An Easy-to-Use Random API
77  *
78  * Provides all the power of C++11's random number facility in an easy-to
79  * use wrapper.
80  *
81  * In normal use, it's accessed via one of the following type aliases, which
82  * also use auto_seed_256 by default
83  *
84  * randutils::default_rng
85  * randutils::mt19937_rng
86  *
87  * It's discussed in detail at
88  * http://www.pcg-random.org/posts/ease-of-use-without-loss-of-power.html
89  */
90 
91 #include <cstddef>
92 #include <cstdint>
93 #include <cstdlib>
94 #include <random>
95 #include <array>
96 #include <functional> // for std::hash
97 #include <initializer_list>
98 #include <utility>
99 #include <type_traits>
100 #include <iterator>
101 #include <chrono>
102 #include <thread>
103 #include <algorithm>
104 
105 // Ugly platform-specific code for auto_seeded
106 
107 #if !defined(RANDUTILS_CPU_ENTROPY) && defined(__has_builtin)
108 #if __has_builtin(__builtin_readcyclecounter)
109 #define RANDUTILS_CPU_ENTROPY __builtin_readcyclecounter()
110 #endif
111 #endif
112 #if !defined(RANDUTILS_CPU_ENTROPY)
113 #if __i386__
114 #if __GNUC__
115 #define RANDUTILS_CPU_ENTROPY __builtin_ia32_rdtsc()
116 #else
117 #include <immintrin.h>
118 #define RANDUTILS_CPU_ENTROPY __rdtsc()
119 #endif
120 #else
121 #define RANDUTILS_CPU_ENTROPY 0
122 #endif
123 #endif
124 
125 #if defined(RANDUTILS_GETPID)
126 // Already defined externally
127 #elif defined(_WIN64) || defined(_WIN32)
128 #include <process.h>
129 #define RANDUTILS_GETPID _getpid()
130 #elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
131 #include <unistd.h>
132 #define RANDUTILS_GETPID getpid()
133 #else
134 #define RANDUTILS_GETPID 0
135 #endif
136 
137 #if __cpp_constexpr >= 201304L
138 #define RANDUTILS_GENERALIZED_CONSTEXPR constexpr
139 #else
140 #define RANDUTILS_GENERALIZED_CONSTEXPR
141 #endif
142 
143 namespace randutils
144 {
146 //
147 // seed_seq_fe
148 //
150 
151 /*
152  * seed_seq_fe implements a fixed-entropy seed sequence; it conforms to all
153  * the requirements of a Seed Sequence concept.
154  *
155  * seed_seq_fe<N> implements a seed sequence which seeds based on a store of
156  * N * 32 bits of entropy. Typically, it would be initialized with N or more
157  * integers.
158  *
159  * seed_seq_fe128 and seed_seq_fe256 are provided as convenience typedefs for
160  * 128- and 256-bit entropy stores respectively. These variants outperform
161  * std::seed_seq, while being better mixing the bits it is provided as entropy.
162  * In almost all common use cases, they serve as better drop-in replacements
163  * for seed_seq.
164  *
165  * Technical details
166  *
167  * Assuming it constructed with M seed integers as input, it exhibits the
168  * following properties
169  *
170  * * Diffusion/Avalanche: A single-bit change in any of the M inputs has a
171  * 50% chance of flipping every bit in the bitstream produced by generate.
172  * Initializing the N-word entropy store with M words requires O(N * M)
173  * time precisely because of the avalanche requirements. Once constructed,
174  * calls to generate are linear in the number of words generated.
175  *
176  * * Bias freedom/Bijection: If M == N, the state of the entropy store is a
177  * bijection from the M inputs (i.e., no states occur twice, none are
178  * omitted). If M > N the number of times each state can occur is the same
179  * (each state occurs 2**(32*(M-N)) times, where ** is the power function).
180  * If M < N, some states cannot occur (bias) but no state occurs more
181  * than once (it's impossible to avoid bias if M < N; ideally N should not
182  * be chosen so that it is more than M).
183  *
184  * Likewise, the generate function has similar properties (with the entropy
185  * store as the input data). If more outputs are requested than there is
186  * entropy, some outputs cannot occur. For example, the Mersenne Twister
187  * will request 624 outputs, to initialize it's 19937-bit state, which is
188  * much larger than a 128-bit or 256-bit entropy pool. But in practice,
189  * limiting the Mersenne Twister to 2**128 possible initializations gives
190  * us enough initializations to give a unique initialization to trillions
191  * of computers for billions of years. If you really have 624 words of
192  * *real* high-quality entropy you want to use, you probably don't need
193  * an entropy mixer like this class at all. But if you *really* want to,
194  * nothing is stopping you from creating a randutils::seed_seq_fe<624>.
195  *
196  * * As a consequence of the above properties, if all parts of the provided
197  * seed data are kept constant except one, and the remaining part is varied
198  * through K different states, K different output sequences will be produced.
199  *
200  * * Also, because the amount of entropy stored is fixed, this class never
201  * performs dynamic allocation and is free of the possibility of generating
202  * an exception.
203  *
204  * Ideas used to implement this code include hashing, a simple PCG generator
205  * based on an MCG base with an XorShift output function and permutation
206  * functions on tuples.
207  *
208  * More detail at
209  * http://www.pcg-random.org/posts/developing-a-seed_seq-alternative.html
210  */
211 
212 template <size_t count = 4, typename IntRep = uint32_t, size_t mix_rounds = 1 + (count <= 2)>
213 struct seed_seq_fe
214 {
215 public:
216  // types
217  typedef IntRep result_type;
218 
219 private:
220  static constexpr uint32_t INIT_A = 0x43b0d7e5;
221  static constexpr uint32_t MULT_A = 0x931e8875;
222 
223  static constexpr uint32_t INIT_B = 0x8b51f9dd;
224  static constexpr uint32_t MULT_B = 0x58f38ded;
225 
226  static constexpr uint32_t MIX_MULT_L = 0xca01f9dd;
227  static constexpr uint32_t MIX_MULT_R = 0x4973f715;
228  static constexpr uint32_t XSHIFT = sizeof(IntRep) * 8 / 2;
229 
230  RANDUTILS_GENERALIZED_CONSTEXPR
231  static IntRep
232  fast_exp(IntRep x, IntRep power)
233  {
234  IntRep result = IntRep(1);
235  IntRep multiplier = x;
236  while (power != IntRep(0))
237  {
238  IntRep thismult = power & IntRep(1) ? multiplier : IntRep(1);
239  result *= thismult;
240  power >>= 1;
241  multiplier *= multiplier;
242  }
243  return result;
244  }
245 
246  std::array<IntRep, count> mixer_;
247 
248  template <typename InputIter>
249  void mix_entropy(InputIter begin, InputIter end);
250 
251 public:
252  seed_seq_fe(const seed_seq_fe&) = delete;
253  void operator=(const seed_seq_fe&) = delete;
254 
255  template <typename T>
256  seed_seq_fe(std::initializer_list<T> init)
257  {
258  seed(init.begin(), init.end());
259  }
260 
261  template <typename InputIter>
262  seed_seq_fe(InputIter begin, InputIter end)
263  {
264  seed(begin, end);
265  }
266 
267  // generating functions
268  template <typename RandomAccessIterator>
269  void generate(RandomAccessIterator first, RandomAccessIterator last) const;
270 
271  static constexpr size_t
272  size()
273  {
274  return count;
275  }
276 
277  template <typename OutputIterator>
278  void param(OutputIterator dest) const;
279 
280  template <typename InputIter>
281  void
282  seed(InputIter begin, InputIter end)
283  {
284  mix_entropy(begin, end);
285  // For very small sizes, we do some additional mixing. For normal
286  // sizes, this loop never performs any iterations.
287  for (size_t i = 1; i < mix_rounds; ++i) stir();
288  }
289 
290  seed_seq_fe&
291  stir()
292  {
293  mix_entropy(mixer_.begin(), mixer_.end());
294  return *this;
295  }
296 };
297 
298 template <size_t count, typename IntRep, size_t r>
299 template <typename InputIter>
300 void
301 seed_seq_fe<count, IntRep, r>::mix_entropy(InputIter begin, InputIter end)
302 {
303  auto hash_const = INIT_A;
304  auto hash = [&](IntRep value)
305  {
306  value ^= hash_const;
307  hash_const *= MULT_A;
308  value *= hash_const;
309  value ^= value >> XSHIFT;
310  return value;
311  };
312  auto mix = [](IntRep x, IntRep y)
313  {
314  IntRep result = MIX_MULT_L * x - MIX_MULT_R * y;
315  result ^= result >> XSHIFT;
316  return result;
317  };
318 
319  InputIter current = begin;
320  for (auto& elem : mixer_)
321  {
322  if (current != end)
323  elem = hash(*current++);
324  else
325  elem = hash(0U);
326  }
327  for (auto& src : mixer_)
328  for (auto& dest : mixer_)
329  if (&src != &dest) dest = mix(dest, hash(src));
330  for (; current != end; ++current)
331  for (auto& dest : mixer_) dest = mix(dest, hash(*current));
332 }
333 
334 template <size_t count, typename IntRep, size_t mix_rounds>
335 template <typename OutputIterator>
336 void
337 seed_seq_fe<count, IntRep, mix_rounds>::param(OutputIterator dest) const
338 {
339  const IntRep INV_A = fast_exp(MULT_A, IntRep(-1));
340  const IntRep MIX_INV_L = fast_exp(MIX_MULT_L, IntRep(-1));
341 
342  auto mixer_copy = mixer_;
343  for (size_t round = 0; round < mix_rounds; ++round)
344  {
345  // Advance to the final value. We'll backtrack from that.
346  auto hash_const = INIT_A * fast_exp(MULT_A, IntRep(count * count));
347 
348  for (auto src = mixer_copy.rbegin(); src != mixer_copy.rend(); ++src)
349  for (auto dest = mixer_copy.rbegin(); dest != mixer_copy.rend(); ++dest)
350  if (src != dest)
351  {
352  IntRep revhashed = *src;
353  auto mult_const = hash_const;
354  hash_const *= INV_A;
355  revhashed ^= hash_const;
356  revhashed *= mult_const;
357  revhashed ^= revhashed >> XSHIFT;
358  IntRep unmixed = *dest;
359  unmixed ^= unmixed >> XSHIFT;
360  unmixed += MIX_MULT_R * revhashed;
361  unmixed *= MIX_INV_L;
362  *dest = unmixed;
363  }
364  for (auto i = mixer_copy.rbegin(); i != mixer_copy.rend(); ++i)
365  {
366  IntRep unhashed = *i;
367  unhashed ^= unhashed >> XSHIFT;
368  unhashed *= fast_exp(hash_const, IntRep(-1));
369  hash_const *= INV_A;
370  unhashed ^= hash_const;
371  *i = unhashed;
372  }
373  }
374  std::copy(mixer_copy.begin(), mixer_copy.end(), dest);
375 }
376 
377 template <size_t count, typename IntRep, size_t mix_rounds>
378 template <typename RandomAccessIterator>
379 void
380 seed_seq_fe<count, IntRep, mix_rounds>::generate(RandomAccessIterator dest_begin,
381  RandomAccessIterator dest_end) const
382 {
383  auto src_begin = mixer_.begin();
384  auto src_end = mixer_.end();
385  auto src = src_begin;
386  auto hash_const = INIT_B;
387  for (auto dest = dest_begin; dest != dest_end; ++dest)
388  {
389  auto dataval = *src;
390  if (++src == src_end) src = src_begin;
391  dataval ^= hash_const;
392  hash_const *= MULT_B;
393  dataval *= hash_const;
394  dataval ^= dataval >> XSHIFT;
395  *dest = dataval;
396  }
397 }
398 
399 using seed_seq_fe128 = seed_seq_fe<4, uint32_t>;
400 using seed_seq_fe256 = seed_seq_fe<8, uint32_t>;
401 
403 //
404 // auto_seeded
405 //
407 
408 /*
409  * randutils::auto_seeded
410  *
411  * Extends a seed sequence class with a nondeterministic default constructor.
412  * Uses a variety of local sources of entropy to portably initialize any
413  * seed sequence to a good default state.
414  *
415  * In normal use, it's accessed via one of the following type aliases, which
416  * use seed_seq_fe128 and seed_seq_fe256 above.
417  *
418  * randutils::auto_seed_128
419  * randutils::auto_seed_256
420  *
421  * It's discussed in detail at
422  * http://www.pcg-random.org/posts/simple-portable-cpp-seed-entropy.html
423  * and its motivation (why you can't just use std::random_device) here
424  * http://www.pcg-random.org/posts/cpps-random_device.html
425  */
426 
427 template <typename SeedSeq>
428 class auto_seeded : public SeedSeq
429 {
430  using default_seeds = std::array<uint32_t, 11>;
431 
432  template <typename T>
433  static uint32_t
434  crushto32(T value)
435  {
436  if (sizeof(T) <= 4)
437  return uint32_t(value);
438  else
439  {
440  uint64_t result = uint64_t(value);
441  result *= 0xbc2ad017d719504d;
442  return uint32_t(result ^ (result >> 32));
443  }
444  }
445 
446  template <typename T>
447  static uint32_t
448  hash(T&& value)
449  {
450  return crushto32(
451  std::hash<typename std::remove_reference<typename std::remove_cv<T>::type>::type>{}(
452  std::forward<T>(value)));
453  }
454 
455  static constexpr uint32_t
456  fnv(uint32_t hash, const char* pos)
457  {
458  return *pos == '\0' ? hash : fnv((hash * 16777619U) ^ *pos, pos + 1);
459  }
460 
461  default_seeds
462  local_entropy()
463  {
464  // This is a constant that changes every time we compile the code
465  // constexpr uint32_t compile_stamp = fnv(2166136261U, __DATE__ __TIME__ __FILE__);
466 
467  // Some people think you shouldn't use the random device much because
468  // on some platforms it could be expensive to call or "use up" vital
469  // system-wide entropy, so we just call it once.
470  static uint32_t random_int = std::random_device{}();
471 
472  // The heap can vary from run to run as well.
473  void* malloc_addr = malloc(sizeof(int));
474  free(malloc_addr);
475  auto heap = hash(malloc_addr);
476  auto stack = hash(&malloc_addr);
477 
478  // Every call, we increment our random int. We don't care about race
479  // conditons. The more, the merrier.
480  random_int += 0xedf19156;
481 
482  // Classic seed, the time. It ought to change, especially since
483  // this is (hopefully) nanosecond resolution time.
484  auto hitime = std::chrono::high_resolution_clock::now().time_since_epoch().count();
485 
486  // Address of the thing being initialized. That can mean that
487  // different seed sequences in different places in memory will be
488  // different. Even for the same object, it may vary from run to
489  // run in systems with ASLR, such as OS X, but on Linux it might not
490  // unless we compile with -fPIC -pic.
491  auto self_data = hash(this);
492 
493  // The address of the time function. It should hopefully be in
494  // a system library that hopefully isn't always in the same place
495  // (might not change until system is rebooted though)
496  // auto time_func = hash(&std::chrono::high_resolution_clock::now);
497 
498  // The address of the exit function. It should hopefully be in
499  // a system library that hopefully isn't always in the same place
500  // (might not change until system is rebooted though). Hopefully
501  // it's in a different library from time_func.
502  auto exit_func = hash(&_Exit);
503 
504  // The address of a local function. That may be in a totally
505  // different part of memory. On OS X it'll vary from run to run thanks
506  // to ASLR, on Linux it might not unless we compile with -fPIC -pic.
507  // Need the cast because it's an overloaded
508  // function and we need to pick the right one.
509  auto self_func = hash(static_cast<uint32_t (*)(uint64_t)>(&auto_seeded::crushto32));
510 
511  // Hash our thread id. It seems to vary from run to run on OS X, not
512  // so much on Linux.
513  auto thread_id = hash(std::this_thread::get_id());
514 
515 // Hash of the ID of a type. May or may not vary, depending on
516 // implementation.
517 #if __cpp_rtti || __GXX_RTTI
518  auto type_id = crushto32(typeid(*this).hash_code());
519 #else
520  uint32_t type_id = 0;
521 #endif
522 
523  // Platform-specific entropy
524  auto pid = crushto32(RANDUTILS_GETPID);
525  auto cpu = crushto32(RANDUTILS_CPU_ENTROPY);
526 
527  return {{random_int, crushto32(hitime), stack, heap, self_data, self_func, exit_func,
528  thread_id, type_id, pid, cpu}};
529  }
530 
531 public:
532  using SeedSeq::SeedSeq;
533 
534  using base_seed_seq = SeedSeq;
535 
536  const base_seed_seq&
537  base() const
538  {
539  return *this;
540  }
541 
542  base_seed_seq&
543  base()
544  {
545  return *this;
546  }
547 
548  auto_seeded(default_seeds seeds)
549  : SeedSeq(seeds.begin(), seeds.end())
550  {
551  // Nothing else to do
552  }
553 
554  auto_seeded()
555  : auto_seeded(local_entropy())
556  {
557  // Nothing else to do
558  }
559 };
560 
561 using auto_seed_128 = auto_seeded<seed_seq_fe128>;
562 using auto_seed_256 = auto_seeded<seed_seq_fe256>;
563 
565 //
566 // uniform_distribution
567 //
569 
570 /*
571  * This template typedef provides either
572  * - uniform_int_distribution, or
573  * - uniform_real_distribution
574  * depending on the provided type
575  */
576 
577 template <typename Numeric>
578 using uniform_distribution =
579  typename std::conditional<std::is_integral<Numeric>::value,
580  std::uniform_int_distribution<Numeric>,
581  std::uniform_real_distribution<Numeric>>::type;
582 
584 //
585 // random_generator
586 //
588 
589 /*
590  * randutils::random_generator
591  *
592  * An Easy-to-Use Random API
593  *
594  * Provides all the power of C++11's random number facility in an easy-to
595  * use wrapper.
596  *
597  * In normal use, it's accessed via one of the following type aliases, which
598  * also use auto_seed_256 by default
599  *
600  * randutils::default_rng
601  * randutils::mt19937_rng
602  *
603  * It's discussed in detail at
604  * http://www.pcg-random.org/posts/ease-of-use-without-loss-of-power.html
605  */
606 
607 template <typename RandomEngine = std::default_random_engine,
608  typename DefaultSeedSeq = auto_seed_256>
609 class random_generator
610 {
611 public:
612  using engine_type = RandomEngine;
613  using default_seed_type = DefaultSeedSeq;
614 
615 private:
616  engine_type engine_;
617 
618  // This SFNAE evilness provides a mechanism to cast classes that aren't
619  // themselves (technically) Seed Sequences but derive from a seed
620  // sequence to be passed to functions that require actual Seed Squences.
621  // To do so, the class should provide a the type base_seed_seq and a
622  // base() member function.
623 
624  template <typename T>
625  static constexpr bool
626  has_base_seed_seq(typename T::base_seed_seq*)
627  {
628  return true;
629  }
630 
631  template <typename T>
632  static constexpr bool has_base_seed_seq(...)
633  {
634  return false;
635  }
636 
637  template <typename SeedSeqBased>
638  static auto seed_seq_cast(
639  SeedSeqBased&& seq, typename std::enable_if<has_base_seed_seq<SeedSeqBased>(0)>::type* = 0)
640  -> decltype(seq.base())
641  {
642  return seq.base();
643  }
644 
645  template <typename SeedSeq>
646  static SeedSeq
647  seed_seq_cast(SeedSeq&& seq, typename std::enable_if<!has_base_seed_seq<SeedSeq>(0)>::type* = 0)
648  {
649  return seq;
650  }
651 
652 public:
653  template <typename Seeding = default_seed_type, typename... Params>
654  random_generator(Seeding&& seeding = default_seed_type{})
655  : engine_{seed_seq_cast(std::forward<Seeding>(seeding))}
656  {
657  // Nothing (else) to do
658  }
659 
660  // Work around Clang DR777 bug in Clang 3.6 and earlier by adding a
661  // redundant overload rather than mixing parameter packs and default
662  // arguments.
663  // https://llvm.org/bugs/show_bug.cgi?id=23029
664  template <typename Seeding, typename... Params>
665  random_generator(Seeding&& seeding, Params&&... params)
666  : engine_{seed_seq_cast(std::forward<Seeding>(seeding)), std::forward<Params>(params)...}
667  {
668  // Nothing (else) to do
669  }
670 
671  template <typename Seeding = default_seed_type, typename... Params>
672  void
673  seed(Seeding&& seeding = default_seed_type{})
674  {
675  engine_.seed(seed_seq_cast(seeding));
676  }
677 
678  // Work around Clang DR777 bug in Clang 3.6 and earlier by adding a
679  // redundant overload rather than mixing parameter packs and default
680  // arguments.
681  // https://llvm.org/bugs/show_bug.cgi?id=23029
682  template <typename Seeding, typename... Params>
683  void
684  seed(Seeding&& seeding, Params&&... params)
685  {
686  engine_.seed(seed_seq_cast(seeding), std::forward<Params>(params)...);
687  }
688 
689  RandomEngine&
690  engine()
691  {
692  return engine_;
693  }
694 
695  template <typename ResultType,
696  template <typename> class DistTmpl = std::normal_distribution,
697  typename... Params>
698  ResultType
699  variate(Params&&... params)
700  {
701  DistTmpl<ResultType> dist(std::forward<Params>(params)...);
702 
703  return dist(engine_);
704  }
705 
706  template <typename Numeric>
707  Numeric
708  uniform(Numeric lower, Numeric upper)
709  {
710  return variate<Numeric, uniform_distribution>(lower, upper);
711  }
712 
713  template <template <typename> class DistTmpl = uniform_distribution,
714  typename Iter,
715  typename... Params>
716  void
717  generate(Iter first, Iter last, Params&&... params)
718  {
719  using result_type = typename std::remove_reference<decltype(*(first))>::type;
720 
721  DistTmpl<result_type> dist(std::forward<Params>(params)...);
722 
723  std::generate(first, last, [&]
724  {
725  return dist(engine_);
726  });
727  }
728 
729  template <template <typename> class DistTmpl = uniform_distribution,
730  typename Range,
731  typename... Params>
732  void
733  generate(Range&& range, Params&&... params)
734  {
735  generate<DistTmpl>(std::begin(range), std::end(range), std::forward<Params>(params)...);
736  }
737 
738  template <typename Iter>
739  void
740  shuffle(Iter first, Iter last)
741  {
742  std::shuffle(first, last, engine_);
743  }
744 
745  template <typename Range>
746  void
747  shuffle(Range&& range)
748  {
749  shuffle(std::begin(range), std::end(range));
750  }
751 
752  template <typename Iter>
753  Iter
754  choose(Iter first, Iter last)
755  {
756  auto dist = std::distance(first, last);
757  if (dist < 2) return first;
758  using distance_type = decltype(dist);
759  distance_type choice = uniform(distance_type(0), --dist);
760  std::advance(first, choice);
761  return first;
762  }
763 
764  template <typename Range>
765  auto choose(Range&& range) -> decltype(std::begin(range))
766  {
767  return choose(std::begin(range), std::end(range));
768  }
769 
770  template <typename Range>
771  auto pick(Range&& range) -> decltype(*std::begin(range))
772  {
773  return *choose(std::begin(range), std::end(range));
774  }
775 
776  template <typename T>
777  auto pick(std::initializer_list<T> range) -> decltype(*range.begin())
778  {
779  return *choose(range.begin(), range.end());
780  }
781 
782  template <typename Size, typename Iter>
783  Iter
784  sample(Size to_go, Iter first, Iter last)
785  {
786  auto total = std::distance(first, last);
787  using value_type = decltype(*first);
788 
789  return std::stable_partition(first, last, [&](const value_type&)
790  {
791  --total;
792  using distance_type = decltype(total);
793  distance_type zero{};
794  if (uniform(zero, total) < to_go)
795  {
796  --to_go;
797  return true;
798  }
799  else
800  {
801  return false;
802  }
803  });
804  }
805 
806  template <typename Size, typename Range>
807  auto sample(Size to_go, Range&& range) -> decltype(std::begin(range))
808  {
809  return sample(to_go, std::begin(range), std::end(range));
810  }
811 };
812 
813 using default_rng = random_generator<std::default_random_engine>;
814 using mt19937_rng = random_generator<std::mt19937>;
815 }
816 
817 #endif // RANDUTILS_HPP
unsigned int uint32_t
Unsigned 32-bit integer.
Definition: types.h:115
void copy(T *dest, const T *src, size_t len)
Copy one array of objects to another.
Definition: util_inl.h:690
unsigned long uint64_t
Unsigned 64-bit integer.
Definition: types.h:154
void init()
Initialize UTL++.
size_t count(const FwdIt &begin, const FwdIt &end, const Predicate *pred=nullptr, bool predVal=true)
Count objects that satisfy a Predicate.