@@ -36,6 +36,234 @@ PERF_TEST_P(VectorLength, phase64f, testing::Values(128, 1000, 128*1024, 512*102
3636 SANITY_CHECK (angle, 5e-5 );
3737}
3838
39+ // generates random vectors, performs Gram-Schmidt orthogonalization on them
40+ Mat randomOrtho (int rows, int ftype, RNG& rng)
41+ {
42+ Mat result (rows, rows, ftype);
43+ rng.fill (result, RNG::UNIFORM, cv::Scalar (-1 ), cv::Scalar (1 ));
44+
45+ for (int i = 0 ; i < rows; i++)
46+ {
47+ Mat v = result.row (i);
48+
49+ for (int j = 0 ; j < i; j++)
50+ {
51+ Mat p = result.row (j);
52+ v -= p.dot (v) * p;
53+ }
54+
55+ v = v * (1 . / cv::norm (v));
56+ }
57+
58+ return result;
59+ }
60+
61+ template <typename FType>
62+ Mat buildRandomMat (int rows, int cols, RNG& rng, int rank, bool symmetrical)
63+ {
64+ int mtype = cv::traits::Depth<FType>::value;
65+ Mat u = randomOrtho (rows, mtype, rng);
66+ Mat v = randomOrtho (cols, mtype, rng);
67+ Mat s (rows, cols, mtype, Scalar (0 ));
68+
69+ std::vector<FType> singVals (rank);
70+ rng.fill (singVals, RNG::UNIFORM, Scalar (0 ), Scalar (10 ));
71+ std::sort (singVals.begin (), singVals.end ());
72+ auto singIter = singVals.rbegin ();
73+ for (int i = 0 ; i < rank; i++)
74+ {
75+ s.at <FType>(i, i) = *singIter++;
76+ }
77+
78+ if (symmetrical)
79+ return u * s * u.t ();
80+ else
81+ return u * s * v.t ();
82+ }
83+
84+ Mat buildRandomMat (int rows, int cols, int mtype, RNG& rng, int rank, bool symmetrical)
85+ {
86+ if (mtype == CV_32F)
87+ {
88+ return buildRandomMat<float >(rows, cols, rng, rank, symmetrical);
89+ }
90+ else if (mtype == CV_64F)
91+ {
92+ return buildRandomMat<double >(rows, cols, rng, rank, symmetrical);
93+ }
94+ else
95+ {
96+ CV_Error (cv::Error::StsBadArg, " This type is not supported" );
97+ }
98+ }
99+
100+ CV_ENUM (SolveDecompEnum, DECOMP_LU, DECOMP_SVD, DECOMP_EIG, DECOMP_CHOLESKY, DECOMP_QR)
101+
102+ enum RankMatrixOptions
103+ {
104+ RANK_HALF, RANK_MINUS_1, RANK_FULL
105+ };
106+
107+ CV_ENUM (RankEnum, RANK_HALF, RANK_MINUS_1, RANK_FULL)
108+
109+ enum SolutionsOptions
110+ {
111+ NO_SOLUTIONS, ONE_SOLUTION, MANY_SOLUTIONS
112+ };
113+
114+ CV_ENUM (SolutionsEnum, NO_SOLUTIONS, ONE_SOLUTION, MANY_SOLUTIONS)
115+
116+ typedef perf::TestBaseWithParam<std::tuple<int , RankEnum, MatDepth, SolveDecompEnum, bool , SolutionsEnum>> SolveTest;
117+
118+ PERF_TEST_P (SolveTest, randomMat, ::testing::Combine(
119+ ::testing::Values (31 , 64 , 100 ),
120+ ::testing::Values(RANK_HALF, RANK_MINUS_1, RANK_FULL),
121+ ::testing::Values(CV_32F, CV_64F),
122+ ::testing::Values(DECOMP_LU, DECOMP_SVD, DECOMP_EIG, DECOMP_CHOLESKY, DECOMP_QR),
123+ ::testing::Bool(), // normal
124+ ::testing::Values(NO_SOLUTIONS, ONE_SOLUTION, MANY_SOLUTIONS)
125+ ))
126+ {
127+ auto t = GetParam ();
128+ int size = std::get<0 >(t);
129+ auto rankEnum = std::get<1 >(t);
130+ int mtype = std::get<2 >(t);
131+ int method = std::get<3 >(t);
132+ bool normal = std::get<4 >(t);
133+ auto solutions = std::get<5 >(t);
134+
135+ bool symmetrical = (method == DECOMP_CHOLESKY || method == DECOMP_LU);
136+
137+ if (normal)
138+ {
139+ method |= DECOMP_NORMAL;
140+ }
141+
142+ int rank = size;
143+ switch (rankEnum)
144+ {
145+ case RANK_HALF: rank /= 2 ; break ;
146+ case RANK_MINUS_1: rank -= 1 ; break ;
147+ default : break ;
148+ }
149+
150+ RNG& rng = theRNG ();
151+ Mat A = buildRandomMat (size, size, mtype, rng, rank, symmetrical);
152+ Mat x (size, 1 , mtype);
153+ Mat b (size, 1 , mtype);
154+
155+ switch (solutions)
156+ {
157+ // no solutions, let's make b random
158+ case NO_SOLUTIONS:
159+ {
160+ rng.fill (b, RNG::UNIFORM, Scalar (-1 ), Scalar (1 ));
161+ }
162+ break ;
163+ // exactly 1 solution, let's combine b from A and x
164+ case ONE_SOLUTION:
165+ {
166+ rng.fill (x, RNG::UNIFORM, Scalar (-10 ), Scalar (10 ));
167+ b = A * x;
168+ }
169+ break ;
170+ // infinitely many solutions, let's make b zero
171+ default :
172+ {
173+ b = 0 ;
174+ }
175+ break ;
176+ }
177+
178+ TEST_CYCLE () cv::solve (A, b, x, method);
179+
180+ SANITY_CHECK_NOTHING ();
181+ }
182+
183+ typedef perf::TestBaseWithParam<std::tuple<std::tuple<int , int >, RankEnum, MatDepth, bool , bool >> SvdTest;
184+
185+ PERF_TEST_P (SvdTest, decompose, ::testing::Combine(
186+ ::testing::Values (std::make_tuple(5 , 15 ), std::make_tuple(32 , 32 ), std::make_tuple(100 , 100 )),
187+ ::testing::Values(RANK_HALF, RANK_MINUS_1, RANK_FULL),
188+ ::testing::Values(CV_32F, CV_64F),
189+ ::testing::Bool(), // symmetrical
190+ ::testing::Bool() // needUV
191+ ))
192+ {
193+ auto t = GetParam ();
194+ auto rc = std::get<0 >(t);
195+ auto rankEnum = std::get<1 >(t);
196+ int mtype = std::get<2 >(t);
197+ bool symmetrical = std::get<3 >(t);
198+ bool needUV = std::get<4 >(t);
199+
200+ int rows = std::get<0 >(rc);
201+ int cols = std::get<1 >(rc);
202+
203+ if (symmetrical)
204+ {
205+ rows = max (rows, cols);
206+ cols = rows;
207+ }
208+
209+ int rank = std::min (rows, cols);
210+ switch (rankEnum)
211+ {
212+ case RANK_HALF: rank /= 2 ; break ;
213+ case RANK_MINUS_1: rank -= 1 ; break ;
214+ default : break ;
215+ }
216+
217+ int flags = needUV ? 0 : SVD::NO_UV;
218+
219+ RNG& rng = theRNG ();
220+ Mat A = buildRandomMat (rows, cols, mtype, rng, rank, symmetrical);
221+ TEST_CYCLE () cv::SVD svd (A, flags);
222+
223+ SANITY_CHECK_NOTHING ();
224+ }
225+
226+
227+ PERF_TEST_P (SvdTest, backSubst, ::testing::Combine(
228+ ::testing::Values (std::make_tuple(5 , 15 ), std::make_tuple(32 , 32 ), std::make_tuple(100 , 100 )),
229+ ::testing::Values(RANK_HALF, RANK_MINUS_1, RANK_FULL),
230+ ::testing::Values(CV_32F, CV_64F),
231+ // back substitution works the same regardless of source matrix properties
232+ ::testing::Values(true ),
233+ // back substitution has no sense without u and v
234+ ::testing::Values(true ) // needUV
235+ ))
236+ {
237+ auto t = GetParam ();
238+ auto rc = std::get<0 >(t);
239+ auto rankEnum = std::get<1 >(t);
240+ int mtype = std::get<2 >(t);
241+
242+ int rows = std::get<0 >(rc);
243+ int cols = std::get<1 >(rc);
244+
245+ int rank = std::min (rows, cols);
246+ switch (rankEnum)
247+ {
248+ case RANK_HALF: rank /= 2 ; break ;
249+ case RANK_MINUS_1: rank -= 1 ; break ;
250+ default : break ;
251+ }
252+
253+ RNG& rng = theRNG ();
254+ Mat A = buildRandomMat (rows, cols, mtype, rng, rank, /* symmetrical */ false );
255+ cv::SVD svd (A);
256+ // preallocate to not spend time on it during backSubst()
257+ Mat dst (cols, 1 , mtype);
258+ Mat rhs (rows, 1 , mtype);
259+ rng.fill (rhs, RNG::UNIFORM, Scalar (-10 ), Scalar (10 ));
260+
261+ TEST_CYCLE () svd.backSubst (rhs, dst);
262+
263+ SANITY_CHECK_NOTHING ();
264+ }
265+
266+
39267typedef perf::TestBaseWithParam< testing::tuple<int , int , int > > KMeans;
40268
41269PERF_TEST_P_ (KMeans, single_iter)
0 commit comments