Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
testMatrixInverse.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 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 inversions.
32 */
33
38
39#include <cmath>
40#include <fstream>
41#include <iostream>
42#include <stdio.h>
43#include <stdlib.h>
44#include <vector>
45
46#include <visp3/core/vpColVector.h>
47#include <visp3/core/vpMatrix.h>
48#include <visp3/core/vpTime.h>
49#include <visp3/io/vpParseArgv.h>
50
51// List of allowed command line options
52#define GETOPTARGS "cdn:i:pf:R:C:vh"
53
54#ifdef ENABLE_VISP_NAMESPACE
55using namespace VISP_NAMESPACE_NAME;
56#endif
57
58void usage(const char *name, const char *badparam);
59bool getOptions(int argc, const char **argv, unsigned int &nb_matrices, unsigned int &nb_iterations,
60 bool &use_plot_file, std::string &plotfile, unsigned int &nbrows, unsigned int &nbcols, bool &verbose);
61
62vpMatrix make_random_matrix(unsigned int nbrows, unsigned int nbcols);
63vpMatrix make_random_symmetric_positive_matrix(unsigned int n);
64vpMatrix make_random_triangular_matrix(unsigned int nbrows);
65void create_bench_random_matrix(unsigned int nb_matrices, unsigned int nb_rows, unsigned int nb_cols, bool verbose,
66 std::vector<vpMatrix> &bench);
67void create_bench_symmetric_positive_matrix(unsigned int nb_matrices, unsigned int n, bool verbose,
68 std::vector<vpMatrix> &bench);
69void create_bench_random_triangular_matrix(unsigned int nb_matrices, unsigned int n, bool verbose,
70 std::vector<vpMatrix> &bench);
71int test_inverse(const std::vector<vpMatrix> &bench, const std::vector<vpMatrix> &result);
72int test_inverse_lu_small(bool verbose, const std::vector<vpMatrix> &bench, double &time);
73void save_time(const std::string &method, bool verbose, bool use_plot_file, std::ofstream &of, double time);
74#if defined(VISP_HAVE_EIGEN3)
75int test_inverse_lu_eigen3(bool verbose, const std::vector<vpMatrix> &bench, double &time);
76#endif
77
78#if defined(VISP_HAVE_LAPACK)
79int test_inverse_lu_lapack(bool verbose, const std::vector<vpMatrix> &bench, double &time);
80int test_inverse_cholesky_lapack(bool verbose, const std::vector<vpMatrix> &bench, double &time);
81int test_inverse_qr_lapack(bool verbose, const std::vector<vpMatrix> &bench, double &time);
82#endif
83#if defined(VISP_HAVE_OPENCV)
84int test_inverse_lu_opencv(bool verbose, const std::vector<vpMatrix> &bench, double &time);
85int test_inverse_cholesky_opencv(bool verbose, const std::vector<vpMatrix> &bench, double &time);
86#endif
87#if defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV)
88int test_pseudo_inverse(bool verbose, const std::vector<vpMatrix> &bench, double &time);
89int test_inverse_triangular(bool verbose, const std::vector<vpMatrix> &bench, double &time);
90#endif
91
98void usage(const char *name, const char *badparam)
99{
100 fprintf(stdout, "\n\
101Test matrix inversions\n\
102using LU, QR and Cholesky methods as well as Pseudo-inverse.\n\
103Outputs a comparison of these methods.\n\
104\n\
105SYNOPSIS\n\
106 %s [-n <number of matrices>] [-f <plot filename>]\n\
107 [-R <number of rows>] [-C <number of columns>]\n\
108 [-i <number of iterations>] [-p] [-h]\n",
109 name);
110
111 fprintf(stdout, "\n\
112OPTIONS: Default\n\
113 -n <number of matrices> \n\
114 Number of matrices inverted during each test loop.\n\
115\n\
116 -i <number of iterations> \n\
117 Number of iterations of the test.\n\
118\n\
119 -f <plot filename> \n\
120 Set output path for plot output.\n\
121 The plot logs the times of \n\
122 the different inversion methods: \n\
123 QR,LU,Cholesky and Pseudo-inverse.\n\
124\n\
125 -R <number of rows>\n\
126 Number of rows of the automatically generated matrices \n\
127 we test on.\n\
128\n\
129 -C <number of columns>\n\
130 Number of colums of the automatically generated matrices \n\
131 we test on.\n\
132\n\
133 -p \n\
134 Plot into filename in the gnuplot format. \n\
135 If this option is used, tests results will be logged \n\
136 into a filename specified with -f.\n\
137\n\
138 -h\n\
139 Print the help.\n\n");
140
141 if (badparam) {
142 fprintf(stderr, "ERROR: \n");
143 fprintf(stderr, "\nBad parameter [%s]\n", badparam);
144 }
145}
146
154bool getOptions(int argc, const char **argv, unsigned int &nb_matrices, unsigned int &nb_iterations,
155 bool &use_plot_file, std::string &plotfile, unsigned int &nbrows, unsigned int &nbcols, bool &verbose)
156{
157 const char *optarg_;
158 int c;
159 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
160
161 switch (c) {
162 case 'h':
163 usage(argv[0], nullptr);
164 return false;
165 case 'n':
166 nb_matrices = static_cast<unsigned int>(atoi(optarg_));
167 break;
168 case 'i':
169 nb_iterations = static_cast<unsigned int>(atoi(optarg_));
170 break;
171 case 'f':
172 plotfile = optarg_;
173 use_plot_file = true;
174 break;
175 case 'p':
176 use_plot_file = true;
177 break;
178 case 'R':
179 nbrows = static_cast<unsigned int>(atoi(optarg_));
180 break;
181 case 'C':
182 nbcols = static_cast<unsigned int>(atoi(optarg_));
183 break;
184 case 'v':
185 verbose = true;
186 break;
187 // add default options -c -d
188 case 'c':
189 break;
190 case 'd':
191 break;
192 default:
193 usage(argv[0], optarg_);
194 return false;
195 }
196 }
197
198 if ((c == 1) || (c == -1)) {
199 // standalone param or error
200 usage(argv[0], nullptr);
201 std::cerr << "ERROR: " << std::endl;
202 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
203 return false;
204 }
205
206 return true;
207}
208
209vpMatrix make_random_matrix(unsigned int nbrows, unsigned int nbcols)
210{
211 vpMatrix A;
212 A.resize(nbrows, nbcols);
213
214 for (unsigned int i = 0; i < A.getRows(); i++)
215 for (unsigned int j = 0; j < A.getCols(); j++)
216 A[i][j] = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
217 return A;
218}
219
220vpMatrix make_random_symmetric_positive_matrix(unsigned int n)
221{
222 vpMatrix A;
223 A.resize(n, n);
224 vpMatrix I;
225 I.eye(n);
226
227 for (unsigned int i = 0; i < A.getRows(); i++)
228 for (unsigned int j = 0; j < A.getCols(); j++)
229 A[i][j] = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
230
231 A = 0.5 * (A + A.t());
232 A = A + n * I;
233 return A;
234}
235
236vpMatrix make_random_triangular_matrix(unsigned int nbrows)
237{
238 vpMatrix A;
239 A.resize(nbrows, nbrows);
240
241 for (unsigned int i = 0; i < A.getRows(); i++) {
242 for (unsigned int j = i; j < A.getCols(); j++) {
243 A[i][j] = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
244 if (i != j) {
245 A[j][i] = 0;
246 }
247 }
248 }
249
250 return A;
251}
252
253void create_bench_random_matrix(unsigned int nb_matrices, unsigned int nb_rows, unsigned int nb_cols, bool verbose,
254 std::vector<vpMatrix> &bench)
255{
256 if (verbose)
257 std::cout << "Create a bench of " << nb_matrices << " " << nb_rows << " by " << nb_cols << " matrices" << std::endl;
258 bench.clear();
259 for (unsigned int i = 0; i < nb_matrices; i++) {
260 vpMatrix M;
261#if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_OPENCV)
262 double det = 0.;
263 // don't put singular matrices in the benchmark
264 for (M = make_random_matrix(nb_rows, nb_cols); std::fabs(det = M.AtA().det()) < .01;
265 M = make_random_matrix(nb_rows, nb_cols)) {
266 if (verbose) {
267 std::cout << " Generated random matrix AtA=" << std::endl << M.AtA() << std::endl;
268 std::cout << " Generated random matrix not invertible: det=" << det << ". Retrying..." << std::endl;
269 }
270 }
271#else
272 M = make_random_matrix(nb_rows, nb_cols);
273#endif
274 bench.push_back(M);
275 }
276}
277
278void create_bench_symmetric_positive_matrix(unsigned int nb_matrices, unsigned int n, bool verbose,
279 std::vector<vpMatrix> &bench)
280{
281 if (verbose)
282 std::cout << "Create a bench of " << nb_matrices << " " << n << " by " << n << " symmetric positive matrices"
283 << std::endl;
284 bench.clear();
285 for (unsigned int i = 0; i < nb_matrices; i++) {
286 vpMatrix M;
287#if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_OPENCV)
288 double det = 0.;
289 // don't put singular matrices in the benchmark
290 for (M = make_random_symmetric_positive_matrix(n); std::fabs(det = M.det()) < .01;
291 M = make_random_symmetric_positive_matrix(n)) {
292 if (verbose) {
293 std::cout << " Generated random symmetric positive matrix A=" << std::endl << M << std::endl;
294 std::cout << " Generated random symmetric positive matrix not "
295 "invertibleL: det="
296 << det << ". Retrying..." << std::endl;
297 }
298 }
299#else
300 M = make_random_symmetric_positive_matrix(n);
301#endif
302 bench.push_back(M);
303 }
304}
305
306void create_bench_random_triangular_matrix(unsigned int nb_matrices, unsigned int n, bool verbose,
307 std::vector<vpMatrix> &bench)
308{
309 if (verbose)
310 std::cout << "Create a bench of " << nb_matrices << " " << n << " by " << n << " triangular matrices" << std::endl;
311 bench.clear();
312 for (unsigned int i = 0; i < nb_matrices; i++) {
313 vpMatrix M;
314#if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_OPENCV)
315 double det = 0.;
316 // don't put singular matrices in the benchmark
317 for (M = make_random_triangular_matrix(n); std::fabs(det = M.det()) < .01; M = make_random_triangular_matrix(n)) {
318 if (verbose) {
319 std::cout << " Generated random symmetric positive matrix A=" << std::endl << M << std::endl;
320 std::cout << " Generated random symmetric positive matrix not "
321 "invertibleL: det="
322 << det << ". Retrying..." << std::endl;
323 }
324 }
325#else
326 M = make_random_triangular_matrix(n);
327#endif
328 bench.push_back(M);
329 }
330}
331
332int test_inverse(const std::vector<vpMatrix> &bench, const std::vector<vpMatrix> &result)
333{
334 double epsilon = 1e-10;
335 for (unsigned int i = 0; i < bench.size(); i++) {
336 vpMatrix I = bench[i] * result[i];
337 if (std::fabs(I.frobeniusNorm() - sqrt(static_cast<double>(bench[0].AtA().getRows()))) > epsilon) {
338 std::cout << "Bad inverse[" << i << "]: " << I.frobeniusNorm() << " " << sqrt(static_cast<double>(bench[0].AtA().getRows()))
339 << std::endl;
340 return EXIT_FAILURE;
341 }
342 }
343 return EXIT_SUCCESS;
344}
345
346int test_inverse_lu_small(bool verbose, const std::vector<vpMatrix> &bench, double &time)
347{
348 if (verbose)
349 std::cout << "Test inverse by LU on small matrices" << std::endl;
350 // Compute inverse
351 if (verbose)
352 std::cout << " Inverting " << bench[0].getRows() << "x" << bench[0].getCols() << " small matrix." << std::endl;
353 std::vector<vpMatrix> result(bench.size());
354 double t = vpTime::measureTimeMs();
355 for (unsigned int i = 0; i < bench.size(); i++) {
356 result[i] = bench[i].inverseByLU();
357 }
358 time = vpTime::measureTimeMs() - t;
359
360 // Test inverse
361 return test_inverse(bench, result);
362}
363
364#if defined(VISP_HAVE_EIGEN3)
365int test_inverse_lu_eigen3(bool verbose, const std::vector<vpMatrix> &bench, double &time)
366{
367 if (verbose)
368 std::cout << "Test inverse by LU using Eigen3 3rd party" << std::endl;
369 // Compute inverse
370 if (verbose)
371 std::cout << " Inverting " << bench[0].AtA().getRows() << "x" << bench[0].AtA().getCols()
372 << " matrix using LU decomposition (Eigen3)." << std::endl;
373 std::vector<vpMatrix> result(bench.size());
374 double t = vpTime::measureTimeMs();
375 for (unsigned int i = 0; i < bench.size(); i++) {
376 result[i] = bench[i].AtA().inverseByLUEigen3() * bench[i].transpose();
377 }
378 time = vpTime::measureTimeMs() - t;
379
380 // Test inverse
381 return test_inverse(bench, result);
382}
383#endif
384
385#if defined(VISP_HAVE_LAPACK)
386int test_inverse_lu_lapack(bool verbose, const std::vector<vpMatrix> &bench, double &time)
387{
388 if (verbose)
389 std::cout << "Test inverse by LU using Lapack 3rd party" << std::endl;
390 // Compute inverse
391 if (verbose)
392 std::cout << " Inverting " << bench[0].AtA().getRows() << "x" << bench[0].AtA().getCols()
393 << " matrix using LU decomposition (Lapack)." << std::endl;
394 std::vector<vpMatrix> result(bench.size());
395 double t = vpTime::measureTimeMs();
396 for (unsigned int i = 0; i < bench.size(); i++) {
397 result[i] = bench[i].AtA().inverseByLULapack() * bench[i].transpose();
398 }
399 time = vpTime::measureTimeMs() - t;
400
401 // Test inverse
402 return test_inverse(bench, result);
403}
404
405int test_inverse_cholesky_lapack(bool verbose, const std::vector<vpMatrix> &bench, double &time)
406{
407 if (verbose)
408 std::cout << "Test inverse by Cholesky using Lapack 3rd party" << std::endl;
409 // Compute inverse
410 if (verbose)
411 std::cout << " Inverting " << bench[0].AtA().getRows() << "x" << bench[0].AtA().getCols()
412 << " matrix using cholesky decomposition (Lapack)." << std::endl;
413 std::vector<vpMatrix> result(bench.size());
414 double t = vpTime::measureTimeMs();
415 for (unsigned int i = 0; i < bench.size(); i++) {
416 result[i] = bench[i].AtA().inverseByCholeskyLapack() * bench[i].transpose();
417 }
418 time = vpTime::measureTimeMs() - t;
419
420 // Test inverse
421 return test_inverse(bench, result);
422}
423
424int test_inverse_qr_lapack(bool verbose, const std::vector<vpMatrix> &bench, double &time)
425{
426 if (verbose)
427 std::cout << "Test inverse by QR using Lapack 3rd party" << std::endl;
428 // Compute inverse
429 if (verbose)
430 std::cout << " Inverting " << bench[0].AtA().getRows() << "x" << bench[0].AtA().getCols()
431 << " matrix using QR decomposition (Lapack)" << std::endl;
432 std::vector<vpMatrix> result(bench.size());
433 double t = vpTime::measureTimeMs();
434 for (unsigned int i = 0; i < bench.size(); i++) {
435 result[i] = bench[i].AtA().inverseByQRLapack() * bench[i].transpose();
436 }
437 time = vpTime::measureTimeMs() - t;
438
439 // Test inverse
440 return test_inverse(bench, result);
441}
442#endif
443
444#if defined(VISP_HAVE_OPENCV)
445int test_inverse_lu_opencv(bool verbose, const std::vector<vpMatrix> &bench, double &time)
446{
447 if (verbose)
448 std::cout << "Test inverse by LU using OpenCV 3rd party" << std::endl;
449 // Compute inverse
450 if (verbose)
451 std::cout << " Inverting " << bench[0].AtA().getRows() << "x" << bench[0].AtA().getCols()
452 << " matrix using LU decomposition (OpenCV)" << std::endl;
453 std::vector<vpMatrix> result(bench.size());
454 double t = vpTime::measureTimeMs();
455 for (unsigned int i = 0; i < bench.size(); i++) {
456 result[i] = bench[i].AtA().inverseByLUOpenCV() * bench[i].transpose();
457 }
458 time = vpTime::measureTimeMs() - t;
459
460 // Test inverse
461 return test_inverse(bench, result);
462}
463
464int test_inverse_cholesky_opencv(bool verbose, const std::vector<vpMatrix> &bench, double &time)
465{
466 if (verbose)
467 std::cout << "Test inverse by Cholesky using OpenCV 3rd party" << std::endl;
468 // Compute inverse
469 if (verbose)
470 std::cout << " Inverting " << bench[0].AtA().getRows() << "x" << bench[0].AtA().getCols()
471 << " matrix using Cholesky decomposition (OpenCV)" << std::endl;
472 std::vector<vpMatrix> result(bench.size());
473 double t = vpTime::measureTimeMs();
474 for (unsigned int i = 0; i < bench.size(); i++) {
475 result[i] = bench[i].AtA().inverseByCholeskyOpenCV() * bench[i].transpose();
476 }
477 time = vpTime::measureTimeMs() - t;
478
479 // Test inverse
480 return test_inverse(bench, result);
481}
482#endif
483
484#if defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV)
485// SVD is only available for these 3rd parties
486int test_pseudo_inverse(bool verbose, const std::vector<vpMatrix> &bench, double &time)
487{
488 if (verbose)
489 std::cout << "Test pseudo inverse using either Lapack, Eigen3 or OpenCV 3rd party" << std::endl;
490 // Compute inverse
491 if (verbose)
492 std::cout << " Pseudo inverting " << bench[0].AtA().getRows() << "x" << bench[0].AtA().getCols() << " matrix"
493 << std::endl;
494 std::vector<vpMatrix> result(bench.size());
495 double t = vpTime::measureTimeMs();
496 for (unsigned int i = 0; i < bench.size(); i++) {
497 result[i] = bench[i].AtA().pseudoInverse() * bench[i].transpose();
498 }
499 time = vpTime::measureTimeMs() - t;
500
501 // Test inverse
502 return test_inverse(bench, result);
503}
504
505int test_inverse_triangular(bool verbose, const std::vector<vpMatrix> &bench, double &time)
506{
507 if (verbose)
508 std::cout << "Test inverse triangular using Lapack" << std::endl;
509 // Compute inverse
510 if (verbose)
511 std::cout << " Triangular inverse " << bench[0].getRows() << "x" << bench[0].getCols() << " matrix" << std::endl;
512 std::vector<vpMatrix> result(bench.size());
513 double t = vpTime::measureTimeMs();
514 for (unsigned int i = 0; i < bench.size(); i++) {
515 result[i] = bench[i].inverseTriangular(true);
516 }
517 time = vpTime::measureTimeMs() - t;
518
519 // Test inverse
520 return test_inverse(bench, result);
521}
522#endif
523
524void save_time(const std::string &method, bool verbose, bool use_plot_file, std::ofstream &of, double time)
525{
526 if (use_plot_file)
527 of << time << "\t";
528 if (verbose || !use_plot_file) {
529 std::cout << method << time << std::endl;
530 }
531}
532
533int main(int argc, const char *argv[])
534{
535 try {
536 unsigned int nb_matrices = 1000;
537 unsigned int nb_iterations = 10;
538 unsigned int nb_rows = 6;
539 unsigned int nb_cols = 6;
540 bool verbose = false;
541 std::string plotfile("plot-inv.csv");
542 bool use_plot_file = false;
543 std::ofstream of;
544
545 // Read the command line options
546 if (getOptions(argc, argv, nb_matrices, nb_iterations, use_plot_file, plotfile, nb_rows, nb_cols, verbose) ==
547 false) {
548 return EXIT_FAILURE;
549 }
550
551 if (use_plot_file) {
552 of.open(plotfile.c_str());
553 of << "iter"
554 << "\t";
555
556#if defined(VISP_HAVE_LAPACK)
557 of << "\"LU Lapack\""
558 << "\t";
559#endif
560#if defined(VISP_HAVE_EIGEN3)
561 of << "\"LU Eigen3\""
562 << "\t";
563#endif
564#if defined(VISP_HAVE_OPENCV)
565 of << "\"LU OpenCV\""
566 << "\t";
567#endif
568
569#if defined(VISP_HAVE_LAPACK)
570 of << "\"Cholesky Lapack\""
571 << "\t";
572#endif
573
574#if defined(VISP_HAVE_OPENCV)
575 of << "\"Cholesky OpenCV\""
576 << "\t";
577#endif
578
579#if defined(VISP_HAVE_LAPACK)
580 of << "\"QR Lapack\""
581 << "\t";
582#endif
583
584#if defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV)
585 of << "\"Pseudo inverse (Lapack, Eigen3 or OpenCV)\""
586 << "\t";
587#endif
588 of << std::endl;
589 }
590
591 int ret = EXIT_SUCCESS;
592 for (unsigned int iter = 0; iter < nb_iterations; iter++) {
593 std::vector<vpMatrix> bench_random_matrices_11;
594 create_bench_random_matrix(nb_matrices, 1, 1, verbose, bench_random_matrices_11);
595 std::vector<vpMatrix> bench_random_matrices_22;
596 create_bench_random_matrix(nb_matrices, 2, 2, verbose, bench_random_matrices_22);
597 std::vector<vpMatrix> bench_random_matrices_33;
598 create_bench_random_matrix(nb_matrices, 3, 3, verbose, bench_random_matrices_33);
599#if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_OPENCV)
600 std::vector<vpMatrix> bench_random_matrices;
601 create_bench_random_matrix(nb_matrices, nb_rows, nb_cols, verbose, bench_random_matrices);
602 std::vector<vpMatrix> bench_symmetric_positive_matrices;
603 create_bench_symmetric_positive_matrix(nb_matrices, nb_rows, verbose, bench_symmetric_positive_matrices);
604 std::vector<vpMatrix> bench_triangular_matrices;
605 create_bench_random_triangular_matrix(nb_matrices, nb_rows, verbose, bench_triangular_matrices);
606#endif
607
608 if (use_plot_file)
609 of << iter << "\t";
610
611 double time;
612
613 // LU inverse on 1 by 1 matrices
614 ret += test_inverse_lu_small(verbose, bench_random_matrices_11, time);
615 save_time("Inverse by LU 1x1: ", verbose, use_plot_file, of, time);
616 // LU inverse on 2 by 2 matrices
617 ret += test_inverse_lu_small(verbose, bench_random_matrices_22, time);
618 save_time("Inverse by LU 2x2: ", verbose, use_plot_file, of, time);
619 // LU inverse on 3 by 3 matrices
620 ret += test_inverse_lu_small(verbose, bench_random_matrices_33, time);
621 save_time("Inverse by LU 3x3: ", verbose, use_plot_file, of, time);
622
623 // LU decomposition
624#if defined(VISP_HAVE_LAPACK)
625 ret += test_inverse_lu_lapack(verbose, bench_random_matrices, time);
626 save_time("Inverse by LU (Lapack): ", verbose, use_plot_file, of, time);
627#endif
628
629#if defined(VISP_HAVE_EIGEN3)
630 ret += test_inverse_lu_eigen3(verbose, bench_random_matrices, time);
631 save_time("Inverse by LU (Eigen3): ", verbose, use_plot_file, of, time);
632#endif
633
634#if defined(VISP_HAVE_OPENCV)
635 ret += test_inverse_lu_opencv(verbose, bench_random_matrices, time);
636 save_time("Inverse by LU (OpenCV): ", verbose, use_plot_file, of, time);
637#endif
638
639 // Cholesky for symmetric positive matrices
640#if defined(VISP_HAVE_LAPACK)
641 ret += test_inverse_cholesky_lapack(verbose, bench_symmetric_positive_matrices, time);
642 save_time("Inverse by Cholesly (Lapack): ", verbose, use_plot_file, of, time);
643#endif
644
645#if defined(VISP_HAVE_OPENCV)
646 ret += test_inverse_cholesky_opencv(verbose, bench_symmetric_positive_matrices, time);
647 save_time("Inverse by Cholesky (OpenCV): ", verbose, use_plot_file, of, time);
648#endif
649
650 // QR decomposition
651#if defined(VISP_HAVE_LAPACK)
652 ret += test_inverse_qr_lapack(verbose, bench_random_matrices, time);
653 save_time("Inverse by QR (Lapack): ", verbose, use_plot_file, of, time);
654#endif
655
656 // Pseudo-inverse with SVD
657#if defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV)
658 ret += test_pseudo_inverse(verbose, bench_random_matrices, time);
659 save_time("Pseudo inverse (Lapack, Eigen3, OpenCV): ", verbose, use_plot_file, of, time);
660#endif
661
662 // Test inverse triangular
663#if defined(VISP_HAVE_LAPACK)
664 ret += test_inverse_triangular(verbose, bench_triangular_matrices, time);
665 save_time("Triangular inverse (Lapack): ", verbose, use_plot_file, of, time);
666#endif
667
668 if (use_plot_file)
669 of << std::endl;
670 }
671 if (use_plot_file) {
672 of.close();
673 std::cout << "Result saved in " << plotfile << std::endl;
674 }
675
676 if (ret == EXIT_SUCCESS) {
677 std::cout << "Test succeed" << std::endl;
678 }
679 else {
680 std::cout << "Test failed" << std::endl;
681 }
682
683 return ret;
684 }
685 catch (const vpException &e) {
686 std::cout << "Catch an exception: " << e.getStringMessage() << std::endl;
687 return EXIT_FAILURE;
688 }
689}
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
vpMatrix AtA() const
double det(vpDetMethod method=LU_DECOMPOSITION) const
void clear()
Definition vpMatrix.h:247
vpMatrix t() const
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
VISP_EXPORT double measureTimeMs()