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