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