1 // Copyright (C) 2007  Davis E. King (davis@dlib.net)
2 // License: Boost Software License   See LICENSE.txt for the full license.
3 #ifndef DLIB_RAND_KERNEl_1_
4 #define DLIB_RAND_KERNEl_1_
5 
6 #include <string>
7 #include <complex>
8 #include "../algs.h"
9 #include "rand_kernel_abstract.h"
10 #include "mersenne_twister.h"
11 #include "../is_kind.h"
12 #include <iostream>
13 #include "../serialize.h"
14 #include "../string.h"
15 
16 namespace dlib
17 {
18 
19 
20     class rand
21     {
22 
23         /*!
24             INITIAL VALUE
25                 - seed == ""
26 
27             CONVENTION
28                 - the random numbers come from the boost mersenne_twister code
29                 - get_seed() == seed
30         !*/
31 
32         public:
33 
34             // These typedefs are here for backwards compatibility with older versions of dlib.
35             typedef rand kernel_1a;
36             typedef rand float_1a;
37 
rand()38             rand(
39             )
40             {
41                 init();
42             }
43 
rand(time_t seed_value)44             rand (
45                 time_t seed_value
46             )
47             {
48                 init();
49                 set_seed(cast_to_string(seed_value));
50             }
51 
rand(const std::string & seed_value)52             rand (
53                 const std::string& seed_value
54             )
55             {
56                 init();
57                 set_seed(seed_value);
58             }
59 
~rand()60             virtual ~rand(
61             )
62             {}
63 
clear()64             void clear(
65             )
66             {
67                 mt.seed();
68                 seed.clear();
69 
70                 has_gaussian = false;
71                 next_gaussian = 0;
72 
73                 // prime the generator a bit
74                 for (int i = 0; i < 10000; ++i)
75                     mt();
76             }
77 
get_seed()78             const std::string& get_seed (
79             )
80             {
81                 return seed;
82             }
83 
set_seed(const std::string & value)84             void set_seed (
85                 const std::string& value
86             )
87             {
88                 seed = value;
89 
90                 // make sure we do the seeding so that using a seed of "" gives the same
91                 // state as calling this->clear()
92                 if (value.size() != 0)
93                 {
94                     uint32 s = 0;
95                     for (std::string::size_type i = 0; i < seed.size(); ++i)
96                     {
97                         s = (s*37) + static_cast<uint32>(seed[i]);
98                     }
99                     mt.seed(s);
100                 }
101                 else
102                 {
103                     mt.seed();
104                 }
105 
106                 // prime the generator a bit
107                 for (int i = 0; i < 10000; ++i)
108                     mt();
109 
110 
111                 has_gaussian = false;
112                 next_gaussian = 0;
113             }
114 
get_random_8bit_number()115             unsigned char get_random_8bit_number (
116             )
117             {
118                 return static_cast<unsigned char>(mt());
119             }
120 
get_random_16bit_number()121             uint16 get_random_16bit_number (
122             )
123             {
124                 return static_cast<uint16>(mt());
125             }
126 
get_random_32bit_number()127             inline uint32 get_random_32bit_number (
128             )
129             {
130                 return mt();
131             }
132 
get_random_64bit_number()133             inline uint64 get_random_64bit_number (
134             )
135             {
136                 const uint64 a = get_random_32bit_number();
137                 const uint64 b = get_random_32bit_number();
138                 return (a<<32)|b;
139             }
140 
get_double_in_range(double begin,double end)141             double get_double_in_range (
142                 double begin,
143                 double end
144             )
145             {
146                 DLIB_ASSERT(begin <= end);
147                 return begin + get_random_double()*(end-begin);
148             }
149 
get_integer_in_range(long long begin,long long end)150             long long get_integer_in_range(
151                 long long begin,
152                 long long end
153             )
154             {
155                 DLIB_ASSERT(begin <= end);
156                 if (begin == end)
157                     return begin;
158 
159                 auto r = get_random_64bit_number();
160                 const auto limit = std::numeric_limits<decltype(r)>::max();
161                 const auto range = end-begin;
162                 // Use rejection sampling to remove the biased sampling you would get with
163                 // the naive get_random_64bit_number()%range sampling.
164                 while(r >= (limit/range)*range)
165                     r = get_random_64bit_number();
166 
167                 return begin + static_cast<long long>(r%range);
168             }
169 
get_integer(long long end)170             long long get_integer(
171                 long long end
172             )
173             {
174                 DLIB_ASSERT(end >= 0);
175 
176                 return get_integer_in_range(0,end);
177             }
178 
get_random_double()179             double get_random_double (
180             )
181             {
182                 uint32 temp;
183 
184                 temp = rand::get_random_32bit_number();
185                 temp &= 0xFFFFFF;
186 
187                 double val = static_cast<double>(temp);
188 
189                 val *= 0x1000000;
190 
191                 temp = rand::get_random_32bit_number();
192                 temp &= 0xFFFFFF;
193 
194                 val += temp;
195 
196                 val /= max_val;
197 
198                 if (val < 1.0)
199                 {
200                     return val;
201                 }
202                 else
203                 {
204                     // return a value slightly less than 1.0
205                     return 1.0 - std::numeric_limits<double>::epsilon();
206                 }
207             }
208 
get_random_float()209             float get_random_float (
210             )
211             {
212                 uint32 temp;
213 
214                 temp = rand::get_random_32bit_number();
215                 temp &= 0xFFFFFF;
216 
217                 const float scale = 1.0/0x1000000;
218 
219                 const float val = static_cast<float>(temp)*scale;
220                 if (val < 1.0f)
221                 {
222                     return val;
223                 }
224                 else
225                 {
226                     // return a value slightly less than 1.0
227                     return 1.0f - std::numeric_limits<float>::epsilon();
228                 }
229             }
230 
get_random_complex_gaussian()231             std::complex<double> get_random_complex_gaussian (
232             )
233             {
234                 double x1, x2, w;
235 
236                 const double rndmax = std::numeric_limits<dlib::uint32>::max();
237 
238                 // Generate a pair of Gaussian random numbers using the Box-Muller transformation.
239                 do
240                 {
241                     const double rnd1 = get_random_32bit_number()/rndmax;
242                     const double rnd2 = get_random_32bit_number()/rndmax;
243 
244                     x1 = 2.0 * rnd1 - 1.0;
245                     x2 = 2.0 * rnd2 - 1.0;
246                     w = x1 * x1 + x2 * x2;
247                 } while ( w >= 1.0 );
248 
249                 w = std::sqrt( (-2.0 * std::log( w ) ) / w );
250                 return std::complex<double>(x1 * w, x2 * w);
251             }
252 
get_random_gaussian()253             double get_random_gaussian (
254             )
255             {
256                 if (has_gaussian)
257                 {
258                     has_gaussian = false;
259                     return next_gaussian;
260                 }
261 
262                 std::complex<double> r = get_random_complex_gaussian();
263                 next_gaussian = r.imag();
264                 has_gaussian = true;
265                 return r.real();
266             }
267 
get_random_exponential(double lambda)268             double get_random_exponential (
269                 double lambda
270             )
271             {
272                 DLIB_ASSERT(lambda > 0, "lambda must be greater than zero");
273                 double u = 0.0;
274                 while (u == 0.0)
275                     u = get_random_double();
276                 return -std::log( u ) / lambda;
277             }
278 
get_random_weibull(double lambda,double k,double gamma)279             double get_random_weibull (
280                 double lambda,
281                 double k,
282                 double gamma
283             )
284             {
285                 DLIB_ASSERT(k > 0, "k must be greater than zero");
286                 DLIB_ASSERT(lambda > 0, "lambda must be greater than zero");
287                 double u = 0.0;
288                 while (u == 0.0)
289                     u = get_random_double();
290                 return gamma + lambda*std::pow(-std::log(u), 1.0 / k);
291             }
292 
swap(rand & item)293             void swap (
294                 rand& item
295             )
296             {
297                 exchange(mt,item.mt);
298                 exchange(seed, item.seed);
299                 exchange(has_gaussian, item.has_gaussian);
300                 exchange(next_gaussian, item.next_gaussian);
301             }
302 
303             friend void serialize(
304                 const rand& item,
305                 std::ostream& out
306             );
307 
308             friend void deserialize(
309                 rand& item,
310                 std::istream& in
311             );
312 
313         private:
314 
init()315             void init()
316             {
317                 // prime the generator a bit
318                 for (int i = 0; i < 10000; ++i)
319                     mt();
320 
321                 max_val =  0xFFFFFF;
322                 max_val *= 0x1000000;
323                 max_val += 0xFFFFFF;
324                 max_val += 0.05;
325 
326 
327                 has_gaussian = false;
328                 next_gaussian = 0;
329             }
330 
331             mt19937 mt;
332 
333             std::string seed;
334 
335 
336             double max_val;
337             bool has_gaussian;
338             double next_gaussian;
339     };
340 
341 
swap(rand & a,rand & b)342     inline void swap (
343         rand& a,
344         rand& b
345     ) { a.swap(b); }
346 
347 
348     template <>
349     struct is_rand<rand>
350     {
351         static const bool value = true;
352     };
353 
354     inline void serialize(
355         const rand& item,
356         std::ostream& out
357     )
358     {
359         int version = 1;
360         serialize(version, out);
361 
362         serialize(item.mt, out);
363         serialize(item.seed, out);
364         serialize(item.has_gaussian, out);
365         serialize(item.next_gaussian, out);
366     }
367 
368     inline void deserialize(
369         rand& item,
370         std::istream& in
371     )
372     {
373         int version;
374         deserialize(version, in);
375         if (version != 1)
376             throw serialization_error("Error deserializing object of type rand: unexpected version.");
377 
378         deserialize(item.mt, in);
379         deserialize(item.seed, in);
380         deserialize(item.has_gaussian, in);
381         deserialize(item.next_gaussian, in);
382     }
383 }
384 
385 #endif // DLIB_RAND_KERNEl_1_
386 
387 
388