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