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