SolidUtils
Random.hpp
Go to the documentation of this file.
1 
29 #ifndef SOLIDUTILS_INCLUDE_RANDOM_HPP
30 #define SOLIDUTILS_INCLUDE_RANDOM_HPP
31 
32 
33 #include "Debug.hpp"
34 #include "FastIntDistribution.hpp"
35 
36 #include <cstddef>
37 #include <algorithm>
38 #include <type_traits>
39 
40 
41 
42 namespace sl
43 {
44 
53 class Random
54 {
55  public:
66  template<typename T, typename URBG>
67  static T inRange(
68  T const min,
69  T const max,
70  URBG&& rng) noexcept
71  {
72  T const range = max - min;
73  return min + static_cast<T>(static_cast<uint64_t>(rng()) % range);
74  }
75 
76 
89  template <typename T, typename URBG>
90  static void fillWithRange(
91  T * const data,
92  size_t const num,
93  T const min,
94  T const max,
95  URBG&& rng) noexcept
96  {
97  if (min == max) {
98  for (size_t i = 0; i < num; ++i) {
99  data[i] = min;
100  }
101  } else {
102  for (size_t i = 0; i < num; ++i) {
103  data[i] = inRange(min, max, rng);
104  }
105  }
106  }
107 
108 
117  template <typename T, typename URBG>
118  static void fillWithPerm(
119  T * const data,
120  size_t const num,
121  T const offset,
122  URBG&& rng) noexcept
123  {
124  for (size_t i = 0; i < num; ++i) {
125  data[i] = static_cast<T>(i)+offset;
126  }
127 
128  pseudoShuffle(data, num, rng);
129  }
130 
142  template <typename T, typename URBG>
143  static void pseudoShuffle(
144  T * const data,
145  size_t const num,
146  URBG&& rng) noexcept
147  {
148  constexpr size_t swapSize = 8;
149  constexpr size_t minSize = 64;
150 
151  if (num < minSize) {
152  // for small arrays, resort to std::shuffle
153  std::shuffle(data, data+num, rng);
154  } else {
155  FastIntDistribution<size_t> indexDist(0, num-swapSize);
156  FastIntDistribution<int> swapDist(0, 4);
157 
158  // The below swapping is originally based on the algorithm used in
159  // `randArrayPermute()` function in George Karypis's GKLib.
160 
161  // perform several network swaps
162  for (size_t swap = 0; swap < num/swapSize; ++swap) {
163  size_t const start = indexDist(rng);
164  size_t const end = indexDist(rng);
165  int const swapSet = swapDist(rng);
166  switch (swapSet) {
167  case 0:
168  std::swap(data[start], data[end+1]);
169  std::swap(data[start+1], data[end+4]);
170  std::swap(data[start+2], data[end+7]);
171  std::swap(data[start+3], data[end+3]);
172  std::swap(data[start+4], data[end+2]);
173  std::swap(data[start+5], data[end+6]);
174  std::swap(data[start+6], data[end]);
175  std::swap(data[start+7], data[end+5]);
176  break;
177  case 1:
178  std::swap(data[start], data[end+5]);
179  std::swap(data[start+1], data[end+3]);
180  std::swap(data[start+2], data[end+1]);
181  std::swap(data[start+3], data[end+6]);
182  std::swap(data[start+4], data[end]);
183  std::swap(data[start+5], data[end+7]);
184  std::swap(data[start+6], data[end+2]);
185  std::swap(data[start+7], data[end+4]);
186  break;
187  case 2:
188  std::swap(data[start], data[end+3]);
189  std::swap(data[start+1], data[end+5]);
190  std::swap(data[start+2], data[end+6]);
191  std::swap(data[start+3], data[end+1]);
192  std::swap(data[start+4], data[end+2]);
193  std::swap(data[start+5], data[end]);
194  std::swap(data[start+6], data[end+4]);
195  std::swap(data[start+7], data[end+7]);
196  break;
197  case 3:
198  std::swap(data[start], data[end+7]);
199  std::swap(data[start+1], data[end]);
200  std::swap(data[start+2], data[end+2]);
201  std::swap(data[start+3], data[end+3]);
202  std::swap(data[start+4], data[end+4]);
203  std::swap(data[start+5], data[end+1]);
204  std::swap(data[start+6], data[end+6]);
205  std::swap(data[start+7], data[end+5]);
206  break;
207  }
208  }
209  }
210  }
211 
212 
213 
214 
215 };
216 
217 
218 }
219 
220 
221 #endif
Definition: Alloc.hpp:40
static void fillWithPerm(T *const data, size_t const num, T const offset, URBG &&rng) noexcept
Fill a memory location with a permutation vector.
Definition: Random.hpp:118
static void pseudoShuffle(T *const data, size_t const num, URBG &&rng) noexcept
Re-order the elements in array in a randomly. This is less random than std::shuffle, but is significantly faster for large arrays.
Definition: Random.hpp:143
static void fillWithRange(T *const data, size_t const num, T const min, T const max, URBG &&rng) noexcept
Fill a container with random numbers. If min and max are the same, an optimization is used where rand...
Definition: Random.hpp:90
This distribution is designed to be fast and consistent across platforms. However, it will not be uniform.
Definition: FastIntDistribution.hpp:47
The FastIntDistribution class.
static T inRange(T const min, T const max, URBG &&rng) noexcept
Get a random number within the given range. The distribution may not be uniform.
Definition: Random.hpp:67
Debugging functions.
The Random class provides wrappers around base &#39;random&#39; functionality, such as getting a number withi...
Definition: Random.hpp:53