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