1 #include "test_precomp.hpp"
6 class Core_RandTest : public cvtest::BaseTest
12 bool check_pdf(const Mat& hist, double scale, int dist_type,
13 double& refval, double& realval);
17 Core_RandTest::Core_RandTest()
21 static double chi2_p95(int n)
23 static float chi2_tab95[] = {
24 3.841f, 5.991f, 7.815f, 9.488f, 11.07f, 12.59f, 14.07f, 15.51f,
25 16.92f, 18.31f, 19.68f, 21.03f, 21.03f, 22.36f, 23.69f, 25.00f,
26 26.30f, 27.59f, 28.87f, 30.14f, 31.41f, 32.67f, 33.92f, 35.17f,
27 36.42f, 37.65f, 38.89f, 40.11f, 41.34f, 42.56f, 43.77f };
28 static const double xp = 1.64;
32 return chi2_tab95[n-1];
33 return n + sqrt((double)2*n)*xp + 0.6666666666666*(xp*xp - 1);
36 bool Core_RandTest::check_pdf(const Mat& hist, double scale,
37 int dist_type, double& refval, double& realval)
39 Mat hist0(hist.size(), CV_32F);
40 const int* H = hist.ptr<int>();
41 float* H0 = hist0.ptr<float>();
42 int i, hsz = hist.cols;
45 for( i = 0; i < hsz; i++ )
47 CV_Assert( fabs(1./sum - scale) < FLT_EPSILON );
49 if( dist_type == CV_RAND_UNI )
51 float scale0 = (float)(1./hsz);
52 for( i = 0; i < hsz; i++ )
57 double sum2 = 0, r = (hsz-1.)/2;
58 double alpha = 2*sqrt(2.)/r, beta = -alpha*r;
59 for( i = 0; i < hsz; i++ )
61 double x = i*alpha + beta;
62 H0[i] = (float)exp(-x*x);
66 for( i = 0; i < hsz; i++ )
67 H0[i] = (float)(H0[i]*sum2);
71 for( i = 0; i < hsz; i++ )
74 double b = H[i]*scale;
76 chi2 += (a - b)*(a - b)/(a + b);
80 double chi2_pval = chi2_p95(hsz - 1 - (dist_type == CV_RAND_NORMAL ? 2 : 0));
81 refval = chi2_pval*0.01;
82 return realval <= refval;
85 void Core_RandTest::run( int )
87 static int _ranges[][2] =
88 {{ 0, 256 }, { -128, 128 }, { 0, 65536 }, { -32768, 32768 },
89 { -1000000, 1000000 }, { -1000, 1000 }, { -1000, 1000 }};
91 const int MAX_SDIM = 10;
92 const int N = 2000000;
93 const int maxSlice = 1000;
94 const int MAX_HIST_SIZE = 1000;
97 RNG& rng = ts->get_rng();
98 RNG tested_rng = theRNG();
99 test_case_count = 200;
101 for( int idx = 0; idx < test_case_count; idx++ )
103 progress = update_progress( progress, idx, test_case_count, 0 );
104 ts->update_context( this, idx, false );
106 int depth = cvtest::randInt(rng) % (CV_64F+1);
107 int c, cn = (cvtest::randInt(rng) % 4) + 1;
108 int type = CV_MAKETYPE(depth, cn);
109 int dist_type = cvtest::randInt(rng) % (CV_RAND_NORMAL+1);
117 bool do_sphere_test = dist_type == CV_RAND_UNI;
121 arr[0].create(1, SZ, type);
122 arr[1].create(1, SZ, type);
123 bool fast_algo = dist_type == CV_RAND_UNI && depth < CV_32F;
125 for( c = 0; c < cn; c++ )
128 if( dist_type == CV_RAND_UNI )
130 a = (int)(cvtest::randInt(rng) % (_ranges[depth][1] -
131 _ranges[depth][0])) + _ranges[depth][0];
134 b = (int)(cvtest::randInt(rng) % (_ranges[depth][1] -
135 _ranges[depth][0])) + _ranges[depth][0];
137 while( abs(a-b) <= 1 );
141 unsigned r = (unsigned)(b - a);
142 fast_algo = fast_algo && r <= 256 && (r & (r-1)) == 0;
143 hsz = min((unsigned)(b - a), (unsigned)MAX_HIST_SIZE);
144 do_sphere_test = do_sphere_test && b - a >= 100;
148 int vrange = _ranges[depth][1] - _ranges[depth][0];
149 int meanrange = vrange/16;
150 int mindiv = MAX(vrange/20, 5);
151 int maxdiv = MIN(vrange/8, 10000);
153 a = cvtest::randInt(rng) % meanrange - meanrange/2 +
154 (_ranges[depth][0] + _ranges[depth][1])/2;
155 b = cvtest::randInt(rng) % (maxdiv - mindiv) + mindiv;
156 hsz = min((unsigned)b*9, (unsigned)MAX_HIST_SIZE);
160 hist[c].create(1, hsz, CV_32S);
163 cv::RNG saved_rng = tested_rng;
164 int maxk = fast_algo ? 0 : 1;
165 for( k = 0; k <= maxk; k++ )
167 tested_rng = saved_rng;
168 int sz = 0, dsz = 0, slice;
169 for( slice = 0; slice < maxSlice; slice++, sz += dsz )
171 dsz = slice+1 < maxSlice ? (int)(cvtest::randInt(rng) % (SZ - sz + 1)) : SZ - sz;
172 Mat aslice = arr[k].colRange(sz, sz + dsz);
173 tested_rng.fill(aslice, dist_type, A, B);
177 if( maxk >= 1 && cvtest::norm(arr[0], arr[1], NORM_INF) > eps)
179 ts->printf( cvtest::TS::LOG, "RNG output depends on the array lengths (some generated numbers get lost?)" );
180 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
184 for( c = 0; c < cn; c++ )
186 const uchar* data = arr[0].ptr();
187 int* H = hist[c].ptr<int>();
188 int HSZ = hist[c].cols;
189 double minVal = dist_type == CV_RAND_UNI ? A[c] : A[c] - B[c]*4;
190 double maxVal = dist_type == CV_RAND_UNI ? B[c] : A[c] + B[c]*4;
191 double scale = HSZ/(maxVal - minVal);
192 double delta = -minVal*scale;
194 hist[c] = Scalar::all(0);
196 for( i = c; i < SZ*cn; i += cn )
198 double val = depth == CV_8U ? ((const uchar*)data)[i] :
199 depth == CV_8S ? ((const schar*)data)[i] :
200 depth == CV_16U ? ((const ushort*)data)[i] :
201 depth == CV_16S ? ((const short*)data)[i] :
202 depth == CV_32S ? ((const int*)data)[i] :
203 depth == CV_32F ? ((const float*)data)[i] :
204 ((const double*)data)[i];
205 int ival = cvFloor(val*scale + delta);
206 if( (unsigned)ival < (unsigned)HSZ )
211 else if( dist_type == CV_RAND_UNI )
213 if( (minVal <= val && val < maxVal) || (depth >= CV_32F && val == maxVal) )
215 H[ival < 0 ? 0 : HSZ-1]++;
225 if( dist_type == CV_RAND_UNI && W[c] != SZ )
227 ts->printf( cvtest::TS::LOG, "Uniform RNG gave values out of the range [%g,%g) on channel %d/%d\n",
229 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
232 if( dist_type == CV_RAND_NORMAL && W[c] < SZ*.90)
234 ts->printf( cvtest::TS::LOG, "Normal RNG gave too many values out of the range (%g+4*%g,%g+4*%g) on channel %d/%d\n",
235 A[c], B[c], A[c], B[c], c, cn);
236 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
239 double refval = 0, realval = 0;
241 if( !check_pdf(hist[c], 1./W[c], dist_type, refval, realval) )
243 ts->printf( cvtest::TS::LOG, "RNG failed Chi-square test "
244 "(got %g vs probable maximum %g) on channel %d/%d\n",
245 realval, refval, c, cn);
246 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
251 // Monte-Carlo test. Compute volume of SDIM-dimensional sphere
252 // inscribed in [-1,1]^SDIM cube.
255 int SDIM = cvtest::randInt(rng) % (MAX_SDIM-1) + 2;
256 int N0 = (SZ*cn/SDIM), n = 0;
258 const uchar* data = arr[0].ptr();
259 double scale[4], delta[4];
260 for( c = 0; c < cn; c++ )
262 scale[c] = 2./(B[c] - A[c]);
263 delta[c] = -A[c]*scale[c] - 1;
266 for( i = k = c = 0; i <= SZ*cn - SDIM; i++, k++, c++ )
268 double val = depth == CV_8U ? ((const uchar*)data)[i] :
269 depth == CV_8S ? ((const schar*)data)[i] :
270 depth == CV_16U ? ((const ushort*)data)[i] :
271 depth == CV_16S ? ((const short*)data)[i] :
272 depth == CV_32S ? ((const int*)data)[i] :
273 depth == CV_32F ? ((const float*)data)[i] : ((const double*)data)[i];
274 c &= c < cn ? -1 : 0;
275 val = val*scale[c] + delta[c];
285 double V = ((double)n/N0)*(1 << SDIM);
287 // the theoretically computed volume
289 double V0 = sdim + 1;
290 for( sdim += 2; sdim <= SDIM; sdim += 2 )
293 if( fabs(V - V0) > 0.3*fabs(V0) )
295 ts->printf( cvtest::TS::LOG, "RNG failed %d-dim sphere volume test (got %g instead of %g)\n",
297 ts->printf( cvtest::TS::LOG, "depth = %d, N0 = %d\n", depth, N0);
298 ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
305 TEST(Core_Rand, quality) { Core_RandTest test; test.safe_run(); }
308 class Core_RandRangeTest : public cvtest::BaseTest
311 Core_RandRangeTest() {}
312 ~Core_RandRangeTest() {}
316 Mat a(Size(1280, 720), CV_8U, Scalar(20));
317 Mat af(Size(1280, 720), CV_32F, Scalar(20));
318 theRNG().fill(a, RNG::UNIFORM, -DBL_MAX, DBL_MAX);
319 theRNG().fill(af, RNG::UNIFORM, -DBL_MAX, DBL_MAX);
320 int n0 = 0, n255 = 0, nx = 0;
321 int nfmin = 0, nfmax = 0, nfx = 0;
323 for( int i = 0; i < a.rows; i++ )
324 for( int j = 0; j < a.cols; j++ )
326 int v = a.at<uchar>(i,j);
327 double vf = af.at<float>(i,j);
329 else if( v == 255 ) n255++;
331 if( vf < FLT_MAX*-0.999f ) nfmin++;
332 else if( vf > FLT_MAX*0.999f ) nfmax++;
335 CV_Assert( n0 > nx*2 && n255 > nx*2 );
336 CV_Assert( nfmin > nfx*2 && nfmax > nfx*2 );
340 TEST(Core_Rand, range) { Core_RandRangeTest test; test.safe_run(); }
343 TEST(Core_RNG_MT19937, regression)
346 int actual[61] = {0, };
347 const size_t length = (sizeof(actual) / sizeof(actual[0]));
348 for (int i = 0; i < 10000; ++i )
350 actual[(unsigned)(rng.next() ^ i) % length]++;
353 int expected[length] = {
354 177, 158, 180, 177, 160, 179, 143, 162,
355 177, 144, 170, 174, 165, 168, 168, 156,
356 177, 157, 159, 169, 177, 182, 166, 154,
357 144, 180, 168, 152, 170, 187, 160, 145,
358 139, 164, 157, 179, 148, 183, 159, 160,
359 196, 184, 149, 142, 162, 148, 163, 152,
360 168, 173, 160, 181, 172, 181, 155, 153,
361 158, 171, 138, 150, 150 };
363 for (size_t i = 0; i < length; ++i)
365 ASSERT_EQ(expected[i], actual[i]);
370 TEST(Core_Rand, Regression_Stack_Corruption)
372 int bufsz = 128; //enough for 14 doubles
373 AutoBuffer<uchar> buffer(bufsz);
375 cv::Mat_<cv::Point2d> x(2, 3, (cv::Point2d*)(buffer+offset)); offset += x.total()*x.elemSize();
376 double& param1 = *(double*)(buffer+offset); offset += sizeof(double);
377 double& param2 = *(double*)(buffer+offset); offset += sizeof(double);
378 param1 = -9; param2 = 2;
380 cv::theRNG().fill(x, cv::RNG::NORMAL, param1, param2);
382 ASSERT_EQ(param1, -9);
383 ASSERT_EQ(param2, 2);