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