Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
testMatrixPseudoInverse.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * Test various svd decompositions.
32 */
33
38
39#include <algorithm>
40#include <stdio.h>
41#include <stdlib.h>
42#include <vector>
43
44#include <visp3/core/vpColVector.h>
45#include <visp3/core/vpMatrix.h>
46#include <visp3/core/vpTime.h>
47#include <visp3/io/vpParseArgv.h>
48
49// List of allowed command line options
50#define GETOPTARGS "cdn:i:pf:R:C:vh"
51
52#ifdef ENABLE_VISP_NAMESPACE
53using namespace VISP_NAMESPACE_NAME;
54#endif
55
56void usage(const char *name, const char *badparam);
57bool getOptions(int argc, const char **argv, unsigned int &nb_matrices, unsigned int &nb_iterations,
58 bool &use_plot_file, std::string &plotfile, unsigned int &nbrows, unsigned int &nbcols, bool &verbose);
59
60
61
62vpMatrix make_random_matrix(unsigned int nbrows, unsigned int nbcols);
63void create_bench_random_matrix(unsigned int nb_matrices, unsigned int nb_rows, unsigned int nb_cols, bool verbose,
64 std::vector<vpMatrix> &bench);
65int test_pseudo_inverse(const std::vector<vpMatrix> &A, const std::vector<vpMatrix> &Api);
66int test_pseudo_inverse(const std::vector<vpMatrix> &A, const std::vector<vpMatrix> &Api,
67 const std::vector<vpColVector> &sv, const std::vector<vpMatrix> &imA,
68 const std::vector<vpMatrix> &imAt, const std::vector<vpMatrix> &kerAt);
69int test_pseudo_inverse_default(bool verbose, const std::vector<vpMatrix> &bench, std::vector<double> &time);
70void save_time(const std::string &method, unsigned int nrows, unsigned int ncols, bool verbose, bool use_plot_file,
71 std::ofstream &of, const std::vector<double> &time);
72#if defined(VISP_HAVE_EIGEN3)
73int test_pseudo_inverse_eigen3(bool verbose, const std::vector<vpMatrix> &bench, std::vector<double> &time);
74#endif
75#if defined(VISP_HAVE_LAPACK)
76int test_pseudo_inverse_lapack(bool verbose, const std::vector<vpMatrix> &bench, std::vector<double> &time);
77#endif
78#if defined(VISP_HAVE_OPENCV)
79int test_pseudo_inverse_opencv(bool verbose, const std::vector<vpMatrix> &bench, std::vector<double> &time);
80#endif
81
88void usage(const char *name, const char *badparam)
89{
90 fprintf(stdout, "\n\
91Test matrix pseudo-inverse.\n\
92Outputs a comparison of the results obtained by supported 3rd parties.\n\
93\n\
94SYNOPSIS\n\
95 %s [-n <number of matrices>] [-f <plot filename>]\n\
96 [-R <number of rows>] [-C <number of columns>]\n\
97 [-i <number of iterations>] [-p] [-h]\n",
98 name);
99
100 fprintf(stdout, "\n\
101OPTIONS: Default\n\
102 -n <number of matrices> \n\
103 Number of matrices inverted during each test loop.\n\
104\n\
105 -i <number of iterations> \n\
106 Number of iterations of the test.\n\
107\n\
108 -f <plot filename> \n\
109 Set output path for plot output.\n\
110 The plot logs the times of \n\
111 the different inversion methods: \n\
112 QR,LU,Cholesky and Pseudo-inverse.\n\
113\n\
114 -R <number of rows>\n\
115 Number of rows of the automatically generated matrices \n\
116 we test on.\n\
117\n\
118 -C <number of columns>\n\
119 Number of colums of the automatically generated matrices \n\
120 we test on.\n\
121\n\
122 -p \n\
123 Plot into filename in the gnuplot format. \n\
124 If this option is used, tests results will be logged \n\
125 into a filename specified with -f.\n\
126\n\
127 -h\n\
128 Print the help.\n\n");
129
130 if (badparam) {
131 fprintf(stderr, "ERROR: \n");
132 fprintf(stderr, "\nBad parameter [%s]\n", badparam);
133 }
134}
135
141bool getOptions(int argc, const char **argv, unsigned int &nb_matrices, unsigned int &nb_iterations,
142 bool &use_plot_file, std::string &plotfile, unsigned int &nbrows, unsigned int &nbcols, bool &verbose)
143{
144 const char *optarg_;
145 int c;
146 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
147
148 switch (c) {
149 case 'h':
150 usage(argv[0], nullptr);
151 return false;
152 case 'n':
153 nb_matrices = static_cast<unsigned int>(atoi(optarg_));
154 break;
155 case 'i':
156 nb_iterations = static_cast<unsigned int>(atoi(optarg_));
157 break;
158 case 'f':
159 plotfile = optarg_;
160 use_plot_file = true;
161 break;
162 case 'p':
163 use_plot_file = true;
164 break;
165 case 'R':
166 nbrows = static_cast<unsigned int>(atoi(optarg_));
167 break;
168 case 'C':
169 nbcols = static_cast<unsigned int>(atoi(optarg_));
170 break;
171 case 'v':
172 verbose = true;
173 break;
174 // add default options -c -d
175 case 'c':
176 break;
177 case 'd':
178 break;
179 default:
180 usage(argv[0], optarg_);
181 return false;
182 }
183 }
184
185 if ((c == 1) || (c == -1)) {
186 // standalone param or error
187 usage(argv[0], nullptr);
188 std::cerr << "ERROR: " << std::endl;
189 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
190 return false;
191 }
192
193 return true;
194}
195
196vpMatrix make_random_matrix(unsigned int nbrows, unsigned int nbcols)
197{
198 vpMatrix A;
199 A.resize(nbrows, nbcols);
200
201 for (unsigned int i = 0; i < A.getRows(); i++) {
202 for (unsigned int j = 0; j < A.getCols(); j++) {
203 A[i][j] = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
204 }
205 }
206
207 return A;
208}
209
210void create_bench_random_matrix(unsigned int nb_matrices, unsigned int nb_rows, unsigned int nb_cols, bool verbose,
211 std::vector<vpMatrix> &bench)
212{
213 if (verbose)
214 std::cout << "Create a bench of " << nb_matrices << " " << nb_rows << " by " << nb_cols << " matrices" << std::endl;
215 bench.clear();
216 for (unsigned int i = 0; i < nb_matrices; i++) {
217 vpMatrix M = make_random_matrix(nb_rows, nb_cols);
218 bench.push_back(M);
219 }
220}
221
222int test_pseudo_inverse(const std::vector<vpMatrix> &A, const std::vector<vpMatrix> &Api)
223{
224 double allowed_error = 1e-3;
225 double error = 0;
226 vpMatrix A_Api, Api_A;
227
228 for (unsigned int i = 0; i < A.size(); i++) {
229 error = (A[i] * Api[i] * A[i] - A[i]).frobeniusNorm();
230 if (error > allowed_error) {
231 std::cout << "Bad pseudo-inverse [" << i << "] test A A^+ A = A: euclidean norm: " << error << std::endl;
232 return EXIT_FAILURE;
233 }
234 error = (Api[i] * A[i] * Api[i] - Api[i]).frobeniusNorm();
235 if (error > allowed_error) {
236 std::cout << "Bad pseudo-inverse [" << i << "] test A^+ A A^+ = A^+: euclidean norm: " << error << std::endl;
237 return EXIT_FAILURE;
238 }
239 A_Api = A[i] * Api[i];
240 error = (A_Api.transpose() - A_Api).frobeniusNorm();
241 if (error > allowed_error) {
242 std::cout << "Bad pseudo-inverse [" << i << "] test (A A^+)^T = A A^+: euclidean norm: " << error << std::endl;
243 return EXIT_FAILURE;
244 }
245 Api_A = Api[i] * A[i];
246 error = (Api_A.transpose() - Api_A).frobeniusNorm();
247 if (error > allowed_error) {
248 std::cout << "Bad pseudo-inverse [" << i << "] test (A^+ A )^T = A^+ A: euclidean norm: " << error << std::endl;
249 return EXIT_FAILURE;
250 }
251 }
252
253 return EXIT_SUCCESS;
254}
255
256int test_pseudo_inverse(const std::vector<vpMatrix> &A, const std::vector<vpMatrix> &Api,
257 const std::vector<vpColVector> &sv, const std::vector<vpMatrix> &imA,
258 const std::vector<vpMatrix> &imAt, const std::vector<vpMatrix> &kerAt)
259{
260 double allowed_error = 1e-3;
261 // test Api
262 if (test_pseudo_inverse(A, Api) == EXIT_FAILURE) {
263 return EXIT_FAILURE;
264 }
265
266 // test kerA
267 for (unsigned int i = 0; i < kerAt.size(); i++) {
268 if (kerAt[i].size()) {
269 vpMatrix nullspace = A[i] * kerAt[i].t();
270 double error = nullspace.frobeniusNorm();
271 if (error > allowed_error) {
272 std::cout << "Bad kernel [" << i << "]: euclidean norm: " << error << std::endl;
273 return EXIT_FAILURE;
274 }
275 }
276 }
277
278 // test sv, imA, imAt, kerA
279 for (unsigned int i = 0; i < kerAt.size(); i++) {
280 unsigned int rank = imA[i].getCols();
281 vpMatrix U, S(rank, A[i].getCols()), Vt(A[i].getCols(), A[i].getCols());
282 U = imA[i];
283
284 for (unsigned int j = 0; j < rank; j++)
285 S[j][j] = sv[i][j];
286
287 Vt.insert(imAt[i].t(), 0, 0);
288 Vt.insert(kerAt[i], imAt[i].getCols(), 0);
289
290 double error = (U * S * Vt - A[i]).frobeniusNorm();
291
292 if (error > allowed_error) {
293 std::cout << "Bad imA, imAt, sv, kerAt [" << i << "]: euclidean norm: " << error << std::endl;
294 return EXIT_FAILURE;
295 }
296 }
297
298 return EXIT_SUCCESS;
299}
300
301int test_pseudo_inverse_default(bool verbose, const std::vector<vpMatrix> &bench, std::vector<double> &time)
302{
303 if (verbose)
304 std::cout << "Test pseudo-inverse using default 3rd party" << std::endl;
305 if (verbose)
306 std::cout << " Pseudo-inverse on a " << bench[0].getRows() << "x" << bench[0].getCols() << " matrix" << std::endl;
307
308 size_t size = bench.size();
309 std::vector<vpMatrix> PI(size), imA(size), imAt(size), kerAt(size);
310 std::vector<vpColVector> sv(size);
311 int ret = EXIT_SUCCESS;
312 time.clear();
313
314 // test 1
315 double t = vpTime::measureTimeMs();
316 for (unsigned int i = 0; i < bench.size(); i++) {
317 PI[i] = bench[i].pseudoInverse();
318 }
319 time.push_back(vpTime::measureTimeMs() - t);
320 for (unsigned int i = 0; i < time.size(); i++) {
321 ret += test_pseudo_inverse(bench, PI);
322 }
323
324 // test 2
326 for (unsigned int i = 0; i < bench.size(); i++) {
327 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
328 unsigned int rank = bench[i].pseudoInverse(PI[i]);
329 if (rank != rank_bench) {
330 if (verbose) {
331 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
332 }
333 ret += EXIT_FAILURE;
334 }
335 }
336 time.push_back(vpTime::measureTimeMs() - t);
337 for (unsigned int i = 0; i < time.size(); i++) {
338 ret += test_pseudo_inverse(bench, PI);
339 }
340
341 // test 3
343 for (unsigned int i = 0; i < bench.size(); i++) {
344 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
345 unsigned int rank = bench[i].pseudoInverse(PI[i], sv[i]);
346 if (rank != rank_bench) {
347 if (verbose) {
348 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
349 }
350 ret += EXIT_FAILURE;
351 }
352 }
353 time.push_back(vpTime::measureTimeMs() - t);
354 for (unsigned int i = 0; i < time.size(); i++) {
355 ret += test_pseudo_inverse(bench, PI);
356 }
357
358 // test 4
360 for (unsigned int i = 0; i < bench.size(); i++) {
361 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
362 unsigned int rank = bench[i].pseudoInverse(PI[i], sv[i], 1e-6, imA[i], imAt[i]);
363 if (rank != rank_bench) {
364 if (verbose) {
365 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
366 }
367 ret += EXIT_FAILURE;
368 }
369 }
370 time.push_back(vpTime::measureTimeMs() - t);
371 for (unsigned int i = 0; i < time.size(); i++) {
372 ret += test_pseudo_inverse(bench, PI);
373 }
374
375 // test 5
377 for (unsigned int i = 0; i < bench.size(); i++) {
378 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
379 unsigned int rank = bench[i].pseudoInverse(PI[i], sv[i], 1e-6, imA[i], imAt[i], kerAt[i]);
380 if (rank != rank_bench) {
381 if (verbose) {
382 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
383 }
384 ret += EXIT_FAILURE;
385 }
386 }
387 time.push_back(vpTime::measureTimeMs() - t);
388 for (unsigned int i = 0; i < time.size(); i++) {
389 ret += test_pseudo_inverse(bench, PI, sv, imA, imAt, kerAt);
390 }
391
392 //-------------------
393
394 // test 6
396 for (unsigned int i = 0; i < bench.size(); i++) {
397 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
398 PI[i] = bench[i].pseudoInverse(static_cast<int>(rank_bench));
399 }
400 time.push_back(vpTime::measureTimeMs() - t);
401 for (unsigned int i = 0; i < time.size(); i++) {
402 ret += test_pseudo_inverse(bench, PI);
403 }
404
405 // test 7
407 for (unsigned int i = 0; i < bench.size(); i++) {
408 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
409 unsigned int rank = bench[i].pseudoInverse(PI[i], static_cast<int>(rank_bench));
410 if (rank != rank_bench) {
411 if (verbose) {
412 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
413 }
414 ret += EXIT_FAILURE;
415 }
416 }
417 time.push_back(vpTime::measureTimeMs() - t);
418 for (unsigned int i = 0; i < time.size(); i++) {
419 ret += test_pseudo_inverse(bench, PI);
420 }
421
422 // test 8
424 for (unsigned int i = 0; i < bench.size(); i++) {
425 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
426 unsigned int rank = bench[i].pseudoInverse(PI[i], sv[i], static_cast<int>(rank_bench));
427 if (rank != rank_bench) {
428 if (verbose) {
429 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
430 }
431 ret += EXIT_FAILURE;
432 }
433 }
434 time.push_back(vpTime::measureTimeMs() - t);
435 for (unsigned int i = 0; i < time.size(); i++) {
436 ret += test_pseudo_inverse(bench, PI);
437 }
438
439 // test 9
441 for (unsigned int i = 0; i < bench.size(); i++) {
442 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
443 unsigned int rank = bench[i].pseudoInverse(PI[i], sv[i], static_cast<int>(rank_bench), imA[i], imAt[i]);
444 if (rank != rank_bench) {
445 if (verbose) {
446 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
447 }
448 ret += EXIT_FAILURE;
449 }
450 }
451 time.push_back(vpTime::measureTimeMs() - t);
452 for (unsigned int i = 0; i < time.size(); i++) {
453 ret += test_pseudo_inverse(bench, PI);
454 }
455
456 // test 10
458 for (unsigned int i = 0; i < bench.size(); i++) {
459 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
460 unsigned int rank = bench[i].pseudoInverse(PI[i], sv[i], static_cast<int>(rank_bench), imA[i], imAt[i], kerAt[i]);
461 if (rank != rank_bench) {
462 if (verbose) {
463 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
464 }
465 ret += EXIT_FAILURE;
466 }
467 }
468 time.push_back(vpTime::measureTimeMs() - t);
469 for (unsigned int i = 0; i < time.size(); i++) {
470 ret += test_pseudo_inverse(bench, PI, sv, imA, imAt, kerAt);
471 }
472
473 return ret;
474}
475
476#if defined(VISP_HAVE_EIGEN3)
477int test_pseudo_inverse_eigen3(bool verbose, const std::vector<vpMatrix> &bench, std::vector<double> &time)
478{
479 if (verbose)
480 std::cout << "Test pseudo-inverse using Eigen3 3rd party" << std::endl;
481 if (verbose)
482 std::cout << " Pseudo-inverse on a " << bench[0].getRows() << "x" << bench[0].getCols() << " matrix" << std::endl;
483
484 size_t size = bench.size();
485 std::vector<vpMatrix> PI(size), imA(size), imAt(size), kerAt(size);
486 std::vector<vpColVector> sv(size);
487 int ret = EXIT_SUCCESS;
488 time.clear();
489
490 // test 1
491 double t = vpTime::measureTimeMs();
492 for (unsigned int i = 0; i < bench.size(); i++) {
493 PI[i] = bench[i].pseudoInverseEigen3();
494 }
495 time.push_back(vpTime::measureTimeMs() - t);
496 for (unsigned int i = 0; i < time.size(); i++) {
497 ret += test_pseudo_inverse(bench, PI);
498 }
499
500 // test 2
502 for (unsigned int i = 0; i < bench.size(); i++) {
503 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
504 unsigned int rank = bench[i].pseudoInverseEigen3(PI[i]);
505 if (rank != rank_bench) {
506 if (verbose) {
507 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
508 }
509 ret += EXIT_FAILURE;
510 }
511 }
512 time.push_back(vpTime::measureTimeMs() - t);
513 for (unsigned int i = 0; i < time.size(); i++) {
514 ret += test_pseudo_inverse(bench, PI);
515 }
516
517 // test 3
519 for (unsigned int i = 0; i < bench.size(); i++) {
520 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
521 unsigned int rank = bench[i].pseudoInverseEigen3(PI[i], sv[i]);
522 if (rank != rank_bench) {
523 if (verbose) {
524 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
525 }
526 ret += EXIT_FAILURE;
527 }
528 }
529 time.push_back(vpTime::measureTimeMs() - t);
530 for (unsigned int i = 0; i < time.size(); i++) {
531 ret += test_pseudo_inverse(bench, PI);
532 }
533
534 // test 4
536 for (unsigned int i = 0; i < bench.size(); i++) {
537 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
538 unsigned int rank = bench[i].pseudoInverseEigen3(PI[i], sv[i], 1e-6, imA[i], imAt[i], kerAt[i]);
539 if (rank != rank_bench) {
540 if (verbose) {
541 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
542 }
543 ret += EXIT_FAILURE;
544 }
545 }
546 time.push_back(vpTime::measureTimeMs() - t);
547 for (unsigned int i = 0; i < time.size(); i++) {
548 ret += test_pseudo_inverse(bench, PI, sv, imA, imAt, kerAt);
549 }
550
551 //-------------------
552
553 // test 5
555 for (unsigned int i = 0; i < bench.size(); i++) {
556 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
557 PI[i] = bench[i].pseudoInverseEigen3(static_cast<int>(rank_bench));
558 }
559 time.push_back(vpTime::measureTimeMs() - t);
560 for (unsigned int i = 0; i < time.size(); i++) {
561 ret += test_pseudo_inverse(bench, PI);
562 }
563
564 // test 6
566 for (unsigned int i = 0; i < bench.size(); i++) {
567 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
568 unsigned int rank = bench[i].pseudoInverseEigen3(PI[i], static_cast<int>(rank_bench));
569 if (rank != rank_bench) {
570 if (verbose) {
571 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
572 }
573 ret += EXIT_FAILURE;
574 }
575 }
576 time.push_back(vpTime::measureTimeMs() - t);
577 for (unsigned int i = 0; i < time.size(); i++) {
578 ret += test_pseudo_inverse(bench, PI);
579 }
580
581 // test 7
583 for (unsigned int i = 0; i < bench.size(); i++) {
584 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
585 unsigned int rank = bench[i].pseudoInverseEigen3(PI[i], sv[i], static_cast<int>(rank_bench));
586 if (rank != rank_bench) {
587 if (verbose) {
588 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
589 }
590 ret += EXIT_FAILURE;
591 }
592 }
593 time.push_back(vpTime::measureTimeMs() - t);
594 for (unsigned int i = 0; i < time.size(); i++) {
595 ret += test_pseudo_inverse(bench, PI);
596 }
597
598 // test 8
600 for (unsigned int i = 0; i < bench.size(); i++) {
601 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
602 unsigned int rank = bench[i].pseudoInverseEigen3(PI[i], sv[i], static_cast<int>(rank_bench), imA[i], imAt[i], kerAt[i]);
603 if (rank != rank_bench) {
604 if (verbose) {
605 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
606 }
607 ret += EXIT_FAILURE;
608 }
609 }
610 time.push_back(vpTime::measureTimeMs() - t);
611
612 for (unsigned int i = 0; i < time.size(); i++) {
613 ret += test_pseudo_inverse(bench, PI, sv, imA, imAt, kerAt);
614 }
615
616 return ret;
617}
618#endif
619
620#if defined(VISP_HAVE_LAPACK)
621int test_pseudo_inverse_lapack(bool verbose, const std::vector<vpMatrix> &bench, std::vector<double> &time)
622{
623 if (verbose)
624 std::cout << "Test pseudo-inverse using Eigen3 3rd party" << std::endl;
625 if (verbose)
626 std::cout << " Pseudo-inverse on a " << bench[0].getRows() << "x" << bench[0].getCols() << " matrix" << std::endl;
627
628 size_t size = bench.size();
629 std::vector<vpMatrix> PI(size), imA(size), imAt(size), kerAt(size);
630 std::vector<vpColVector> sv(size);
631 int ret = EXIT_SUCCESS;
632 time.clear();
633
634 // test 1
635 double t = vpTime::measureTimeMs();
636 for (unsigned int i = 0; i < bench.size(); i++) {
637 PI[i] = bench[i].pseudoInverseLapack();
638 }
639 time.push_back(vpTime::measureTimeMs() - t);
640 for (unsigned int i = 0; i < time.size(); i++) {
641 ret += test_pseudo_inverse(bench, PI);
642 }
643
644 // test 2
646 for (unsigned int i = 0; i < bench.size(); i++) {
647 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
648 unsigned int rank = bench[i].pseudoInverseLapack(PI[i]);
649 if (rank != rank_bench) {
650 if (verbose) {
651 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
652 }
653 ret += EXIT_FAILURE;
654 }
655 }
656 time.push_back(vpTime::measureTimeMs() - t);
657 for (unsigned int i = 0; i < time.size(); i++) {
658 ret += test_pseudo_inverse(bench, PI);
659 }
660
661 // test 3
663 for (unsigned int i = 0; i < bench.size(); i++) {
664 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
665 unsigned int rank = bench[i].pseudoInverseLapack(PI[i], sv[i]);
666 if (rank != rank_bench) {
667 if (verbose) {
668 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
669 }
670 ret += EXIT_FAILURE;
671 }
672 }
673 time.push_back(vpTime::measureTimeMs() - t);
674 for (unsigned int i = 0; i < time.size(); i++) {
675 ret += test_pseudo_inverse(bench, PI);
676 }
677
678 // test 4
680 for (unsigned int i = 0; i < bench.size(); i++) {
681 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
682 unsigned int rank = bench[i].pseudoInverseLapack(PI[i], sv[i], 1e-6, imA[i], imAt[i], kerAt[i]);
683 if (rank != rank_bench) {
684 if (verbose) {
685 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
686 }
687 ret += EXIT_FAILURE;
688 }
689 }
690 time.push_back(vpTime::measureTimeMs() - t);
691 for (unsigned int i = 0; i < time.size(); i++) {
692 ret += test_pseudo_inverse(bench, PI, sv, imA, imAt, kerAt);
693 }
694
695 //-------------------
696
697 // test 5
699 for (unsigned int i = 0; i < bench.size(); i++) {
700 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
701 PI[i] = bench[i].pseudoInverseLapack(static_cast<int>(rank_bench));
702 }
703 time.push_back(vpTime::measureTimeMs() - t);
704 for (unsigned int i = 0; i < time.size(); i++) {
705 ret += test_pseudo_inverse(bench, PI);
706 }
707
708 // test 6
710 for (unsigned int i = 0; i < bench.size(); i++) {
711 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
712 unsigned int rank = bench[i].pseudoInverseLapack(PI[i], static_cast<int>(rank_bench));
713 if (rank != rank_bench) {
714 if (verbose) {
715 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
716 }
717 ret += EXIT_FAILURE;
718 }
719 }
720 time.push_back(vpTime::measureTimeMs() - t);
721 for (unsigned int i = 0; i < time.size(); i++) {
722 ret += test_pseudo_inverse(bench, PI);
723 }
724
725 // test 7
727 for (unsigned int i = 0; i < bench.size(); i++) {
728 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
729 unsigned int rank = bench[i].pseudoInverseLapack(PI[i], sv[i], static_cast<int>(rank_bench));
730 if (rank != rank_bench) {
731 if (verbose) {
732 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
733 }
734 ret += EXIT_FAILURE;
735 }
736 }
737 time.push_back(vpTime::measureTimeMs() - t);
738 for (unsigned int i = 0; i < time.size(); i++) {
739 ret += test_pseudo_inverse(bench, PI);
740 }
741
742 // test 8
744 for (unsigned int i = 0; i < bench.size(); i++) {
745 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
746 unsigned int rank = bench[i].pseudoInverseLapack(PI[i], sv[i], static_cast<int>(rank_bench), imA[i], imAt[i], kerAt[i]);
747 if (rank != rank_bench) {
748 if (verbose) {
749 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
750 }
751 ret += EXIT_FAILURE;
752 }
753 }
754 time.push_back(vpTime::measureTimeMs() - t);
755
756 for (unsigned int i = 0; i < time.size(); i++) {
757 ret += test_pseudo_inverse(bench, PI, sv, imA, imAt, kerAt);
758 }
759
760 return ret;
761}
762#endif
763
764#if defined(VISP_HAVE_OPENCV)
765int test_pseudo_inverse_opencv(bool verbose, const std::vector<vpMatrix> &bench, std::vector<double> &time)
766{
767 if (verbose)
768 std::cout << "Test pseudo-inverse using OpenCV 3rd party" << std::endl;
769 if (verbose)
770 std::cout << " Pseudo-inverse on a " << bench[0].getRows() << "x" << bench[0].getCols() << " matrix" << std::endl;
771
772 size_t size = bench.size();
773 std::vector<vpMatrix> PI(size), imA(size), imAt(size), kerAt(size);
774 std::vector<vpColVector> sv(size);
775 int ret = EXIT_SUCCESS;
776 time.clear();
777
778 // test 1
779 double t = vpTime::measureTimeMs();
780 for (unsigned int i = 0; i < bench.size(); i++) {
781 PI[i] = bench[i].pseudoInverseOpenCV();
782 }
783 time.push_back(vpTime::measureTimeMs() - t);
784 for (unsigned int i = 0; i < time.size(); i++) {
785 ret += test_pseudo_inverse(bench, PI);
786 }
787
788 // test 2
790 for (unsigned int i = 0; i < bench.size(); i++) {
791 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
792 unsigned int rank = bench[i].pseudoInverseOpenCV(PI[i]);
793 if (rank != rank_bench) {
794 if (verbose) {
795 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
796 }
797 ret += EXIT_FAILURE;
798 }
799 }
800 time.push_back(vpTime::measureTimeMs() - t);
801 for (unsigned int i = 0; i < time.size(); i++) {
802 ret += test_pseudo_inverse(bench, PI);
803 }
804
805 // test 3
807 for (unsigned int i = 0; i < bench.size(); i++) {
808 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
809 unsigned int rank = bench[i].pseudoInverseOpenCV(PI[i], sv[i]);
810 if (rank != rank_bench) {
811 if (verbose) {
812 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
813 }
814 ret += EXIT_FAILURE;
815 }
816 }
817 time.push_back(vpTime::measureTimeMs() - t);
818 for (unsigned int i = 0; i < time.size(); i++) {
819 ret += test_pseudo_inverse(bench, PI);
820 }
821
822 // test 4
824 for (unsigned int i = 0; i < bench.size(); i++) {
825 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
826 unsigned int rank = bench[i].pseudoInverseOpenCV(PI[i], sv[i], 1e-6, imA[i], imAt[i], kerAt[i]);
827 if (rank != rank_bench) {
828 if (verbose) {
829 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
830 }
831 ret += EXIT_FAILURE;
832 }
833 }
834 time.push_back(vpTime::measureTimeMs() - t);
835 for (unsigned int i = 0; i < time.size(); i++) {
836 ret += test_pseudo_inverse(bench, PI, sv, imA, imAt, kerAt);
837 }
838 //-------------------
839
840 // test 5
842 for (unsigned int i = 0; i < bench.size(); i++) {
843 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
844 PI[i] = bench[i].pseudoInverseOpenCV(static_cast<int>(rank_bench));
845 }
846 time.push_back(vpTime::measureTimeMs() - t);
847 for (unsigned int i = 0; i < time.size(); i++) {
848 ret += test_pseudo_inverse(bench, PI);
849 }
850
851 // test 6
853 for (unsigned int i = 0; i < bench.size(); i++) {
854 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
855 unsigned int rank = bench[i].pseudoInverseOpenCV(PI[i], static_cast<int>(rank_bench));
856 if (rank != rank_bench) {
857 if (verbose) {
858 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
859 }
860 ret += EXIT_FAILURE;
861 }
862 }
863 time.push_back(vpTime::measureTimeMs() - t);
864 for (unsigned int i = 0; i < time.size(); i++) {
865 ret += test_pseudo_inverse(bench, PI);
866 }
867
868 // test 7
870 for (unsigned int i = 0; i < bench.size(); i++) {
871 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
872 unsigned int rank = bench[i].pseudoInverseOpenCV(PI[i], sv[i], static_cast<int>(rank_bench));
873 if (rank != rank_bench) {
874 if (verbose) {
875 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
876 }
877 ret += EXIT_FAILURE;
878 }
879 }
880 time.push_back(vpTime::measureTimeMs() - t);
881 for (unsigned int i = 0; i < time.size(); i++) {
882 ret += test_pseudo_inverse(bench, PI);
883 }
884
885 // test 8
887 for (unsigned int i = 0; i < bench.size(); i++) {
888 unsigned int rank_bench = std::min(bench[i].getRows(), bench[i].getCols());
889 unsigned int rank = bench[i].pseudoInverseOpenCV(PI[i], sv[i], static_cast<int>(rank_bench), imA[i], imAt[i], kerAt[i]);
890 if (rank != rank_bench) {
891 if (verbose) {
892 std::cout << " Error in the rank (" << rank << ")" << " while expected rank is " << rank_bench << std::endl;
893 }
894 ret += EXIT_FAILURE;
895 }
896 }
897 time.push_back(vpTime::measureTimeMs() - t);
898
899 for (unsigned int i = 0; i < time.size(); i++) {
900 ret += test_pseudo_inverse(bench, PI, sv, imA, imAt, kerAt);
901 }
902
903 return ret;
904}
905#endif
906
907void save_time(const std::string &method, unsigned int nrows, unsigned int ncols, bool verbose, bool use_plot_file,
908 std::ofstream &of, const std::vector<double> &time)
909{
910 for (size_t i = 0; i < time.size(); i++) {
911 if (use_plot_file)
912 of << time[i] << "\t";
913 if (verbose) {
914 std::cout << " " << method << " pseudo inverse (" << nrows << "x" << ncols << ")"
915 << " time test " << i << ": " << time[i] << std::endl;
916 }
917 }
918}
919
920int main(int argc, const char *argv[])
921{
922 try {
923#if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_OPENCV)
924 unsigned int nb_matrices = 10;
925 unsigned int nb_iterations = 10;
926 unsigned int nb_rows = 12;
927 unsigned int nb_cols = 6;
928 bool verbose = false;
929 std::string plotfile("plot-pseudo-inv.csv");
930 bool use_plot_file = false;
931 std::ofstream of;
932
933 unsigned int nb_svd_functions = 4; // 4 tests for each existing vpMatrix::pseudoInverse(...) functions
934 unsigned int nb_test_matrix_size = 3; // 3 tests: m > n, m = n, m < n
935 std::vector<double> time(nb_svd_functions);
936 std::vector<unsigned int> nrows(nb_test_matrix_size), ncols(nb_test_matrix_size);
937
938 // Read the command line options
939 if (getOptions(argc, argv, nb_matrices, nb_iterations, use_plot_file, plotfile, nb_rows, nb_cols, verbose) ==
940 false) {
941 return EXIT_FAILURE;
942 }
943
944 for (unsigned int s = 0; s < nb_test_matrix_size; s++) {
945 // consider m > n, m = n, m < n
946 if (s == 0) {
947 nrows[s] = nb_rows;
948 ncols[s] = nb_cols;
949 }
950 else if (s == 1) {
951 nrows[s] = nb_cols;
952 ncols[s] = nb_cols;
953 }
954 else {
955 nrows[s] = nb_cols;
956 ncols[s] = nb_rows;
957 }
958 }
959
960 if (use_plot_file) {
961 of.open(plotfile.c_str());
962 of << "iter"
963 << "\t";
964
965 for (unsigned int s = 0; s < nb_test_matrix_size; s++) {
966 for (unsigned int i = 0; i < nb_svd_functions; i++)
967 of << "\"default " << nrows[s] << "x" << ncols[s] << " test " << i << "\""
968 << "\t";
969
970#if defined(VISP_HAVE_LAPACK)
971 for (unsigned int i = 0; i < nb_svd_functions; i++)
972 of << "\"Lapack " << nrows[s] << "x" << ncols[s] << " test " << i << "\""
973 << "\t";
974#endif
975#if defined(VISP_HAVE_EIGEN3)
976 for (unsigned int i = 0; i < nb_svd_functions; i++)
977 of << "\"Eigen3 " << nrows[s] << "x" << ncols[s] << " test " << i << "\""
978 << "\t";
979#endif
980#if defined(VISP_HAVE_OPENCV)
981 for (unsigned int i = 0; i < nb_svd_functions; i++)
982 of << "\"OpenCV " << nrows[s] << "x" << ncols[s] << " test " << i << "\""
983 << "\t";
984#endif
985 }
986 of << std::endl;
987 }
988
989 int ret_default = EXIT_SUCCESS;
990 int ret_lapack = EXIT_SUCCESS;
991 int ret_eigen3 = EXIT_SUCCESS;
992 int ret_opencv = EXIT_SUCCESS;
993
994 for (unsigned int iter = 0; iter < nb_iterations; iter++) {
995
996 if (use_plot_file)
997 of << iter << "\t";
998
999 for (unsigned int s = 0; s < nb_test_matrix_size; s++) {
1000 std::vector<vpMatrix> bench_random_matrices;
1001 create_bench_random_matrix(nb_matrices, nrows[s], ncols[s], verbose, bench_random_matrices);
1002
1003 ret_default += test_pseudo_inverse_default(verbose, bench_random_matrices, time);
1004 save_time("default -", nrows[s], ncols[s], verbose, use_plot_file, of, time);
1005
1006#if defined(VISP_HAVE_LAPACK)
1007 ret_lapack += test_pseudo_inverse_lapack(verbose, bench_random_matrices, time);
1008 save_time("Lapack -", nrows[s], ncols[s], verbose, use_plot_file, of, time);
1009#endif
1010
1011#if defined(VISP_HAVE_EIGEN3)
1012 ret_eigen3 += test_pseudo_inverse_eigen3(verbose, bench_random_matrices, time);
1013 save_time("Eigen3 -", nrows[s], ncols[s], verbose, use_plot_file, of, time);
1014#endif
1015
1016#if defined(VISP_HAVE_OPENCV)
1017 ret_opencv += test_pseudo_inverse_opencv(verbose, bench_random_matrices, time);
1018 save_time("OpenCV -", nrows[s], ncols[s], verbose, use_plot_file, of, time);
1019#endif
1020 }
1021 if (use_plot_file)
1022 of << std::endl;
1023 }
1024 if (use_plot_file) {
1025 of.close();
1026 std::cout << "Result saved in " << plotfile << std::endl;
1027 }
1028
1029 std::cout << "Resume testing:" << std::endl;
1030 std::cout << " Pseudo-inverse (default): " << (ret_default ? "failed" : "success") << std::endl;
1031#if defined(VISP_HAVE_LAPACK)
1032 std::cout << " Pseudo-inverse (lapack) : " << (ret_lapack ? "failed" : "success") << std::endl;
1033#endif
1034#if defined(VISP_HAVE_EIGEN3)
1035 std::cout << " Pseudo-inverse (eigen3) : " << (ret_eigen3 ? "failed" : "success") << std::endl;
1036#endif
1037#if defined(VISP_HAVE_OPENCV)
1038 std::cout << " Pseudo-inverse (opencv) : " << (ret_opencv ? "failed" : "success") << std::endl;
1039#endif
1040
1041 int ret = ret_default + ret_lapack + ret_eigen3 + ret_opencv;
1042
1043 std::cout << " Global test : " << (ret ? "failed" : "success") << std::endl;
1044
1045 return ret;
1046#else
1047 (void)argc;
1048 (void)argv;
1049 std::cout << "Test does nothing since you dont't have Lapack, Eigen3 or OpenCV 3rd party" << std::endl;
1050 return EXIT_SUCCESS;
1051#endif
1052 }
1053 catch (const vpException &e) {
1054 std::cout << "Catch an exception: " << e.getStringMessage() << std::endl;
1055 return EXIT_FAILURE;
1056 }
1057}
unsigned int getCols() const
Definition vpArray2D.h:423
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition vpArray2D.h:448
unsigned int getRows() const
Definition vpArray2D.h:433
error that can be emitted by ViSP classes.
Definition vpException.h:60
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
double frobeniusNorm() const
void clear()
Definition vpMatrix.h:247
void insert(const vpMatrix &A, unsigned int r, unsigned int c)
vpMatrix transpose() const
vpMatrix t() const
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
VISP_EXPORT double measureTimeMs()