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