]> rtime.felk.cvut.cz Git - opencv.git/blob - opencv/tests/cxcore/src/amath.cpp
improved coverage of cvGemm, cvTransform and cvPow
[opencv.git] / opencv / tests / cxcore / src / amath.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 //////////////////////////////////////////////////////////////////////////////////////////
43 /////////////////// tests for matrix operations and math functions ///////////////////////
44 //////////////////////////////////////////////////////////////////////////////////////////
45
46 #include "cxcoretest.h"
47 #include <float.h>
48 #include <math.h>
49
50 /// !!! NOTE !!! These tests happily avoid overflow cases & out-of-range arguments
51 /// so that output arrays contain neigher Inf's nor Nan's.
52 /// Handling such cases would require special modification of check function
53 /// (validate_test_results) => TBD.
54 /// Also, need some logarithmic-scale generation of input data. Right now it is done (in some tests)
55 /// by generating min/max boundaries for random data in logarimithic scale, but
56 /// within the same test case all the input array elements are of the same order.
57
58 static const CvSize math_sizes[] = {{10,1}, {100,1}, {10000,1}, {-1,-1}};
59 static const int math_depths[] = { CV_32F, CV_64F, -1 };
60 static const char* math_param_names[] = { "size", "depth", 0 };
61
62 static const CvSize matrix_sizes[] = {{3,3}, {4,4}, {10,10}, {30,30}, {100,100}, {500,500}, {-1,-1}};
63
64 class CxCore_MathTestImpl : public CvArrTest
65 {
66 public:
67     CxCore_MathTestImpl( const char* test_name, const char* test_funcs );
68 protected:
69     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
70     double get_success_error_level( int /*test_case_idx*/, int i, int j );
71     bool test_nd;
72 };
73
74
75 CxCore_MathTestImpl::CxCore_MathTestImpl( const char* test_name, const char* test_funcs )
76     : CvArrTest( test_name, test_funcs, "" )
77 {
78     optional_mask = false;
79
80     test_array[INPUT].push(NULL);
81     test_array[OUTPUT].push(NULL);
82     test_array[REF_OUTPUT].push(NULL);
83
84     default_timing_param_names = math_param_names;
85
86     size_list = math_sizes;
87     whole_size_list = 0;
88     depth_list = math_depths;
89     cn_list = 0;
90     test_nd = false;
91 }
92
93
94 double CxCore_MathTestImpl::get_success_error_level( int /*test_case_idx*/, int i, int j )
95 {
96     return CV_MAT_DEPTH(test_mat[i][j].type) == CV_32F ? FLT_EPSILON*128 : DBL_EPSILON*1024;
97 }
98
99
100 void CxCore_MathTestImpl::get_test_array_types_and_sizes( int test_case_idx,
101                                                       CvSize** sizes, int** types )
102 {
103     CvRNG* rng = ts->get_rng();
104     int depth = cvTsRandInt(rng)%2 + CV_32F;
105     int cn = cvTsRandInt(rng) % 4 + 1, type = CV_MAKETYPE(depth, cn);
106     int i, j;
107     CvArrTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
108
109     for( i = 0; i < max_arr; i++ )
110     {
111         int count = test_array[i].size();
112         for( j = 0; j < count; j++ )
113             types[i][j] = type;
114     }
115     test_nd = cvTsRandInt(rng)%3 == 0;
116 }
117
118 CxCore_MathTestImpl math_test( "math", "" );
119
120
121 class CxCore_MathTest : public CxCore_MathTestImpl
122 {
123 public:
124     CxCore_MathTest( const char* test_name, const char* test_funcs );
125 };
126
127
128 CxCore_MathTest::CxCore_MathTest( const char* test_name, const char* test_funcs )
129     : CxCore_MathTestImpl( test_name, test_funcs )
130 {
131     size_list = 0;
132     depth_list = 0;
133 }
134
135
136 ////////// exp /////////////
137 class CxCore_ExpTest : public CxCore_MathTest
138 {
139 public:
140     CxCore_ExpTest();
141 protected:
142     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
143     void get_minmax_bounds( int i, int j, int type, CvScalar* low, CvScalar* high );
144     double get_success_error_level( int /*test_case_idx*/, int i, int j );
145     void run_func();
146     void prepare_to_validation( int test_case_idx );
147     int out_type;
148 };
149
150
151 CxCore_ExpTest::CxCore_ExpTest()
152     : CxCore_MathTest( "math-exp", "cvExp" )
153 {
154     out_type = 0;
155 }
156
157
158 double CxCore_ExpTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
159 {
160     int in_depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
161     int out_depth = CV_MAT_DEPTH(test_mat[OUTPUT][0].type);
162     int min_depth = MIN(in_depth, out_depth);
163     return min_depth == CV_32F ? 1e-5 : 1e-8;
164 }
165
166
167 void CxCore_ExpTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
168 {
169     CxCore_MathTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
170     out_type = types[OUTPUT][0];
171     /*if( CV_MAT_DEPTH(types[INPUT][0]) == CV_32F && (cvRandInt(ts->get_rng()) & 3) == 0 )
172         types[OUTPUT][0] = types[REF_OUTPUT][0] =
173             out_type = (types[INPUT][0] & ~CV_MAT_DEPTH_MASK)|CV_64F;*/
174 }
175
176 void CxCore_ExpTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
177 {
178     double l = cvTsRandReal(ts->get_rng())*10+1;
179     double u = cvTsRandReal(ts->get_rng())*10+1;
180     l *= -l;
181     u *= u;
182     *low = cvScalarAll(l);
183     *high = cvScalarAll(CV_MAT_DEPTH(out_type)==CV_64F? u : u*0.5);
184 }
185
186
187 void CxCore_ExpTest::run_func()
188 {
189     if(!test_nd)
190         cvExp( test_array[INPUT][0], test_array[OUTPUT][0] );
191     else
192     {
193         cv::MatND a = cv::cvarrToMatND(test_array[INPUT][0]);
194         cv::MatND b = cv::cvarrToMatND(test_array[OUTPUT][0]);
195         cv::exp(a, b);
196     }
197 }
198
199
200 void CxCore_ExpTest::prepare_to_validation( int /*test_case_idx*/ )
201 {
202     CvMat* a = &test_mat[INPUT][0];
203     CvMat* b = &test_mat[REF_OUTPUT][0];
204
205     int a_depth = CV_MAT_DEPTH(a->type);
206     int b_depth = CV_MAT_DEPTH(b->type);
207     int ncols = test_mat[INPUT][0].cols*CV_MAT_CN(a->type);
208     int i, j;
209
210     for( i = 0; i < a->rows; i++ )
211     {
212         uchar* a_data = a->data.ptr + i*a->step;
213         uchar* b_data = b->data.ptr + i*b->step;
214
215         if( a_depth == CV_32F && b_depth == CV_32F )
216         {
217             for( j = 0; j < ncols; j++ )
218                 ((float*)b_data)[j] = (float)exp((double)((float*)a_data)[j]);
219         }
220         else if( a_depth == CV_32F && b_depth == CV_64F )
221         {
222             for( j = 0; j < ncols; j++ )
223                 ((double*)b_data)[j] = exp((double)((float*)a_data)[j]);
224         }
225         else
226         {
227             assert( a_depth == CV_64F && b_depth == CV_64F );
228             for( j = 0; j < ncols; j++ )
229                 ((double*)b_data)[j] = exp(((double*)a_data)[j]);
230         }
231     }
232 }
233
234 CxCore_ExpTest exp_test;
235
236
237 ////////// log /////////////
238 class CxCore_LogTest : public CxCore_MathTest
239 {
240 public:
241     CxCore_LogTest();
242 protected:
243     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
244     void get_minmax_bounds( int i, int j, int type, CvScalar* low, CvScalar* high );
245     void run_func();
246     void prepare_to_validation( int test_case_idx );
247 };
248
249
250 CxCore_LogTest::CxCore_LogTest()
251     : CxCore_MathTest( "math-log", "cvLog" )
252 {
253 }
254
255
256 void CxCore_LogTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
257 {
258     CxCore_MathTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
259     /*if( CV_MAT_DEPTH(types[INPUT][0]) == CV_32F && (cvRandInt(ts->get_rng()) & 3) == 0 )
260         types[INPUT][0] = (types[INPUT][0] & ~CV_MAT_DEPTH_MASK)|CV_64F;*/
261 }
262
263
264 void CxCore_LogTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
265 {
266     double l = cvTsRandReal(ts->get_rng())*15-5;
267     double u = cvTsRandReal(ts->get_rng())*15-5;
268     double t;
269     l = exp(l);
270     u = exp(u);
271     if( l > u )
272         CV_SWAP( l, u, t );
273     *low = cvScalarAll(l);
274     *high = cvScalarAll(u);
275 }
276
277
278 void CxCore_LogTest::run_func()
279 {
280     if(!test_nd)
281         cvLog( test_array[INPUT][0], test_array[OUTPUT][0] );
282     else
283     {
284         cv::MatND a = cv::cvarrToMatND(test_array[INPUT][0]);
285         cv::MatND b = cv::cvarrToMatND(test_array[OUTPUT][0]);
286         cv::log(a, b);
287     }
288 }
289
290
291 void CxCore_LogTest::prepare_to_validation( int /*test_case_idx*/ )
292 {
293     CvMat* a = &test_mat[INPUT][0];
294     CvMat* b = &test_mat[REF_OUTPUT][0];
295
296     int a_depth = CV_MAT_DEPTH(a->type);
297     int b_depth = CV_MAT_DEPTH(b->type);
298     int ncols = test_mat[INPUT][0].cols*CV_MAT_CN(a->type);
299     int i, j;
300
301     for( i = 0; i < a->rows; i++ )
302     {
303         uchar* a_data = a->data.ptr + i*a->step;
304         uchar* b_data = b->data.ptr + i*b->step;
305
306         if( a_depth == CV_32F && b_depth == CV_32F )
307         {
308             for( j = 0; j < ncols; j++ )
309                 ((float*)b_data)[j] = (float)log((double)((float*)a_data)[j]);
310         }
311         else if( a_depth == CV_64F && b_depth == CV_32F )
312         {
313             for( j = 0; j < ncols; j++ )
314                 ((float*)b_data)[j] = (float)log(((double*)a_data)[j]);
315         }
316         else
317         {
318             assert( a_depth == CV_64F && b_depth == CV_64F );
319             for( j = 0; j < ncols; j++ )
320                 ((double*)b_data)[j] = log(((double*)a_data)[j]);
321         }
322     }
323 }
324
325 CxCore_LogTest log_test;
326
327
328 ////////// pow /////////////
329
330 static const double math_pow_values[] = { 2., 5., 0.5, -0.5, 1./3, -1./3, CV_PI };
331 static const char* math_pow_param_names[] = { "size", "power", "depth", 0 };
332 static const int math_pow_depths[] = { CV_8U, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F, -1 };
333
334 class CxCore_PowTest : public CxCore_MathTest
335 {
336 public:
337     CxCore_PowTest();
338 protected:
339     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
340     void get_minmax_bounds( int i, int j, int type, CvScalar* low, CvScalar* high );
341     void get_timing_test_array_types_and_sizes( int test_case_idx,
342                                                 CvSize** sizes, int** types,
343                                                 CvSize** whole_sizes, bool* are_images );
344     int write_default_params( CvFileStorage* fs );
345     void print_timing_params( int test_case_idx, char* ptr, int params_left );
346     void run_func();
347     int prepare_test_case( int test_case_idx );
348     void prepare_to_validation( int test_case_idx );
349     double get_success_error_level( int test_case_idx, int i, int j );
350     double power;
351 };
352
353
354 CxCore_PowTest::CxCore_PowTest()
355     : CxCore_MathTest( "math-pow", "cvPow" )
356 {
357     power = 0;
358     default_timing_param_names = math_pow_param_names;
359     depth_list = math_pow_depths;
360 }
361
362
363 void CxCore_PowTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
364 {
365     CvRNG* rng = ts->get_rng();
366     int depth = cvTsRandInt(rng) % (CV_64F+1);
367     int cn = cvTsRandInt(rng) % 4 + 1;
368     int i, j;
369     CvArrTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
370     depth += depth == CV_8S;
371     
372     if( depth < CV_32F || cvTsRandInt(rng)%8 == 0 )
373         // integer power
374         power = (int)(cvTsRandInt(rng)%21 - 10);
375     else
376     {
377         i = cvTsRandInt(rng)%16;
378         power = i == 15 ? 0.5 : i == 14 ? -0.5 : cvTsRandReal(rng)*10 - 5;
379     }
380
381     for( i = 0; i < max_arr; i++ )
382     {
383         int count = test_array[i].size();
384         int type = CV_MAKETYPE(depth, cn);
385         for( j = 0; j < count; j++ )
386             types[i][j] = type;
387     }
388     test_nd = cvTsRandInt(rng)%3 == 0;
389 }
390
391
392 void CxCore_PowTest::get_timing_test_array_types_and_sizes( int test_case_idx,
393                                                     CvSize** sizes, int** types,
394                                                     CvSize** whole_sizes, bool* are_images )
395 {
396     CxCore_MathTest::get_timing_test_array_types_and_sizes( test_case_idx,
397                                     sizes, types, whole_sizes, are_images );
398     power = cvReadReal( find_timing_param( "power" ), 0.2 );
399 }
400
401
402 int CxCore_PowTest::write_default_params( CvFileStorage* fs )
403 {
404     int i, code = CxCore_MathTest::write_default_params(fs);
405     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
406         return code;
407     start_write_param( fs );
408     cvStartWriteStruct( fs, "power", CV_NODE_SEQ + CV_NODE_FLOW );
409     for( i = 0; i < CV_DIM(math_pow_values); i++ )
410         cvWriteReal( fs, 0, math_pow_values[i] );
411     cvEndWriteStruct(fs);
412     return code;
413 }
414
415
416 int CxCore_PowTest::prepare_test_case( int test_case_idx )
417 {
418     int code = CxCore_MathTest::prepare_test_case( test_case_idx );
419     if( code > 0 && ts->get_testing_mode() == CvTS::TIMING_MODE )
420     {
421         if( cvRound(power) != power && CV_MAT_DEPTH(test_mat[INPUT][0].type) < CV_32F )
422             return 0;
423     }
424     return code;
425 }
426
427
428 void CxCore_PowTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
429 {
430     sprintf( ptr, "%g,", power );
431     ptr += strlen(ptr);
432     params_left--;
433     CxCore_MathTest::print_timing_params( test_case_idx, ptr, params_left );
434 }
435
436
437 double CxCore_PowTest::get_success_error_level( int test_case_idx, int i, int j )
438 {
439     int type = cvGetElemType( test_array[i][j] );
440     if( CV_MAT_DEPTH(type) < CV_32F )
441         return power == cvRound(power) && power >= 0 ? 0 : 1;
442     else
443         return CxCore_MathTest::get_success_error_level( test_case_idx, i, j );
444 }
445
446
447 void CxCore_PowTest::get_minmax_bounds( int /*i*/, int /*j*/, int type, CvScalar* low, CvScalar* high )
448 {
449     double l, u = cvTsRandInt(ts->get_rng())%1000 + 1;
450     if( power > 0 )
451     {
452         double mval = cvTsMaxVal(type);
453         double u1 = pow(mval,1./power)*2;
454         u = MIN(u,u1);
455     }
456
457     l = power == cvRound(power) ? -u : FLT_EPSILON;
458     *low = cvScalarAll(l);
459     *high = cvScalarAll(u);
460 }
461
462
463 void CxCore_PowTest::run_func()
464 {
465     if(!test_nd)
466         cvPow( test_array[INPUT][0], test_array[OUTPUT][0], power );
467     else
468     {
469         cv::MatND a = cv::cvarrToMatND(test_array[INPUT][0]);
470         cv::MatND b = cv::cvarrToMatND(test_array[OUTPUT][0]);
471         if(power == 0.5)
472             cv::sqrt(a, b);
473         else
474             cv::pow(a, power, b);
475     }
476 }
477
478
479 inline static int ipow( int a, int power )
480 {
481     int b = 1;
482     while( power > 0 )
483     {
484         if( power&1 )
485             b *= a, power--;
486         else
487             a *= a, power >>= 1;
488     }
489     return b;
490 }
491
492
493 inline static double ipow( double a, int power )
494 {
495     double b = 1.;
496     while( power > 0 )
497     {
498         if( power&1 )
499             b *= a, power--;
500         else
501             a *= a, power >>= 1;
502     }
503     return b;
504 }
505
506
507 void CxCore_PowTest::prepare_to_validation( int /*test_case_idx*/ )
508 {
509     CvMat* a = &test_mat[INPUT][0];
510     CvMat* b = &test_mat[REF_OUTPUT][0];
511
512     int depth = CV_MAT_DEPTH(a->type);
513     int ncols = test_mat[INPUT][0].cols*CV_MAT_CN(a->type);
514     int ipower = cvRound(power), apower = abs(ipower);
515     int i, j;
516
517     for( i = 0; i < a->rows; i++ )
518     {
519         uchar* a_data = a->data.ptr + i*a->step;
520         uchar* b_data = b->data.ptr + i*b->step;
521
522         switch( depth )
523         {
524         case CV_8U:
525             if( ipower < 0 )
526                 for( j = 0; j < ncols; j++ )
527                 {
528                     int val = ((uchar*)a_data)[j];
529                     ((uchar*)b_data)[j] = (uchar)(val <= 1 ? val :
530                                         val == 2 && ipower == -1 ? 1 : 0);
531                 }
532             else
533                 for( j = 0; j < ncols; j++ )
534                 {
535                     int val = ((uchar*)a_data)[j];
536                     val = ipow( val, ipower );
537                     ((uchar*)b_data)[j] = CV_CAST_8U(val);
538                 }
539             break;
540         case CV_8S:
541             if( ipower < 0 )
542                 for( j = 0; j < ncols; j++ )
543                 {
544                     int val = ((char*)a_data)[j];
545                     ((char*)b_data)[j] = (char)((val&~1)==0 ? val :
546                                           val ==-1 ? 1-2*(ipower&1) :
547                                           val == 2 && ipower == -1 ? 1 : 0);
548                 }
549             else
550                 for( j = 0; j < ncols; j++ )
551                 {
552                     int val = ((char*)a_data)[j];
553                     val = ipow( val, ipower );
554                     ((char*)b_data)[j] = CV_CAST_8S(val);
555                 }
556             break;
557         case CV_16U:
558             if( ipower < 0 )
559                 for( j = 0; j < ncols; j++ )
560                 {
561                     int val = ((ushort*)a_data)[j];
562                     ((ushort*)b_data)[j] = (ushort)((val&~1)==0 ? val :
563                                           val ==-1 ? 1-2*(ipower&1) :
564                                           val == 2 && ipower == -1 ? 1 : 0);
565                 }
566             else
567                 for( j = 0; j < ncols; j++ )
568                 {
569                     int val = ((ushort*)a_data)[j];
570                     val = ipow( val, ipower );
571                     ((ushort*)b_data)[j] = CV_CAST_16U(val);
572                 }
573             break;
574         case CV_16S:
575             if( ipower < 0 )
576                 for( j = 0; j < ncols; j++ )
577                 {
578                     int val = ((short*)a_data)[j];
579                     ((short*)b_data)[j] = (short)((val&~1)==0 ? val :
580                                           val ==-1 ? 1-2*(ipower&1) :
581                                           val == 2 && ipower == -1 ? 1 : 0);
582                 }
583             else
584                 for( j = 0; j < ncols; j++ )
585                 {
586                     int val = ((short*)a_data)[j];
587                     val = ipow( val, ipower );
588                     ((short*)b_data)[j] = CV_CAST_16S(val);
589                 }
590             break;
591         case CV_32S:
592             if( ipower < 0 )
593                 for( j = 0; j < ncols; j++ )
594                 {
595                     int val = ((int*)a_data)[j];
596                     ((int*)b_data)[j] = (val&~1)==0 ? val :
597                                         val ==-1 ? 1-2*(ipower&1) :
598                                         val == 2 && ipower == -1 ? 1 : 0;
599                 }
600             else
601                 for( j = 0; j < ncols; j++ )
602                 {
603                     int val = ((int*)a_data)[j];
604                     val = ipow( val, ipower );
605                     ((int*)b_data)[j] = val;
606                 }
607             break;
608         case CV_32F:
609             if( power != ipower )
610                 for( j = 0; j < ncols; j++ )
611                 {
612                     double val = ((float*)a_data)[j];
613                     val = pow( fabs(val), power );
614                     ((float*)b_data)[j] = CV_CAST_32F(val);
615                 }
616             else
617                 for( j = 0; j < ncols; j++ )
618                 {
619                     double val = ((float*)a_data)[j];
620                     if( ipower < 0 )
621                         val = 1./val;
622                     val = ipow( val, apower );
623                     ((float*)b_data)[j] = (float)val;
624                 }
625             break;
626         case CV_64F:
627             if( power != ipower )
628                 for( j = 0; j < ncols; j++ )
629                 {
630                     double val = ((double*)a_data)[j];
631                     val = pow( fabs(val), power );
632                     ((double*)b_data)[j] = CV_CAST_64F(val);
633                 }
634             else
635                 for( j = 0; j < ncols; j++ )
636                 {
637                     double val = ((double*)a_data)[j];
638                     if( ipower < 0 )
639                         val = 1./val;
640                     val = ipow( val, apower );
641                     ((double*)b_data)[j] = (double)val;
642                 }
643             break;
644         }
645     }
646 }
647
648 CxCore_PowTest pow_test;
649
650
651
652 ////////// cart2polar /////////////
653 class CxCore_CartToPolarTest : public CxCore_MathTest
654 {
655 public:
656     CxCore_CartToPolarTest();
657 protected:
658     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
659     double get_success_error_level( int test_case_idx, int i, int j );
660     void run_func();
661     void prepare_to_validation( int test_case_idx );
662     int use_degrees;
663 };
664
665
666 CxCore_CartToPolarTest::CxCore_CartToPolarTest()
667     : CxCore_MathTest( "math-cart2polar", "cvCartToPolar" )
668 {
669     use_degrees = 0;
670     test_array[INPUT].push(NULL);
671     test_array[OUTPUT].push(NULL);
672     test_array[REF_OUTPUT].push(NULL);
673 }
674
675
676 void CxCore_CartToPolarTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
677 {
678     CvRNG* rng = ts->get_rng();
679     CxCore_MathTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
680
681     use_degrees = cvTsRandInt(rng) & 1;
682     if( cvTsRandInt(rng) % 4 == 0 ) // check missing magnitude/angle cases
683     {
684         int idx = cvTsRandInt(rng) & 1;
685         sizes[OUTPUT][idx] = sizes[REF_OUTPUT][idx] = cvSize(0,0);
686     }
687 }
688
689
690 void CxCore_CartToPolarTest::run_func()
691 {
692     if(!test_nd)
693     {
694         cvCartToPolar( test_array[INPUT][0], test_array[INPUT][1],
695                     test_array[OUTPUT][0], test_array[OUTPUT][1], use_degrees );
696     }
697     else
698     {
699         cv::Mat X = cv::cvarrToMat(test_array[INPUT][0]);
700         cv::Mat Y = cv::cvarrToMat(test_array[INPUT][1]);
701         cv::Mat mag = test_array[OUTPUT][0] ? cv::cvarrToMat(test_array[OUTPUT][0]) : cv::Mat();
702         cv::Mat ph = test_array[OUTPUT][1] ? cv::cvarrToMat(test_array[OUTPUT][1]) : cv::Mat();
703         if(!mag.data)
704             cv::phase(X, Y, ph, use_degrees);
705         else if(!ph.data)
706             cv::magnitude(X, Y, mag);
707         else
708             cv::cartToPolar(X, Y, mag, ph, use_degrees);
709     }
710 }
711
712
713 double CxCore_CartToPolarTest::get_success_error_level( int test_case_idx, int i, int j )
714 {
715     return j == 1 ? 0.5*(use_degrees ? 1 : CV_PI/180.) :
716         CxCore_MathTest::get_success_error_level( test_case_idx, i, j );
717 }
718
719
720 void CxCore_CartToPolarTest::prepare_to_validation( int /*test_case_idx*/ )
721 {
722     CvMat* x = &test_mat[INPUT][0];
723     CvMat* y = &test_mat[INPUT][1];
724     CvMat* mag = test_array[REF_OUTPUT][0] ? &test_mat[REF_OUTPUT][0] : 0;
725     CvMat* angle = test_array[REF_OUTPUT][1] ? &test_mat[REF_OUTPUT][1] : 0;
726     double C = use_degrees ? 180./CV_PI : 1.;
727
728     int depth = CV_MAT_DEPTH(x->type);
729     int ncols = x->cols*CV_MAT_CN(x->type);
730     int i, j;
731
732     for( i = 0; i < x->rows; i++ )
733     {
734         uchar* x_data = x->data.ptr + i*x->step;
735         uchar* y_data = y->data.ptr + i*y->step;
736         uchar* mag_data = mag ? mag->data.ptr + i*mag->step : 0;
737         uchar* angle_data = angle ? angle->data.ptr + i*angle->step : 0;
738
739         if( depth == CV_32F )
740         {
741             for( j = 0; j < ncols; j++ )
742             {
743                 double xval = ((float*)x_data)[j];
744                 double yval = ((float*)y_data)[j];
745
746                 if( mag_data )
747                     ((float*)mag_data)[j] = (float)sqrt(xval*xval + yval*yval);
748                 if( angle_data )
749                 {
750                     double a = atan2( yval, xval );
751                     if( a < 0 )
752                         a += CV_PI*2;
753                     a *= C;
754                     ((float*)angle_data)[j] = (float)a;
755                 }
756             }
757         }
758         else
759         {
760             assert( depth == CV_64F );
761             for( j = 0; j < ncols; j++ )
762             {
763                 double xval = ((double*)x_data)[j];
764                 double yval = ((double*)y_data)[j];
765
766                 if( mag_data )
767                     ((double*)mag_data)[j] = sqrt(xval*xval + yval*yval);
768                 if( angle_data )
769                 {
770                     double a = atan2( yval, xval );
771                     if( a < 0 )
772                         a += CV_PI*2;
773                     a *= C;
774                     ((double*)angle_data)[j] = a;
775                 }
776             }
777         }
778     }
779
780     if( angle )
781     {
782         // hack: increase angle value by 1 (so that alpha becomes 1+alpha)
783         // to hide large relative errors in case of very small angles
784         cvTsAdd( &test_mat[OUTPUT][1], cvScalarAll(1.), 0, cvScalarAll(0.),
785                  cvScalarAll(1.), &test_mat[OUTPUT][1], 0 );
786         cvTsAdd( &test_mat[REF_OUTPUT][1], cvScalarAll(1.), 0, cvScalarAll(0.),
787                  cvScalarAll(1.), &test_mat[REF_OUTPUT][1], 0 );
788     }
789 }
790
791 CxCore_CartToPolarTest cart2polar_test;
792
793
794
795 ////////// polar2cart /////////////
796 class CxCore_PolarToCartTest : public CxCore_MathTest
797 {
798 public:
799     CxCore_PolarToCartTest();
800 protected:
801     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
802     double get_success_error_level( int test_case_idx, int i, int j );
803     void run_func();
804     void prepare_to_validation( int test_case_idx );
805     int use_degrees;
806 };
807
808
809 CxCore_PolarToCartTest::CxCore_PolarToCartTest()
810     : CxCore_MathTest( "math-polar2cart", "cvPolarToCart" )
811 {
812     use_degrees = 0;
813     test_array[INPUT].push(NULL);
814     test_array[OUTPUT].push(NULL);
815     test_array[REF_OUTPUT].push(NULL);
816 }
817
818
819 void CxCore_PolarToCartTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
820 {
821     CvRNG* rng = ts->get_rng();
822     CxCore_MathTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
823
824     use_degrees = cvTsRandInt(rng) & 1;
825     if( cvTsRandInt(rng) % 4 == 0 ) // check missing magnitude case
826         sizes[INPUT][1] = cvSize(0,0);
827
828     if( cvTsRandInt(rng) % 4 == 0 ) // check missing x/y cases
829     {
830         int idx = cvTsRandInt(rng) & 1;
831         sizes[OUTPUT][idx] = sizes[REF_OUTPUT][idx] = cvSize(0,0);
832     }
833 }
834
835
836 void CxCore_PolarToCartTest::run_func()
837 {
838     if(!test_nd)
839     {
840         cvPolarToCart( test_array[INPUT][1], test_array[INPUT][0],
841                     test_array[OUTPUT][0], test_array[OUTPUT][1], use_degrees );
842     }
843     else
844     {
845         cv::Mat X = test_array[OUTPUT][0] ? cv::cvarrToMat(test_array[OUTPUT][0]) : cv::Mat();
846         cv::Mat Y = test_array[OUTPUT][1] ? cv::cvarrToMat(test_array[OUTPUT][1]) : cv::Mat();
847         cv::Mat mag = test_array[INPUT][1] ? cv::cvarrToMat(test_array[INPUT][1]) : cv::Mat();
848         cv::Mat ph = test_array[INPUT][0] ? cv::cvarrToMat(test_array[INPUT][0]) : cv::Mat();
849         cv::polarToCart(mag, ph, X, Y, use_degrees);
850     }
851 }
852
853
854 double CxCore_PolarToCartTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
855 {
856     return FLT_EPSILON*100;
857 }
858
859
860 void CxCore_PolarToCartTest::prepare_to_validation( int /*test_case_idx*/ )
861 {
862     CvMat* x = test_array[REF_OUTPUT][0] ? &test_mat[REF_OUTPUT][0] : 0;
863     CvMat* y = test_array[REF_OUTPUT][1] ? &test_mat[REF_OUTPUT][1] : 0;
864     CvMat* angle = &test_mat[INPUT][0];
865     CvMat* mag = test_array[INPUT][1] ? &test_mat[INPUT][1] : 0;
866     double C = use_degrees ? CV_PI/180. : 1.;
867
868     int depth = CV_MAT_DEPTH(angle->type);
869     int ncols = angle->cols*CV_MAT_CN(angle->type);
870     int i, j;
871
872     for( i = 0; i < angle->rows; i++ )
873     {
874         uchar* x_data = x ? x->data.ptr + i*x->step : 0;
875         uchar* y_data = y ? y->data.ptr + i*y->step : 0;
876         uchar* mag_data = mag ? mag->data.ptr + i*mag->step : 0;
877         uchar* angle_data = angle->data.ptr + i*angle->step;
878
879         if( depth == CV_32F )
880         {
881             for( j = 0; j < ncols; j++ )
882             {
883                 double a = ((float*)angle_data)[j]*C;
884                 double m = mag_data ? ((float*)mag_data)[j] : 1.;
885
886                 if( x_data )
887                     ((float*)x_data)[j] = (float)(m*cos(a));
888                 if( y_data )
889                     ((float*)y_data)[j] = (float)(m*sin(a));
890             }
891         }
892         else
893         {
894             assert( depth == CV_64F );
895             for( j = 0; j < ncols; j++ )
896             {
897                 double a = ((double*)angle_data)[j]*C;
898                 double m = mag_data ? ((double*)mag_data)[j] : 1.;
899
900                 if( x_data )
901                     ((double*)x_data)[j] = m*cos(a);
902                 if( y_data )
903                     ((double*)y_data)[j] = m*sin(a);
904             }
905         }
906     }
907 }
908
909 CxCore_PolarToCartTest polar2cart_test;
910
911 ///////////////////////////////////////// matrix tests ////////////////////////////////////////////
912
913 static const int matrix_all_depths[] = { CV_8U, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F, -1 };
914
915 class CxCore_MatrixTestImpl : public CvArrTest
916 {
917 public:
918     CxCore_MatrixTestImpl( const char* test_name, const char* test_funcs, int in_count, int out_count,
919                        bool allow_int, bool scalar_output, int max_cn );
920 protected:
921     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
922     void get_timing_test_array_types_and_sizes( int test_case_idx,
923                                                 CvSize** sizes, int** types,
924                                                 CvSize** whole_sizes, bool* are_images );
925     double get_success_error_level( int test_case_idx, int i, int j );
926     bool allow_int;
927     bool scalar_output;
928     int max_cn;
929 };
930
931
932 CxCore_MatrixTestImpl::CxCore_MatrixTestImpl( const char* test_name, const char* test_funcs,
933                                       int in_count, int out_count,
934                                       bool _allow_int, bool _scalar_output, int _max_cn )
935     : CvArrTest( test_name, test_funcs, "" ),
936     allow_int(_allow_int), scalar_output(_scalar_output), max_cn(_max_cn)
937 {
938     int i;
939     for( i = 0; i < in_count; i++ )
940         test_array[INPUT].push(NULL);
941
942     for( i = 0; i < out_count; i++ )
943     {
944         test_array[OUTPUT].push(NULL);
945         test_array[REF_OUTPUT].push(NULL);
946     }
947
948     element_wise_relative_error = false;
949
950     default_timing_param_names = math_param_names;
951
952     size_list = (CvSize*)matrix_sizes;
953     whole_size_list = 0;
954     depth_list = (int*)math_depths;
955     cn_list = 0;
956 }
957
958
959 void CxCore_MatrixTestImpl::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
960 {
961     CvRNG* rng = ts->get_rng();
962     int depth = cvTsRandInt(rng) % (allow_int ? CV_64F+1 : 2);
963     int cn = cvTsRandInt(rng) % max_cn + 1;
964     int i, j;
965
966     if( allow_int )
967         depth += depth == CV_8S;
968     else
969         depth += CV_32F;
970
971     CvArrTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
972
973     for( i = 0; i < max_arr; i++ )
974     {
975         int count = test_array[i].size();
976         int flag = (i == OUTPUT || i == REF_OUTPUT) && scalar_output;
977         int type = !flag ? CV_MAKETYPE(depth, cn) : CV_64FC1;
978
979         for( j = 0; j < count; j++ )
980         {
981             types[i][j] = type;
982             if( flag )
983                 sizes[i][j] = cvSize( 4, 1 );
984         }
985     }
986 }
987
988
989 void CxCore_MatrixTestImpl::get_timing_test_array_types_and_sizes( int test_case_idx,
990                 CvSize** sizes, int** types, CvSize** whole_sizes, bool* are_images )
991 {
992     CvArrTest::get_timing_test_array_types_and_sizes( test_case_idx,
993                               sizes, types, whole_sizes, are_images );
994     if( scalar_output )
995     {
996         types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;
997         sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize( 4, 1 );
998         whole_sizes[OUTPUT][0] = whole_sizes[REF_OUTPUT][0] = cvSize( 4, 1 );
999     }
1000 }
1001
1002
1003 double CxCore_MatrixTestImpl::get_success_error_level( int test_case_idx, int i, int j )
1004 {
1005     int input_depth = CV_MAT_DEPTH(cvGetElemType( test_array[INPUT][0] ));
1006     double input_precision = input_depth < CV_32F ? 0 : input_depth == CV_32F ?
1007                             1e-5 : 5e-12;
1008     double output_precision = CvArrTest::get_success_error_level( test_case_idx, i, j );
1009     return MAX(input_precision, output_precision);
1010 }
1011
1012 CxCore_MatrixTestImpl matrix_test( "matrix", "", 0, 0, false, false, 0 );
1013
1014
1015 class CxCore_MatrixTest : public CxCore_MatrixTestImpl
1016 {
1017 public:
1018     CxCore_MatrixTest( const char* test_name, const char* test_funcs, int in_count, int out_count,
1019                        bool allow_int, bool scalar_output, int max_cn );
1020 };
1021
1022
1023 CxCore_MatrixTest::CxCore_MatrixTest( const char* test_name, const char* test_funcs,
1024                                       int in_count, int out_count, bool _allow_int,
1025                                       bool _scalar_output, int _max_cn )
1026     : CxCore_MatrixTestImpl( test_name, test_funcs, in_count, out_count,
1027                              _allow_int, _scalar_output, _max_cn )
1028 {
1029     size_list = 0;
1030     depth_list = 0;
1031 }
1032
1033
1034 ///////////////// Trace /////////////////////
1035
1036 class CxCore_TraceTest : public CxCore_MatrixTest
1037 {
1038 public:
1039     CxCore_TraceTest();
1040 protected:
1041     void run_func();
1042     void prepare_to_validation( int test_case_idx );
1043 };
1044
1045
1046 CxCore_TraceTest::CxCore_TraceTest() :
1047     CxCore_MatrixTest( "matrix-trace", "cvTrace", 1, 1, true, true, 4 )
1048 {
1049 }
1050
1051
1052 void CxCore_TraceTest::run_func()
1053 {
1054     *((CvScalar*)(test_mat[OUTPUT][0].data.db)) = cvTrace(test_array[INPUT][0]);
1055 }
1056
1057
1058 void CxCore_TraceTest::prepare_to_validation( int )
1059 {
1060     CvMat* mat = &test_mat[INPUT][0];
1061     int i, j, count = MIN( mat->rows, mat->cols );
1062     CvScalar trace = {{0,0,0,0}};
1063
1064     for( i = 0; i < count; i++ )
1065     {
1066         CvScalar el = cvGet2D( mat, i, i );
1067         for( j = 0; j < 4; j++ )
1068             trace.val[j] += el.val[j];
1069     }
1070
1071     *((CvScalar*)(test_mat[REF_OUTPUT][0].data.db)) = trace;
1072 }
1073
1074 CxCore_TraceTest trace_test;
1075
1076
1077 ///////// dotproduct //////////
1078
1079 class CxCore_DotProductTest : public CxCore_MatrixTest
1080 {
1081 public:
1082     CxCore_DotProductTest();
1083 protected:
1084     void run_func();
1085     void prepare_to_validation( int test_case_idx );
1086 };
1087
1088
1089 CxCore_DotProductTest::CxCore_DotProductTest() :
1090     CxCore_MatrixTest( "matrix-dotproduct", "cvDotProduct", 2, 1, true, true, 4 )
1091 {
1092     depth_list = matrix_all_depths;
1093 }
1094
1095
1096 void CxCore_DotProductTest::run_func()
1097 {
1098     *((CvScalar*)(test_mat[OUTPUT][0].data.ptr)) =
1099         cvRealScalar(cvDotProduct( test_array[INPUT][0], test_array[INPUT][1] ));
1100 }
1101
1102
1103 void CxCore_DotProductTest::prepare_to_validation( int )
1104 {
1105     *((CvScalar*)(test_mat[REF_OUTPUT][0].data.ptr)) =
1106         cvRealScalar(cvTsCrossCorr( &test_mat[INPUT][0], &test_mat[INPUT][1] ));
1107 }
1108
1109 CxCore_DotProductTest dotproduct_test;
1110
1111
1112 ///////// crossproduct //////////
1113
1114 static const CvSize cross_product_sizes[] = {{3,1}, {-1,-1}};
1115
1116 class CxCore_CrossProductTest : public CxCore_MatrixTest
1117 {
1118 public:
1119     CxCore_CrossProductTest();
1120 protected:
1121     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1122     void run_func();
1123     void prepare_to_validation( int test_case_idx );
1124 };
1125
1126
1127 CxCore_CrossProductTest::CxCore_CrossProductTest() :
1128     CxCore_MatrixTest( "matrix-crossproduct", "cvCrossProduct", 2, 1, false, false, 1 )
1129 {
1130     size_list = cross_product_sizes;
1131 }
1132
1133
1134 void CxCore_CrossProductTest::get_test_array_types_and_sizes( int /*test_case_idx*/, CvSize** sizes, int** types )
1135 {
1136     CvRNG* rng = ts->get_rng();
1137     int depth = cvTsRandInt(rng) % 2 + CV_32F;
1138     int cn = cvTsRandInt(rng) & 1 ? 3 : 1, type = CV_MAKETYPE(depth, cn);
1139     CvSize sz;
1140
1141     types[INPUT][0] = types[INPUT][1] = types[OUTPUT][0] = types[REF_OUTPUT][0] = type;
1142
1143     if( cn == 3 )
1144         sz = cvSize(1,1);
1145     else if( cvTsRandInt(rng) & 1 )
1146         sz = cvSize(3,1);
1147     else
1148         sz = cvSize(1,3);
1149
1150     sizes[INPUT][0] = sizes[INPUT][1] = sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sz;
1151 }
1152
1153
1154 void CxCore_CrossProductTest::run_func()
1155 {
1156     cvCrossProduct( test_array[INPUT][0], test_array[INPUT][1], test_array[OUTPUT][0] );
1157 }
1158
1159
1160 void CxCore_CrossProductTest::prepare_to_validation( int )
1161 {
1162     CvScalar a = {{0,0,0,0}}, b = {{0,0,0,0}}, c = {{0,0,0,0}};
1163
1164     if( test_mat[INPUT][0].rows > 1 )
1165     {
1166         a.val[0] = cvGetReal2D( &test_mat[INPUT][0], 0, 0 );
1167         a.val[1] = cvGetReal2D( &test_mat[INPUT][0], 1, 0 );
1168         a.val[2] = cvGetReal2D( &test_mat[INPUT][0], 2, 0 );
1169
1170         b.val[0] = cvGetReal2D( &test_mat[INPUT][1], 0, 0 );
1171         b.val[1] = cvGetReal2D( &test_mat[INPUT][1], 1, 0 );
1172         b.val[2] = cvGetReal2D( &test_mat[INPUT][1], 2, 0 );
1173     }
1174     else if( test_mat[INPUT][0].cols > 1 )
1175     {
1176         a.val[0] = cvGetReal1D( &test_mat[INPUT][0], 0 );
1177         a.val[1] = cvGetReal1D( &test_mat[INPUT][0], 1 );
1178         a.val[2] = cvGetReal1D( &test_mat[INPUT][0], 2 );
1179
1180         b.val[0] = cvGetReal1D( &test_mat[INPUT][1], 0 );
1181         b.val[1] = cvGetReal1D( &test_mat[INPUT][1], 1 );
1182         b.val[2] = cvGetReal1D( &test_mat[INPUT][1], 2 );
1183     }
1184     else
1185     {
1186         a = cvGet1D( &test_mat[INPUT][0], 0 );
1187         b = cvGet1D( &test_mat[INPUT][1], 0 );
1188     }
1189
1190     c.val[2] = a.val[0]*b.val[1] - a.val[1]*b.val[0];
1191     c.val[1] = -a.val[0]*b.val[2] + a.val[2]*b.val[0];
1192     c.val[0] = a.val[1]*b.val[2] - a.val[2]*b.val[1];
1193
1194     if( test_mat[REF_OUTPUT][0].rows > 1 )
1195     {
1196         cvSetReal2D( &test_mat[REF_OUTPUT][0], 0, 0, c.val[0] );
1197         cvSetReal2D( &test_mat[REF_OUTPUT][0], 1, 0, c.val[1] );
1198         cvSetReal2D( &test_mat[REF_OUTPUT][0], 2, 0, c.val[2] );
1199     }
1200     else if( test_mat[REF_OUTPUT][0].cols > 1 )
1201     {
1202         cvSetReal1D( &test_mat[REF_OUTPUT][0], 0, c.val[0] );
1203         cvSetReal1D( &test_mat[REF_OUTPUT][0], 1, c.val[1] );
1204         cvSetReal1D( &test_mat[REF_OUTPUT][0], 2, c.val[2] );
1205     }
1206     else
1207     {
1208         cvSet1D( &test_mat[REF_OUTPUT][0], 0, c );
1209     }
1210 }
1211
1212 CxCore_CrossProductTest crossproduct_test;
1213
1214
1215 ///////////////// scaleadd /////////////////////
1216
1217 class CxCore_ScaleAddTest : public CxCore_MatrixTest
1218 {
1219 public:
1220     CxCore_ScaleAddTest();
1221 protected:
1222     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1223     void get_timing_test_array_types_and_sizes( int test_case_idx,
1224                                                 CvSize** sizes, int** types,
1225                                                 CvSize** whole_sizes, bool* are_images );
1226     int prepare_test_case( int test_case_idx );
1227     void run_func();
1228     void prepare_to_validation( int test_case_idx );
1229     CvScalar alpha;
1230 };
1231
1232 CxCore_ScaleAddTest::CxCore_ScaleAddTest() :
1233     CxCore_MatrixTest( "matrix-scaleadd", "cvScaleAdd", 3, 1, false, false, 4 )
1234 {
1235     alpha = cvScalarAll(0);
1236 }
1237
1238
1239 void CxCore_ScaleAddTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1240 {
1241     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1242     sizes[INPUT][2] = cvSize(1,1);
1243     types[INPUT][2] &= CV_MAT_DEPTH_MASK;
1244 }
1245
1246
1247 void CxCore_ScaleAddTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1248                                                 CvSize** sizes, int** types,
1249                                                 CvSize** whole_sizes, bool* are_images )
1250 {
1251     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx, sizes, types,
1252                                                               whole_sizes, are_images );
1253     sizes[INPUT][2] = cvSize(1,1);
1254     types[INPUT][2] &= CV_MAT_DEPTH_MASK;
1255 }
1256
1257
1258 int CxCore_ScaleAddTest::prepare_test_case( int test_case_idx )
1259 {
1260     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
1261     if( code > 0 )
1262         alpha = cvGet1D( &test_mat[INPUT][2], 0 );
1263     return code;
1264 }
1265
1266
1267 void CxCore_ScaleAddTest::run_func()
1268 {
1269     cvScaleAdd( test_array[INPUT][0], alpha, test_array[INPUT][1], test_array[OUTPUT][0] );
1270 }
1271
1272
1273 void CxCore_ScaleAddTest::prepare_to_validation( int )
1274 {
1275     cvTsAdd( &test_mat[INPUT][0], cvScalarAll(alpha.val[0]),
1276              &test_mat[INPUT][1], cvScalarAll(1.),
1277              cvScalarAll(0.), &test_mat[REF_OUTPUT][0], 0 );
1278 }
1279
1280 CxCore_ScaleAddTest scaleadd_test;
1281
1282
1283 ///////////////// gemm /////////////////////
1284
1285 static const char* matrix_gemm_param_names[] = { "size", "add_c", "mul_type", "depth", 0 };
1286 static const char* matrix_gemm_mul_types[] = { "AB", "AtB", "ABt", "AtBt", 0 };
1287 static const int matrix_gemm_add_c_flags[] = { 0, 1 };
1288
1289 class CxCore_GEMMTest : public CxCore_MatrixTest
1290 {
1291 public:
1292     CxCore_GEMMTest();
1293 protected:
1294     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1295     void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high );
1296     void get_timing_test_array_types_and_sizes( int test_case_idx,
1297                                                 CvSize** sizes, int** types,
1298                                                 CvSize** whole_sizes, bool* are_images );
1299     int write_default_params( CvFileStorage* fs );
1300     void print_timing_params( int test_case_idx, char* ptr, int params_left );
1301     int prepare_test_case( int test_case_idx );
1302     void run_func();
1303     void prepare_to_validation( int test_case_idx );
1304     int tabc_flag;
1305     double alpha, beta;
1306 };
1307
1308 CxCore_GEMMTest::CxCore_GEMMTest() :
1309     CxCore_MatrixTest( "matrix-gemm", "cvGEMM", 5, 1, false, false, 2 )
1310 {
1311     test_case_count = 100;
1312     max_log_array_size = 10;
1313     default_timing_param_names = matrix_gemm_param_names;
1314     alpha = beta = 0;
1315 }
1316
1317
1318 void CxCore_GEMMTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1319 {
1320     CvRNG* rng = ts->get_rng();
1321     CvSize sizeA;
1322     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1323     sizeA = sizes[INPUT][0];
1324     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1325     sizes[INPUT][0] = sizeA;
1326     sizes[INPUT][2] = sizes[INPUT][3] = cvSize(1,1);
1327     types[INPUT][2] = types[INPUT][3] &= ~CV_MAT_CN_MASK;
1328
1329     tabc_flag = cvTsRandInt(rng) & 7;
1330
1331     switch( tabc_flag & (CV_GEMM_A_T|CV_GEMM_B_T) )
1332     {
1333     case 0:
1334         sizes[INPUT][1].height = sizes[INPUT][0].width;
1335         sizes[OUTPUT][0].height = sizes[INPUT][0].height;
1336         sizes[OUTPUT][0].width = sizes[INPUT][1].width;
1337         break;
1338     case CV_GEMM_B_T:
1339         sizes[INPUT][1].width = sizes[INPUT][0].width;
1340         sizes[OUTPUT][0].height = sizes[INPUT][0].height;
1341         sizes[OUTPUT][0].width = sizes[INPUT][1].height;
1342         break;
1343     case CV_GEMM_A_T:
1344         sizes[INPUT][1].height = sizes[INPUT][0].height;
1345         sizes[OUTPUT][0].height = sizes[INPUT][0].width;
1346         sizes[OUTPUT][0].width = sizes[INPUT][1].width;
1347         break;
1348     case CV_GEMM_A_T | CV_GEMM_B_T:
1349         sizes[INPUT][1].width = sizes[INPUT][0].height;
1350         sizes[OUTPUT][0].height = sizes[INPUT][0].width;
1351         sizes[OUTPUT][0].width = sizes[INPUT][1].height;
1352         break;
1353     }
1354
1355     sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
1356
1357     if( cvTsRandInt(rng) & 1 )
1358         sizes[INPUT][4] = cvSize(0,0);
1359     else if( !(tabc_flag & CV_GEMM_C_T) )
1360         sizes[INPUT][4] = sizes[OUTPUT][0];
1361     else
1362     {
1363         sizes[INPUT][4].width = sizes[OUTPUT][0].height;
1364         sizes[INPUT][4].height = sizes[OUTPUT][0].width;
1365     }
1366 }
1367
1368
1369 void CxCore_GEMMTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1370                                                     CvSize** sizes, int** types,
1371                                                     CvSize** whole_sizes, bool* are_images )
1372 {
1373     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
1374                                     sizes, types, whole_sizes, are_images );
1375     const char* mul_type = cvReadString( find_timing_param("mul_type"), "AB" );
1376     if( strcmp( mul_type, "AtB" ) == 0 )
1377         tabc_flag = CV_GEMM_A_T;
1378     else if( strcmp( mul_type, "ABt" ) == 0 )
1379         tabc_flag = CV_GEMM_B_T;
1380     else if( strcmp( mul_type, "AtBt" ) == 0 )
1381         tabc_flag = CV_GEMM_A_T + CV_GEMM_B_T;
1382     else
1383         tabc_flag = 0;
1384
1385     if( cvReadInt( find_timing_param( "add_c" ), 0 ) == 0 )
1386         sizes[INPUT][4] = cvSize(0,0);
1387 }
1388
1389
1390 int CxCore_GEMMTest::write_default_params( CvFileStorage* fs )
1391 {
1392     int code = CxCore_MatrixTest::write_default_params(fs);
1393     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
1394         return code;
1395     write_string_list( fs, "mul_type", matrix_gemm_mul_types );
1396     write_int_list( fs, "add_c", matrix_gemm_add_c_flags, CV_DIM(matrix_gemm_add_c_flags) );
1397     return code;
1398 }
1399
1400
1401 void CxCore_GEMMTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
1402 {
1403     sprintf( ptr, "%s%s,%s,",
1404         tabc_flag & CV_GEMM_A_T ? "At" : "A",
1405         tabc_flag & CV_GEMM_B_T ? "Bt" : "B",
1406         test_array[INPUT][4] ? "plusC" : "" );
1407     ptr += strlen(ptr);
1408     params_left -= 2;
1409     CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left );
1410 }
1411
1412
1413 int CxCore_GEMMTest::prepare_test_case( int test_case_idx )
1414 {
1415     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
1416     if( code > 0 )
1417     {
1418         alpha = cvmGet( &test_mat[INPUT][2], 0, 0 );
1419         beta = cvmGet( &test_mat[INPUT][3], 0, 0 );
1420     }
1421     return code;
1422 }
1423
1424
1425 void CxCore_GEMMTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
1426 {
1427     *low = cvScalarAll(-10.);
1428     *high = cvScalarAll(10.);
1429 }
1430
1431
1432 void CxCore_GEMMTest::run_func()
1433 {
1434     cvGEMM( test_array[INPUT][0], test_array[INPUT][1], alpha,
1435             test_array[INPUT][4], beta, test_array[OUTPUT][0], tabc_flag );
1436 }
1437
1438
1439 void CxCore_GEMMTest::prepare_to_validation( int )
1440 {
1441     cvTsGEMM( &test_mat[INPUT][0], &test_mat[INPUT][1], alpha,
1442         test_array[INPUT][4] ? &test_mat[INPUT][4] : 0,
1443         beta, &test_mat[REF_OUTPUT][0], tabc_flag );
1444 }
1445
1446 CxCore_GEMMTest gemm_test;
1447
1448
1449 ///////////////// multransposed /////////////////////
1450
1451 static const char* matrix_multrans_param_names[] = { "size", "use_delta", "mul_type", "depth", 0 };
1452 static const int matrix_multrans_use_delta_flags[] = { 0, 1 };
1453 static const char* matrix_multrans_mul_types[] = { "AAt", "AtA", 0 };
1454
1455 class CxCore_MulTransposedTest : public CxCore_MatrixTest
1456 {
1457 public:
1458     CxCore_MulTransposedTest();
1459 protected:
1460     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1461     void get_timing_test_array_types_and_sizes( int test_case_idx,
1462                                                 CvSize** sizes, int** types,
1463                                                 CvSize** whole_sizes, bool* are_images );
1464     int write_default_params( CvFileStorage* fs );
1465     void print_timing_params( int test_case_idx, char* ptr, int params_left );
1466     void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high );
1467     void run_func();
1468     void prepare_to_validation( int test_case_idx );
1469     int order;
1470 };
1471
1472
1473 CxCore_MulTransposedTest::CxCore_MulTransposedTest() :
1474     CxCore_MatrixTest( "matrix-multransposed", "cvMulTransposed, cvRepeat", 2, 1, false, false, 1 )
1475 {
1476     test_case_count = 100;
1477     order = 0;
1478     test_array[TEMP].push(NULL);
1479     default_timing_param_names = matrix_multrans_param_names;
1480 }
1481
1482
1483 void CxCore_MulTransposedTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1484 {
1485     CvRNG* rng = ts->get_rng();
1486     int bits = cvTsRandInt(rng);
1487     int src_type = cvTsRandInt(rng) % 5;
1488     int dst_type = cvTsRandInt(rng) % 2;
1489
1490     src_type = src_type == 0 ? CV_8U : src_type == 1 ? CV_16U : src_type == 2 ? CV_16S :
1491                src_type == 3 ? CV_32F : CV_64F;
1492     dst_type = dst_type == 0 ? CV_32F : CV_64F;
1493     dst_type = MAX( dst_type, src_type );
1494
1495     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1496
1497     if( bits & 1 )
1498         sizes[INPUT][1] = cvSize(0,0);
1499     else
1500     {
1501         sizes[INPUT][1] = sizes[INPUT][0];
1502         if( bits & 2 )
1503             sizes[INPUT][1].height = 1;
1504         if( bits & 4 )
1505             sizes[INPUT][1].width = 1;
1506     }
1507
1508     sizes[TEMP][0] = sizes[INPUT][0];
1509     types[INPUT][0] = src_type;
1510     types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][1] = types[TEMP][0] = dst_type;
1511
1512     order = (bits & 8) != 0;
1513     sizes[OUTPUT][0].width = sizes[OUTPUT][0].height = order == 0 ?
1514         sizes[INPUT][0].height : sizes[INPUT][0].width;
1515     sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
1516 }
1517
1518
1519 void CxCore_MulTransposedTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1520                                                     CvSize** sizes, int** types,
1521                                                     CvSize** whole_sizes, bool* are_images )
1522 {
1523     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
1524                                     sizes, types, whole_sizes, are_images );
1525     const char* mul_type = cvReadString( find_timing_param("mul_type"), "AAt" );
1526     order = strcmp( mul_type, "AtA" ) == 0;
1527
1528     if( cvReadInt( find_timing_param( "use_delta" ), 0 ) == 0 )
1529         sizes[INPUT][1] = cvSize(0,0);
1530 }
1531
1532
1533 int CxCore_MulTransposedTest::write_default_params( CvFileStorage* fs )
1534 {
1535     int code = CxCore_MatrixTest::write_default_params(fs);
1536     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
1537         return code;
1538     write_string_list( fs, "mul_type", matrix_multrans_mul_types );
1539     write_int_list( fs, "use_delta", matrix_multrans_use_delta_flags,
1540                     CV_DIM(matrix_multrans_use_delta_flags) );
1541     return code;
1542 }
1543
1544
1545 void CxCore_MulTransposedTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
1546 {
1547     sprintf( ptr, "%s,%s,", order == 0 ? "AAt" : "AtA", test_array[INPUT][1] ? "delta" : "" );
1548     ptr += strlen(ptr);
1549     params_left -= 2;
1550     CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left );
1551 }
1552
1553
1554 void CxCore_MulTransposedTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
1555 {
1556     *low = cvScalarAll(-10.);
1557     *high = cvScalarAll(10.);
1558 }
1559
1560
1561 void CxCore_MulTransposedTest::run_func()
1562 {
1563     cvMulTransposed( test_array[INPUT][0], test_array[OUTPUT][0],
1564                      order, test_array[INPUT][1] );
1565 }
1566
1567
1568 void CxCore_MulTransposedTest::prepare_to_validation( int )
1569 {
1570     CvMat* delta = test_array[INPUT][1] ? &test_mat[INPUT][1] : 0;
1571     if( delta )
1572     {
1573         if( test_mat[INPUT][1].rows < test_mat[INPUT][0].rows ||
1574             test_mat[INPUT][1].cols < test_mat[INPUT][0].cols )
1575         {
1576             cvRepeat( delta, &test_mat[TEMP][0] );
1577             delta = &test_mat[TEMP][0];
1578         }
1579         cvTsAdd( &test_mat[INPUT][0], cvScalarAll(1.), delta, cvScalarAll(-1.),
1580                  cvScalarAll(0.), &test_mat[TEMP][0], 0 );
1581     }
1582     else
1583         cvTsConvert( &test_mat[INPUT][0], &test_mat[TEMP][0] );
1584     delta = &test_mat[TEMP][0];
1585
1586     cvTsGEMM( delta, delta, 1., 0, 0, &test_mat[REF_OUTPUT][0], order == 0 ? CV_GEMM_B_T : CV_GEMM_A_T );
1587 }
1588
1589 CxCore_MulTransposedTest multransposed_test;
1590
1591
1592 ///////////////// Transform /////////////////////
1593
1594 static const CvSize matrix_transform_sizes[] = {{10,10}, {100,100}, {720,480}, {-1,-1}};
1595 static const CvSize matrix_transform_whole_sizes[] = {{10,10}, {720,480}, {720,480}, {-1,-1}};
1596 static const int matrix_transform_channels[] = { 2, 3, 4, -1 };
1597 static const char* matrix_transform_param_names[] = { "size", "channels", "depth", 0 };
1598
1599 class CxCore_TransformTest : public CxCore_MatrixTest
1600 {
1601 public:
1602     CxCore_TransformTest();
1603 protected:
1604     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1605     double get_success_error_level( int test_case_idx, int i, int j );
1606     void get_timing_test_array_types_and_sizes( int test_case_idx,
1607                                                 CvSize** sizes, int** types,
1608                                                 CvSize** whole_sizes, bool* are_images );
1609     int prepare_test_case( int test_case_idx );
1610     void print_timing_params( int test_case_idx, char* ptr, int params_left );
1611     void run_func();
1612     void prepare_to_validation( int test_case_idx );
1613     
1614     double scale;
1615     bool diagMtx;
1616 };
1617
1618
1619 CxCore_TransformTest::CxCore_TransformTest() :
1620     CxCore_MatrixTest( "matrix-transform", "cvTransform", 3, 1, true, false, 4 )
1621 {
1622     default_timing_param_names = matrix_transform_param_names;
1623     cn_list = matrix_transform_channels;
1624     depth_list = matrix_all_depths;
1625     size_list = matrix_transform_sizes;
1626     whole_size_list = matrix_transform_whole_sizes;
1627 }
1628
1629
1630 void CxCore_TransformTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1631 {
1632     CvRNG* rng = ts->get_rng();
1633     int bits = cvTsRandInt(rng);
1634     int depth, dst_cn, mat_cols, mattype;
1635     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1636
1637     mat_cols = CV_MAT_CN(types[INPUT][0]);
1638     depth = CV_MAT_DEPTH(types[INPUT][0]);
1639     dst_cn = cvTsRandInt(rng) % 4 + 1;
1640     types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, dst_cn);
1641
1642     mattype = depth < CV_32S ? CV_32F : depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F;
1643     types[INPUT][1] = mattype;
1644     types[INPUT][2] = CV_MAKETYPE(mattype, dst_cn);
1645     
1646     scale = 1./((cvTsRandInt(rng)%4)*50+1);
1647
1648     if( bits & 2 )
1649     {
1650         sizes[INPUT][2] = cvSize(0,0);
1651         mat_cols += (bits & 4) != 0;
1652     }
1653     else if( bits & 4 )
1654         sizes[INPUT][2] = cvSize(1,1);
1655     else
1656     {
1657         if( bits & 8 )
1658             sizes[INPUT][2] = cvSize(dst_cn,1);
1659         else
1660             sizes[INPUT][2] = cvSize(1,dst_cn);
1661         types[INPUT][2] &= ~CV_MAT_CN_MASK;
1662     }
1663     diagMtx = (bits & 16) != 0;
1664
1665     sizes[INPUT][1] = cvSize(mat_cols,dst_cn);
1666 }
1667
1668
1669 void CxCore_TransformTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1670                 CvSize** sizes, int** types, CvSize** whole_sizes, bool* are_images )
1671 {
1672     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
1673                                     sizes, types, whole_sizes, are_images );
1674     int cn = CV_MAT_CN(types[INPUT][0]);
1675     sizes[INPUT][1] = cvSize(cn + (cn < 4), cn);
1676     sizes[INPUT][2] = cvSize(0,0);
1677     types[INPUT][1] = types[INPUT][2] = CV_64FC1;
1678     scale = 1./1000;
1679 }
1680
1681 int CxCore_TransformTest::prepare_test_case( int test_case_idx )
1682 {
1683     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
1684     if( code > 0 )
1685     {
1686         cvTsAdd(&test_mat[INPUT][1], cvScalarAll(scale), &test_mat[INPUT][1],
1687                 cvScalarAll(0), cvScalarAll(0), &test_mat[INPUT][1], 0 );
1688         if(diagMtx)
1689         {
1690             CvMat* w = cvCloneMat(&test_mat[INPUT][1]);
1691             cvSetIdentity(w, cvScalarAll(1));
1692             cvMul(w, &test_mat[INPUT][1], &test_mat[INPUT][1]);
1693             cvReleaseMat(&w);
1694         }
1695     }
1696     return code;
1697 }
1698
1699 void CxCore_TransformTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
1700 {
1701     CvSize size = cvGetMatSize(&test_mat[INPUT][1]);
1702     sprintf( ptr, "matrix=%dx%d,", size.height, size.width );
1703     ptr += strlen(ptr);
1704     params_left--;
1705     CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left );
1706 }
1707
1708
1709 double CxCore_TransformTest::get_success_error_level( int test_case_idx, int i, int j )
1710 {
1711     int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
1712     return depth <= CV_8S ? 1 : depth <= CV_32S ? 8 :
1713         CxCore_MatrixTest::get_success_error_level( test_case_idx, i, j );
1714 }
1715
1716 void CxCore_TransformTest::run_func()
1717 {
1718     cvTransform( test_array[INPUT][0], test_array[OUTPUT][0], &test_mat[INPUT][1],
1719                  test_array[INPUT][2] ? &test_mat[INPUT][2] : 0);
1720 }
1721
1722
1723 void CxCore_TransformTest::prepare_to_validation( int )
1724 {
1725     CvMat* transmat = &test_mat[INPUT][1];
1726     CvMat* shift = test_array[INPUT][2] ? &test_mat[INPUT][2] : 0;
1727
1728     cvTsTransform( &test_mat[INPUT][0], &test_mat[REF_OUTPUT][0], transmat, shift );
1729 }
1730
1731 CxCore_TransformTest transform_test;
1732
1733
1734 ///////////////// PerspectiveTransform /////////////////////
1735
1736 static const int matrix_perspective_transform_channels[] = { 2, 3, -1 };
1737
1738 class CxCore_PerspectiveTransformTest : public CxCore_MatrixTest
1739 {
1740 public:
1741     CxCore_PerspectiveTransformTest();
1742 protected:
1743     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1744     double get_success_error_level( int test_case_idx, int i, int j );
1745     void get_timing_test_array_types_and_sizes( int test_case_idx,
1746                                                 CvSize** sizes, int** types,
1747                                                 CvSize** whole_sizes, bool* are_images );
1748     void run_func();
1749     void prepare_to_validation( int test_case_idx );
1750 };
1751
1752
1753 CxCore_PerspectiveTransformTest::CxCore_PerspectiveTransformTest() :
1754     CxCore_MatrixTest( "matrix-perspective", "cvPerspectiveTransform", 2, 1, false, false, 2 )
1755 {
1756     default_timing_param_names = matrix_transform_param_names;
1757     cn_list = matrix_perspective_transform_channels;
1758     size_list = matrix_transform_sizes;
1759     whole_size_list = matrix_transform_whole_sizes;
1760 }
1761
1762
1763 void CxCore_PerspectiveTransformTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1764 {
1765     CvRNG* rng = ts->get_rng();
1766     int bits = cvTsRandInt(rng);
1767     int depth, cn, mattype;
1768     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1769
1770     cn = CV_MAT_CN(types[INPUT][0]) + 1;
1771     depth = CV_MAT_DEPTH(types[INPUT][0]);
1772     types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn);
1773
1774     mattype = depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F;
1775     types[INPUT][1] = mattype;
1776     sizes[INPUT][1] = cvSize(cn + 1, cn + 1);
1777 }
1778
1779
1780 double CxCore_PerspectiveTransformTest::get_success_error_level( int test_case_idx, int i, int j )
1781 {
1782     int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
1783     return depth == CV_32F ? 1e-4 : depth == CV_64F ? 1e-8 :
1784                 CxCore_MatrixTest::get_success_error_level(test_case_idx, i, j);
1785 }
1786
1787
1788 void CxCore_PerspectiveTransformTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1789                         CvSize** sizes, int** types, CvSize** whole_sizes, bool* are_images )
1790 {
1791     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
1792                                     sizes, types, whole_sizes, are_images );
1793     int cn = CV_MAT_CN(types[INPUT][0]);
1794     sizes[INPUT][1] = cvSize(cn + 1, cn + 1);
1795     types[INPUT][1] = CV_64FC1;
1796 }
1797
1798
1799 void CxCore_PerspectiveTransformTest::run_func()
1800 {
1801     cvPerspectiveTransform( test_array[INPUT][0], test_array[OUTPUT][0], &test_mat[INPUT][1] );
1802 }
1803
1804
1805 static void cvTsPerspectiveTransform( const CvArr* _src, CvArr* _dst, const CvMat* transmat )
1806 {
1807     int i, j, cols;
1808     int cn, depth, mat_depth;
1809     CvMat astub, bstub, *a, *b;
1810     double mat[16], *buf;
1811
1812     a = cvGetMat( _src, &astub, 0, 0 );
1813     b = cvGetMat( _dst, &bstub, 0, 0 );
1814
1815     cn = CV_MAT_CN(a->type);
1816     depth = CV_MAT_DEPTH(a->type);
1817     mat_depth = CV_MAT_DEPTH(transmat->type);
1818     cols = transmat->cols;
1819
1820     // prepare cn x (cn + 1) transform matrix
1821     if( mat_depth == CV_32F )
1822     {
1823         for( i = 0; i < transmat->rows; i++ )
1824             for( j = 0; j < cols; j++ )
1825                 mat[i*cols + j] = ((float*)(transmat->data.ptr + transmat->step*i))[j];
1826     }
1827     else
1828     {
1829         assert( mat_depth == CV_64F );
1830         for( i = 0; i < transmat->rows; i++ )
1831             for( j = 0; j < cols; j++ )
1832                 mat[i*cols + j] = ((double*)(transmat->data.ptr + transmat->step*i))[j];
1833     }
1834
1835     // transform data
1836     cols = a->cols * cn;
1837     buf = (double*)cvStackAlloc( cols * sizeof(double) );
1838
1839     for( i = 0; i < a->rows; i++ )
1840     {
1841         uchar* src = a->data.ptr + i*a->step;
1842         uchar* dst = b->data.ptr + i*b->step;
1843
1844         switch( depth )
1845         {
1846         case CV_32F:
1847             for( j = 0; j < cols; j++ )
1848                 buf[j] = ((float*)src)[j];
1849             break;
1850         case CV_64F:
1851             for( j = 0; j < cols; j++ )
1852                 buf[j] = ((double*)src)[j];
1853             break;
1854         default:
1855             assert(0);
1856         }
1857
1858         switch( cn )
1859         {
1860         case 2:
1861             for( j = 0; j < cols; j += 2 )
1862             {
1863                 double t0 = buf[j]*mat[0] + buf[j+1]*mat[1] + mat[2];
1864                 double t1 = buf[j]*mat[3] + buf[j+1]*mat[4] + mat[5];
1865                 double w = buf[j]*mat[6] + buf[j+1]*mat[7] + mat[8];
1866                 w = w ? 1./w : 0;
1867                 buf[j] = t0*w;
1868                 buf[j+1] = t1*w;
1869             }
1870             break;
1871         case 3:
1872             for( j = 0; j < cols; j += 3 )
1873             {
1874                 double t0 = buf[j]*mat[0] + buf[j+1]*mat[1] + buf[j+2]*mat[2] + mat[3];
1875                 double t1 = buf[j]*mat[4] + buf[j+1]*mat[5] + buf[j+2]*mat[6] + mat[7];
1876                 double t2 = buf[j]*mat[8] + buf[j+1]*mat[9] + buf[j+2]*mat[10] + mat[11];
1877                 double w = buf[j]*mat[12] + buf[j+1]*mat[13] + buf[j+2]*mat[14] + mat[15];
1878                 w = w ? 1./w : 0;
1879                 buf[j] = t0*w;
1880                 buf[j+1] = t1*w;
1881                 buf[j+2] = t2*w;
1882             }
1883             break;
1884         default:
1885             assert(0);
1886         }
1887
1888         switch( depth )
1889         {
1890         case CV_32F:
1891             for( j = 0; j < cols; j++ )
1892                 ((float*)dst)[j] = (float)buf[j];
1893             break;
1894         case CV_64F:
1895             for( j = 0; j < cols; j++ )
1896                 ((double*)dst)[j] = buf[j];
1897             break;
1898         default:
1899             assert(0);
1900         }
1901     }
1902 }
1903
1904
1905 void CxCore_PerspectiveTransformTest::prepare_to_validation( int )
1906 {
1907     CvMat* transmat = &test_mat[INPUT][1];
1908     cvTsPerspectiveTransform( test_array[INPUT][0], test_array[REF_OUTPUT][0], transmat );
1909 }
1910
1911 CxCore_PerspectiveTransformTest perspective_test;
1912
1913
1914 ///////////////// Mahalanobis /////////////////////
1915
1916 class CxCore_MahalanobisTest : public CxCore_MatrixTest
1917 {
1918 public:
1919     CxCore_MahalanobisTest();
1920 protected:
1921     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1922     void get_timing_test_array_types_and_sizes( int test_case_idx,
1923                                                 CvSize** sizes, int** types,
1924                                                 CvSize** whole_sizes, bool* are_images );
1925     int prepare_test_case( int test_case_idx );
1926     void run_func();
1927     void prepare_to_validation( int test_case_idx );
1928 };
1929
1930
1931 CxCore_MahalanobisTest::CxCore_MahalanobisTest() :
1932     CxCore_MatrixTest( "matrix-mahalanobis", "cvMahalanobis", 3, 1, false, true, 1 )
1933 {
1934     test_case_count = 100;
1935     test_array[TEMP].push(NULL);
1936     test_array[TEMP].push(NULL);
1937     test_array[TEMP].push(NULL);
1938 }
1939
1940
1941 void CxCore_MahalanobisTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1942 {
1943     CvRNG* rng = ts->get_rng();
1944     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1945
1946     if( cvTsRandInt(rng) & 1 )
1947         sizes[INPUT][0].width = sizes[INPUT][1].width = 1;
1948     else
1949         sizes[INPUT][0].height = sizes[INPUT][1].height = 1;
1950
1951     sizes[TEMP][0] = sizes[TEMP][1] = sizes[INPUT][0];
1952     sizes[INPUT][2].width = sizes[INPUT][2].height = sizes[INPUT][0].width + sizes[INPUT][0].height - 1;
1953     sizes[TEMP][2] = sizes[INPUT][2];
1954     types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[INPUT][0];
1955 }
1956
1957
1958 void CxCore_MahalanobisTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1959                         CvSize** sizes, int** types, CvSize** whole_sizes, bool* are_images )
1960 {
1961     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
1962                                     sizes, types, whole_sizes, are_images );
1963     sizes[INPUT][0].height = sizes[INPUT][1].height = 1;
1964 }
1965
1966
1967 int CxCore_MahalanobisTest::prepare_test_case( int test_case_idx )
1968 {
1969     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
1970     if( code > 0 && ts->get_testing_mode() == CvTS::CORRECTNESS_CHECK_MODE )
1971     {
1972         // make sure that the inverted "covariation" matrix is symmetrix and positively defined.
1973         cvTsGEMM( &test_mat[INPUT][2], &test_mat[INPUT][2], 1., 0, 0., &test_mat[TEMP][2], CV_GEMM_B_T );
1974         cvTsCopy( &test_mat[TEMP][2], &test_mat[INPUT][2] );
1975     }
1976
1977     return code;
1978 }
1979
1980
1981 void CxCore_MahalanobisTest::run_func()
1982 {
1983     *((CvScalar*)(test_mat[OUTPUT][0].data.db)) =
1984         cvRealScalar(cvMahalanobis(test_array[INPUT][0], test_array[INPUT][1], test_array[INPUT][2]));
1985 }
1986
1987 void CxCore_MahalanobisTest::prepare_to_validation( int )
1988 {
1989     cvTsAdd( &test_mat[INPUT][0], cvScalarAll(1.),
1990              &test_mat[INPUT][1], cvScalarAll(-1.),
1991              cvScalarAll(0.), &test_mat[TEMP][0], 0 );
1992     if( test_mat[INPUT][0].rows == 1 )
1993         cvTsGEMM( &test_mat[TEMP][0], &test_mat[INPUT][2], 1.,
1994                   0, 0., &test_mat[TEMP][1], 0 );
1995     else
1996         cvTsGEMM( &test_mat[INPUT][2], &test_mat[TEMP][0], 1.,
1997                   0, 0., &test_mat[TEMP][1], 0 );
1998
1999     *((CvScalar*)(test_mat[REF_OUTPUT][0].data.db)) =
2000         cvRealScalar(sqrt(cvTsCrossCorr(&test_mat[TEMP][0], &test_mat[TEMP][1])));
2001 }
2002
2003 CxCore_MahalanobisTest mahalanobis_test;
2004
2005
2006 ///////////////// covarmatrix /////////////////////
2007
2008 class CxCore_CovarMatrixTest : public CxCore_MatrixTest
2009 {
2010 public:
2011     CxCore_CovarMatrixTest();
2012 protected:
2013     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
2014     int prepare_test_case( int test_case_idx );
2015     void run_func();
2016     void prepare_to_validation( int test_case_idx );
2017     CvTestPtrVec temp_hdrs;
2018     uchar* hdr_data;
2019     int flags, t_flag, len, count;
2020     bool are_images;
2021 };
2022
2023
2024 CxCore_CovarMatrixTest::CxCore_CovarMatrixTest() :
2025     CxCore_MatrixTest( "matrix-covar", "cvCalcCovarMatrix", 1, 1, true, false, 1 ),
2026         flags(0), t_flag(0), are_images(false)
2027 {
2028     test_case_count = 100;
2029     test_array[INPUT_OUTPUT].push(NULL);
2030     test_array[REF_INPUT_OUTPUT].push(NULL);
2031     test_array[TEMP].push(NULL);
2032     test_array[TEMP].push(NULL);
2033
2034     support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
2035 }
2036
2037
2038 void CxCore_CovarMatrixTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
2039 {
2040     CvRNG* rng = ts->get_rng();
2041     int bits = cvTsRandInt(rng);
2042     int i, single_matrix;
2043     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2044
2045     flags = bits & (CV_COVAR_NORMAL | CV_COVAR_USE_AVG | CV_COVAR_SCALE | CV_COVAR_ROWS );
2046     single_matrix = flags & CV_COVAR_ROWS;
2047     t_flag = (bits & 256) != 0;
2048
2049     const int min_count = 2;
2050
2051     if( !t_flag )
2052     {
2053         len = sizes[INPUT][0].width;
2054         count = sizes[INPUT][0].height;
2055         count = MAX(count, min_count);
2056         sizes[INPUT][0] = cvSize(len, count);
2057     }
2058     else
2059     {
2060         len = sizes[INPUT][0].height;
2061         count = sizes[INPUT][0].width;
2062         count = MAX(count, min_count);
2063         sizes[INPUT][0] = cvSize(count, len);
2064     }
2065
2066     if( single_matrix && t_flag )
2067         flags = (flags & ~CV_COVAR_ROWS) | CV_COVAR_COLS;
2068
2069     if( CV_MAT_DEPTH(types[INPUT][0]) == CV_32S )
2070         types[INPUT][0] = (types[INPUT][0] & ~CV_MAT_DEPTH_MASK) | CV_32F;
2071
2072     sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = flags & CV_COVAR_NORMAL ? cvSize(len,len) : cvSize(count,count);
2073     sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = !t_flag ? cvSize(len,1) : cvSize(1,len);
2074     sizes[TEMP][0] = sizes[INPUT][0];
2075
2076     types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] =
2077     types[OUTPUT][0] = types[REF_OUTPUT][0] = types[TEMP][0] =
2078         CV_MAT_DEPTH(types[INPUT][0]) == CV_64F || (bits & 512) ? CV_64F : CV_32F;
2079
2080     are_images = (bits & 1024) != 0;
2081     for( i = 0; i < (single_matrix ? 1 : count); i++ )
2082         temp_hdrs.push(NULL);
2083 }
2084
2085
2086 int CxCore_CovarMatrixTest::prepare_test_case( int test_case_idx )
2087 {
2088     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
2089     if( code > 0 )
2090     {
2091         int i;
2092         int single_matrix = flags & (CV_COVAR_ROWS|CV_COVAR_COLS);
2093         int hdr_size = are_images ? sizeof(IplImage) : sizeof(CvMat);
2094
2095         hdr_data = (uchar*)cvAlloc( count*hdr_size );
2096         if( single_matrix )
2097         {
2098             if( !are_images )
2099                 *((CvMat*)hdr_data) = test_mat[INPUT][0];
2100             else
2101                 cvGetImage( &test_mat[INPUT][0], (IplImage*)hdr_data );
2102             temp_hdrs[0] = hdr_data;
2103         }
2104         else
2105             for( i = 0; i < count; i++ )
2106             {
2107                 CvMat part;
2108                 void* ptr = hdr_data + i*hdr_size;
2109
2110                 if( !t_flag )
2111                     cvGetRow( &test_mat[INPUT][0], &part, i );
2112                 else
2113                     cvGetCol( &test_mat[INPUT][0], &part, i );
2114
2115                 if( !are_images )
2116                     *((CvMat*)ptr) = part;
2117                 else
2118                     cvGetImage( &part, (IplImage*)ptr );
2119
2120                 temp_hdrs[i] = ptr;
2121             }
2122     }
2123
2124     return code;
2125 }
2126
2127
2128 void CxCore_CovarMatrixTest::run_func()
2129 {
2130     cvCalcCovarMatrix( (const void**)&temp_hdrs[0], count,
2131                        test_array[OUTPUT][0], test_array[INPUT_OUTPUT][0], flags );
2132 }
2133
2134
2135 void CxCore_CovarMatrixTest::prepare_to_validation( int )
2136 {
2137     CvMat* avg = &test_mat[REF_INPUT_OUTPUT][0];
2138     double scale = 1.;
2139
2140     if( !(flags & CV_COVAR_USE_AVG) )
2141     {
2142         int i;
2143         cvTsZero( avg );
2144
2145         for( i = 0; i < count; i++ )
2146         {
2147             CvMat stub, *vec = 0;
2148             if( flags & CV_COVAR_ROWS )
2149                 vec = cvGetRow( temp_hdrs[0], &stub, i );
2150             else if( flags & CV_COVAR_COLS )
2151                 vec = cvGetCol( temp_hdrs[0], &stub, i );
2152             else
2153                 vec = cvGetMat( temp_hdrs[i], &stub );
2154
2155             cvTsAdd( avg, cvScalarAll(1.), vec,
2156                      cvScalarAll(1.), cvScalarAll(0.), avg, 0 );
2157         }
2158
2159         cvTsAdd( avg, cvScalarAll(1./count), 0,
2160                  cvScalarAll(0.), cvScalarAll(0.), avg, 0 );
2161     }
2162
2163     if( flags & CV_COVAR_SCALE )
2164     {
2165         scale = 1./count;
2166     }
2167
2168     cvRepeat( avg, &test_mat[TEMP][0] );
2169     cvTsAdd( &test_mat[INPUT][0], cvScalarAll(1.),
2170              &test_mat[TEMP][0], cvScalarAll(-1.),
2171              cvScalarAll(0.), &test_mat[TEMP][0], 0 );
2172
2173     cvTsGEMM( &test_mat[TEMP][0], &test_mat[TEMP][0],
2174               scale, 0, 0., &test_mat[REF_OUTPUT][0],
2175               t_flag ^ ((flags & CV_COVAR_NORMAL) != 0) ?
2176               CV_GEMM_A_T : CV_GEMM_B_T );
2177
2178     cvFree( &hdr_data );
2179     temp_hdrs.clear();
2180 }
2181
2182 CxCore_CovarMatrixTest covarmatrix_test;
2183
2184
2185 static void cvTsFloodWithZeros( CvMat* mat, CvRNG* rng )
2186 {
2187     int k, total = mat->rows*mat->cols;
2188     int zero_total = cvTsRandInt(rng) % total;
2189     assert( CV_MAT_TYPE(mat->type) == CV_32FC1 ||
2190             CV_MAT_TYPE(mat->type) == CV_64FC1 );
2191
2192     for( k = 0; k < zero_total; k++ )
2193     {
2194         int i = cvTsRandInt(rng) % mat->rows;
2195         int j = cvTsRandInt(rng) % mat->cols;
2196         uchar* row = mat->data.ptr + mat->step*i;
2197
2198         if( CV_MAT_DEPTH(mat->type) == CV_32FC1 )
2199             ((float*)row)[j] = 0.f;
2200         else
2201             ((double*)row)[j] = 0.;
2202     }
2203 }
2204
2205
2206 ///////////////// determinant /////////////////////
2207
2208 class CxCore_DetTest : public CxCore_MatrixTest
2209 {
2210 public:
2211     CxCore_DetTest();
2212 protected:
2213     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
2214     double get_success_error_level( int test_case_idx, int i, int j );
2215     void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high );
2216     int prepare_test_case( int test_case_idx );
2217     void run_func();
2218     void prepare_to_validation( int test_case_idx );
2219 };
2220
2221
2222 CxCore_DetTest::CxCore_DetTest() :
2223     CxCore_MatrixTest( "matrix-det", "cvDet", 1, 1, false, true, 1 )
2224 {
2225     test_case_count = 100;
2226     max_log_array_size = 7;
2227     test_array[TEMP].push(NULL);
2228 }
2229
2230
2231 void CxCore_DetTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
2232 {
2233     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2234
2235     sizes[INPUT][0].width = sizes[INPUT][0].height = sizes[INPUT][0].height;
2236     sizes[TEMP][0] = sizes[INPUT][0];
2237     types[TEMP][0] = CV_64FC1;
2238 }
2239
2240
2241 void CxCore_DetTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
2242 {
2243     *low = cvScalarAll(-2.);
2244     *high = cvScalarAll(2.);
2245 }
2246
2247
2248 double CxCore_DetTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
2249 {
2250     return CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0])) == CV_32F ? 1e-2 : 1e-5;
2251 }
2252
2253
2254 int CxCore_DetTest::prepare_test_case( int test_case_idx )
2255 {
2256     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
2257     if( code > 0 )
2258         cvTsFloodWithZeros( &test_mat[INPUT][0], ts->get_rng() );
2259
2260     return code;
2261 }
2262
2263
2264 void CxCore_DetTest::run_func()
2265 {
2266     *((CvScalar*)(test_mat[OUTPUT][0].data.db)) = cvRealScalar(cvDet(test_array[INPUT][0]));
2267 }
2268
2269
2270 // LU method that chooses the optimal in a column pivot element
2271 static double cvTsLU( CvMat* a, CvMat* b=NULL, CvMat* x=NULL, int* rank=0 )
2272 {
2273     int i, j, k, N = a->rows, N1 = a->cols, Nm = MIN(N, N1), step = a->step/sizeof(double);
2274     int M = b ? b->cols : 0, b_step = b ? b->step/sizeof(double) : 0;
2275     int x_step = x ? x->step/sizeof(double) : 0;
2276     double *a0 = a->data.db, *b0 = b ? b->data.db : 0;
2277     double *x0 = x ? x->data.db : 0;
2278     double t, det = 1.;
2279     assert( CV_MAT_TYPE(a->type) == CV_64FC1 &&
2280             (!b || CV_ARE_TYPES_EQ(a,b)) && (!x || CV_ARE_TYPES_EQ(a,x)));
2281
2282     for( i = 0; i < Nm; i++ )
2283     {
2284         double max_val = fabs(a0[i*step + i]);
2285         double *a1, *a2, *b1 = 0, *b2 = 0;
2286         k = i;
2287
2288         for( j = i+1; j < N; j++ )
2289         {
2290             t = fabs(a0[j*step + i]);
2291             if( max_val < t )
2292             {
2293                 max_val = t;
2294                 k = j;
2295             }
2296         }
2297
2298         if( k != i )
2299         {
2300             for( j = i; j < N1; j++ )
2301                 CV_SWAP( a0[i*step + j], a0[k*step + j], t );
2302
2303             for( j = 0; j < M; j++ )
2304                 CV_SWAP( b0[i*b_step + j], b0[k*b_step + j], t );
2305             det = -det;
2306         }
2307
2308         if( max_val == 0 )
2309         {
2310             if( rank )
2311                 *rank = i;
2312             return 0.;
2313         }
2314
2315         a1 = a0 + i*step;
2316         a2 = a1 + step;
2317         b1 = b0 + i*b_step;
2318         b2 = b1 + b_step;
2319
2320         for( j = i+1; j < N; j++, a2 += step, b2 += b_step )
2321         {
2322             t = a2[i]/a1[i];
2323             for( k = i+1; k < N1; k++ )
2324                 a2[k] -= t*a1[k];
2325
2326             for( k = 0; k < M; k++ )
2327                 b2[k] -= t*b1[k];
2328         }
2329
2330         det *= a1[i];
2331     }
2332
2333     if( x )
2334     {
2335         assert( b );
2336
2337         for( i = N-1; i >= 0; i-- )
2338         {
2339             double* a1 = a0 + i*step;
2340             double* b1 = b0 + i*b_step;
2341             for( j = 0; j < M; j++ )
2342             {
2343                 t = b1[j];
2344                 for( k = i+1; k < N1; k++ )
2345                     t -= a1[k]*x0[k*x_step + j];
2346                 x0[i*x_step + j] = t/a1[i];
2347             }
2348         }
2349     }
2350
2351     if( rank )
2352         *rank = i;
2353     return det;
2354 }
2355
2356
2357 void CxCore_DetTest::prepare_to_validation( int )
2358 {
2359     if( !CV_ARE_TYPES_EQ( &test_mat[INPUT][0], &test_mat[TEMP][0] ))
2360         cvTsConvert( &test_mat[INPUT][0], &test_mat[TEMP][0] );
2361     else
2362         cvTsCopy( &test_mat[INPUT][0], &test_mat[TEMP][0], 0 );
2363
2364     *((CvScalar*)(test_mat[REF_OUTPUT][0].data.db)) = cvRealScalar(cvTsLU(&test_mat[TEMP][0], 0, 0));
2365 }
2366
2367 CxCore_DetTest det_test;
2368
2369
2370
2371 ///////////////// invert /////////////////////
2372
2373 static const char* matrix_solve_invert_param_names[] = { "size", "method", "depth", 0 };
2374 static const char* matrix_solve_invert_methods[] = { "LU", "SVD", 0 };
2375
2376 class CxCore_InvertTest : public CxCore_MatrixTest
2377 {
2378 public:
2379     CxCore_InvertTest();
2380 protected:
2381     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
2382     void get_timing_test_array_types_and_sizes( int test_case_idx,
2383                                                 CvSize** sizes, int** types,
2384                                                 CvSize** whole_sizes, bool* are_images );
2385     int write_default_params( CvFileStorage* fs );
2386     void print_timing_params( int test_case_idx, char* ptr, int params_left );
2387     void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high );
2388     double get_success_error_level( int test_case_idx, int i, int j );
2389     int prepare_test_case( int test_case_idx );
2390     void run_func();
2391     void prepare_to_validation( int test_case_idx );
2392     int method, rank;
2393     double result;
2394 };
2395
2396
2397 CxCore_InvertTest::CxCore_InvertTest() :
2398     CxCore_MatrixTest( "matrix-invert", "cvInvert, cvSVD, cvSVBkSb", 1, 1, false, false, 1 ), method(0), rank(0), result(0.)
2399 {
2400     test_case_count = 100;
2401     max_log_array_size = 7;
2402     test_array[TEMP].push(NULL);
2403     test_array[TEMP].push(NULL);
2404
2405     default_timing_param_names = matrix_solve_invert_param_names;
2406 }
2407
2408
2409 void CxCore_InvertTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
2410 {
2411     CvRNG* rng = ts->get_rng();
2412     int bits = cvTsRandInt(rng);
2413     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2414     int min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
2415
2416     if( (bits & 3) == 0 )
2417     {
2418         method = CV_SVD;
2419         if( bits & 4 )
2420         {
2421             sizes[INPUT][0] = cvSize(min_size, min_size);
2422             if( bits & 8 )
2423                 method = CV_SVD_SYM;
2424         }
2425     }
2426     else
2427     {
2428         method = CV_LU;
2429         sizes[INPUT][0] = cvSize(min_size, min_size);
2430     }
2431
2432     sizes[TEMP][0].width = sizes[INPUT][0].height;
2433     sizes[TEMP][0].height = sizes[INPUT][0].width;
2434     sizes[TEMP][1] = sizes[INPUT][0];
2435     types[TEMP][0] = types[INPUT][0];
2436     types[TEMP][1] = CV_64FC1;
2437     sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(min_size, min_size);
2438 }
2439
2440
2441 void CxCore_InvertTest::get_timing_test_array_types_and_sizes( int test_case_idx,
2442                                                     CvSize** sizes, int** types,
2443                                                     CvSize** whole_sizes, bool* are_images )
2444 {
2445     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
2446                                     sizes, types, whole_sizes, are_images );
2447     const char* method_str = cvReadString( find_timing_param("method"), "LU" );
2448     method = strcmp( method_str, "LU" ) == 0 ? CV_LU : CV_SVD;
2449 }
2450
2451
2452 int CxCore_InvertTest::write_default_params( CvFileStorage* fs )
2453 {
2454     int code = CxCore_MatrixTest::write_default_params(fs);
2455     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
2456         return code;
2457     write_string_list( fs, "method", matrix_solve_invert_methods );
2458     return code;
2459 }
2460
2461
2462 void CxCore_InvertTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
2463 {
2464     sprintf( ptr, "%s,", method == CV_LU ? "LU" : "SVD" );
2465     ptr += strlen(ptr);
2466     params_left--;
2467     CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left );
2468 }
2469
2470
2471 double CxCore_InvertTest::get_success_error_level( int /*test_case_idx*/, int, int )
2472 {
2473     return CV_MAT_DEPTH(cvGetElemType(test_array[OUTPUT][0])) == CV_32F ? 1e-2 : 1e-7;
2474 }
2475
2476 int CxCore_InvertTest::prepare_test_case( int test_case_idx )
2477 {
2478     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
2479     if( code > 0 )
2480     {
2481         cvTsFloodWithZeros( &test_mat[INPUT][0], ts->get_rng() );
2482
2483         if( method == CV_SVD_SYM )
2484         {
2485             cvTsGEMM( &test_mat[INPUT][0], &test_mat[INPUT][0], 1.,
2486                       0, 0., &test_mat[TEMP][0], CV_GEMM_B_T );
2487             cvTsCopy( &test_mat[TEMP][0], &test_mat[INPUT][0] );
2488         }
2489     }
2490
2491     return code;
2492 }
2493
2494
2495
2496 void CxCore_InvertTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
2497 {
2498     *low = cvScalarAll(-2.);
2499     *high = cvScalarAll(2.);
2500 }
2501
2502
2503 void CxCore_InvertTest::run_func()
2504 {
2505     result = cvInvert(test_array[INPUT][0], test_array[TEMP][0], method);
2506 }
2507
2508
2509 static double cvTsSVDet( CvMat* mat )
2510 {
2511     int type = CV_MAT_TYPE(mat->type);
2512     int i, nm = MIN( mat->rows, mat->cols );
2513     CvMat* w = cvCreateMat( nm, 1, type );
2514     double det = 1.;
2515
2516     cvSVD( mat, w, 0, 0, 0 );
2517
2518     if( type == CV_32FC1 )
2519     {
2520         for( i = 0; i < nm; i++ )
2521             det *= w->data.fl[i];
2522     }
2523     else
2524     {
2525         for( i = 0; i < nm; i++ )
2526             det *= w->data.db[i];
2527     }
2528
2529     cvReleaseMat( &w );
2530     return det;
2531 }
2532
2533 void CxCore_InvertTest::prepare_to_validation( int )
2534 {
2535     CvMat* input = &test_mat[INPUT][0];
2536     double det = cvTsSVDet( input );
2537     double threshold = (CV_MAT_DEPTH(input->type) == CV_32F ? FLT_EPSILON : DBL_EPSILON)*500;
2538
2539     if( CV_MAT_TYPE(input->type) == CV_32FC1 )
2540         cvTsConvert( input, &test_mat[TEMP][1] );
2541     else
2542         cvTsCopy( input, &test_mat[TEMP][1], 0 );
2543
2544     if( (method == CV_LU && result == 0) ||
2545         (det < threshold || result < threshold) )
2546     {
2547         cvTsZero( &test_mat[OUTPUT][0] );
2548         cvTsZero( &test_mat[REF_OUTPUT][0] );
2549         //cvTsAdd( 0, cvScalarAll(0.), 0, cvScalarAll(0.), cvScalarAll(fabs(det)>1e-3),
2550         //         &test_mat[REF_OUTPUT][0], 0 );
2551         return;
2552     }
2553
2554     if( input->rows >= input->cols )
2555         cvTsGEMM( &test_mat[TEMP][0], input, 1., 0, 0., &test_mat[OUTPUT][0], 0 );
2556     else
2557         cvTsGEMM( input, &test_mat[TEMP][0], 1., 0, 0., &test_mat[OUTPUT][0], 0 );
2558
2559     cvTsSetIdentity( &test_mat[REF_OUTPUT][0], cvScalarAll(1.) );
2560 }
2561
2562 CxCore_InvertTest invert_test;
2563
2564
2565 ///////////////// solve /////////////////////
2566
2567 class CxCore_SolveTest : public CxCore_MatrixTest
2568 {
2569 public:
2570     CxCore_SolveTest();
2571 protected:
2572     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
2573     void get_timing_test_array_types_and_sizes( int test_case_idx,
2574                                                 CvSize** sizes, int** types,
2575                                                 CvSize** whole_sizes, bool* are_images );
2576     int write_default_params( CvFileStorage* fs );
2577     void print_timing_params( int test_case_idx, char* ptr, int params_left );
2578     void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high );
2579     double get_success_error_level( int test_case_idx, int i, int j );
2580     int prepare_test_case( int test_case_idx );
2581     void run_func();
2582     void prepare_to_validation( int test_case_idx );
2583     int method, rank;
2584     double result;
2585 };
2586
2587
2588 CxCore_SolveTest::CxCore_SolveTest() :
2589     CxCore_MatrixTest( "matrix-solve", "cvSolve, cvSVD, cvSVBkSb", 2, 1, false, false, 1 ), method(0), rank(0), result(0.)
2590 {
2591     test_case_count = 100;
2592     max_log_array_size = 7;
2593     test_array[TEMP].push(NULL);
2594     test_array[TEMP].push(NULL);
2595
2596     default_timing_param_names = matrix_solve_invert_param_names;
2597 }
2598
2599
2600 void CxCore_SolveTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
2601 {
2602     CvRNG* rng = ts->get_rng();
2603     int bits = cvTsRandInt(rng);
2604     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2605     CvSize in_sz = sizes[INPUT][0];
2606     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2607     sizes[INPUT][0] = in_sz;
2608     int min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
2609
2610     if( (bits & 3) == 0 )
2611     {
2612         method = CV_SVD;
2613         if( bits & 4 )
2614         {
2615             sizes[INPUT][0] = cvSize(min_size, min_size);
2616             /*if( bits & 8 )
2617                 method = CV_SVD_SYM;*/
2618         }
2619     }
2620     else
2621     {
2622         method = CV_LU;
2623         sizes[INPUT][0] = cvSize(min_size, min_size);
2624     }
2625
2626     sizes[INPUT][1].height = sizes[INPUT][0].height;
2627     sizes[TEMP][0].width = sizes[INPUT][1].width;
2628     sizes[TEMP][0].height = sizes[INPUT][0].width;
2629     sizes[TEMP][1] = sizes[INPUT][0];
2630     types[TEMP][0] = types[INPUT][0];
2631     types[TEMP][1] = CV_64FC1;
2632     sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(sizes[INPUT][1].width, min_size);
2633 }
2634
2635 void CxCore_SolveTest::get_timing_test_array_types_and_sizes( int test_case_idx,
2636                                                     CvSize** sizes, int** types,
2637                                                     CvSize** whole_sizes, bool* are_images )
2638 {
2639     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
2640                                     sizes, types, whole_sizes, are_images );
2641     const char* method_str = cvReadString( find_timing_param("method"), "LU" );
2642     sizes[INPUT][1].width = sizes[TEMP][0].width = sizes[OUTPUT][0].width = sizes[REF_OUTPUT][0].width = 1;
2643     method = strcmp( method_str, "LU" ) == 0 ? CV_LU : CV_SVD;
2644 }
2645
2646
2647 int CxCore_SolveTest::write_default_params( CvFileStorage* fs )
2648 {
2649     int code = CxCore_MatrixTest::write_default_params(fs);
2650     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
2651         return code;
2652     write_string_list( fs, "method", matrix_solve_invert_methods );
2653     return code;
2654 }
2655
2656
2657 void CxCore_SolveTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
2658 {
2659     sprintf( ptr, "%s,", method == CV_LU ? "LU" : "SVD" );
2660     ptr += strlen(ptr);
2661     params_left--;
2662     CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left );
2663 }
2664
2665
2666 int CxCore_SolveTest::prepare_test_case( int test_case_idx )
2667 {
2668     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
2669
2670     /*if( method == CV_SVD_SYM )
2671     {
2672         cvTsGEMM( test_array[INPUT][0], test_array[INPUT][0], 1.,
2673                   0, 0., test_array[TEMP][0], CV_GEMM_B_T );
2674         cvTsCopy( test_array[TEMP][0], test_array[INPUT][0] );
2675     }*/
2676
2677     return code;
2678 }
2679
2680
2681 void CxCore_SolveTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
2682 {
2683     *low = cvScalarAll(-2.);
2684     *high = cvScalarAll(2.);
2685 }
2686
2687
2688 double CxCore_SolveTest::get_success_error_level( int /*test_case_idx*/, int, int )
2689 {
2690     return CV_MAT_DEPTH(cvGetElemType(test_array[OUTPUT][0])) == CV_32F ? 3e-2 : 1e-8;
2691 }
2692
2693
2694 void CxCore_SolveTest::run_func()
2695 {
2696     result = cvSolve(test_array[INPUT][0], test_array[INPUT][1], test_array[TEMP][0], method);
2697 }
2698
2699 void CxCore_SolveTest::prepare_to_validation( int )
2700 {
2701     //int rank = test_mat[REF_OUTPUT][0].rows;
2702     CvMat* dst;
2703
2704     if( method == CV_LU && result == 0 )
2705     {
2706         if( CV_MAT_TYPE(test_mat[INPUT][0].type) == CV_32FC1 )
2707             cvTsConvert( &test_mat[INPUT][0], &test_mat[TEMP][1] );
2708         else
2709             cvTsCopy( &test_mat[INPUT][0], &test_mat[TEMP][1], 0 );
2710
2711         cvTsZero( &test_mat[OUTPUT][0] );
2712         double det = cvTsLU( &test_mat[TEMP][1], 0, 0 );
2713         cvTsAdd( 0, cvScalarAll(0.), 0, cvScalarAll(0.), cvScalarAll(det != 0),
2714                  &test_mat[REF_OUTPUT][0], 0 );
2715         return;
2716     }
2717
2718     dst = test_mat[INPUT][0].rows <= test_mat[INPUT][0].cols ? &test_mat[OUTPUT][0] : &test_mat[INPUT][1];
2719
2720     cvTsGEMM( &test_mat[INPUT][0], &test_mat[TEMP][0], 1., &test_mat[INPUT][1], -1., dst, 0 );
2721     if( dst != &test_mat[OUTPUT][0] )
2722         cvTsGEMM( &test_mat[INPUT][0], dst, 1., 0, 0., &test_mat[OUTPUT][0], CV_GEMM_A_T );
2723     cvTsZero( &test_mat[REF_OUTPUT][0] );
2724 }
2725
2726 CxCore_SolveTest solve_test;
2727
2728
2729 ///////////////// SVD /////////////////////
2730
2731 static const char* matrix_svd_param_names[] = { "size", "output", "depth", 0 };
2732 static const char* matrix_svd_output_modes[] = { "w", "all", 0 };
2733
2734 class CxCore_SVDTest : public CxCore_MatrixTest
2735 {
2736 public:
2737     CxCore_SVDTest();
2738 protected:
2739     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
2740     void get_timing_test_array_types_and_sizes( int test_case_idx,
2741                                                 CvSize** sizes, int** types,
2742                                                 CvSize** whole_sizes, bool* are_images );
2743     double get_success_error_level( int test_case_idx, int i, int j );
2744     int write_default_params( CvFileStorage* fs );
2745     void print_timing_params( int test_case_idx, char* ptr, int params_left );
2746     void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high );
2747     int prepare_test_case( int test_case_idx );
2748     void run_func();
2749     void prepare_to_validation( int test_case_idx );
2750     int flags;
2751     bool have_u, have_v, symmetric, compact, vector_w;
2752 };
2753
2754
2755 CxCore_SVDTest::CxCore_SVDTest() :
2756     CxCore_MatrixTest( "matrix-svd", "cvSVD", 1, 4, false, false, 1 ),
2757         flags(0), have_u(false), have_v(false), symmetric(false), compact(false), vector_w(false)
2758 {
2759     test_case_count = 100;
2760     test_array[TEMP].push(NULL);
2761     test_array[TEMP].push(NULL);
2762     test_array[TEMP].push(NULL);
2763     test_array[TEMP].push(NULL);
2764
2765     default_timing_param_names = matrix_svd_param_names;
2766 }
2767
2768
2769 void CxCore_SVDTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
2770 {
2771     CvRNG* rng = ts->get_rng();
2772     int bits = cvTsRandInt(rng);
2773     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2774     int min_size, i, m, n;
2775
2776     min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
2777
2778     flags = bits & (CV_SVD_MODIFY_A+CV_SVD_U_T+CV_SVD_V_T);
2779     have_u = (bits & 8) != 0;
2780     have_v = (bits & 16) != 0;
2781     symmetric = (bits & 32) != 0;
2782     compact = (bits & 64) != 0;
2783     vector_w = (bits & 128) != 0;
2784
2785     if( symmetric )
2786         sizes[INPUT][0] = cvSize(min_size, min_size);
2787
2788     m = sizes[INPUT][0].height;
2789     n = sizes[INPUT][0].width;
2790
2791     if( compact )
2792         sizes[TEMP][0] = cvSize(min_size, min_size);
2793     else
2794         sizes[TEMP][0] = sizes[INPUT][0];
2795     sizes[TEMP][3] = cvSize(0,0);
2796
2797     if( vector_w )
2798     {
2799         sizes[TEMP][3] = sizes[TEMP][0];
2800         if( bits & 256 )
2801             sizes[TEMP][0] = cvSize(1, min_size);
2802         else
2803             sizes[TEMP][0] = cvSize(min_size, 1);
2804     }
2805
2806     if( have_u )
2807     {
2808         sizes[TEMP][1] = compact ? cvSize(min_size, m) : cvSize(m, m);
2809
2810         if( flags & CV_SVD_U_T )
2811             CV_SWAP( sizes[TEMP][1].width, sizes[TEMP][1].height, i );
2812     }
2813     else
2814         sizes[TEMP][1] = cvSize(0,0);
2815
2816     if( have_v )
2817     {
2818         sizes[TEMP][2] = compact ? cvSize(n, min_size) : cvSize(n, n);
2819
2820         if( !(flags & CV_SVD_V_T) )
2821             CV_SWAP( sizes[TEMP][2].width, sizes[TEMP][2].height, i );
2822     }
2823     else
2824         sizes[TEMP][2] = cvSize(0,0);
2825
2826     types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[TEMP][3] = types[INPUT][0];
2827     types[OUTPUT][0] = types[OUTPUT][1] = types[OUTPUT][2] = types[INPUT][0];
2828     types[OUTPUT][3] = CV_8UC1;
2829     sizes[OUTPUT][0] = !have_u || !have_v ? cvSize(0,0) : sizes[INPUT][0];
2830     sizes[OUTPUT][1] = !have_u ? cvSize(0,0) : compact ? cvSize(min_size,min_size) : cvSize(m,m);
2831     sizes[OUTPUT][2] = !have_v ? cvSize(0,0) : compact ? cvSize(min_size,min_size) : cvSize(n,n);
2832     sizes[OUTPUT][3] = cvSize(min_size,1);
2833
2834     for( i = 0; i < 4; i++ )
2835     {
2836         sizes[REF_OUTPUT][i] = sizes[OUTPUT][i];
2837         types[REF_OUTPUT][i] = types[OUTPUT][i];
2838     }
2839 }
2840
2841
2842 void CxCore_SVDTest::get_timing_test_array_types_and_sizes( int test_case_idx,
2843                                                     CvSize** sizes, int** types,
2844                                                     CvSize** whole_sizes, bool* are_images )
2845 {
2846     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
2847                                     sizes, types, whole_sizes, are_images );
2848     const char* output_str = cvReadString( find_timing_param("output"), "all" );
2849     bool need_all = strcmp( output_str, "all" ) == 0;
2850     int i, count = test_array[OUTPUT].size();
2851     vector_w = true;
2852     symmetric = false;
2853     compact = true;
2854     sizes[TEMP][0] = cvSize(1,sizes[INPUT][0].height);
2855     if( need_all )
2856     {
2857         have_u = have_v = true;
2858     }
2859     else
2860     {
2861         have_u = have_v = false;
2862         sizes[TEMP][1] = sizes[TEMP][2] = cvSize(0,0);
2863     }
2864
2865     flags = CV_SVD_U_T + CV_SVD_V_T;
2866     for( i = 0; i < count; i++ )
2867         sizes[OUTPUT][i] = sizes[REF_OUTPUT][i] = cvSize(0,0);
2868     sizes[OUTPUT][0] = cvSize(1,1);
2869 }
2870
2871
2872 int CxCore_SVDTest::write_default_params( CvFileStorage* fs )
2873 {
2874     int code = CxCore_MatrixTest::write_default_params(fs);
2875     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
2876         return code;
2877     write_string_list( fs, "output", matrix_svd_output_modes );
2878     return code;
2879 }
2880
2881
2882 void CxCore_SVDTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
2883 {
2884     sprintf( ptr, "%s,", have_u ? "all" : "w" );
2885     ptr += strlen(ptr);
2886     params_left--;
2887     CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left );
2888 }
2889
2890
2891 int CxCore_SVDTest::prepare_test_case( int test_case_idx )
2892 {
2893     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
2894     if( code > 0 )
2895     {
2896         CvMat* input = &test_mat[INPUT][0];
2897         cvTsFloodWithZeros( input, ts->get_rng() );
2898
2899         if( symmetric && (have_u || have_v) )
2900         {
2901             CvMat* temp = &test_mat[TEMP][have_u ? 1 : 2];
2902             cvTsGEMM( input, input, 1.,
2903                       0, 0., temp, CV_GEMM_B_T );
2904             cvTsCopy( temp, input );
2905         }
2906
2907         if( (flags & CV_SVD_MODIFY_A) && test_array[OUTPUT][0] )
2908             cvTsCopy( input, &test_mat[OUTPUT][0] );
2909     }
2910
2911     return code;
2912 }
2913
2914
2915 void CxCore_SVDTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
2916 {
2917     *low = cvScalarAll(-2.);
2918     *high = cvScalarAll(2.);
2919 }
2920
2921 double CxCore_SVDTest::get_success_error_level( int test_case_idx, int i, int j )
2922 {
2923     int input_depth = CV_MAT_DEPTH(cvGetElemType( test_array[INPUT][0] ));
2924     double input_precision = input_depth < CV_32F ? 0 : input_depth == CV_32F ?
2925                             5e-5 : 5e-11;
2926     double output_precision = CvArrTest::get_success_error_level( test_case_idx, i, j );
2927     return MAX(input_precision, output_precision);
2928 }
2929
2930 void CxCore_SVDTest::run_func()
2931 {
2932     CvArr* src = test_array[!(flags & CV_SVD_MODIFY_A) ? INPUT : OUTPUT][0];
2933     if( !src )
2934         src = test_array[INPUT][0];
2935     cvSVD( src, test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], flags );
2936 }
2937
2938
2939 void CxCore_SVDTest::prepare_to_validation( int )
2940 {
2941     CvMat* input = &test_mat[INPUT][0];
2942     int m = input->rows, n = input->cols, min_size = MIN(m, n);
2943     CvMat *src, *dst, *w;
2944     double prev = 0, threshold = CV_MAT_TYPE(input->type) == CV_32FC1 ? FLT_EPSILON : DBL_EPSILON;
2945     int i, j = 0, step;
2946
2947     if( have_u )
2948     {
2949         src = &test_mat[TEMP][1];
2950         dst = &test_mat[OUTPUT][1];
2951         cvTsGEMM( src, src, 1., 0, 0., dst, src->rows == dst->rows ? CV_GEMM_B_T : CV_GEMM_A_T );
2952         cvTsSetIdentity( &test_mat[REF_OUTPUT][1], cvScalarAll(1.) );
2953     }
2954
2955     if( have_v )
2956     {
2957         src = &test_mat[TEMP][2];
2958         dst = &test_mat[OUTPUT][2];
2959         cvTsGEMM( src, src, 1., 0, 0., dst, src->rows == dst->rows ? CV_GEMM_B_T : CV_GEMM_A_T );
2960         cvTsSetIdentity( &test_mat[REF_OUTPUT][2], cvScalarAll(1.) );
2961     }
2962
2963     w = &test_mat[TEMP][0];
2964     step = w->rows == 1 ? 1 : w->step/CV_ELEM_SIZE(w->type);
2965     for( i = 0; i < min_size; i++ )
2966     {
2967         double norm = 0, aii;
2968         uchar* row_ptr;
2969         if( w->rows > 1 && w->cols > 1 )
2970         {
2971             CvMat row;
2972             cvGetRow( w, &row, i );
2973             norm = cvNorm( &row, 0, CV_L1 );
2974             j = i;
2975             row_ptr = row.data.ptr;
2976         }
2977         else
2978         {
2979             row_ptr = w->data.ptr;
2980             j = i*step;
2981         }
2982
2983         aii = CV_MAT_TYPE(w->type) == CV_32FC1 ?
2984             (double)((float*)row_ptr)[j] : ((double*)row_ptr)[j];
2985         if( w->rows == 1 || w->cols == 1 )
2986             norm = aii;
2987         norm = fabs(norm - aii);
2988         test_mat[OUTPUT][3].data.ptr[i] = aii >= 0 && norm < threshold && (i == 0 || aii <= prev);
2989         prev = aii;
2990     }
2991
2992     cvTsAdd( 0, cvScalarAll(0.), 0, cvScalarAll(0.),
2993              cvScalarAll(1.), &test_mat[REF_OUTPUT][3], 0 );
2994
2995     if( have_u && have_v )
2996     {
2997         if( vector_w )
2998         {
2999             cvTsZero( &test_mat[TEMP][3] );
3000             for( i = 0; i < min_size; i++ )
3001             {
3002                 double val = cvGetReal1D( w, i );
3003                 cvSetReal2D( &test_mat[TEMP][3], i, i, val );
3004             }
3005             w = &test_mat[TEMP][3];
3006         }
3007
3008         if( m >= n )
3009         {
3010             cvTsGEMM( &test_mat[TEMP][1], w, 1., 0, 0., &test_mat[REF_OUTPUT][0],
3011                       flags & CV_SVD_U_T ? CV_GEMM_A_T : 0 );
3012             cvTsGEMM( &test_mat[REF_OUTPUT][0], &test_mat[TEMP][2], 1., 0, 0.,
3013                       &test_mat[OUTPUT][0], flags & CV_SVD_V_T ? 0 : CV_GEMM_B_T );
3014         }
3015         else
3016         {
3017             cvTsGEMM( w, &test_mat[TEMP][2], 1., 0, 0., &test_mat[REF_OUTPUT][0],
3018                       flags & CV_SVD_V_T ? 0 : CV_GEMM_B_T );
3019             cvTsGEMM( &test_mat[TEMP][1], &test_mat[REF_OUTPUT][0], 1., 0, 0.,
3020                       &test_mat[OUTPUT][0], flags & CV_SVD_U_T ? CV_GEMM_A_T : 0 );
3021         }
3022
3023         cvTsCopy( &test_mat[INPUT][0], &test_mat[REF_OUTPUT][0], 0 );
3024     }
3025 }
3026
3027
3028 CxCore_SVDTest svd_test;
3029
3030
3031 ///////////////// SVBkSb /////////////////////
3032
3033 class CxCore_SVBkSbTest : public CxCore_MatrixTest
3034 {
3035 public:
3036     CxCore_SVBkSbTest();
3037 protected:
3038     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
3039     void get_timing_test_array_types_and_sizes( int test_case_idx,
3040                                                 CvSize** sizes, int** types,
3041                                                 CvSize** whole_sizes, bool* are_images );
3042     double get_success_error_level( int test_case_idx, int i, int j );
3043     void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high );
3044     int prepare_test_case( int test_case_idx );
3045     void run_func();
3046     void prepare_to_validation( int test_case_idx );
3047     int flags;
3048     bool have_b, symmetric, compact, vector_w;
3049 };
3050
3051
3052 CxCore_SVBkSbTest::CxCore_SVBkSbTest() :
3053     CxCore_MatrixTest( "matrix-svbksb", "cvSVBkSb", 2, 1, false, false, 1 ),
3054         flags(0), have_b(false), symmetric(false), compact(false), vector_w(false)
3055 {
3056     test_case_count = 100;
3057     test_array[TEMP].push(NULL);
3058     test_array[TEMP].push(NULL);
3059     test_array[TEMP].push(NULL);
3060 }
3061
3062
3063 void CxCore_SVBkSbTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
3064 {
3065     CvRNG* rng = ts->get_rng();
3066     int bits = cvTsRandInt(rng);
3067     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
3068     int min_size, i, m, n;
3069     CvSize b_size;
3070
3071     min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
3072
3073     flags = bits & (CV_SVD_MODIFY_A+CV_SVD_U_T+CV_SVD_V_T);
3074     have_b = (bits & 16) != 0;
3075     symmetric = (bits & 32) != 0;
3076     compact = (bits & 64) != 0;
3077     vector_w = (bits & 128) != 0;
3078
3079     if( symmetric )
3080         sizes[INPUT][0] = cvSize(min_size, min_size);
3081
3082     m = sizes[INPUT][0].height;
3083     n = sizes[INPUT][0].width;
3084
3085     sizes[INPUT][1] = cvSize(0,0);
3086     b_size = cvSize(m,m);
3087     if( have_b )
3088     {
3089         sizes[INPUT][1].height = sizes[INPUT][0].height;
3090         sizes[INPUT][1].width = cvTsRandInt(rng) % 100 + 1;
3091         b_size = sizes[INPUT][1];
3092     }
3093
3094     if( compact )
3095         sizes[TEMP][0] = cvSize(min_size, min_size);
3096     else
3097         sizes[TEMP][0] = sizes[INPUT][0];
3098
3099     if( vector_w )
3100     {
3101         if( bits & 256 )
3102             sizes[TEMP][0] = cvSize(1, min_size);
3103         else
3104             sizes[TEMP][0] = cvSize(min_size, 1);
3105     }
3106
3107     sizes[TEMP][1] = compact ? cvSize(min_size, m) : cvSize(m, m);
3108
3109     if( flags & CV_SVD_U_T )
3110         CV_SWAP( sizes[TEMP][1].width, sizes[TEMP][1].height, i );
3111
3112     sizes[TEMP][2] = compact ? cvSize(n, min_size) : cvSize(n, n);
3113
3114     if( !(flags & CV_SVD_V_T) )
3115         CV_SWAP( sizes[TEMP][2].width, sizes[TEMP][2].height, i );
3116
3117     types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[INPUT][0];
3118     types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][0];
3119     sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize( b_size.width, n );
3120 }
3121
3122
3123 void CxCore_SVBkSbTest::get_timing_test_array_types_and_sizes( int test_case_idx,
3124                                                     CvSize** sizes, int** types,
3125                                                     CvSize** whole_sizes, bool* are_images )
3126 {
3127     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
3128                                     sizes, types, whole_sizes, are_images );
3129     have_b = true;
3130     vector_w = true;
3131     compact = true;
3132     sizes[TEMP][0] = cvSize(1,sizes[INPUT][0].height);
3133     sizes[INPUT][1] = sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(1,sizes[INPUT][0].height);
3134     flags = CV_SVD_U_T + CV_SVD_V_T;
3135 }
3136
3137
3138 int CxCore_SVBkSbTest::prepare_test_case( int test_case_idx )
3139 {
3140     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
3141     if( code > 0 )
3142     {
3143         CvMat* input = &test_mat[INPUT][0];
3144         cvTsFloodWithZeros( input, ts->get_rng() );
3145
3146         if( symmetric )
3147         {
3148             CvMat* temp = &test_mat[TEMP][1];
3149             cvTsGEMM( input, input, 1., 0, 0., temp, CV_GEMM_B_T );
3150             cvTsCopy( temp, input );
3151         }
3152
3153         cvSVD( input, test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], flags );
3154     }
3155
3156     return code;
3157 }
3158
3159
3160 void CxCore_SVBkSbTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
3161 {
3162     *low = cvScalarAll(-2.);
3163     *high = cvScalarAll(2.);
3164 }
3165
3166
3167 double CxCore_SVBkSbTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
3168 {
3169     return CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0])) == CV_32F ? 1e-3 : 1e-7;
3170 }
3171
3172
3173 void CxCore_SVBkSbTest::run_func()
3174 {
3175     cvSVBkSb( test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2],
3176               test_array[INPUT][1], test_array[OUTPUT][0], flags );
3177 }
3178
3179
3180 void CxCore_SVBkSbTest::prepare_to_validation( int )
3181 {
3182     CvMat* input = &test_mat[INPUT][0];
3183     int i, m = input->rows, n = input->cols, min_size = MIN(m, n), nb;
3184     bool is_float = CV_MAT_DEPTH(input->type) == CV_32F;
3185     CvSize w_size = compact ? cvSize(min_size,min_size) : cvSize(m,n);
3186     CvMat* w = &test_mat[TEMP][0];
3187     CvMat* wdb = cvCreateMat( w_size.height, w_size.width, CV_64FC1 );
3188     // use exactly the same threshold as in icvSVD... ,
3189     // so the changes in the library and here should be synchronized.
3190     double threshold = cvSum( w ).val[0]*2*(is_float ? FLT_EPSILON : DBL_EPSILON);
3191     CvMat *u, *v, *b, *t0, *t1;
3192
3193     cvTsZero(wdb);
3194     for( i = 0; i < min_size; i++ )
3195     {
3196         double wii = vector_w ? cvGetReal1D(w,i) : cvGetReal2D(w,i,i);
3197         cvSetReal2D( wdb, i, i, wii > threshold ? 1./wii : 0. );
3198     }
3199
3200     u = &test_mat[TEMP][1];
3201     v = &test_mat[TEMP][2];
3202     b = 0;
3203     nb = m;
3204
3205     if( test_array[INPUT][1] )
3206     {
3207         b = &test_mat[INPUT][1];
3208         nb = b->cols;
3209     }
3210
3211     if( is_float )
3212     {
3213         u = cvCreateMat( u->rows, u->cols, CV_64F );
3214         cvTsConvert( &test_mat[TEMP][1], u );
3215         if( b )
3216         {
3217             b = cvCreateMat( b->rows, b->cols, CV_64F );
3218             cvTsConvert( &test_mat[INPUT][1], b );
3219         }
3220     }
3221
3222     t0 = cvCreateMat( wdb->cols, nb, CV_64F );
3223
3224     if( b )
3225         cvTsGEMM( u, b, 1., 0, 0., t0, !(flags & CV_SVD_U_T) ? CV_GEMM_A_T : 0 );
3226     else if( flags & CV_SVD_U_T )
3227         cvTsCopy( u, t0 );
3228     else
3229         cvTsTranspose( u, t0 );
3230
3231     if( is_float )
3232     {
3233         cvReleaseMat( &b );
3234
3235         if( !symmetric )
3236         {
3237             cvReleaseMat( &u );
3238             v = cvCreateMat( v->rows, v->cols, CV_64F );
3239         }
3240         else
3241         {
3242             v = u;
3243             u = 0;
3244         }
3245         cvTsConvert( &test_mat[TEMP][2], v );
3246     }
3247
3248     t1 = cvCreateMat( wdb->rows, nb, CV_64F );
3249     cvTsGEMM( wdb, t0, 1, 0, 0, t1, 0 );
3250
3251     if( !is_float || !symmetric )
3252     {
3253         cvReleaseMat( &t0 );
3254         t0 = !is_float ? &test_mat[REF_OUTPUT][0] : cvCreateMat( test_mat[REF_OUTPUT][0].rows, nb, CV_64F );
3255     }
3256
3257     cvTsGEMM( v, t1, 1, 0, 0, t0, flags & CV_SVD_V_T ? CV_GEMM_A_T : 0 );
3258     cvReleaseMat( &t1 );
3259
3260     if( t0 != &test_mat[REF_OUTPUT][0] )
3261     {
3262         cvTsConvert( t0, &test_mat[REF_OUTPUT][0] );
3263         cvReleaseMat( &t0 );
3264     }
3265
3266     if( v != &test_mat[TEMP][2] )
3267         cvReleaseMat( &v );
3268
3269     cvReleaseMat( &wdb );
3270 }
3271
3272
3273 CxCore_SVBkSbTest svbksb_test;
3274
3275
3276 // TODO: eigenvv, invsqrt, cbrt, fastarctan, (round, floor, ceil(?)),
3277
3278 /* End of file. */
3279