1 /****************************************************************************/ 2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo 3 // Copyright (C) 2005-2019 German Aerospace Center (DLR) and others. 4 // This program and the accompanying materials 5 // are made available under the terms of the Eclipse Public License v2.0 6 // which accompanies this distribution, and is available at 7 // http://www.eclipse.org/legal/epl-v20.html 8 // SPDX-License-Identifier: EPL-2.0 9 /****************************************************************************/ 10 /// @file RandHelper.h 11 /// @author Daniel Krajzewicz 12 /// @author Michael Behrisch 13 /// @author Jakob Erdmann 14 /// @date Fri, 29.04.2005 15 /// @version $Id$ 16 /// 17 // 18 /****************************************************************************/ 19 #ifndef RandHelper_h 20 #define RandHelper_h 21 22 23 // =========================================================================== 24 // included modules 25 // =========================================================================== 26 27 #include <cassert> 28 #include <vector> 29 #include <random> 30 #include <sstream> 31 #include <iostream> 32 33 //#define DEBUG_RANDCALLS 34 35 // =========================================================================== 36 // class declarations 37 // =========================================================================== 38 class OptionsCont; 39 40 41 // =========================================================================== 42 // class definitions 43 // =========================================================================== 44 /** 45 * @class RandHelper 46 * @brief Utility functions for using a global, resetable random number generator 47 */ 48 class RandHelper { 49 public: 50 /// @brief Initialises the given options container with random number options 51 static void insertRandOptions(); 52 53 /// @brief Initialises the random number generator with hardware randomness or seed 54 static void initRand(std::mt19937* which = 0, const bool random = false, const int seed = 23423); 55 56 /// @brief Reads the given random number options and initialises the random number generator in accordance 57 static void initRandGlobal(std::mt19937* which = 0); 58 59 /// @brief Returns a random real number in [0, 1) 60 static inline double rand(std::mt19937* rng = 0) { 61 if (rng == 0) { 62 rng = &myRandomNumberGenerator; 63 } 64 const double res = double((*rng)() / 4294967296.0); 65 #ifdef DEBUG_RANDCALLS 66 myCallCount++; 67 if (myCallCount == myDebugIndex) { 68 std::cout << "DEBUG\n"; // for setting breakpoint 69 } 70 std::cout << " rand call=" << myCallCount << " val=" << res << "\n"; 71 #endif 72 return res; 73 } 74 75 /// @brief Returns a random real number in [0, maxV) 76 static inline double rand(double maxV, std::mt19937* rng = 0) { 77 return maxV * rand(rng); 78 } 79 80 /// @brief Returns a random real number in [minV, maxV) 81 static inline double rand(double minV, double maxV, std::mt19937* rng = 0) { 82 return minV + (maxV - minV) * rand(rng); 83 } 84 85 /// @brief Returns a random integer in [0, maxV-1] 86 static inline int rand(int maxV, std::mt19937* rng = 0) { 87 if (rng == 0) { 88 rng = &myRandomNumberGenerator; 89 } 90 unsigned int usedBits = maxV - 1; 91 usedBits |= usedBits >> 1; 92 usedBits |= usedBits >> 2; 93 usedBits |= usedBits >> 4; 94 usedBits |= usedBits >> 8; 95 usedBits |= usedBits >> 16; 96 97 // Draw numbers until one is found in [0, maxV-1] 98 int result; 99 do { 100 result = (*rng)() & usedBits; 101 } while (result >= maxV); 102 return result; 103 } 104 105 /// @brief Returns a random integer in [minV, maxV-1] 106 static inline int rand(int minV, int maxV, std::mt19937* rng = 0) { 107 return minV + rand(maxV - minV, rng); 108 } 109 110 /// @brief Returns a random 64 bit integer in [0, maxV-1] 111 static inline long long int rand(long long int maxV, std::mt19937* rng = 0) { 112 if (maxV <= std::numeric_limits<int>::max()) { 113 return rand((int)maxV, rng); 114 } 115 if (rng == 0) { 116 rng = &myRandomNumberGenerator; 117 } 118 unsigned long long int usedBits = maxV - 1; 119 usedBits |= usedBits >> 1; 120 usedBits |= usedBits >> 2; 121 usedBits |= usedBits >> 4; 122 usedBits |= usedBits >> 8; 123 usedBits |= usedBits >> 16; 124 usedBits |= usedBits >> 32; 125 126 // Draw numbers until one is found in [0, maxV-1] 127 long long int result; 128 do { 129 result = (((unsigned long long int)(*rng)() << 32) | (*rng)()) & usedBits; // toss unused bits to shorten search 130 } while (result >= maxV); 131 return result; 132 } 133 134 /// @brief Returns a random 64 bit integer in [minV, maxV-1] 135 static inline long long int rand(long long int minV, long long int maxV, std::mt19937* rng = 0) { 136 return minV + rand(maxV - minV, rng); 137 } 138 139 /// @brief Access to a random number from a normal distribution 140 static inline double randNorm(double mean, double variance, std::mt19937* rng = 0) { 141 // Polar method to avoid cosine 142 double u, q; 143 do { 144 u = rand(2.0, rng) - 1; 145 const double v = rand(2.0, rng) - 1; 146 q = u * u + v * v; 147 } while (q == 0.0 || q >= 1.0); 148 return (double)(mean + variance * u * sqrt(-2 * log(q) / q)); 149 } 150 151 /// @brief Returns a random element from the given vector 152 template<class T> 153 static inline const T& 154 getRandomFrom(const std::vector<T>& v, std::mt19937* rng = 0) { 155 assert(v.size() > 0); 156 return v[rand((int)v.size(), rng)]; 157 } 158 159 /// @brief save rng state to string 160 static std::string saveState(std::mt19937* rng = 0) { 161 if (rng == 0) { 162 rng = &myRandomNumberGenerator; 163 } 164 std::ostringstream oss; 165 oss << (*rng); 166 return oss.str(); 167 } 168 169 /// @brief load rng state from string 170 static void loadState(const std::string& state, std::mt19937* rng = 0) { 171 if (rng == 0) { 172 rng = &myRandomNumberGenerator; 173 } 174 std::istringstream iss(state); 175 iss >> (*rng); 176 } 177 178 179 protected: 180 /// @brief the random number generator to use 181 static std::mt19937 myRandomNumberGenerator; 182 183 /// @brief only used for debugging; 184 static int myCallCount; 185 static int myDebugIndex; 186 187 }; 188 189 #endif 190 191 /****************************************************************************/ 192