]> rtime.felk.cvut.cz Git - opencv.git/blob - opencv/tests/cxcore/src/amath.cpp
extended exp, log, pow etc. tests to check C++ API as well
[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;
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     default_timing_param_names = matrix_gemm_param_names;
1313     alpha = beta = 0;
1314 }
1315
1316
1317 void CxCore_GEMMTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1318 {
1319     CvRNG* rng = ts->get_rng();
1320     CvSize sizeA;
1321     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1322     sizeA = sizes[INPUT][0];
1323     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1324     sizes[INPUT][0] = sizeA;
1325     sizes[INPUT][2] = sizes[INPUT][3] = cvSize(1,1);
1326     types[INPUT][2] = types[INPUT][3] &= ~CV_MAT_CN_MASK;
1327
1328     tabc_flag = cvTsRandInt(rng) & 7;
1329
1330     switch( tabc_flag & (CV_GEMM_A_T|CV_GEMM_B_T) )
1331     {
1332     case 0:
1333         sizes[INPUT][1].height = sizes[INPUT][0].width;
1334         sizes[OUTPUT][0].height = sizes[INPUT][0].height;
1335         sizes[OUTPUT][0].width = sizes[INPUT][1].width;
1336         break;
1337     case CV_GEMM_B_T:
1338         sizes[INPUT][1].width = sizes[INPUT][0].width;
1339         sizes[OUTPUT][0].height = sizes[INPUT][0].height;
1340         sizes[OUTPUT][0].width = sizes[INPUT][1].height;
1341         break;
1342     case CV_GEMM_A_T:
1343         sizes[INPUT][1].height = sizes[INPUT][0].height;
1344         sizes[OUTPUT][0].height = sizes[INPUT][0].width;
1345         sizes[OUTPUT][0].width = sizes[INPUT][1].width;
1346         break;
1347     case CV_GEMM_A_T | CV_GEMM_B_T:
1348         sizes[INPUT][1].width = sizes[INPUT][0].height;
1349         sizes[OUTPUT][0].height = sizes[INPUT][0].width;
1350         sizes[OUTPUT][0].width = sizes[INPUT][1].height;
1351         break;
1352     }
1353
1354     sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
1355
1356     if( cvTsRandInt(rng) & 1 )
1357         sizes[INPUT][4] = cvSize(0,0);
1358     else if( !(tabc_flag & CV_GEMM_C_T) )
1359         sizes[INPUT][4] = sizes[OUTPUT][0];
1360     else
1361     {
1362         sizes[INPUT][4].width = sizes[OUTPUT][0].height;
1363         sizes[INPUT][4].height = sizes[OUTPUT][0].width;
1364     }
1365 }
1366
1367
1368 void CxCore_GEMMTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1369                                                     CvSize** sizes, int** types,
1370                                                     CvSize** whole_sizes, bool* are_images )
1371 {
1372     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
1373                                     sizes, types, whole_sizes, are_images );
1374     const char* mul_type = cvReadString( find_timing_param("mul_type"), "AB" );
1375     if( strcmp( mul_type, "AtB" ) == 0 )
1376         tabc_flag = CV_GEMM_A_T;
1377     else if( strcmp( mul_type, "ABt" ) == 0 )
1378         tabc_flag = CV_GEMM_B_T;
1379     else if( strcmp( mul_type, "AtBt" ) == 0 )
1380         tabc_flag = CV_GEMM_A_T + CV_GEMM_B_T;
1381     else
1382         tabc_flag = 0;
1383
1384     if( cvReadInt( find_timing_param( "add_c" ), 0 ) == 0 )
1385         sizes[INPUT][4] = cvSize(0,0);
1386 }
1387
1388
1389 int CxCore_GEMMTest::write_default_params( CvFileStorage* fs )
1390 {
1391     int code = CxCore_MatrixTest::write_default_params(fs);
1392     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
1393         return code;
1394     write_string_list( fs, "mul_type", matrix_gemm_mul_types );
1395     write_int_list( fs, "add_c", matrix_gemm_add_c_flags, CV_DIM(matrix_gemm_add_c_flags) );
1396     return code;
1397 }
1398
1399
1400 void CxCore_GEMMTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
1401 {
1402     sprintf( ptr, "%s%s,%s,",
1403         tabc_flag & CV_GEMM_A_T ? "At" : "A",
1404         tabc_flag & CV_GEMM_B_T ? "Bt" : "B",
1405         test_array[INPUT][4] ? "plusC" : "" );
1406     ptr += strlen(ptr);
1407     params_left -= 2;
1408     CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left );
1409 }
1410
1411
1412 int CxCore_GEMMTest::prepare_test_case( int test_case_idx )
1413 {
1414     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
1415     if( code > 0 )
1416     {
1417         alpha = cvmGet( &test_mat[INPUT][2], 0, 0 );
1418         beta = cvmGet( &test_mat[INPUT][3], 0, 0 );
1419     }
1420     return code;
1421 }
1422
1423
1424 void CxCore_GEMMTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
1425 {
1426     *low = cvScalarAll(-10.);
1427     *high = cvScalarAll(10.);
1428 }
1429
1430
1431 void CxCore_GEMMTest::run_func()
1432 {
1433     cvGEMM( test_array[INPUT][0], test_array[INPUT][1], alpha,
1434             test_array[INPUT][4], beta, test_array[OUTPUT][0], tabc_flag );
1435 }
1436
1437
1438 void CxCore_GEMMTest::prepare_to_validation( int )
1439 {
1440     cvTsGEMM( &test_mat[INPUT][0], &test_mat[INPUT][1], alpha,
1441         test_array[INPUT][4] ? &test_mat[INPUT][4] : 0,
1442         beta, &test_mat[REF_OUTPUT][0], tabc_flag );
1443 }
1444
1445 CxCore_GEMMTest gemm_test;
1446
1447
1448 ///////////////// multransposed /////////////////////
1449
1450 static const char* matrix_multrans_param_names[] = { "size", "use_delta", "mul_type", "depth", 0 };
1451 static const int matrix_multrans_use_delta_flags[] = { 0, 1 };
1452 static const char* matrix_multrans_mul_types[] = { "AAt", "AtA", 0 };
1453
1454 class CxCore_MulTransposedTest : public CxCore_MatrixTest
1455 {
1456 public:
1457     CxCore_MulTransposedTest();
1458 protected:
1459     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1460     void get_timing_test_array_types_and_sizes( int test_case_idx,
1461                                                 CvSize** sizes, int** types,
1462                                                 CvSize** whole_sizes, bool* are_images );
1463     int write_default_params( CvFileStorage* fs );
1464     void print_timing_params( int test_case_idx, char* ptr, int params_left );
1465     void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high );
1466     void run_func();
1467     void prepare_to_validation( int test_case_idx );
1468     int order;
1469 };
1470
1471
1472 CxCore_MulTransposedTest::CxCore_MulTransposedTest() :
1473     CxCore_MatrixTest( "matrix-multransposed", "cvMulTransposed, cvRepeat", 2, 1, false, false, 1 )
1474 {
1475     test_case_count = 100;
1476     order = 0;
1477     test_array[TEMP].push(NULL);
1478     default_timing_param_names = matrix_multrans_param_names;
1479 }
1480
1481
1482 void CxCore_MulTransposedTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1483 {
1484     CvRNG* rng = ts->get_rng();
1485     int bits = cvTsRandInt(rng);
1486     int src_type = cvTsRandInt(rng) % 5;
1487     int dst_type = cvTsRandInt(rng) % 2;
1488
1489     src_type = src_type == 0 ? CV_8U : src_type == 1 ? CV_16U : src_type == 2 ? CV_16S :
1490                src_type == 3 ? CV_32F : CV_64F;
1491     dst_type = dst_type == 0 ? CV_32F : CV_64F;
1492     dst_type = MAX( dst_type, src_type );
1493
1494     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1495
1496     if( bits & 1 )
1497         sizes[INPUT][1] = cvSize(0,0);
1498     else
1499     {
1500         sizes[INPUT][1] = sizes[INPUT][0];
1501         if( bits & 2 )
1502             sizes[INPUT][1].height = 1;
1503         if( bits & 4 )
1504             sizes[INPUT][1].width = 1;
1505     }
1506
1507     sizes[TEMP][0] = sizes[INPUT][0];
1508     types[INPUT][0] = src_type;
1509     types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][1] = types[TEMP][0] = dst_type;
1510
1511     order = (bits & 8) != 0;
1512     sizes[OUTPUT][0].width = sizes[OUTPUT][0].height = order == 0 ?
1513         sizes[INPUT][0].height : sizes[INPUT][0].width;
1514     sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
1515 }
1516
1517
1518 void CxCore_MulTransposedTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1519                                                     CvSize** sizes, int** types,
1520                                                     CvSize** whole_sizes, bool* are_images )
1521 {
1522     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
1523                                     sizes, types, whole_sizes, are_images );
1524     const char* mul_type = cvReadString( find_timing_param("mul_type"), "AAt" );
1525     order = strcmp( mul_type, "AtA" ) == 0;
1526
1527     if( cvReadInt( find_timing_param( "use_delta" ), 0 ) == 0 )
1528         sizes[INPUT][1] = cvSize(0,0);
1529 }
1530
1531
1532 int CxCore_MulTransposedTest::write_default_params( CvFileStorage* fs )
1533 {
1534     int code = CxCore_MatrixTest::write_default_params(fs);
1535     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
1536         return code;
1537     write_string_list( fs, "mul_type", matrix_multrans_mul_types );
1538     write_int_list( fs, "use_delta", matrix_multrans_use_delta_flags,
1539                     CV_DIM(matrix_multrans_use_delta_flags) );
1540     return code;
1541 }
1542
1543
1544 void CxCore_MulTransposedTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
1545 {
1546     sprintf( ptr, "%s,%s,", order == 0 ? "AAt" : "AtA", test_array[INPUT][1] ? "delta" : "" );
1547     ptr += strlen(ptr);
1548     params_left -= 2;
1549     CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left );
1550 }
1551
1552
1553 void CxCore_MulTransposedTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
1554 {
1555     *low = cvScalarAll(-10.);
1556     *high = cvScalarAll(10.);
1557 }
1558
1559
1560 void CxCore_MulTransposedTest::run_func()
1561 {
1562     cvMulTransposed( test_array[INPUT][0], test_array[OUTPUT][0],
1563                      order, test_array[INPUT][1] );
1564 }
1565
1566
1567 void CxCore_MulTransposedTest::prepare_to_validation( int )
1568 {
1569     CvMat* delta = test_array[INPUT][1] ? &test_mat[INPUT][1] : 0;
1570     if( delta )
1571     {
1572         if( test_mat[INPUT][1].rows < test_mat[INPUT][0].rows ||
1573             test_mat[INPUT][1].cols < test_mat[INPUT][0].cols )
1574         {
1575             cvRepeat( delta, &test_mat[TEMP][0] );
1576             delta = &test_mat[TEMP][0];
1577         }
1578         cvTsAdd( &test_mat[INPUT][0], cvScalarAll(1.), delta, cvScalarAll(-1.),
1579                  cvScalarAll(0.), &test_mat[TEMP][0], 0 );
1580     }
1581     else
1582         cvTsConvert( &test_mat[INPUT][0], &test_mat[TEMP][0] );
1583     delta = &test_mat[TEMP][0];
1584
1585     cvTsGEMM( delta, delta, 1., 0, 0, &test_mat[REF_OUTPUT][0], order == 0 ? CV_GEMM_B_T : CV_GEMM_A_T );
1586 }
1587
1588 CxCore_MulTransposedTest multransposed_test;
1589
1590
1591 ///////////////// Transform /////////////////////
1592
1593 static const CvSize matrix_transform_sizes[] = {{10,10}, {100,100}, {720,480}, {-1,-1}};
1594 static const CvSize matrix_transform_whole_sizes[] = {{10,10}, {720,480}, {720,480}, {-1,-1}};
1595 static const int matrix_transform_channels[] = { 2, 3, 4, -1 };
1596 static const char* matrix_transform_param_names[] = { "size", "channels", "depth", 0 };
1597
1598 class CxCore_TransformTest : public CxCore_MatrixTest
1599 {
1600 public:
1601     CxCore_TransformTest();
1602 protected:
1603     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1604     double get_success_error_level( int test_case_idx, int i, int j );
1605     void get_timing_test_array_types_and_sizes( int test_case_idx,
1606                                                 CvSize** sizes, int** types,
1607                                                 CvSize** whole_sizes, bool* are_images );
1608     int prepare_test_case( int test_case_idx );
1609     void print_timing_params( int test_case_idx, char* ptr, int params_left );
1610     void run_func();
1611     void prepare_to_validation( int test_case_idx );
1612     
1613     double scale;
1614 };
1615
1616
1617 CxCore_TransformTest::CxCore_TransformTest() :
1618     CxCore_MatrixTest( "matrix-transform", "cvTransform", 3, 1, true, false, 4 )
1619 {
1620     default_timing_param_names = matrix_transform_param_names;
1621     cn_list = matrix_transform_channels;
1622     depth_list = matrix_all_depths;
1623     size_list = matrix_transform_sizes;
1624     whole_size_list = matrix_transform_whole_sizes;
1625 }
1626
1627
1628 void CxCore_TransformTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1629 {
1630     CvRNG* rng = ts->get_rng();
1631     int bits = cvTsRandInt(rng);
1632     int depth, dst_cn, mat_cols, mattype;
1633     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1634
1635     mat_cols = CV_MAT_CN(types[INPUT][0]);
1636     depth = CV_MAT_DEPTH(types[INPUT][0]);
1637     dst_cn = cvTsRandInt(rng) % 4 + 1;
1638     types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, dst_cn);
1639
1640     mattype = depth < CV_32S ? CV_32F : depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F;
1641     types[INPUT][1] = mattype;
1642     types[INPUT][2] = CV_MAKETYPE(mattype, dst_cn);
1643     
1644     scale = 1./((cvTsRandInt(rng)%4)*50+1);
1645
1646     if( bits & 2 )
1647     {
1648         sizes[INPUT][2] = cvSize(0,0);
1649         mat_cols += (bits & 4) != 0;
1650     }
1651     else if( bits & 4 )
1652         sizes[INPUT][2] = cvSize(1,1);
1653     else
1654     {
1655         if( bits & 8 )
1656             sizes[INPUT][2] = cvSize(dst_cn,1);
1657         else
1658             sizes[INPUT][2] = cvSize(1,dst_cn);
1659         types[INPUT][2] &= ~CV_MAT_CN_MASK;
1660     }
1661
1662     sizes[INPUT][1] = cvSize(mat_cols,dst_cn);
1663 }
1664
1665
1666 void CxCore_TransformTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1667                 CvSize** sizes, int** types, CvSize** whole_sizes, bool* are_images )
1668 {
1669     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
1670                                     sizes, types, whole_sizes, are_images );
1671     int cn = CV_MAT_CN(types[INPUT][0]);
1672     sizes[INPUT][1] = cvSize(cn + (cn < 4), cn);
1673     sizes[INPUT][2] = cvSize(0,0);
1674     types[INPUT][1] = types[INPUT][2] = CV_64FC1;
1675     scale = 1./1000;
1676 }
1677
1678 int CxCore_TransformTest::prepare_test_case( int test_case_idx )
1679 {
1680     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
1681     if( code > 0 )
1682         cvTsAdd(&test_mat[INPUT][1], cvScalarAll(scale), &test_mat[INPUT][1],
1683                 cvScalarAll(0), cvScalarAll(0), &test_mat[INPUT][1], 0 );
1684     return code;
1685 }
1686
1687 void CxCore_TransformTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
1688 {
1689     CvSize size = cvGetMatSize(&test_mat[INPUT][1]);
1690     sprintf( ptr, "matrix=%dx%d,", size.height, size.width );
1691     ptr += strlen(ptr);
1692     params_left--;
1693     CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left );
1694 }
1695
1696
1697 double CxCore_TransformTest::get_success_error_level( int test_case_idx, int i, int j )
1698 {
1699     int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
1700     return depth <= CV_8S ? 1 : depth <= CV_32S ? 8 :
1701         CxCore_MatrixTest::get_success_error_level( test_case_idx, i, j );
1702 }
1703
1704 void CxCore_TransformTest::run_func()
1705 {
1706     cvTransform( test_array[INPUT][0], test_array[OUTPUT][0], &test_mat[INPUT][1],
1707                  test_array[INPUT][2] ? &test_mat[INPUT][2] : 0);
1708 }
1709
1710
1711 void CxCore_TransformTest::prepare_to_validation( int )
1712 {
1713     CvMat* transmat = &test_mat[INPUT][1];
1714     CvMat* shift = test_array[INPUT][2] ? &test_mat[INPUT][2] : 0;
1715
1716     cvTsTransform( &test_mat[INPUT][0], &test_mat[REF_OUTPUT][0], transmat, shift );
1717 }
1718
1719 CxCore_TransformTest transform_test;
1720
1721
1722 ///////////////// PerspectiveTransform /////////////////////
1723
1724 static const int matrix_perspective_transform_channels[] = { 2, 3, -1 };
1725
1726 class CxCore_PerspectiveTransformTest : public CxCore_MatrixTest
1727 {
1728 public:
1729     CxCore_PerspectiveTransformTest();
1730 protected:
1731     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1732     double get_success_error_level( int test_case_idx, int i, int j );
1733     void get_timing_test_array_types_and_sizes( int test_case_idx,
1734                                                 CvSize** sizes, int** types,
1735                                                 CvSize** whole_sizes, bool* are_images );
1736     void run_func();
1737     void prepare_to_validation( int test_case_idx );
1738 };
1739
1740
1741 CxCore_PerspectiveTransformTest::CxCore_PerspectiveTransformTest() :
1742     CxCore_MatrixTest( "matrix-perspective", "cvPerspectiveTransform", 2, 1, false, false, 2 )
1743 {
1744     default_timing_param_names = matrix_transform_param_names;
1745     cn_list = matrix_perspective_transform_channels;
1746     size_list = matrix_transform_sizes;
1747     whole_size_list = matrix_transform_whole_sizes;
1748 }
1749
1750
1751 void CxCore_PerspectiveTransformTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1752 {
1753     CvRNG* rng = ts->get_rng();
1754     int bits = cvTsRandInt(rng);
1755     int depth, cn, mattype;
1756     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1757
1758     cn = CV_MAT_CN(types[INPUT][0]) + 1;
1759     depth = CV_MAT_DEPTH(types[INPUT][0]);
1760     types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn);
1761
1762     mattype = depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F;
1763     types[INPUT][1] = mattype;
1764     sizes[INPUT][1] = cvSize(cn + 1, cn + 1);
1765 }
1766
1767
1768 double CxCore_PerspectiveTransformTest::get_success_error_level( int test_case_idx, int i, int j )
1769 {
1770     int depth = CV_MAT_DEPTH(test_mat[INPUT][0].type);
1771     return depth == CV_32F ? 1e-4 : depth == CV_64F ? 1e-8 :
1772                 CxCore_MatrixTest::get_success_error_level(test_case_idx, i, j);
1773 }
1774
1775
1776 void CxCore_PerspectiveTransformTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1777                         CvSize** sizes, int** types, CvSize** whole_sizes, bool* are_images )
1778 {
1779     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
1780                                     sizes, types, whole_sizes, are_images );
1781     int cn = CV_MAT_CN(types[INPUT][0]);
1782     sizes[INPUT][1] = cvSize(cn + 1, cn + 1);
1783     types[INPUT][1] = CV_64FC1;
1784 }
1785
1786
1787 void CxCore_PerspectiveTransformTest::run_func()
1788 {
1789     cvPerspectiveTransform( test_array[INPUT][0], test_array[OUTPUT][0], &test_mat[INPUT][1] );
1790 }
1791
1792
1793 static void cvTsPerspectiveTransform( const CvArr* _src, CvArr* _dst, const CvMat* transmat )
1794 {
1795     int i, j, cols;
1796     int cn, depth, mat_depth;
1797     CvMat astub, bstub, *a, *b;
1798     double mat[16], *buf;
1799
1800     a = cvGetMat( _src, &astub, 0, 0 );
1801     b = cvGetMat( _dst, &bstub, 0, 0 );
1802
1803     cn = CV_MAT_CN(a->type);
1804     depth = CV_MAT_DEPTH(a->type);
1805     mat_depth = CV_MAT_DEPTH(transmat->type);
1806     cols = transmat->cols;
1807
1808     // prepare cn x (cn + 1) transform matrix
1809     if( mat_depth == CV_32F )
1810     {
1811         for( i = 0; i < transmat->rows; i++ )
1812             for( j = 0; j < cols; j++ )
1813                 mat[i*cols + j] = ((float*)(transmat->data.ptr + transmat->step*i))[j];
1814     }
1815     else
1816     {
1817         assert( mat_depth == CV_64F );
1818         for( i = 0; i < transmat->rows; i++ )
1819             for( j = 0; j < cols; j++ )
1820                 mat[i*cols + j] = ((double*)(transmat->data.ptr + transmat->step*i))[j];
1821     }
1822
1823     // transform data
1824     cols = a->cols * cn;
1825     buf = (double*)cvStackAlloc( cols * sizeof(double) );
1826
1827     for( i = 0; i < a->rows; i++ )
1828     {
1829         uchar* src = a->data.ptr + i*a->step;
1830         uchar* dst = b->data.ptr + i*b->step;
1831
1832         switch( depth )
1833         {
1834         case CV_32F:
1835             for( j = 0; j < cols; j++ )
1836                 buf[j] = ((float*)src)[j];
1837             break;
1838         case CV_64F:
1839             for( j = 0; j < cols; j++ )
1840                 buf[j] = ((double*)src)[j];
1841             break;
1842         default:
1843             assert(0);
1844         }
1845
1846         switch( cn )
1847         {
1848         case 2:
1849             for( j = 0; j < cols; j += 2 )
1850             {
1851                 double t0 = buf[j]*mat[0] + buf[j+1]*mat[1] + mat[2];
1852                 double t1 = buf[j]*mat[3] + buf[j+1]*mat[4] + mat[5];
1853                 double w = buf[j]*mat[6] + buf[j+1]*mat[7] + mat[8];
1854                 w = w ? 1./w : 0;
1855                 buf[j] = t0*w;
1856                 buf[j+1] = t1*w;
1857             }
1858             break;
1859         case 3:
1860             for( j = 0; j < cols; j += 3 )
1861             {
1862                 double t0 = buf[j]*mat[0] + buf[j+1]*mat[1] + buf[j+2]*mat[2] + mat[3];
1863                 double t1 = buf[j]*mat[4] + buf[j+1]*mat[5] + buf[j+2]*mat[6] + mat[7];
1864                 double t2 = buf[j]*mat[8] + buf[j+1]*mat[9] + buf[j+2]*mat[10] + mat[11];
1865                 double w = buf[j]*mat[12] + buf[j+1]*mat[13] + buf[j+2]*mat[14] + mat[15];
1866                 w = w ? 1./w : 0;
1867                 buf[j] = t0*w;
1868                 buf[j+1] = t1*w;
1869                 buf[j+2] = t2*w;
1870             }
1871             break;
1872         default:
1873             assert(0);
1874         }
1875
1876         switch( depth )
1877         {
1878         case CV_32F:
1879             for( j = 0; j < cols; j++ )
1880                 ((float*)dst)[j] = (float)buf[j];
1881             break;
1882         case CV_64F:
1883             for( j = 0; j < cols; j++ )
1884                 ((double*)dst)[j] = buf[j];
1885             break;
1886         default:
1887             assert(0);
1888         }
1889     }
1890 }
1891
1892
1893 void CxCore_PerspectiveTransformTest::prepare_to_validation( int )
1894 {
1895     CvMat* transmat = &test_mat[INPUT][1];
1896     cvTsPerspectiveTransform( test_array[INPUT][0], test_array[REF_OUTPUT][0], transmat );
1897 }
1898
1899 CxCore_PerspectiveTransformTest perspective_test;
1900
1901
1902 ///////////////// Mahalanobis /////////////////////
1903
1904 class CxCore_MahalanobisTest : public CxCore_MatrixTest
1905 {
1906 public:
1907     CxCore_MahalanobisTest();
1908 protected:
1909     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
1910     void get_timing_test_array_types_and_sizes( int test_case_idx,
1911                                                 CvSize** sizes, int** types,
1912                                                 CvSize** whole_sizes, bool* are_images );
1913     int prepare_test_case( int test_case_idx );
1914     void run_func();
1915     void prepare_to_validation( int test_case_idx );
1916 };
1917
1918
1919 CxCore_MahalanobisTest::CxCore_MahalanobisTest() :
1920     CxCore_MatrixTest( "matrix-mahalanobis", "cvMahalanobis", 3, 1, false, true, 1 )
1921 {
1922     test_case_count = 100;
1923     test_array[TEMP].push(NULL);
1924     test_array[TEMP].push(NULL);
1925     test_array[TEMP].push(NULL);
1926 }
1927
1928
1929 void CxCore_MahalanobisTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
1930 {
1931     CvRNG* rng = ts->get_rng();
1932     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
1933
1934     if( cvTsRandInt(rng) & 1 )
1935         sizes[INPUT][0].width = sizes[INPUT][1].width = 1;
1936     else
1937         sizes[INPUT][0].height = sizes[INPUT][1].height = 1;
1938
1939     sizes[TEMP][0] = sizes[TEMP][1] = sizes[INPUT][0];
1940     sizes[INPUT][2].width = sizes[INPUT][2].height = sizes[INPUT][0].width + sizes[INPUT][0].height - 1;
1941     sizes[TEMP][2] = sizes[INPUT][2];
1942     types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[INPUT][0];
1943 }
1944
1945
1946 void CxCore_MahalanobisTest::get_timing_test_array_types_and_sizes( int test_case_idx,
1947                         CvSize** sizes, int** types, CvSize** whole_sizes, bool* are_images )
1948 {
1949     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
1950                                     sizes, types, whole_sizes, are_images );
1951     sizes[INPUT][0].height = sizes[INPUT][1].height = 1;
1952 }
1953
1954
1955 int CxCore_MahalanobisTest::prepare_test_case( int test_case_idx )
1956 {
1957     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
1958     if( code > 0 && ts->get_testing_mode() == CvTS::CORRECTNESS_CHECK_MODE )
1959     {
1960         // make sure that the inverted "covariation" matrix is symmetrix and positively defined.
1961         cvTsGEMM( &test_mat[INPUT][2], &test_mat[INPUT][2], 1., 0, 0., &test_mat[TEMP][2], CV_GEMM_B_T );
1962         cvTsCopy( &test_mat[TEMP][2], &test_mat[INPUT][2] );
1963     }
1964
1965     return code;
1966 }
1967
1968
1969 void CxCore_MahalanobisTest::run_func()
1970 {
1971     *((CvScalar*)(test_mat[OUTPUT][0].data.db)) =
1972         cvRealScalar(cvMahalanobis(test_array[INPUT][0], test_array[INPUT][1], test_array[INPUT][2]));
1973 }
1974
1975 void CxCore_MahalanobisTest::prepare_to_validation( int )
1976 {
1977     cvTsAdd( &test_mat[INPUT][0], cvScalarAll(1.),
1978              &test_mat[INPUT][1], cvScalarAll(-1.),
1979              cvScalarAll(0.), &test_mat[TEMP][0], 0 );
1980     if( test_mat[INPUT][0].rows == 1 )
1981         cvTsGEMM( &test_mat[TEMP][0], &test_mat[INPUT][2], 1.,
1982                   0, 0., &test_mat[TEMP][1], 0 );
1983     else
1984         cvTsGEMM( &test_mat[INPUT][2], &test_mat[TEMP][0], 1.,
1985                   0, 0., &test_mat[TEMP][1], 0 );
1986
1987     *((CvScalar*)(test_mat[REF_OUTPUT][0].data.db)) =
1988         cvRealScalar(sqrt(cvTsCrossCorr(&test_mat[TEMP][0], &test_mat[TEMP][1])));
1989 }
1990
1991 CxCore_MahalanobisTest mahalanobis_test;
1992
1993
1994 ///////////////// covarmatrix /////////////////////
1995
1996 class CxCore_CovarMatrixTest : public CxCore_MatrixTest
1997 {
1998 public:
1999     CxCore_CovarMatrixTest();
2000 protected:
2001     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
2002     int prepare_test_case( int test_case_idx );
2003     void run_func();
2004     void prepare_to_validation( int test_case_idx );
2005     CvTestPtrVec temp_hdrs;
2006     uchar* hdr_data;
2007     int flags, t_flag, len, count;
2008     bool are_images;
2009 };
2010
2011
2012 CxCore_CovarMatrixTest::CxCore_CovarMatrixTest() :
2013     CxCore_MatrixTest( "matrix-covar", "cvCalcCovarMatrix", 1, 1, true, false, 1 ),
2014         flags(0), t_flag(0), are_images(false)
2015 {
2016     test_case_count = 100;
2017     test_array[INPUT_OUTPUT].push(NULL);
2018     test_array[REF_INPUT_OUTPUT].push(NULL);
2019     test_array[TEMP].push(NULL);
2020     test_array[TEMP].push(NULL);
2021
2022     support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
2023 }
2024
2025
2026 void CxCore_CovarMatrixTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
2027 {
2028     CvRNG* rng = ts->get_rng();
2029     int bits = cvTsRandInt(rng);
2030     int i, single_matrix;
2031     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2032
2033     flags = bits & (CV_COVAR_NORMAL | CV_COVAR_USE_AVG | CV_COVAR_SCALE | CV_COVAR_ROWS );
2034     single_matrix = flags & CV_COVAR_ROWS;
2035     t_flag = (bits & 256) != 0;
2036
2037     const int min_count = 2;
2038
2039     if( !t_flag )
2040     {
2041         len = sizes[INPUT][0].width;
2042         count = sizes[INPUT][0].height;
2043         count = MAX(count, min_count);
2044         sizes[INPUT][0] = cvSize(len, count);
2045     }
2046     else
2047     {
2048         len = sizes[INPUT][0].height;
2049         count = sizes[INPUT][0].width;
2050         count = MAX(count, min_count);
2051         sizes[INPUT][0] = cvSize(count, len);
2052     }
2053
2054     if( single_matrix && t_flag )
2055         flags = (flags & ~CV_COVAR_ROWS) | CV_COVAR_COLS;
2056
2057     if( CV_MAT_DEPTH(types[INPUT][0]) == CV_32S )
2058         types[INPUT][0] = (types[INPUT][0] & ~CV_MAT_DEPTH_MASK) | CV_32F;
2059
2060     sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = flags & CV_COVAR_NORMAL ? cvSize(len,len) : cvSize(count,count);
2061     sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = !t_flag ? cvSize(len,1) : cvSize(1,len);
2062     sizes[TEMP][0] = sizes[INPUT][0];
2063
2064     types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] =
2065     types[OUTPUT][0] = types[REF_OUTPUT][0] = types[TEMP][0] =
2066         CV_MAT_DEPTH(types[INPUT][0]) == CV_64F || (bits & 512) ? CV_64F : CV_32F;
2067
2068     are_images = (bits & 1024) != 0;
2069     for( i = 0; i < (single_matrix ? 1 : count); i++ )
2070         temp_hdrs.push(NULL);
2071 }
2072
2073
2074 int CxCore_CovarMatrixTest::prepare_test_case( int test_case_idx )
2075 {
2076     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
2077     if( code > 0 )
2078     {
2079         int i;
2080         int single_matrix = flags & (CV_COVAR_ROWS|CV_COVAR_COLS);
2081         int hdr_size = are_images ? sizeof(IplImage) : sizeof(CvMat);
2082
2083         hdr_data = (uchar*)cvAlloc( count*hdr_size );
2084         if( single_matrix )
2085         {
2086             if( !are_images )
2087                 *((CvMat*)hdr_data) = test_mat[INPUT][0];
2088             else
2089                 cvGetImage( &test_mat[INPUT][0], (IplImage*)hdr_data );
2090             temp_hdrs[0] = hdr_data;
2091         }
2092         else
2093             for( i = 0; i < count; i++ )
2094             {
2095                 CvMat part;
2096                 void* ptr = hdr_data + i*hdr_size;
2097
2098                 if( !t_flag )
2099                     cvGetRow( &test_mat[INPUT][0], &part, i );
2100                 else
2101                     cvGetCol( &test_mat[INPUT][0], &part, i );
2102
2103                 if( !are_images )
2104                     *((CvMat*)ptr) = part;
2105                 else
2106                     cvGetImage( &part, (IplImage*)ptr );
2107
2108                 temp_hdrs[i] = ptr;
2109             }
2110     }
2111
2112     return code;
2113 }
2114
2115
2116 void CxCore_CovarMatrixTest::run_func()
2117 {
2118     cvCalcCovarMatrix( (const void**)&temp_hdrs[0], count,
2119                        test_array[OUTPUT][0], test_array[INPUT_OUTPUT][0], flags );
2120 }
2121
2122
2123 void CxCore_CovarMatrixTest::prepare_to_validation( int )
2124 {
2125     CvMat* avg = &test_mat[REF_INPUT_OUTPUT][0];
2126     double scale = 1.;
2127
2128     if( !(flags & CV_COVAR_USE_AVG) )
2129     {
2130         int i;
2131         cvTsZero( avg );
2132
2133         for( i = 0; i < count; i++ )
2134         {
2135             CvMat stub, *vec = 0;
2136             if( flags & CV_COVAR_ROWS )
2137                 vec = cvGetRow( temp_hdrs[0], &stub, i );
2138             else if( flags & CV_COVAR_COLS )
2139                 vec = cvGetCol( temp_hdrs[0], &stub, i );
2140             else
2141                 vec = cvGetMat( temp_hdrs[i], &stub );
2142
2143             cvTsAdd( avg, cvScalarAll(1.), vec,
2144                      cvScalarAll(1.), cvScalarAll(0.), avg, 0 );
2145         }
2146
2147         cvTsAdd( avg, cvScalarAll(1./count), 0,
2148                  cvScalarAll(0.), cvScalarAll(0.), avg, 0 );
2149     }
2150
2151     if( flags & CV_COVAR_SCALE )
2152     {
2153         scale = 1./count;
2154     }
2155
2156     cvRepeat( avg, &test_mat[TEMP][0] );
2157     cvTsAdd( &test_mat[INPUT][0], cvScalarAll(1.),
2158              &test_mat[TEMP][0], cvScalarAll(-1.),
2159              cvScalarAll(0.), &test_mat[TEMP][0], 0 );
2160
2161     cvTsGEMM( &test_mat[TEMP][0], &test_mat[TEMP][0],
2162               scale, 0, 0., &test_mat[REF_OUTPUT][0],
2163               t_flag ^ ((flags & CV_COVAR_NORMAL) != 0) ?
2164               CV_GEMM_A_T : CV_GEMM_B_T );
2165
2166     cvFree( &hdr_data );
2167     temp_hdrs.clear();
2168 }
2169
2170 CxCore_CovarMatrixTest covarmatrix_test;
2171
2172
2173 static void cvTsFloodWithZeros( CvMat* mat, CvRNG* rng )
2174 {
2175     int k, total = mat->rows*mat->cols;
2176     int zero_total = cvTsRandInt(rng) % total;
2177     assert( CV_MAT_TYPE(mat->type) == CV_32FC1 ||
2178             CV_MAT_TYPE(mat->type) == CV_64FC1 );
2179
2180     for( k = 0; k < zero_total; k++ )
2181     {
2182         int i = cvTsRandInt(rng) % mat->rows;
2183         int j = cvTsRandInt(rng) % mat->cols;
2184         uchar* row = mat->data.ptr + mat->step*i;
2185
2186         if( CV_MAT_DEPTH(mat->type) == CV_32FC1 )
2187             ((float*)row)[j] = 0.f;
2188         else
2189             ((double*)row)[j] = 0.;
2190     }
2191 }
2192
2193
2194 ///////////////// determinant /////////////////////
2195
2196 class CxCore_DetTest : public CxCore_MatrixTest
2197 {
2198 public:
2199     CxCore_DetTest();
2200 protected:
2201     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
2202     double get_success_error_level( int test_case_idx, int i, int j );
2203     void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high );
2204     int prepare_test_case( int test_case_idx );
2205     void run_func();
2206     void prepare_to_validation( int test_case_idx );
2207 };
2208
2209
2210 CxCore_DetTest::CxCore_DetTest() :
2211     CxCore_MatrixTest( "matrix-det", "cvDet", 1, 1, false, true, 1 )
2212 {
2213     test_case_count = 100;
2214     max_log_array_size = 7;
2215     test_array[TEMP].push(NULL);
2216 }
2217
2218
2219 void CxCore_DetTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
2220 {
2221     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2222
2223     sizes[INPUT][0].width = sizes[INPUT][0].height = sizes[INPUT][0].height;
2224     sizes[TEMP][0] = sizes[INPUT][0];
2225     types[TEMP][0] = CV_64FC1;
2226 }
2227
2228
2229 void CxCore_DetTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
2230 {
2231     *low = cvScalarAll(-2.);
2232     *high = cvScalarAll(2.);
2233 }
2234
2235
2236 double CxCore_DetTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
2237 {
2238     return CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0])) == CV_32F ? 1e-2 : 1e-5;
2239 }
2240
2241
2242 int CxCore_DetTest::prepare_test_case( int test_case_idx )
2243 {
2244     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
2245     if( code > 0 )
2246         cvTsFloodWithZeros( &test_mat[INPUT][0], ts->get_rng() );
2247
2248     return code;
2249 }
2250
2251
2252 void CxCore_DetTest::run_func()
2253 {
2254     *((CvScalar*)(test_mat[OUTPUT][0].data.db)) = cvRealScalar(cvDet(test_array[INPUT][0]));
2255 }
2256
2257
2258 // LU method that chooses the optimal in a column pivot element
2259 static double cvTsLU( CvMat* a, CvMat* b=NULL, CvMat* x=NULL, int* rank=0 )
2260 {
2261     int i, j, k, N = a->rows, N1 = a->cols, Nm = MIN(N, N1), step = a->step/sizeof(double);
2262     int M = b ? b->cols : 0, b_step = b ? b->step/sizeof(double) : 0;
2263     int x_step = x ? x->step/sizeof(double) : 0;
2264     double *a0 = a->data.db, *b0 = b ? b->data.db : 0;
2265     double *x0 = x ? x->data.db : 0;
2266     double t, det = 1.;
2267     assert( CV_MAT_TYPE(a->type) == CV_64FC1 &&
2268             (!b || CV_ARE_TYPES_EQ(a,b)) && (!x || CV_ARE_TYPES_EQ(a,x)));
2269
2270     for( i = 0; i < Nm; i++ )
2271     {
2272         double max_val = fabs(a0[i*step + i]);
2273         double *a1, *a2, *b1 = 0, *b2 = 0;
2274         k = i;
2275
2276         for( j = i+1; j < N; j++ )
2277         {
2278             t = fabs(a0[j*step + i]);
2279             if( max_val < t )
2280             {
2281                 max_val = t;
2282                 k = j;
2283             }
2284         }
2285
2286         if( k != i )
2287         {
2288             for( j = i; j < N1; j++ )
2289                 CV_SWAP( a0[i*step + j], a0[k*step + j], t );
2290
2291             for( j = 0; j < M; j++ )
2292                 CV_SWAP( b0[i*b_step + j], b0[k*b_step + j], t );
2293             det = -det;
2294         }
2295
2296         if( max_val == 0 )
2297         {
2298             if( rank )
2299                 *rank = i;
2300             return 0.;
2301         }
2302
2303         a1 = a0 + i*step;
2304         a2 = a1 + step;
2305         b1 = b0 + i*b_step;
2306         b2 = b1 + b_step;
2307
2308         for( j = i+1; j < N; j++, a2 += step, b2 += b_step )
2309         {
2310             t = a2[i]/a1[i];
2311             for( k = i+1; k < N1; k++ )
2312                 a2[k] -= t*a1[k];
2313
2314             for( k = 0; k < M; k++ )
2315                 b2[k] -= t*b1[k];
2316         }
2317
2318         det *= a1[i];
2319     }
2320
2321     if( x )
2322     {
2323         assert( b );
2324
2325         for( i = N-1; i >= 0; i-- )
2326         {
2327             double* a1 = a0 + i*step;
2328             double* b1 = b0 + i*b_step;
2329             for( j = 0; j < M; j++ )
2330             {
2331                 t = b1[j];
2332                 for( k = i+1; k < N1; k++ )
2333                     t -= a1[k]*x0[k*x_step + j];
2334                 x0[i*x_step + j] = t/a1[i];
2335             }
2336         }
2337     }
2338
2339     if( rank )
2340         *rank = i;
2341     return det;
2342 }
2343
2344
2345 void CxCore_DetTest::prepare_to_validation( int )
2346 {
2347     if( !CV_ARE_TYPES_EQ( &test_mat[INPUT][0], &test_mat[TEMP][0] ))
2348         cvTsConvert( &test_mat[INPUT][0], &test_mat[TEMP][0] );
2349     else
2350         cvTsCopy( &test_mat[INPUT][0], &test_mat[TEMP][0], 0 );
2351
2352     *((CvScalar*)(test_mat[REF_OUTPUT][0].data.db)) = cvRealScalar(cvTsLU(&test_mat[TEMP][0], 0, 0));
2353 }
2354
2355 CxCore_DetTest det_test;
2356
2357
2358
2359 ///////////////// invert /////////////////////
2360
2361 static const char* matrix_solve_invert_param_names[] = { "size", "method", "depth", 0 };
2362 static const char* matrix_solve_invert_methods[] = { "LU", "SVD", 0 };
2363
2364 class CxCore_InvertTest : public CxCore_MatrixTest
2365 {
2366 public:
2367     CxCore_InvertTest();
2368 protected:
2369     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
2370     void get_timing_test_array_types_and_sizes( int test_case_idx,
2371                                                 CvSize** sizes, int** types,
2372                                                 CvSize** whole_sizes, bool* are_images );
2373     int write_default_params( CvFileStorage* fs );
2374     void print_timing_params( int test_case_idx, char* ptr, int params_left );
2375     void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high );
2376     double get_success_error_level( int test_case_idx, int i, int j );
2377     int prepare_test_case( int test_case_idx );
2378     void run_func();
2379     void prepare_to_validation( int test_case_idx );
2380     int method, rank;
2381     double result;
2382 };
2383
2384
2385 CxCore_InvertTest::CxCore_InvertTest() :
2386     CxCore_MatrixTest( "matrix-invert", "cvInvert, cvSVD, cvSVBkSb", 1, 1, false, false, 1 ), method(0), rank(0), result(0.)
2387 {
2388     test_case_count = 100;
2389     max_log_array_size = 7;
2390     test_array[TEMP].push(NULL);
2391     test_array[TEMP].push(NULL);
2392
2393     default_timing_param_names = matrix_solve_invert_param_names;
2394 }
2395
2396
2397 void CxCore_InvertTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
2398 {
2399     CvRNG* rng = ts->get_rng();
2400     int bits = cvTsRandInt(rng);
2401     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2402     int min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
2403
2404     if( (bits & 3) == 0 )
2405     {
2406         method = CV_SVD;
2407         if( bits & 4 )
2408         {
2409             sizes[INPUT][0] = cvSize(min_size, min_size);
2410             if( bits & 8 )
2411                 method = CV_SVD_SYM;
2412         }
2413     }
2414     else
2415     {
2416         method = CV_LU;
2417         sizes[INPUT][0] = cvSize(min_size, min_size);
2418     }
2419
2420     sizes[TEMP][0].width = sizes[INPUT][0].height;
2421     sizes[TEMP][0].height = sizes[INPUT][0].width;
2422     sizes[TEMP][1] = sizes[INPUT][0];
2423     types[TEMP][0] = types[INPUT][0];
2424     types[TEMP][1] = CV_64FC1;
2425     sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(min_size, min_size);
2426 }
2427
2428
2429 void CxCore_InvertTest::get_timing_test_array_types_and_sizes( int test_case_idx,
2430                                                     CvSize** sizes, int** types,
2431                                                     CvSize** whole_sizes, bool* are_images )
2432 {
2433     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
2434                                     sizes, types, whole_sizes, are_images );
2435     const char* method_str = cvReadString( find_timing_param("method"), "LU" );
2436     method = strcmp( method_str, "LU" ) == 0 ? CV_LU : CV_SVD;
2437 }
2438
2439
2440 int CxCore_InvertTest::write_default_params( CvFileStorage* fs )
2441 {
2442     int code = CxCore_MatrixTest::write_default_params(fs);
2443     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
2444         return code;
2445     write_string_list( fs, "method", matrix_solve_invert_methods );
2446     return code;
2447 }
2448
2449
2450 void CxCore_InvertTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
2451 {
2452     sprintf( ptr, "%s,", method == CV_LU ? "LU" : "SVD" );
2453     ptr += strlen(ptr);
2454     params_left--;
2455     CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left );
2456 }
2457
2458
2459 double CxCore_InvertTest::get_success_error_level( int /*test_case_idx*/, int, int )
2460 {
2461     return CV_MAT_DEPTH(cvGetElemType(test_array[OUTPUT][0])) == CV_32F ? 1e-2 : 1e-7;
2462 }
2463
2464 int CxCore_InvertTest::prepare_test_case( int test_case_idx )
2465 {
2466     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
2467     if( code > 0 )
2468     {
2469         cvTsFloodWithZeros( &test_mat[INPUT][0], ts->get_rng() );
2470
2471         if( method == CV_SVD_SYM )
2472         {
2473             cvTsGEMM( &test_mat[INPUT][0], &test_mat[INPUT][0], 1.,
2474                       0, 0., &test_mat[TEMP][0], CV_GEMM_B_T );
2475             cvTsCopy( &test_mat[TEMP][0], &test_mat[INPUT][0] );
2476         }
2477     }
2478
2479     return code;
2480 }
2481
2482
2483
2484 void CxCore_InvertTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
2485 {
2486     *low = cvScalarAll(-2.);
2487     *high = cvScalarAll(2.);
2488 }
2489
2490
2491 void CxCore_InvertTest::run_func()
2492 {
2493     result = cvInvert(test_array[INPUT][0], test_array[TEMP][0], method);
2494 }
2495
2496
2497 static double cvTsSVDet( CvMat* mat )
2498 {
2499     int type = CV_MAT_TYPE(mat->type);
2500     int i, nm = MIN( mat->rows, mat->cols );
2501     CvMat* w = cvCreateMat( nm, 1, type );
2502     double det = 1.;
2503
2504     cvSVD( mat, w, 0, 0, 0 );
2505
2506     if( type == CV_32FC1 )
2507     {
2508         for( i = 0; i < nm; i++ )
2509             det *= w->data.fl[i];
2510     }
2511     else
2512     {
2513         for( i = 0; i < nm; i++ )
2514             det *= w->data.db[i];
2515     }
2516
2517     cvReleaseMat( &w );
2518     return det;
2519 }
2520
2521 void CxCore_InvertTest::prepare_to_validation( int )
2522 {
2523     CvMat* input = &test_mat[INPUT][0];
2524     double det = cvTsSVDet( input );
2525     double threshold = (CV_MAT_DEPTH(input->type) == CV_32F ? FLT_EPSILON : DBL_EPSILON)*500;
2526
2527     if( CV_MAT_TYPE(input->type) == CV_32FC1 )
2528         cvTsConvert( input, &test_mat[TEMP][1] );
2529     else
2530         cvTsCopy( input, &test_mat[TEMP][1], 0 );
2531
2532     if( (method == CV_LU && result == 0) ||
2533         (det < threshold || result < threshold) )
2534     {
2535         cvTsZero( &test_mat[OUTPUT][0] );
2536         cvTsZero( &test_mat[REF_OUTPUT][0] );
2537         //cvTsAdd( 0, cvScalarAll(0.), 0, cvScalarAll(0.), cvScalarAll(fabs(det)>1e-3),
2538         //         &test_mat[REF_OUTPUT][0], 0 );
2539         return;
2540     }
2541
2542     if( input->rows >= input->cols )
2543         cvTsGEMM( &test_mat[TEMP][0], input, 1., 0, 0., &test_mat[OUTPUT][0], 0 );
2544     else
2545         cvTsGEMM( input, &test_mat[TEMP][0], 1., 0, 0., &test_mat[OUTPUT][0], 0 );
2546
2547     cvTsSetIdentity( &test_mat[REF_OUTPUT][0], cvScalarAll(1.) );
2548 }
2549
2550 CxCore_InvertTest invert_test;
2551
2552
2553 ///////////////// solve /////////////////////
2554
2555 class CxCore_SolveTest : public CxCore_MatrixTest
2556 {
2557 public:
2558     CxCore_SolveTest();
2559 protected:
2560     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
2561     void get_timing_test_array_types_and_sizes( int test_case_idx,
2562                                                 CvSize** sizes, int** types,
2563                                                 CvSize** whole_sizes, bool* are_images );
2564     int write_default_params( CvFileStorage* fs );
2565     void print_timing_params( int test_case_idx, char* ptr, int params_left );
2566     void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high );
2567     double get_success_error_level( int test_case_idx, int i, int j );
2568     int prepare_test_case( int test_case_idx );
2569     void run_func();
2570     void prepare_to_validation( int test_case_idx );
2571     int method, rank;
2572     double result;
2573 };
2574
2575
2576 CxCore_SolveTest::CxCore_SolveTest() :
2577     CxCore_MatrixTest( "matrix-solve", "cvSolve, cvSVD, cvSVBkSb", 2, 1, false, false, 1 ), method(0), rank(0), result(0.)
2578 {
2579     test_case_count = 100;
2580     max_log_array_size = 7;
2581     test_array[TEMP].push(NULL);
2582     test_array[TEMP].push(NULL);
2583
2584     default_timing_param_names = matrix_solve_invert_param_names;
2585 }
2586
2587
2588 void CxCore_SolveTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
2589 {
2590     CvRNG* rng = ts->get_rng();
2591     int bits = cvTsRandInt(rng);
2592     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2593     CvSize in_sz = sizes[INPUT][0];
2594     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2595     sizes[INPUT][0] = in_sz;
2596     int min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
2597
2598     if( (bits & 3) == 0 )
2599     {
2600         method = CV_SVD;
2601         if( bits & 4 )
2602         {
2603             sizes[INPUT][0] = cvSize(min_size, min_size);
2604             /*if( bits & 8 )
2605                 method = CV_SVD_SYM;*/
2606         }
2607     }
2608     else
2609     {
2610         method = CV_LU;
2611         sizes[INPUT][0] = cvSize(min_size, min_size);
2612     }
2613
2614     sizes[INPUT][1].height = sizes[INPUT][0].height;
2615     sizes[TEMP][0].width = sizes[INPUT][1].width;
2616     sizes[TEMP][0].height = sizes[INPUT][0].width;
2617     sizes[TEMP][1] = sizes[INPUT][0];
2618     types[TEMP][0] = types[INPUT][0];
2619     types[TEMP][1] = CV_64FC1;
2620     sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(sizes[INPUT][1].width, min_size);
2621 }
2622
2623 void CxCore_SolveTest::get_timing_test_array_types_and_sizes( int test_case_idx,
2624                                                     CvSize** sizes, int** types,
2625                                                     CvSize** whole_sizes, bool* are_images )
2626 {
2627     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
2628                                     sizes, types, whole_sizes, are_images );
2629     const char* method_str = cvReadString( find_timing_param("method"), "LU" );
2630     sizes[INPUT][1].width = sizes[TEMP][0].width = sizes[OUTPUT][0].width = sizes[REF_OUTPUT][0].width = 1;
2631     method = strcmp( method_str, "LU" ) == 0 ? CV_LU : CV_SVD;
2632 }
2633
2634
2635 int CxCore_SolveTest::write_default_params( CvFileStorage* fs )
2636 {
2637     int code = CxCore_MatrixTest::write_default_params(fs);
2638     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
2639         return code;
2640     write_string_list( fs, "method", matrix_solve_invert_methods );
2641     return code;
2642 }
2643
2644
2645 void CxCore_SolveTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
2646 {
2647     sprintf( ptr, "%s,", method == CV_LU ? "LU" : "SVD" );
2648     ptr += strlen(ptr);
2649     params_left--;
2650     CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left );
2651 }
2652
2653
2654 int CxCore_SolveTest::prepare_test_case( int test_case_idx )
2655 {
2656     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
2657
2658     /*if( method == CV_SVD_SYM )
2659     {
2660         cvTsGEMM( test_array[INPUT][0], test_array[INPUT][0], 1.,
2661                   0, 0., test_array[TEMP][0], CV_GEMM_B_T );
2662         cvTsCopy( test_array[TEMP][0], test_array[INPUT][0] );
2663     }*/
2664
2665     return code;
2666 }
2667
2668
2669 void CxCore_SolveTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
2670 {
2671     *low = cvScalarAll(-2.);
2672     *high = cvScalarAll(2.);
2673 }
2674
2675
2676 double CxCore_SolveTest::get_success_error_level( int /*test_case_idx*/, int, int )
2677 {
2678     return CV_MAT_DEPTH(cvGetElemType(test_array[OUTPUT][0])) == CV_32F ? 3e-2 : 1e-8;
2679 }
2680
2681
2682 void CxCore_SolveTest::run_func()
2683 {
2684     result = cvSolve(test_array[INPUT][0], test_array[INPUT][1], test_array[TEMP][0], method);
2685 }
2686
2687 void CxCore_SolveTest::prepare_to_validation( int )
2688 {
2689     //int rank = test_mat[REF_OUTPUT][0].rows;
2690     CvMat* dst;
2691
2692     if( method == CV_LU && result == 0 )
2693     {
2694         if( CV_MAT_TYPE(test_mat[INPUT][0].type) == CV_32FC1 )
2695             cvTsConvert( &test_mat[INPUT][0], &test_mat[TEMP][1] );
2696         else
2697             cvTsCopy( &test_mat[INPUT][0], &test_mat[TEMP][1], 0 );
2698
2699         cvTsZero( &test_mat[OUTPUT][0] );
2700         double det = cvTsLU( &test_mat[TEMP][1], 0, 0 );
2701         cvTsAdd( 0, cvScalarAll(0.), 0, cvScalarAll(0.), cvScalarAll(det != 0),
2702                  &test_mat[REF_OUTPUT][0], 0 );
2703         return;
2704     }
2705
2706     dst = test_mat[INPUT][0].rows <= test_mat[INPUT][0].cols ? &test_mat[OUTPUT][0] : &test_mat[INPUT][1];
2707
2708     cvTsGEMM( &test_mat[INPUT][0], &test_mat[TEMP][0], 1., &test_mat[INPUT][1], -1., dst, 0 );
2709     if( dst != &test_mat[OUTPUT][0] )
2710         cvTsGEMM( &test_mat[INPUT][0], dst, 1., 0, 0., &test_mat[OUTPUT][0], CV_GEMM_A_T );
2711     cvTsZero( &test_mat[REF_OUTPUT][0] );
2712 }
2713
2714 CxCore_SolveTest solve_test;
2715
2716
2717 ///////////////// SVD /////////////////////
2718
2719 static const char* matrix_svd_param_names[] = { "size", "output", "depth", 0 };
2720 static const char* matrix_svd_output_modes[] = { "w", "all", 0 };
2721
2722 class CxCore_SVDTest : public CxCore_MatrixTest
2723 {
2724 public:
2725     CxCore_SVDTest();
2726 protected:
2727     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
2728     void get_timing_test_array_types_and_sizes( int test_case_idx,
2729                                                 CvSize** sizes, int** types,
2730                                                 CvSize** whole_sizes, bool* are_images );
2731     double get_success_error_level( int test_case_idx, int i, int j );
2732     int write_default_params( CvFileStorage* fs );
2733     void print_timing_params( int test_case_idx, char* ptr, int params_left );
2734     void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high );
2735     int prepare_test_case( int test_case_idx );
2736     void run_func();
2737     void prepare_to_validation( int test_case_idx );
2738     int flags;
2739     bool have_u, have_v, symmetric, compact, vector_w;
2740 };
2741
2742
2743 CxCore_SVDTest::CxCore_SVDTest() :
2744     CxCore_MatrixTest( "matrix-svd", "cvSVD", 1, 4, false, false, 1 ),
2745         flags(0), have_u(false), have_v(false), symmetric(false), compact(false), vector_w(false)
2746 {
2747     test_case_count = 100;
2748     test_array[TEMP].push(NULL);
2749     test_array[TEMP].push(NULL);
2750     test_array[TEMP].push(NULL);
2751     test_array[TEMP].push(NULL);
2752
2753     default_timing_param_names = matrix_svd_param_names;
2754 }
2755
2756
2757 void CxCore_SVDTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
2758 {
2759     CvRNG* rng = ts->get_rng();
2760     int bits = cvTsRandInt(rng);
2761     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
2762     int min_size, i, m, n;
2763
2764     min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
2765
2766     flags = bits & (CV_SVD_MODIFY_A+CV_SVD_U_T+CV_SVD_V_T);
2767     have_u = (bits & 8) != 0;
2768     have_v = (bits & 16) != 0;
2769     symmetric = (bits & 32) != 0;
2770     compact = (bits & 64) != 0;
2771     vector_w = (bits & 128) != 0;
2772
2773     if( symmetric )
2774         sizes[INPUT][0] = cvSize(min_size, min_size);
2775
2776     m = sizes[INPUT][0].height;
2777     n = sizes[INPUT][0].width;
2778
2779     if( compact )
2780         sizes[TEMP][0] = cvSize(min_size, min_size);
2781     else
2782         sizes[TEMP][0] = sizes[INPUT][0];
2783     sizes[TEMP][3] = cvSize(0,0);
2784
2785     if( vector_w )
2786     {
2787         sizes[TEMP][3] = sizes[TEMP][0];
2788         if( bits & 256 )
2789             sizes[TEMP][0] = cvSize(1, min_size);
2790         else
2791             sizes[TEMP][0] = cvSize(min_size, 1);
2792     }
2793
2794     if( have_u )
2795     {
2796         sizes[TEMP][1] = compact ? cvSize(min_size, m) : cvSize(m, m);
2797
2798         if( flags & CV_SVD_U_T )
2799             CV_SWAP( sizes[TEMP][1].width, sizes[TEMP][1].height, i );
2800     }
2801     else
2802         sizes[TEMP][1] = cvSize(0,0);
2803
2804     if( have_v )
2805     {
2806         sizes[TEMP][2] = compact ? cvSize(n, min_size) : cvSize(n, n);
2807
2808         if( !(flags & CV_SVD_V_T) )
2809             CV_SWAP( sizes[TEMP][2].width, sizes[TEMP][2].height, i );
2810     }
2811     else
2812         sizes[TEMP][2] = cvSize(0,0);
2813
2814     types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[TEMP][3] = types[INPUT][0];
2815     types[OUTPUT][0] = types[OUTPUT][1] = types[OUTPUT][2] = types[INPUT][0];
2816     types[OUTPUT][3] = CV_8UC1;
2817     sizes[OUTPUT][0] = !have_u || !have_v ? cvSize(0,0) : sizes[INPUT][0];
2818     sizes[OUTPUT][1] = !have_u ? cvSize(0,0) : compact ? cvSize(min_size,min_size) : cvSize(m,m);
2819     sizes[OUTPUT][2] = !have_v ? cvSize(0,0) : compact ? cvSize(min_size,min_size) : cvSize(n,n);
2820     sizes[OUTPUT][3] = cvSize(min_size,1);
2821
2822     for( i = 0; i < 4; i++ )
2823     {
2824         sizes[REF_OUTPUT][i] = sizes[OUTPUT][i];
2825         types[REF_OUTPUT][i] = types[OUTPUT][i];
2826     }
2827 }
2828
2829
2830 void CxCore_SVDTest::get_timing_test_array_types_and_sizes( int test_case_idx,
2831                                                     CvSize** sizes, int** types,
2832                                                     CvSize** whole_sizes, bool* are_images )
2833 {
2834     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
2835                                     sizes, types, whole_sizes, are_images );
2836     const char* output_str = cvReadString( find_timing_param("output"), "all" );
2837     bool need_all = strcmp( output_str, "all" ) == 0;
2838     int i, count = test_array[OUTPUT].size();
2839     vector_w = true;
2840     symmetric = false;
2841     compact = true;
2842     sizes[TEMP][0] = cvSize(1,sizes[INPUT][0].height);
2843     if( need_all )
2844     {
2845         have_u = have_v = true;
2846     }
2847     else
2848     {
2849         have_u = have_v = false;
2850         sizes[TEMP][1] = sizes[TEMP][2] = cvSize(0,0);
2851     }
2852
2853     flags = CV_SVD_U_T + CV_SVD_V_T;
2854     for( i = 0; i < count; i++ )
2855         sizes[OUTPUT][i] = sizes[REF_OUTPUT][i] = cvSize(0,0);
2856     sizes[OUTPUT][0] = cvSize(1,1);
2857 }
2858
2859
2860 int CxCore_SVDTest::write_default_params( CvFileStorage* fs )
2861 {
2862     int code = CxCore_MatrixTest::write_default_params(fs);
2863     if( code < 0 || ts->get_testing_mode() != CvTS::TIMING_MODE )
2864         return code;
2865     write_string_list( fs, "output", matrix_svd_output_modes );
2866     return code;
2867 }
2868
2869
2870 void CxCore_SVDTest::print_timing_params( int test_case_idx, char* ptr, int params_left )
2871 {
2872     sprintf( ptr, "%s,", have_u ? "all" : "w" );
2873     ptr += strlen(ptr);
2874     params_left--;
2875     CxCore_MatrixTest::print_timing_params( test_case_idx, ptr, params_left );
2876 }
2877
2878
2879 int CxCore_SVDTest::prepare_test_case( int test_case_idx )
2880 {
2881     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
2882     if( code > 0 )
2883     {
2884         CvMat* input = &test_mat[INPUT][0];
2885         cvTsFloodWithZeros( input, ts->get_rng() );
2886
2887         if( symmetric && (have_u || have_v) )
2888         {
2889             CvMat* temp = &test_mat[TEMP][have_u ? 1 : 2];
2890             cvTsGEMM( input, input, 1.,
2891                       0, 0., temp, CV_GEMM_B_T );
2892             cvTsCopy( temp, input );
2893         }
2894
2895         if( (flags & CV_SVD_MODIFY_A) && test_array[OUTPUT][0] )
2896             cvTsCopy( input, &test_mat[OUTPUT][0] );
2897     }
2898
2899     return code;
2900 }
2901
2902
2903 void CxCore_SVDTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
2904 {
2905     *low = cvScalarAll(-2.);
2906     *high = cvScalarAll(2.);
2907 }
2908
2909 double CxCore_SVDTest::get_success_error_level( int test_case_idx, int i, int j )
2910 {
2911     int input_depth = CV_MAT_DEPTH(cvGetElemType( test_array[INPUT][0] ));
2912     double input_precision = input_depth < CV_32F ? 0 : input_depth == CV_32F ?
2913                             5e-5 : 5e-11;
2914     double output_precision = CvArrTest::get_success_error_level( test_case_idx, i, j );
2915     return MAX(input_precision, output_precision);
2916 }
2917
2918 void CxCore_SVDTest::run_func()
2919 {
2920     CvArr* src = test_array[!(flags & CV_SVD_MODIFY_A) ? INPUT : OUTPUT][0];
2921     if( !src )
2922         src = test_array[INPUT][0];
2923     cvSVD( src, test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], flags );
2924 }
2925
2926
2927 void CxCore_SVDTest::prepare_to_validation( int )
2928 {
2929     CvMat* input = &test_mat[INPUT][0];
2930     int m = input->rows, n = input->cols, min_size = MIN(m, n);
2931     CvMat *src, *dst, *w;
2932     double prev = 0, threshold = CV_MAT_TYPE(input->type) == CV_32FC1 ? FLT_EPSILON : DBL_EPSILON;
2933     int i, j = 0, step;
2934
2935     if( have_u )
2936     {
2937         src = &test_mat[TEMP][1];
2938         dst = &test_mat[OUTPUT][1];
2939         cvTsGEMM( src, src, 1., 0, 0., dst, src->rows == dst->rows ? CV_GEMM_B_T : CV_GEMM_A_T );
2940         cvTsSetIdentity( &test_mat[REF_OUTPUT][1], cvScalarAll(1.) );
2941     }
2942
2943     if( have_v )
2944     {
2945         src = &test_mat[TEMP][2];
2946         dst = &test_mat[OUTPUT][2];
2947         cvTsGEMM( src, src, 1., 0, 0., dst, src->rows == dst->rows ? CV_GEMM_B_T : CV_GEMM_A_T );
2948         cvTsSetIdentity( &test_mat[REF_OUTPUT][2], cvScalarAll(1.) );
2949     }
2950
2951     w = &test_mat[TEMP][0];
2952     step = w->rows == 1 ? 1 : w->step/CV_ELEM_SIZE(w->type);
2953     for( i = 0; i < min_size; i++ )
2954     {
2955         double norm = 0, aii;
2956         uchar* row_ptr;
2957         if( w->rows > 1 && w->cols > 1 )
2958         {
2959             CvMat row;
2960             cvGetRow( w, &row, i );
2961             norm = cvNorm( &row, 0, CV_L1 );
2962             j = i;
2963             row_ptr = row.data.ptr;
2964         }
2965         else
2966         {
2967             row_ptr = w->data.ptr;
2968             j = i*step;
2969         }
2970
2971         aii = CV_MAT_TYPE(w->type) == CV_32FC1 ?
2972             (double)((float*)row_ptr)[j] : ((double*)row_ptr)[j];
2973         if( w->rows == 1 || w->cols == 1 )
2974             norm = aii;
2975         norm = fabs(norm - aii);
2976         test_mat[OUTPUT][3].data.ptr[i] = aii >= 0 && norm < threshold && (i == 0 || aii <= prev);
2977         prev = aii;
2978     }
2979
2980     cvTsAdd( 0, cvScalarAll(0.), 0, cvScalarAll(0.),
2981              cvScalarAll(1.), &test_mat[REF_OUTPUT][3], 0 );
2982
2983     if( have_u && have_v )
2984     {
2985         if( vector_w )
2986         {
2987             cvTsZero( &test_mat[TEMP][3] );
2988             for( i = 0; i < min_size; i++ )
2989             {
2990                 double val = cvGetReal1D( w, i );
2991                 cvSetReal2D( &test_mat[TEMP][3], i, i, val );
2992             }
2993             w = &test_mat[TEMP][3];
2994         }
2995
2996         if( m >= n )
2997         {
2998             cvTsGEMM( &test_mat[TEMP][1], w, 1., 0, 0., &test_mat[REF_OUTPUT][0],
2999                       flags & CV_SVD_U_T ? CV_GEMM_A_T : 0 );
3000             cvTsGEMM( &test_mat[REF_OUTPUT][0], &test_mat[TEMP][2], 1., 0, 0.,
3001                       &test_mat[OUTPUT][0], flags & CV_SVD_V_T ? 0 : CV_GEMM_B_T );
3002         }
3003         else
3004         {
3005             cvTsGEMM( w, &test_mat[TEMP][2], 1., 0, 0., &test_mat[REF_OUTPUT][0],
3006                       flags & CV_SVD_V_T ? 0 : CV_GEMM_B_T );
3007             cvTsGEMM( &test_mat[TEMP][1], &test_mat[REF_OUTPUT][0], 1., 0, 0.,
3008                       &test_mat[OUTPUT][0], flags & CV_SVD_U_T ? CV_GEMM_A_T : 0 );
3009         }
3010
3011         cvTsCopy( &test_mat[INPUT][0], &test_mat[REF_OUTPUT][0], 0 );
3012     }
3013 }
3014
3015
3016 CxCore_SVDTest svd_test;
3017
3018
3019 ///////////////// SVBkSb /////////////////////
3020
3021 class CxCore_SVBkSbTest : public CxCore_MatrixTest
3022 {
3023 public:
3024     CxCore_SVBkSbTest();
3025 protected:
3026     void get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types );
3027     void get_timing_test_array_types_and_sizes( int test_case_idx,
3028                                                 CvSize** sizes, int** types,
3029                                                 CvSize** whole_sizes, bool* are_images );
3030     double get_success_error_level( int test_case_idx, int i, int j );
3031     void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high );
3032     int prepare_test_case( int test_case_idx );
3033     void run_func();
3034     void prepare_to_validation( int test_case_idx );
3035     int flags;
3036     bool have_b, symmetric, compact, vector_w;
3037 };
3038
3039
3040 CxCore_SVBkSbTest::CxCore_SVBkSbTest() :
3041     CxCore_MatrixTest( "matrix-svbksb", "cvSVBkSb", 2, 1, false, false, 1 ),
3042         flags(0), have_b(false), symmetric(false), compact(false), vector_w(false)
3043 {
3044     test_case_count = 100;
3045     test_array[TEMP].push(NULL);
3046     test_array[TEMP].push(NULL);
3047     test_array[TEMP].push(NULL);
3048 }
3049
3050
3051 void CxCore_SVBkSbTest::get_test_array_types_and_sizes( int test_case_idx, CvSize** sizes, int** types )
3052 {
3053     CvRNG* rng = ts->get_rng();
3054     int bits = cvTsRandInt(rng);
3055     CxCore_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
3056     int min_size, i, m, n;
3057     CvSize b_size;
3058
3059     min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
3060
3061     flags = bits & (CV_SVD_MODIFY_A+CV_SVD_U_T+CV_SVD_V_T);
3062     have_b = (bits & 16) != 0;
3063     symmetric = (bits & 32) != 0;
3064     compact = (bits & 64) != 0;
3065     vector_w = (bits & 128) != 0;
3066
3067     if( symmetric )
3068         sizes[INPUT][0] = cvSize(min_size, min_size);
3069
3070     m = sizes[INPUT][0].height;
3071     n = sizes[INPUT][0].width;
3072
3073     sizes[INPUT][1] = cvSize(0,0);
3074     b_size = cvSize(m,m);
3075     if( have_b )
3076     {
3077         sizes[INPUT][1].height = sizes[INPUT][0].height;
3078         sizes[INPUT][1].width = cvTsRandInt(rng) % 100 + 1;
3079         b_size = sizes[INPUT][1];
3080     }
3081
3082     if( compact )
3083         sizes[TEMP][0] = cvSize(min_size, min_size);
3084     else
3085         sizes[TEMP][0] = sizes[INPUT][0];
3086
3087     if( vector_w )
3088     {
3089         if( bits & 256 )
3090             sizes[TEMP][0] = cvSize(1, min_size);
3091         else
3092             sizes[TEMP][0] = cvSize(min_size, 1);
3093     }
3094
3095     sizes[TEMP][1] = compact ? cvSize(min_size, m) : cvSize(m, m);
3096
3097     if( flags & CV_SVD_U_T )
3098         CV_SWAP( sizes[TEMP][1].width, sizes[TEMP][1].height, i );
3099
3100     sizes[TEMP][2] = compact ? cvSize(n, min_size) : cvSize(n, n);
3101
3102     if( !(flags & CV_SVD_V_T) )
3103         CV_SWAP( sizes[TEMP][2].width, sizes[TEMP][2].height, i );
3104
3105     types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[INPUT][0];
3106     types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][0];
3107     sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize( b_size.width, n );
3108 }
3109
3110
3111 void CxCore_SVBkSbTest::get_timing_test_array_types_and_sizes( int test_case_idx,
3112                                                     CvSize** sizes, int** types,
3113                                                     CvSize** whole_sizes, bool* are_images )
3114 {
3115     CxCore_MatrixTest::get_timing_test_array_types_and_sizes( test_case_idx,
3116                                     sizes, types, whole_sizes, are_images );
3117     have_b = true;
3118     vector_w = true;
3119     compact = true;
3120     sizes[TEMP][0] = cvSize(1,sizes[INPUT][0].height);
3121     sizes[INPUT][1] = sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(1,sizes[INPUT][0].height);
3122     flags = CV_SVD_U_T + CV_SVD_V_T;
3123 }
3124
3125
3126 int CxCore_SVBkSbTest::prepare_test_case( int test_case_idx )
3127 {
3128     int code = CxCore_MatrixTest::prepare_test_case( test_case_idx );
3129     if( code > 0 )
3130     {
3131         CvMat* input = &test_mat[INPUT][0];
3132         cvTsFloodWithZeros( input, ts->get_rng() );
3133
3134         if( symmetric )
3135         {
3136             CvMat* temp = &test_mat[TEMP][1];
3137             cvTsGEMM( input, input, 1., 0, 0., temp, CV_GEMM_B_T );
3138             cvTsCopy( temp, input );
3139         }
3140
3141         cvSVD( input, test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], flags );
3142     }
3143
3144     return code;
3145 }
3146
3147
3148 void CxCore_SVBkSbTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, CvScalar* low, CvScalar* high )
3149 {
3150     *low = cvScalarAll(-2.);
3151     *high = cvScalarAll(2.);
3152 }
3153
3154
3155 double CxCore_SVBkSbTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
3156 {
3157     return CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0])) == CV_32F ? 1e-3 : 1e-7;
3158 }
3159
3160
3161 void CxCore_SVBkSbTest::run_func()
3162 {
3163     cvSVBkSb( test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2],
3164               test_array[INPUT][1], test_array[OUTPUT][0], flags );
3165 }
3166
3167
3168 void CxCore_SVBkSbTest::prepare_to_validation( int )
3169 {
3170     CvMat* input = &test_mat[INPUT][0];
3171     int i, m = input->rows, n = input->cols, min_size = MIN(m, n), nb;
3172     bool is_float = CV_MAT_DEPTH(input->type) == CV_32F;
3173     CvSize w_size = compact ? cvSize(min_size,min_size) : cvSize(m,n);
3174     CvMat* w = &test_mat[TEMP][0];
3175     CvMat* wdb = cvCreateMat( w_size.height, w_size.width, CV_64FC1 );
3176     // use exactly the same threshold as in icvSVD... ,
3177     // so the changes in the library and here should be synchronized.
3178     double threshold = cvSum( w ).val[0]*2*(is_float ? FLT_EPSILON : DBL_EPSILON);
3179     CvMat *u, *v, *b, *t0, *t1;
3180
3181     cvTsZero(wdb);
3182     for( i = 0; i < min_size; i++ )
3183     {
3184         double wii = vector_w ? cvGetReal1D(w,i) : cvGetReal2D(w,i,i);
3185         cvSetReal2D( wdb, i, i, wii > threshold ? 1./wii : 0. );
3186     }
3187
3188     u = &test_mat[TEMP][1];
3189     v = &test_mat[TEMP][2];
3190     b = 0;
3191     nb = m;
3192
3193     if( test_array[INPUT][1] )
3194     {
3195         b = &test_mat[INPUT][1];
3196         nb = b->cols;
3197     }
3198
3199     if( is_float )
3200     {
3201         u = cvCreateMat( u->rows, u->cols, CV_64F );
3202         cvTsConvert( &test_mat[TEMP][1], u );
3203         if( b )
3204         {
3205             b = cvCreateMat( b->rows, b->cols, CV_64F );
3206             cvTsConvert( &test_mat[INPUT][1], b );
3207         }
3208     }
3209
3210     t0 = cvCreateMat( wdb->cols, nb, CV_64F );
3211
3212     if( b )
3213         cvTsGEMM( u, b, 1., 0, 0., t0, !(flags & CV_SVD_U_T) ? CV_GEMM_A_T : 0 );
3214     else if( flags & CV_SVD_U_T )
3215         cvTsCopy( u, t0 );
3216     else
3217         cvTsTranspose( u, t0 );
3218
3219     if( is_float )
3220     {
3221         cvReleaseMat( &b );
3222
3223         if( !symmetric )
3224         {
3225             cvReleaseMat( &u );
3226             v = cvCreateMat( v->rows, v->cols, CV_64F );
3227         }
3228         else
3229         {
3230             v = u;
3231             u = 0;
3232         }
3233         cvTsConvert( &test_mat[TEMP][2], v );
3234     }
3235
3236     t1 = cvCreateMat( wdb->rows, nb, CV_64F );
3237     cvTsGEMM( wdb, t0, 1, 0, 0, t1, 0 );
3238
3239     if( !is_float || !symmetric )
3240     {
3241         cvReleaseMat( &t0 );
3242         t0 = !is_float ? &test_mat[REF_OUTPUT][0] : cvCreateMat( test_mat[REF_OUTPUT][0].rows, nb, CV_64F );
3243     }
3244
3245     cvTsGEMM( v, t1, 1, 0, 0, t0, flags & CV_SVD_V_T ? CV_GEMM_A_T : 0 );
3246     cvReleaseMat( &t1 );
3247
3248     if( t0 != &test_mat[REF_OUTPUT][0] )
3249     {
3250         cvTsConvert( t0, &test_mat[REF_OUTPUT][0] );
3251         cvReleaseMat( &t0 );
3252     }
3253
3254     if( v != &test_mat[TEMP][2] )
3255         cvReleaseMat( &v );
3256
3257     cvReleaseMat( &wdb );
3258 }
3259
3260
3261 CxCore_SVBkSbTest svbksb_test;
3262
3263
3264 // TODO: eigenvv, invsqrt, cbrt, fastarctan, (round, floor, ceil(?)),
3265
3266 /* End of file. */
3267