51 #include <visp3/core/vpColVector.h> 52 #include <visp3/core/vpMatrix.h> 53 #include <visp3/core/vpTime.h> 54 #include <visp3/io/vpParseArgv.h> 57 #define GETOPTARGS "cdn:i:pf:R:C:vh" 67 void usage(
const char *name,
const char *badparam)
70 Test matrix inversions\n\ 71 using LU, QR and Cholesky methods as well as Pseudo-inverse.\n\ 72 Outputs a comparison of these methods.\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);
81 -n <number of matrices> \n\ 82 Number of matrices inverted during each test loop.\n\ 84 -i <number of iterations> \n\ 85 Number of iterations of the test.\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\ 93 -R <number of rows>\n\ 94 Number of rows of the automatically generated matrices \n\ 97 -C <number of columns>\n\ 98 Number of colums of the automatically generated matrices \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\ 107 Print the help.\n\n");
110 fprintf(stderr,
"ERROR: \n");
111 fprintf(stderr,
"\nBad parameter [%s]\n", badparam);
122 bool 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)
131 usage(argv[0], NULL);
135 nb_matrices = (
unsigned int)atoi(optarg_);
138 nb_iterations = (
unsigned int)atoi(optarg_);
142 use_plot_file =
true;
145 use_plot_file =
true;
148 nbrows = (
unsigned int)atoi(optarg_);
151 nbcols = (
unsigned int)atoi(optarg_);
162 usage(argv[0], optarg_);
168 if ((c == 1) || (c == -1)) {
170 usage(argv[0], NULL);
171 std::cerr <<
"ERROR: " << std::endl;
172 std::cerr <<
" Bad argument " << optarg_ << std::endl << std::endl;
179 vpMatrix make_random_matrix(
unsigned int nbrows,
unsigned int nbcols)
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;
190 vpMatrix make_random_symmetric_positive_matrix(
unsigned int n)
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;
201 A = 0.5 * (A + A.
t());
206 vpMatrix make_random_triangular_matrix(
unsigned int nbrows)
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);
223 void create_bench_random_matrix(
unsigned int nb_matrices,
unsigned int nb_rows,
unsigned int nb_cols,
bool verbose,
224 std::vector<vpMatrix> &bench)
227 std::cout <<
"Create a bench of " << nb_matrices <<
" " << nb_rows <<
" by " << nb_cols <<
" matrices" << std::endl;
229 for (
unsigned int i = 0; i < nb_matrices; i++) {
231 #if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || (VISP_HAVE_OPENCV_VERSION >= 0x020101) 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)) {
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;
242 M = make_random_matrix(nb_rows, nb_cols);
248 void create_bench_symmetric_positive_matrix(
unsigned int nb_matrices,
unsigned int n,
bool verbose,
249 std::vector<vpMatrix> &bench)
252 std::cout <<
"Create a bench of " << nb_matrices <<
" " << n <<
" by " << n <<
" symmetric positive matrices" 255 for (
unsigned int i = 0; i < nb_matrices; i++) {
257 #if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || (VISP_HAVE_OPENCV_VERSION >= 0x020101) 260 for (M = make_random_symmetric_positive_matrix(n); std::fabs(det = M.
det()) < .01;
261 M = make_random_symmetric_positive_matrix(n)) {
263 std::cout <<
" Generated random symmetric positive matrix A=" << std::endl << M << std::endl;
264 std::cout <<
" Generated random symmetric positive matrix not " 266 << det <<
". Retrying..." << std::endl;
270 M = make_random_symmetric_positive_matrix(n);
276 void create_bench_random_triangular_matrix(
unsigned int nb_matrices,
unsigned int n,
bool verbose,
277 std::vector<vpMatrix> &bench)
280 std::cout <<
"Create a bench of " << nb_matrices <<
" " << n <<
" by " << n <<
" triangular matrices" << std::endl;
282 for (
unsigned int i = 0; i < nb_matrices; i++) {
284 #if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || (VISP_HAVE_OPENCV_VERSION >= 0x020101) 287 for (M = make_random_triangular_matrix(n); std::fabs(det = M.
det()) < .01;
288 M = make_random_triangular_matrix(n)) {
290 std::cout <<
" Generated random symmetric positive matrix A=" << std::endl << M << std::endl;
291 std::cout <<
" Generated random symmetric positive matrix not " 293 << det <<
". Retrying..." << std::endl;
297 M = make_random_triangular_matrix(n);
303 int test_inverse(
const std::vector<vpMatrix> &bench,
const std::vector<vpMatrix> &result)
305 double epsilon = 1e-10;
306 for (
unsigned int i = 0; i < bench.size(); 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())
317 int test_inverse_lu_small(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
320 std::cout <<
"Test inverse by LU on small matrices" << std::endl;
323 std::cout <<
" Inverting " << bench[0].getRows() <<
"x" << bench[0].getCols()
324 <<
" small matrix." << std::endl;
325 std::vector<vpMatrix> result(bench.size());
327 for (
unsigned int i = 0; i < bench.size(); i++) {
328 result[i] = bench[i].inverseByLU();
333 return test_inverse(bench, result);
336 #if defined(VISP_HAVE_EIGEN3) 337 int test_inverse_lu_eigen3(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
340 std::cout <<
"Test inverse by LU using Eigen3 3rd party" << std::endl;
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());
347 for (
unsigned int i = 0; i < bench.size(); i++) {
348 result[i] = bench[i].AtA().inverseByLUEigen3() * bench[i].transpose();
353 return test_inverse(bench, result);
357 #if defined(VISP_HAVE_LAPACK) 358 int test_inverse_lu_lapack(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
361 std::cout <<
"Test inverse by LU using Lapack 3rd party" << std::endl;
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());
368 for (
unsigned int i = 0; i < bench.size(); i++) {
369 result[i] = bench[i].AtA().inverseByLULapack() * bench[i].transpose();
374 return test_inverse(bench, result);
377 int test_inverse_cholesky_lapack(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
380 std::cout <<
"Test inverse by Cholesky using Lapack 3rd party" << std::endl;
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());
387 for (
unsigned int i = 0; i < bench.size(); i++) {
388 result[i] = bench[i].AtA().inverseByCholeskyLapack() * bench[i].transpose();
393 return test_inverse(bench, result);
396 int test_inverse_qr_lapack(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
399 std::cout <<
"Test inverse by QR using Lapack 3rd party" << std::endl;
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());
406 for (
unsigned int i = 0; i < bench.size(); i++) {
407 result[i] = bench[i].AtA().inverseByQRLapack() * bench[i].transpose();
412 return test_inverse(bench, result);
416 #if (VISP_HAVE_OPENCV_VERSION >= 0x020101) 417 int test_inverse_lu_opencv(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
420 std::cout <<
"Test inverse by LU using OpenCV 3rd party" << std::endl;
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());
427 for (
unsigned int i = 0; i < bench.size(); i++) {
428 result[i] = bench[i].AtA().inverseByLUOpenCV() * bench[i].transpose();
433 return test_inverse(bench, result);
436 int test_inverse_cholesky_opencv(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
439 std::cout <<
"Test inverse by Cholesky using OpenCV 3rd party" << std::endl;
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());
446 for (
unsigned int i = 0; i < bench.size(); i++) {
447 result[i] = bench[i].AtA().inverseByCholeskyOpenCV() * bench[i].transpose();
452 return test_inverse(bench, result);
456 #if defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || (VISP_HAVE_OPENCV_VERSION >= 0x020101) 458 int test_pseudo_inverse(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
461 std::cout <<
"Test pseudo inverse using either Lapack, Eigen3 or OpenCV 3rd party" 465 std::cout <<
" Pseudo inverting " << bench[0].AtA().getRows() <<
"x" << bench[0].AtA().getCols() <<
" matrix" 467 std::vector<vpMatrix> result(bench.size());
469 for (
unsigned int i = 0; i < bench.size(); i++) {
470 result[i] = bench[i].AtA().pseudoInverse() * bench[i].transpose();
475 return test_inverse(bench, result);
478 int test_inverse_triangular(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
481 std::cout <<
"Test inverse triangular using Lapack" << std::endl;
484 std::cout <<
" Triangular inverse " << bench[0].getRows() <<
"x" << bench[0].getCols() <<
" matrix" 486 std::vector<vpMatrix> result(bench.size());
488 for (
unsigned int i = 0; i < bench.size(); i++) {
489 result[i] = bench[i].inverseTriangular(
true);
494 return test_inverse(bench, result);
498 void save_time(
const std::string &method,
bool verbose,
bool use_plot_file, std::ofstream &of,
double time)
502 if (verbose || !use_plot_file) {
503 std::cout << method << time << std::endl;
507 int main(
int argc,
const char *argv[])
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;
520 if (getOptions(argc, argv, nb_matrices, nb_iterations, use_plot_file, plotfile, nb_rows, nb_cols, verbose) ==
526 of.open(plotfile.c_str());
530 #if defined(VISP_HAVE_LAPACK) 531 of <<
"\"LU Lapack\"" 534 #if defined(VISP_HAVE_EIGEN3) 535 of <<
"\"LU Eigen3\"" 538 #if (VISP_HAVE_OPENCV_VERSION >= 0x020101) 539 of <<
"\"LU OpenCV\"" 543 #if defined(VISP_HAVE_LAPACK) 544 of <<
"\"Cholesky Lapack\"" 548 #if (VISP_HAVE_OPENCV_VERSION >= 0x020101) 549 of <<
"\"Cholesky OpenCV\"" 553 #if defined(VISP_HAVE_LAPACK) 554 of <<
"\"QR Lapack\"" 558 #if defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || (VISP_HAVE_OPENCV_VERSION >= 0x020101) 559 of <<
"\"Pseudo inverse (Lapack, Eigen3 or OpenCV)\"" 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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
647 std::cout <<
"Result saved in " << plotfile << std::endl;
650 if (ret == EXIT_SUCCESS) {
651 std::cout <<
"Test succeed" << std::endl;
653 std::cout <<
"Test failed" << std::endl;
Implementation of a matrix and operations on matrices.
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
error that can be emited by ViSP classes.
unsigned int getCols() const
VISP_EXPORT double measureTimeMs()
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
double frobeniusNorm() const
unsigned int getRows() const
double det(vpDetMethod method=LU_DECOMPOSITION) const
const std::string & getStringMessage() const
Send a reference (constant) related the error message (can be empty).