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