1 // Copyright (C) 2006 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 4 5 #include <sstream> 6 #include <string> 7 #include <cstdlib> 8 #include <ctime> 9 #include <cmath> 10 #include <dlib/rand.h> 11 #include <dlib/compress_stream.h> 12 #include <dlib/hash.h> 13 #include <dlib/statistics.h> 14 15 #include "tester.h" 16 17 namespace 18 { 19 20 using namespace test; 21 using namespace dlib; 22 using namespace std; 23 24 logger dlog("test.rand"); 25 check_bpp(const std::string str)26 void check_bpp ( 27 const std::string str 28 ) 29 { 30 istringstream rdata; 31 ostringstream sout; 32 rdata.str(str); 33 double compressed_size; 34 compress_stream::kernel_1a cs1; 35 compress_stream::kernel_2a cs2; 36 37 compress_stream_kernel_1< 38 entropy_encoder_model_kernel_5<257,entropy_encoder::kernel_1a,4000000,4>, 39 entropy_decoder_model_kernel_5<257,entropy_decoder::kernel_1a,4000000,4>, 40 crc32::kernel_1a 41 > cs3; 42 43 44 print_spinner(); 45 46 rdata.clear(); 47 rdata.seekg(0); 48 sout.clear(); 49 sout.str(""); 50 cs1.compress(rdata,sout); 51 compressed_size = sout.str().size(); 52 compressed_size *= 8; 53 compressed_size /= str.size(); 54 DLIB_TEST_MSG(compressed_size >= 8, "order 0 bps: " << compressed_size); 55 dlog << LINFO << "order 0: " << compressed_size; 56 57 print_spinner(); 58 59 rdata.clear(); 60 rdata.seekg(0); 61 sout.clear(); 62 sout.str(""); 63 cs2.compress(rdata,sout); 64 compressed_size = sout.str().size(); 65 compressed_size *= 8; 66 compressed_size /= str.size(); 67 DLIB_TEST_MSG(compressed_size >= 8, "order 1 bps: " << compressed_size); 68 dlog << LINFO << "order 1: " << compressed_size; 69 70 print_spinner(); 71 72 rdata.clear(); 73 rdata.seekg(0); 74 sout.clear(); 75 sout.str(""); 76 cs3.compress(rdata,sout); 77 compressed_size = sout.str().size(); 78 compressed_size *= 8; 79 compressed_size /= str.size(); 80 DLIB_TEST_MSG(compressed_size >= 8, "order 4 bps: " << compressed_size); 81 dlog << LINFO << "order 4: " << compressed_size; 82 83 } 84 85 template < 86 typename rand 87 > rand_test()88 void rand_test ( 89 ) 90 /*! 91 requires 92 - rand is an implementation of rand/rand_kernel_abstract.h 93 is instantiated with int 94 ensures 95 - runs tests on rand for compliance with the specs 96 !*/ 97 { 98 99 ostringstream seed; 100 seed << (unsigned int)time(0); 101 102 ostringstream sout; 103 104 105 rand r, r2; 106 DLIB_TEST(r.get_seed() == ""); 107 r.set_seed(seed.str()); 108 109 DLIB_TEST(r.get_seed() == seed.str()); 110 r.clear(); 111 DLIB_TEST(r.get_seed() == ""); 112 swap(r,r2); 113 DLIB_TEST(r.get_seed() == ""); 114 r.set_seed(seed.str()); 115 DLIB_TEST(r.get_seed() == seed.str()); 116 swap(r,r2); 117 DLIB_TEST(r2.get_seed() == seed.str()); 118 DLIB_TEST(r.get_seed() == ""); 119 swap(r,r2); 120 DLIB_TEST(r.get_seed() == seed.str()); 121 DLIB_TEST(r2.get_seed() == ""); 122 123 print_spinner(); 124 unsigned long size = 100000; 125 for (unsigned long i = 0; i < size; ++i) 126 { 127 uint32 ch = r.get_random_32bit_number(); 128 sout.write((char*)&ch,4); 129 } 130 131 check_bpp(sout.str()); 132 sout.clear(); 133 sout.str(""); 134 135 print_spinner(); 136 for (unsigned long i = 0; i < size; ++i) 137 { 138 uint16 ch = r.get_random_16bit_number(); 139 sout.write((char*)&ch,2); 140 } 141 142 check_bpp(sout.str()); 143 sout.clear(); 144 sout.str(""); 145 146 print_spinner(); 147 for (unsigned long i = 0; i < size; ++i) 148 { 149 unsigned char ch = r.get_random_8bit_number(); 150 sout.write((char*)&ch,1); 151 } 152 153 check_bpp(sout.str()); 154 sout.clear(); 155 sout.str(""); 156 157 158 // make sure the things can serialize right 159 { 160 r.clear(); 161 r2.clear(); 162 163 164 for (int i =0; i < 1000; ++i) 165 { 166 r.get_random_32bit_number(); 167 r.get_random_gaussian(); 168 } 169 170 ostringstream sout; 171 serialize(r, sout); 172 173 istringstream sin(sout.str()); 174 deserialize(r2, sin); 175 176 177 for (int i =0; i < 1000; ++i) 178 { 179 DLIB_TEST(r.get_random_32bit_number() == r2.get_random_32bit_number()); 180 DLIB_TEST(std::abs(r.get_random_gaussian() - r2.get_random_gaussian()) < 1e-14); 181 } 182 } 183 184 185 // make sure calling clear() and set_seed("") do the same thing 186 { 187 r.clear(); 188 r2.set_seed(""); 189 rand r3; 190 191 192 DLIB_TEST(r.get_seed() == r2.get_seed()); 193 DLIB_TEST(r.get_seed() == r3.get_seed()); 194 195 196 for (int i =0; i < 1000; ++i) 197 { 198 const uint32 num1 = r.get_random_32bit_number(); 199 const uint32 num2 = r2.get_random_32bit_number(); 200 const uint32 num3 = r3.get_random_32bit_number(); 201 DLIB_TEST( num1 == num2); 202 DLIB_TEST( num1 == num3); 203 } 204 } 205 206 } 207 208 209 template <typename rand_type> test_normal_numbers(rand_type & rnd)210 void test_normal_numbers( 211 rand_type& rnd 212 ) 213 { 214 print_spinner(); 215 dlog << LINFO << "test normality"; 216 double cnt1 = 0; // num <= -1.2 217 double cnt2 = 0; // num <= -0.5 218 double cnt3 = 0; // num <= 0 219 double cnt4 = 0; // num <= 0.5 220 double cnt5 = 0; // num <= 1.2 221 222 const unsigned long total = 1000000; 223 for (unsigned long i = 0; i < total; ++i) 224 { 225 const double r = rnd.get_random_gaussian(); 226 if (r <= -1.2) cnt1 += 1; 227 if (r <= -0.5) cnt2 += 1; 228 if (r <= 0) cnt3 += 1; 229 if (r <= 0.5) cnt4 += 1; 230 if (r <= 1.2) cnt5 += 1; 231 } 232 233 cnt1 /= total; 234 cnt2 /= total; 235 cnt3 /= total; 236 cnt4 /= total; 237 cnt5 /= total; 238 239 dlog << LINFO << "cnt1: "<< cnt1; 240 dlog << LINFO << "cnt2: "<< cnt2; 241 dlog << LINFO << "cnt3: "<< cnt3; 242 dlog << LINFO << "cnt4: "<< cnt4; 243 dlog << LINFO << "cnt5: "<< cnt5; 244 245 DLIB_TEST(std::abs(cnt1 - 0.11507) < 0.001); 246 DLIB_TEST(std::abs(cnt2 - 0.30854) < 0.001); 247 DLIB_TEST(std::abs(cnt3 - 0.5) < 0.001); 248 DLIB_TEST(std::abs(cnt4 - 0.69146) < 0.001); 249 DLIB_TEST(std::abs(cnt5 - 0.88493) < 0.001); 250 251 } 252 test_gaussian_random_hash()253 void test_gaussian_random_hash() 254 { 255 print_spinner(); 256 dlog << LINFO << "test_gaussian_random_hash()"; 257 double cnt1 = 0; // num <= -1.2 258 double cnt2 = 0; // num <= -0.5 259 double cnt3 = 0; // num <= 0 260 double cnt4 = 0; // num <= 0.5 261 double cnt5 = 0; // num <= 1.2 262 263 const unsigned long total = 1000000; 264 for (unsigned long i = 0; i < total; ++i) 265 { 266 const double r = gaussian_random_hash(i,0,0); 267 if (r <= -1.2) cnt1 += 1; 268 if (r <= -0.5) cnt2 += 1; 269 if (r <= 0) cnt3 += 1; 270 if (r <= 0.5) cnt4 += 1; 271 if (r <= 1.2) cnt5 += 1; 272 } 273 for (unsigned long i = 0; i < total; ++i) 274 { 275 const double r = gaussian_random_hash(0,i,0); 276 if (r <= -1.2) cnt1 += 1; 277 if (r <= -0.5) cnt2 += 1; 278 if (r <= 0) cnt3 += 1; 279 if (r <= 0.5) cnt4 += 1; 280 if (r <= 1.2) cnt5 += 1; 281 } 282 for (unsigned long i = 0; i < total; ++i) 283 { 284 const double r = gaussian_random_hash(0,0,i); 285 if (r <= -1.2) cnt1 += 1; 286 if (r <= -0.5) cnt2 += 1; 287 if (r <= 0) cnt3 += 1; 288 if (r <= 0.5) cnt4 += 1; 289 if (r <= 1.2) cnt5 += 1; 290 } 291 292 cnt1 /= total*3; 293 cnt2 /= total*3; 294 cnt3 /= total*3; 295 cnt4 /= total*3; 296 cnt5 /= total*3; 297 298 dlog << LINFO << "cnt1: "<< cnt1; 299 dlog << LINFO << "cnt2: "<< cnt2; 300 dlog << LINFO << "cnt3: "<< cnt3; 301 dlog << LINFO << "cnt4: "<< cnt4; 302 dlog << LINFO << "cnt5: "<< cnt5; 303 304 DLIB_TEST(std::abs(cnt1 - 0.11507) < 0.001); 305 DLIB_TEST(std::abs(cnt2 - 0.30854) < 0.001); 306 DLIB_TEST(std::abs(cnt3 - 0.5) < 0.001); 307 DLIB_TEST(std::abs(cnt4 - 0.69146) < 0.001); 308 DLIB_TEST(std::abs(cnt5 - 0.88493) < 0.001); 309 } 310 test_uniform_random_hash()311 void test_uniform_random_hash() 312 { 313 print_spinner(); 314 dlog << LINFO << "test_uniform_random_hash()"; 315 double cnt1 = 0; // num <= 0.2 316 double cnt2 = 0; // num <= 0.4 317 double cnt3 = 0; // num <= 0.6 318 double cnt4 = 0; // num <= 0.8 319 double cnt5 = 0; // num <= 1.0 320 321 double min_val = 10; 322 double max_val = 0; 323 324 const unsigned long total = 1000000; 325 for (unsigned long i = 0; i < total; ++i) 326 { 327 const double r = uniform_random_hash(i,0,0); 328 min_val = min(r,min_val); 329 max_val = max(r,max_val); 330 331 if (r <= 0.2) cnt1 += 1; 332 if (r <= 0.4) cnt2 += 1; 333 if (r <= 0.6) cnt3 += 1; 334 if (r <= 0.8) cnt4 += 1; 335 if (r <= 1.0) cnt5 += 1; 336 } 337 for (unsigned long i = 0; i < total; ++i) 338 { 339 const double r = uniform_random_hash(0,i,0); 340 min_val = min(r,min_val); 341 max_val = max(r,max_val); 342 343 if (r <= 0.2) cnt1 += 1; 344 if (r <= 0.4) cnt2 += 1; 345 if (r <= 0.6) cnt3 += 1; 346 if (r <= 0.8) cnt4 += 1; 347 if (r <= 1.0) cnt5 += 1; 348 } 349 for (unsigned long i = 0; i < total; ++i) 350 { 351 const double r = uniform_random_hash(0,0,i); 352 min_val = min(r,min_val); 353 max_val = max(r,max_val); 354 355 if (r <= 0.2) cnt1 += 1; 356 if (r <= 0.4) cnt2 += 1; 357 if (r <= 0.6) cnt3 += 1; 358 if (r <= 0.8) cnt4 += 1; 359 if (r <= 1.0) cnt5 += 1; 360 } 361 362 cnt1 /= total*3; 363 cnt2 /= total*3; 364 cnt3 /= total*3; 365 cnt4 /= total*3; 366 cnt5 /= total*3; 367 368 dlog << LINFO << "cnt1: "<< cnt1; 369 dlog << LINFO << "cnt2: "<< cnt2; 370 dlog << LINFO << "cnt3: "<< cnt3; 371 dlog << LINFO << "cnt4: "<< cnt4; 372 dlog << LINFO << "cnt5: "<< cnt5; 373 dlog << LINFO << "min_val: "<< min_val; 374 dlog << LINFO << "max_val: "<< max_val; 375 376 DLIB_TEST(std::abs(cnt1 - 0.2) < 0.001); 377 DLIB_TEST(std::abs(cnt2 - 0.4) < 0.001); 378 DLIB_TEST(std::abs(cnt3 - 0.6) < 0.001); 379 DLIB_TEST(std::abs(cnt4 - 0.8) < 0.001); 380 DLIB_TEST(std::abs(cnt5 - 1.0) < 0.001); 381 DLIB_TEST(std::abs(min_val - 0.0) < 0.001); 382 DLIB_TEST(std::abs(max_val - 1.0) < 0.001); 383 } 384 test_get_integer()385 void test_get_integer() 386 { 387 388 print_spinner(); 389 dlib::rand rnd; 390 391 392 int big_val = 0; 393 int small_val = 0; 394 395 const long long maxval = (((unsigned long long)1)<<62) + (((unsigned long long)1)<<61); 396 for (int i = 0; i < 10000000; ++i) 397 { 398 if (rnd.get_integer(maxval) > maxval/2) 399 ++big_val; 400 else 401 ++small_val; 402 } 403 404 // make sure there isn't any funny bias 405 DLIB_TEST(std::abs(big_val/(double)small_val - 1) < 0.001); 406 407 //cout << big_val/(double)small_val << endl; 408 409 } 410 test_weibull_distribution()411 void test_weibull_distribution() 412 { 413 print_spinner(); 414 dlib::rand rnd(0); 415 416 const size_t N = 1024*1024*4; 417 const double tol = 0.01; 418 double k=1.0, lambda=2.0, g=6.0; 419 420 dlib::running_stats<double> stats; 421 for (size_t i = 0; i < N; i++) 422 stats.add(rnd.get_random_weibull(lambda, k, g)); 423 424 double expected_mean = g + lambda*std::tgamma(1 + 1.0 / k); 425 double expected_var = lambda*lambda*(std::tgamma(1 + 2.0 / k) - std::pow(std::tgamma(1 + 1.0 / k),2)); 426 DLIB_TEST(std::abs(stats.mean() - expected_mean) < tol); 427 DLIB_TEST(std::abs(stats.variance() - expected_var) < tol); 428 } 429 test_exponential_distribution()430 void test_exponential_distribution() 431 { 432 print_spinner(); 433 dlib::rand rnd(0); 434 435 const size_t N = 1024*1024*5; 436 437 const double lambda = 1.5; 438 print_spinner(); 439 dlib::running_stats<double> stats; 440 for (size_t i = 0; i < N; i++) 441 stats.add(rnd.get_random_exponential(lambda)); 442 443 DLIB_TEST(std::abs(stats.mean() - 1.0 / lambda) < 0.001); 444 DLIB_TEST(std::abs(stats.variance() - 1.0 / (lambda*lambda)) < 0.001); 445 DLIB_TEST(std::abs(stats.skewness() - 2.0) < 0.01); 446 DLIB_TEST(std::abs(stats.ex_kurtosis() - 6.0) < 0.1); 447 } 448 449 class rand_tester : public tester 450 { 451 public: rand_tester()452 rand_tester ( 453 ) : 454 tester ("test_rand", 455 "Runs tests on the rand component.") 456 {} 457 perform_test()458 void perform_test ( 459 ) 460 { 461 dlog << LINFO << "testing kernel_1a"; 462 rand_test<dlib::rand>(); 463 rand_test<dlib::rand>(); 464 465 dlib::rand rnd; 466 test_normal_numbers(rnd); 467 test_gaussian_random_hash(); 468 test_uniform_random_hash(); 469 test_get_integer(); 470 test_weibull_distribution(); 471 test_exponential_distribution(); 472 } 473 } a; 474 475 } 476 477 478