Eclipse SUMO - Simulation of Urban MObility
RandHelper.h
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2005-2022 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
20 //
21 /****************************************************************************/
22 #pragma once
23 #include <config.h>
24 #include <cassert>
25 #include <vector>
26 #include <map>
27 #include <random>
28 #include <sstream>
29 #include <iostream>
30 
31 //#define DEBUG_RANDCALLS
32 
33 
34 // ===========================================================================
35 // class definitions
36 // ===========================================================================
42 public:
43  inline void seed(const uint64_t seed) {
44  this->state[0] = splitmix64(splitmix64(seed));
45  this->state[1] = splitmix64(this->state[0]);
46  this->state[2] = splitmix64(this->state[1]);
47  this->state[3] = splitmix64(this->state[2]);
48  }
49 
50  inline uint64_t operator()() {
51  const uint64_t result = rotl64(this->state[0] + this->state[3], 23) + this->state[0];
52  const uint64_t t = this->state[1] << 17;
53  this->state[2] ^= this->state[0];
54  this->state[3] ^= this->state[1];
55  this->state[1] ^= this->state[2];
56  this->state[0] ^= this->state[3];
57  this->state[2] ^= t;
58  this->state[3] = rotl64(this->state[3], 45);
59  return result;
60  }
61 
62  void discard(unsigned long long skip) {
63  while (skip-- > 0) {
64  (*this)();
65  }
66  }
67 
68  friend std::ostream& operator<<(std::ostream& os, const XoShiRo256PlusPlus& r) {
69  os << r.state[0] << r.state[1] << r.state[2] << r.state[3];
70  return os;
71  }
72 
73  friend std::istream& operator>>(std::istream& is, XoShiRo256PlusPlus& r) {
74  is >> r.state[0] >> r.state[1] >> r.state[2] >> r.state[3];
75  return is;
76  }
77 
78 
79 private:
80  static inline uint64_t rotl64(const uint64_t x, const int k) {
81  return (x << k) | (x >> (64 - k));
82  }
83 
84  static inline uint64_t splitmix64(const uint64_t seed) {
85  uint64_t z = (seed + 0x9e3779b97f4a7c15);
86  z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
87  z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
88  return z ^ (z >> 31);
89  }
90 
91  uint64_t state[4];
92 
93 };
94 
95 
96 //class SumoRNG : public XoShiRo256PlusPlus {
97 class SumoRNG : public std::mt19937 {
98 public:
99  unsigned long long int count = 0;
100 };
101 
102 
107 class RandHelper {
108 public:
110  static void insertRandOptions();
111 
113  static void initRand(SumoRNG* which = nullptr, const bool random = false, const int seed = 23423);
114 
116  static void initRandGlobal(SumoRNG* which = nullptr);
117 
119  static inline double rand(SumoRNG* rng = nullptr) {
120  if (rng == nullptr) {
122  }
123  const double res = double((*rng)() / 4294967296.0);
124  rng->count++;
125 #ifdef DEBUG_RANDCALLS
126  if (rng->count == myDebugIndex) {
127  std::cout << "DEBUG\n"; // for setting breakpoint
128  }
129  std::stringstream stream; // to reduce output interleaving from different threads
130  stream << " rng" << myRngId.find(rng)->second << " rand call=" << rng->count << " val=" << res << "\n";
131  std::cout << stream.str();
132 #endif
133  return res;
134  }
135 
137  static inline double rand(double maxV, SumoRNG* rng = nullptr) {
138  return maxV * rand(rng);
139  }
140 
142  static inline double rand(double minV, double maxV, SumoRNG* rng = nullptr) {
143  return minV + (maxV - minV) * rand(rng);
144  }
145 
147  static inline int rand(int maxV, SumoRNG* rng = nullptr) {
148  if (rng == nullptr) {
150  }
151  unsigned int usedBits = maxV - 1;
152  usedBits |= usedBits >> 1;
153  usedBits |= usedBits >> 2;
154  usedBits |= usedBits >> 4;
155  usedBits |= usedBits >> 8;
156  usedBits |= usedBits >> 16;
157 
158  // Draw numbers until one is found in [0, maxV-1]
159  int result;
160  do {
161  result = (*rng)() & usedBits;
162  rng->count++;
163  } while (result >= maxV);
164  return result;
165  }
166 
168  static inline int rand(int minV, int maxV, SumoRNG* rng = nullptr) {
169  return minV + rand(maxV - minV, rng);
170  }
171 
173  static inline long long int rand(long long int maxV, SumoRNG* rng = nullptr) {
174  if (maxV <= std::numeric_limits<int>::max()) {
175  return rand((int)maxV, rng);
176  }
177  if (rng == nullptr) {
179  }
180  unsigned long long int usedBits = maxV - 1;
181  usedBits |= usedBits >> 1;
182  usedBits |= usedBits >> 2;
183  usedBits |= usedBits >> 4;
184  usedBits |= usedBits >> 8;
185  usedBits |= usedBits >> 16;
186  usedBits |= usedBits >> 32;
187 
188  // Draw numbers until one is found in [0, maxV-1]
189  long long int result;
190  do {
191  result = (((unsigned long long int)(*rng)() << 32) | (*rng)()) & usedBits; // toss unused bits to shorten search
192  rng->count += 2;
193  } while (result >= maxV);
194  return result;
195  }
196 
198  static inline long long int rand(long long int minV, long long int maxV, SumoRNG* rng = nullptr) {
199  return minV + rand(maxV - minV, rng);
200  }
201 
203  static double randNorm(double mean, double variance, SumoRNG* rng = nullptr);
204 
206  template<class T>
207  static inline const T&
208  getRandomFrom(const std::vector<T>& v, SumoRNG* rng = nullptr) {
209  assert(v.size() > 0);
210  return v[rand((int)v.size(), rng)];
211  }
212 
214  static std::string saveState(SumoRNG* rng = nullptr) {
215  if (rng == nullptr) {
217  }
218  std::ostringstream oss;
219  if (rng->count < 1000000) { // TODO make this configurable
220  oss << rng->count;
221  } else {
222  oss << (*rng);
223  }
224  return oss.str();
225  }
226 
228  static void loadState(const std::string& state, SumoRNG* rng = nullptr) {
229  if (rng == nullptr) {
231  }
232  std::istringstream iss(state);
233  if (state.size() < 10) {
234  iss >> rng->count;
235  rng->discard(rng->count);
236  } else {
237  iss >> (*rng);
238  }
239  }
240 
241 
242 protected:
245 
246 #ifdef DEBUG_RANDCALLS
247  static std::map<SumoRNG*, int> myRngId;
248  static int myDebugIndex;
249 #endif
250 
251 };
Utility functions for using a global, resetable random number generator.
Definition: RandHelper.h:107
static SumoRNG myRandomNumberGenerator
the default random number generator to use
Definition: RandHelper.h:244
static void loadState(const std::string &state, SumoRNG *rng=nullptr)
load rng state from string
Definition: RandHelper.h:228
static const T & getRandomFrom(const std::vector< T > &v, SumoRNG *rng=nullptr)
Returns a random element from the given vector.
Definition: RandHelper.h:208
static long long int rand(long long int minV, long long int maxV, SumoRNG *rng=nullptr)
Returns a random 64 bit integer in [minV, maxV-1].
Definition: RandHelper.h:198
static double rand(double minV, double maxV, SumoRNG *rng=nullptr)
Returns a random real number in [minV, maxV)
Definition: RandHelper.h:142
static void initRand(SumoRNG *which=nullptr, const bool random=false, const int seed=23423)
Initialises the random number generator with hardware randomness or seed.
Definition: RandHelper.cpp:59
static int rand(int minV, int maxV, SumoRNG *rng=nullptr)
Returns a random integer in [minV, maxV-1].
Definition: RandHelper.h:168
static int rand(int maxV, SumoRNG *rng=nullptr)
Returns a random integer in [0, maxV-1].
Definition: RandHelper.h:147
static double randNorm(double mean, double variance, SumoRNG *rng=nullptr)
Access to a random number from a normal distribution.
Definition: RandHelper.cpp:82
static void insertRandOptions()
Initialises the given options container with random number options.
Definition: RandHelper.cpp:43
static std::string saveState(SumoRNG *rng=nullptr)
save rng state to string
Definition: RandHelper.h:214
static double rand(double maxV, SumoRNG *rng=nullptr)
Returns a random real number in [0, maxV)
Definition: RandHelper.h:137
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
Definition: RandHelper.h:119
static long long int rand(long long int maxV, SumoRNG *rng=nullptr)
Returns a random 64 bit integer in [0, maxV-1].
Definition: RandHelper.h:173
static void initRandGlobal(SumoRNG *which=nullptr)
Reads the given random number options and initialises the random number generator in accordance.
Definition: RandHelper.cpp:75
unsigned long long int count
Definition: RandHelper.h:99
A random number generator as proposed here https://prng.di.unimi.it/xoshiro256plusplus....
Definition: RandHelper.h:41
uint64_t operator()()
Definition: RandHelper.h:50
uint64_t state[4]
Definition: RandHelper.h:91
friend std::ostream & operator<<(std::ostream &os, const XoShiRo256PlusPlus &r)
Definition: RandHelper.h:68
friend std::istream & operator>>(std::istream &is, XoShiRo256PlusPlus &r)
Definition: RandHelper.h:73
void discard(unsigned long long skip)
Definition: RandHelper.h:62
static uint64_t rotl64(const uint64_t x, const int k)
Definition: RandHelper.h:80
void seed(const uint64_t seed)
Definition: RandHelper.h:43
static uint64_t splitmix64(const uint64_t seed)
Definition: RandHelper.h:84