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 void create_bench_random_matrix(
unsigned int nb_matrices,
unsigned int nb_rows,
unsigned int nb_cols,
bool verbose,
207 std::vector<vpMatrix> &bench)
210 std::cout <<
"Create a bench of " << nb_matrices <<
" " << nb_rows <<
" by " << nb_cols <<
" matrices" << std::endl;
212 for (
unsigned int i = 0; i < nb_matrices; i++) {
214 #if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || (VISP_HAVE_OPENCV_VERSION >= 0x020101) || \ 215 defined(VISP_HAVE_GSL) 218 for (M = make_random_matrix(nb_rows, nb_cols); std::fabs(det = M.
AtA().
det()) < .01;
219 M = make_random_matrix(nb_rows, nb_cols)) {
221 std::cout <<
" Generated random matrix AtA=" << std::endl << M.
AtA() << std::endl;
222 std::cout <<
" Generated random matrix not invertible: det=" << det <<
". Retrying..." << std::endl;
226 M = make_random_matrix(nb_rows, nb_cols);
232 void create_bench_symmetric_positive_matrix(
unsigned int nb_matrices,
unsigned int n,
bool verbose,
233 std::vector<vpMatrix> &bench)
236 std::cout <<
"Create a bench of " << nb_matrices <<
" " << n <<
" by " << n <<
" symmetric positive matrices" 239 for (
unsigned int i = 0; i < nb_matrices; i++) {
241 #if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || (VISP_HAVE_OPENCV_VERSION >= 0x020101) || \ 242 defined(VISP_HAVE_GSL) 245 for (M = make_random_symmetric_positive_matrix(n); std::fabs(det = M.
det()) < .01;
246 M = make_random_symmetric_positive_matrix(n)) {
248 std::cout <<
" Generated random symmetric positive matrix A=" << std::endl << M << std::endl;
249 std::cout <<
" Generated random symmetric positive matrix not " 251 << det <<
". Retrying..." << std::endl;
255 M = make_random_symmetric_positive_matrix(n);
261 int test_inverse(
const std::vector<vpMatrix> &bench,
const std::vector<vpMatrix> &result)
263 for (
unsigned int i = 0; i < bench.size(); i++) {
265 if (std::fabs(I.
euclideanNorm() - sqrt((
double)bench[0].AtA().getRows())) > 1e-10) {
266 std::cout <<
"Bad inverse[" << i <<
"]: " << I.
euclideanNorm() <<
" " << sqrt((
double)bench[0].AtA().getRows())
274 #if defined(VISP_HAVE_EIGEN3) 275 int test_inverse_lu_eigen3(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
278 std::cout <<
"Test inverse by LU using Eigen3 3rd party" << std::endl;
281 std::cout <<
" Inverting " << bench[0].AtA().getRows() <<
"x" << bench[0].AtA().getCols()
282 <<
" matrix using LU decomposition (Eigen3)." << std::endl;
283 std::vector<vpMatrix> result(bench.size());
285 for (
unsigned int i = 0; i < bench.size(); i++) {
286 result[i] = bench[i].AtA().inverseByLUEigen3() * bench[i].transpose();
291 return test_inverse(bench, result);
295 #if defined(VISP_HAVE_LAPACK) 296 int test_inverse_lu_lapack(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
299 std::cout <<
"Test inverse by LU using Lapack 3rd party" << std::endl;
302 std::cout <<
" Inverting " << bench[0].AtA().getRows() <<
"x" << bench[0].AtA().getCols()
303 <<
" matrix using LU decomposition (Lapack)." << std::endl;
304 std::vector<vpMatrix> result(bench.size());
306 for (
unsigned int i = 0; i < bench.size(); i++) {
307 result[i] = bench[i].AtA().inverseByLULapack() * bench[i].transpose();
312 return test_inverse(bench, result);
315 int test_inverse_cholesky_lapack(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
318 std::cout <<
"Test inverse by Cholesky using Lapack 3rd party" << std::endl;
321 std::cout <<
" Inverting " << bench[0].AtA().getRows() <<
"x" << bench[0].AtA().getCols()
322 <<
" matrix using cholesky decomposition (Lapack)." << std::endl;
323 std::vector<vpMatrix> result(bench.size());
325 for (
unsigned int i = 0; i < bench.size(); i++) {
326 result[i] = bench[i].AtA().inverseByCholeskyLapack() * bench[i].transpose();
331 return test_inverse(bench, result);
334 int test_inverse_qr_lapack(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
337 std::cout <<
"Test inverse by QR using Lapack 3rd party" << std::endl;
340 std::cout <<
" Inverting " << bench[0].AtA().getRows() <<
"x" << bench[0].AtA().getCols()
341 <<
" matrix using QR decomposition (Lapack)" << std::endl;
342 std::vector<vpMatrix> result(bench.size());
344 for (
unsigned int i = 0; i < bench.size(); i++) {
345 result[i] = bench[i].AtA().inverseByQRLapack() * bench[i].transpose();
350 return test_inverse(bench, result);
354 #if defined(VISP_HAVE_GSL) 355 int test_inverse_lu_gsl(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
358 std::cout <<
"Test inverse by LU using GSL 3rd party" << std::endl;
361 std::cout <<
" Inverting " << bench[0].AtA().getRows() <<
"x" << bench[0].AtA().getCols()
362 <<
" matrix using LU decomposition (GSL)" << std::endl;
363 std::vector<vpMatrix> result(bench.size());
365 for (
unsigned int i = 0; i < bench.size(); i++) {
366 result[i] = bench[i].AtA().inverseByLUGsl() * bench[i].transpose();
371 return test_inverse(bench, result);
375 #if (VISP_HAVE_OPENCV_VERSION >= 0x020101) 376 int test_inverse_lu_opencv(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
379 std::cout <<
"Test inverse by LU using OpenCV 3rd party" << std::endl;
382 std::cout <<
" Inverting " << bench[0].AtA().getRows() <<
"x" << bench[0].AtA().getCols()
383 <<
" matrix using LU decomposition (OpenCV)" << std::endl;
384 std::vector<vpMatrix> result(bench.size());
386 for (
unsigned int i = 0; i < bench.size(); i++) {
387 result[i] = bench[i].AtA().inverseByLUOpenCV() * bench[i].transpose();
392 return test_inverse(bench, result);
395 int test_inverse_cholesky_opencv(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
398 std::cout <<
"Test inverse by Cholesky using OpenCV 3rd party" << std::endl;
401 std::cout <<
" Inverting " << bench[0].AtA().getRows() <<
"x" << bench[0].AtA().getCols()
402 <<
" matrix using Cholesky decomposition (OpenCV)" << std::endl;
403 std::vector<vpMatrix> result(bench.size());
405 for (
unsigned int i = 0; i < bench.size(); i++) {
406 result[i] = bench[i].AtA().inverseByCholeskyOpenCV() * bench[i].transpose();
411 return test_inverse(bench, result);
415 #if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || (VISP_HAVE_OPENCV_VERSION >= 0x020101) || \ 416 defined(VISP_HAVE_GSL) 418 int test_pseudo_inverse(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
421 std::cout <<
"Test pseudo inverse using either Eigen3, Lapack, OpenCV or " 426 std::cout <<
" Pseudo inverting " << bench[0].AtA().getRows() <<
"x" << bench[0].AtA().getCols() <<
" matrix" 428 std::vector<vpMatrix> result(bench.size());
430 for (
unsigned int i = 0; i < bench.size(); i++) {
431 result[i] = bench[i].AtA().pseudoInverse() * bench[i].transpose();
436 return test_inverse(bench, result);
440 void save_time(
const std::string &method,
bool verbose,
bool use_plot_file, std::ofstream &of,
double time)
444 if (verbose || !use_plot_file) {
445 std::cout << method << time << std::endl;
449 int main(
int argc,
const char *argv[])
452 #if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || (VISP_HAVE_OPENCV_VERSION >= 0x020101) || \ 453 defined(VISP_HAVE_GSL) 454 unsigned int nb_matrices = 1000;
455 unsigned int nb_iterations = 10;
456 unsigned int nb_rows = 6;
457 unsigned int nb_cols = 6;
458 bool verbose =
false;
459 std::string plotfile(
"plot-inv.csv");
460 bool use_plot_file =
false;
464 if (getOptions(argc, argv, nb_matrices, nb_iterations, use_plot_file, plotfile, nb_rows, nb_cols, verbose) ==
470 of.open(plotfile.c_str());
474 #if defined(VISP_HAVE_LAPACK) 475 of <<
"\"LU Lapack\"" 478 #if defined(VISP_HAVE_EIGEN3) 479 of <<
"\"LU Eigen3\"" 482 #if (VISP_HAVE_OPENCV_VERSION >= 0x020101) 483 of <<
"\"LU OpenCV\"" 486 #if defined(VISP_HAVE_GSL) 491 #if defined(VISP_HAVE_LAPACK) 492 of <<
"\"Cholesky Lapack\"" 496 #if (VISP_HAVE_OPENCV_VERSION >= 0x020101) 497 of <<
"\"Cholesky OpenCV\"" 501 #if defined(VISP_HAVE_LAPACK) 502 of <<
"\"QR Lapack\"" 506 #if defined(VISP_HAVE_LAPACK) || (VISP_HAVE_OPENCV_VERSION >= 0x020101) || defined(VISP_HAVE_GSL) 507 of <<
"\"Pseudo inverse (Lapack, OpenCV, GSL)\"" 513 int ret = EXIT_SUCCESS;
514 for (
unsigned int iter = 0; iter < nb_iterations; iter++) {
515 std::vector<vpMatrix> bench_random_matrices;
516 create_bench_random_matrix(nb_matrices, nb_rows, nb_cols, verbose, bench_random_matrices);
517 std::vector<vpMatrix> bench_symmetric_positive_matrices;
518 create_bench_symmetric_positive_matrix(nb_matrices, nb_rows, verbose, bench_symmetric_positive_matrices);
525 #if defined(VISP_HAVE_LAPACK) 526 ret += test_inverse_lu_lapack(verbose, bench_random_matrices, time);
527 save_time(
"Inverse by LU (Lapack): ", verbose, use_plot_file, of, time);
530 #if defined(VISP_HAVE_EIGEN3) 531 ret += test_inverse_lu_eigen3(verbose, bench_random_matrices, time);
532 save_time(
"Inverse by LU (Eigen3): ", verbose, use_plot_file, of, time);
535 #if (VISP_HAVE_OPENCV_VERSION >= 0x020101) 536 ret += test_inverse_lu_opencv(verbose, bench_random_matrices, time);
537 save_time(
"Inverse by LU (OpenCV): ", verbose, use_plot_file, of, time);
540 #if defined(VISP_HAVE_GSL) 541 ret += test_inverse_lu_gsl(verbose, bench_random_matrices, time);
542 save_time(
"Inverse by LU (GSL): ", verbose, use_plot_file, of, time);
546 #if defined(VISP_HAVE_LAPACK) 547 ret += test_inverse_cholesky_lapack(verbose, bench_symmetric_positive_matrices, time);
548 save_time(
"Inverse by Cholesly (Lapack): ", verbose, use_plot_file, of, time);
551 #if (VISP_HAVE_OPENCV_VERSION >= 0x020101) 552 ret += test_inverse_cholesky_opencv(verbose, bench_symmetric_positive_matrices, time);
553 save_time(
"Inverse by Cholesky (OpenCV): ", verbose, use_plot_file, of, time);
557 #if defined(VISP_HAVE_LAPACK) 558 ret += test_inverse_qr_lapack(verbose, bench_random_matrices, time);
559 save_time(
"Inverse by QR (Lapack): ", verbose, use_plot_file, of, time);
563 #if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || (VISP_HAVE_OPENCV_VERSION >= 0x020101) || \ 564 defined(VISP_HAVE_GSL) 565 ret += test_pseudo_inverse(verbose, bench_random_matrices, time);
566 save_time(
"Pseudo inverse (Lapack, Eigen3, OpenCV or GSL): ", verbose, use_plot_file, of, time);
574 std::cout <<
"Result saved in " << plotfile << std::endl;
577 if (ret == EXIT_SUCCESS) {
578 std::cout <<
"Test succeed" << std::endl;
580 std::cout <<
"Test failed" << std::endl;
587 std::cout <<
"Test does nothing since you dont't have Eigen3, Lapack, " 588 "OpenCV or GSL 3rd party" Implementation of a matrix and operations on matrices.
void resize(const unsigned int nrows, const unsigned int ncols, const bool flagNullify=true, const 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)
unsigned int getRows() const
double det(vpDetMethod method=LU_DECOMPOSITION) const
double euclideanNorm() const
const std::string & getStringMessage(void) const
Send a reference (constant) related the error message (can be empty).