44 #include <visp3/core/vpColVector.h>
45 #include <visp3/core/vpMatrix.h>
46 #include <visp3/core/vpTime.h>
47 #include <visp3/io/vpParseArgv.h>
50 #define GETOPTARGS "cdn:i:pf:R:C:vh"
52 #ifdef ENABLE_VISP_NAMESPACE
64 void usage(
const char *name,
const char *badparam)
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\
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",
79 -n <number of matrices> \n\
80 Number of matrices inverted during each test loop.\n\
82 -i <number of iterations> \n\
83 Number of iterations of the test.\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\
91 -R <number of rows>\n\
92 Number of rows of the automatically generated matrices \n\
95 -C <number of columns>\n\
96 Number of colums of the automatically generated matrices \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\
105 Print the help.\n\n");
108 fprintf(stderr,
"ERROR: \n");
109 fprintf(stderr,
"\nBad parameter [%s]\n", badparam);
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)
129 usage(argv[0],
nullptr);
133 nb_matrices = (
unsigned int)atoi(optarg_);
136 nb_iterations = (
unsigned int)atoi(optarg_);
140 use_plot_file =
true;
143 use_plot_file =
true;
146 nbrows = (
unsigned int)atoi(optarg_);
149 nbcols = (
unsigned int)atoi(optarg_);
160 usage(argv[0], optarg_);
166 if ((c == 1) || (c == -1)) {
168 usage(argv[0],
nullptr);
169 std::cerr <<
"ERROR: " << std::endl;
170 std::cerr <<
" Bad argument " << optarg_ << std::endl << std::endl;
177 vpMatrix make_random_matrix(
unsigned int nbrows,
unsigned int nbcols)
182 for (
unsigned int i = 0; i < A.
getRows(); i++) {
183 for (
unsigned int j = 0; j < A.
getCols(); j++) {
184 A[i][j] =
static_cast<double>(rand()) /
static_cast<double>(RAND_MAX);
191 vpMatrix make_random_symmetric_matrix(
unsigned int nbrows)
196 for (
unsigned int i = 0; i < A.
getRows(); i++) {
197 for (
unsigned int j = i; j < A.
getCols(); j++) {
198 A[i][j] =
static_cast<double>(rand()) /
static_cast<double>(RAND_MAX);
208 void create_bench_random_matrix(
unsigned int nb_matrices,
unsigned int nb_rows,
unsigned int nb_cols,
bool verbose,
209 std::vector<vpMatrix> &bench)
212 std::cout <<
"Create a bench of " << nb_matrices <<
" " << nb_rows <<
" by " << nb_cols <<
" matrices" << std::endl;
214 for (
unsigned int i = 0; i < nb_matrices; i++) {
230 M = make_random_matrix(nb_rows, nb_cols);
236 void create_bench_random_symmetric_matrix(
unsigned int nb_matrices,
unsigned int nb_rows,
bool verbose,
237 std::vector<vpMatrix> &bench)
240 std::cout <<
"Create a bench of " << nb_matrices <<
" " << nb_rows <<
" by " << nb_rows <<
" symmetric matrices" << std::endl;
242 for (
unsigned int i = 0; i < nb_matrices; i++) {
258 M = make_random_symmetric_matrix(nb_rows);
264 int test_svd(std::vector<vpMatrix> M, std::vector<vpMatrix> U, std::vector<vpColVector> s, std::vector<vpMatrix> V,
double &error)
266 for (
unsigned int i = 0; i < M.size(); i++) {
271 error = D.frobeniusNorm();
273 std::cout <<
"SVD decomposition failed. Error: " << error << std::endl;
280 int test_eigen_values(std::vector<vpMatrix> M, std::vector<vpColVector> e, std::vector<vpMatrix> V,
281 std::vector<vpColVector> e2)
283 for (
unsigned int i = 0; i < M.size(); i++) {
286 std::cout <<
"Eigen values differ" << std::endl;
291 vpMatrix MV_VD = M[i] * V[i] - V[i] * D;
293 std::cout <<
"Eigen values/vector decomposition failed" << std::endl;
300 #if defined(VISP_HAVE_EIGEN3)
301 int test_svd_eigen3(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time,
double &error)
304 std::cout <<
"Test SVD using Eigen3 3rd party" << std::endl;
307 std::cout <<
" SVD on a " << bench[0].getRows() <<
"x" << bench[0].getCols() <<
" matrix" << std::endl;
309 std::vector<vpMatrix> U = bench;
310 std::vector<vpMatrix> V(bench.size());
311 std::vector<vpColVector> s(bench.size());
314 for (
unsigned int i = 0; i < bench.size(); i++) {
315 U[i].svdEigen3(s[i], V[i]);
320 return test_svd(bench, U, s, V, error);
324 #if defined(VISP_HAVE_LAPACK)
325 int test_svd_lapack(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time,
double &error)
328 std::cout <<
"Test SVD using Lapack 3rd party" << std::endl;
331 std::cout <<
" SVD on a " << bench[0].getRows() <<
"x" << bench[0].getCols() <<
" matrix" << std::endl;
333 std::vector<vpMatrix> U = bench;
334 std::vector<vpMatrix> V(bench.size());
335 std::vector<vpColVector> s(bench.size());
338 for (
unsigned int i = 0; i < bench.size(); i++) {
339 U[i].svdLapack(s[i], V[i]);
343 return test_svd(bench, U, s, V, error);
346 int test_eigen_values_lapack(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
349 std::cout <<
"Test eigenValues() using Lapack 3rd party" << std::endl;
351 std::vector<vpColVector> e(bench.size());
352 std::vector<vpColVector> e2(bench.size());
353 std::vector<vpMatrix> V(bench.size());
355 for (
unsigned int i = 0; i < bench.size(); i++) {
356 e2[i] = bench[i].eigenValues();
361 for (
unsigned int i = 0; i < bench.size(); i++) {
362 bench[i].eigenValues(e[i], V[i]);
366 return test_eigen_values(bench, e, V, e2);
370 #if defined(VISP_HAVE_OPENCV)
371 int test_svd_opencv(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time,
double &error)
374 std::cout <<
"Test SVD using OpenCV 3rd party" << std::endl;
377 std::cout <<
" SVD on a " << bench[0].getRows() <<
"x" << bench[0].getCols() <<
" matrix" << std::endl;
379 std::vector<vpMatrix> U = bench;
380 std::vector<vpMatrix> V(bench.size());
381 std::vector<vpColVector> s(bench.size());
384 for (
unsigned int i = 0; i < bench.size(); i++) {
385 U[i].svdOpenCV(s[i], V[i]);
389 return test_svd(bench, U, s, V, error);
393 void save_time(
const std::string &method,
bool verbose,
bool use_plot_file, std::ofstream &of,
double time,
double error)
397 if (verbose || !use_plot_file) {
398 std::cout << method <<
"took " << time <<
"s, error = " << error << std::endl;
402 bool testAllSvds(
const std::string &test_name,
unsigned nb_matrices,
unsigned nb_iterations,
403 unsigned nb_rows,
unsigned nb_cols,
404 bool doEigenValues,
bool verbose,
bool use_plot_file, std::ofstream &of)
406 int ret = EXIT_SUCCESS;
408 for (
unsigned int iter = 0; iter < nb_iterations; iter++) {
409 std::cout <<
"\n-> Iteration: " << iter << std::endl;
410 std::vector<vpMatrix> bench_random_matrices;
411 create_bench_random_matrix(nb_matrices, nb_rows, nb_cols, verbose, bench_random_matrices);
412 std::vector<vpMatrix> bench_random_symmetric_matrices;
413 create_bench_random_symmetric_matrix(nb_matrices, nb_rows, verbose, bench_random_symmetric_matrices);
416 of << test_name << iter <<
"\t";
420 #if defined(VISP_HAVE_LAPACK)
421 std::cout <<
"\n-- Test SVD using lapack" << std::endl;
422 ret_test = test_svd_lapack(verbose, bench_random_matrices, time, error);
424 std::cout << test_name <<
": SVD (Lapack) " << (ret_test ?
"failed" :
"succeed") << std::endl;
425 save_time(
"SVD (Lapack): ", verbose, use_plot_file, of, time, error);
428 #if defined(VISP_HAVE_EIGEN3)
429 std::cout <<
"\n-- Test SVD using eigen" << std::endl;
430 ret_test = test_svd_eigen3(verbose, bench_random_matrices, time, error);
432 std::cout << test_name <<
": SVD (Eigen) " << (ret_test ?
"failed" :
"succeed") << std::endl;
433 save_time(
"SVD (Eigen3): ", verbose, use_plot_file, of, time, error);
436 #if defined(VISP_HAVE_OPENCV)
437 std::cout <<
"\n-- Test SVD using OpenCV" << std::endl;
438 ret_test = test_svd_opencv(verbose, bench_random_matrices, time, error);
440 std::cout << test_name <<
": SVD (OpenCV) " << (ret_test ?
"failed" :
"succeed") << std::endl;
441 save_time(
"SVD (OpenCV): ", verbose, use_plot_file, of, time, error);
444 #if defined(VISP_HAVE_LAPACK)
446 std::cout <<
"\n-- Test Eigen Values using lapack" << std::endl;
447 ret_test = test_eigen_values_lapack(verbose, bench_random_symmetric_matrices, time);
449 std::cout <<
"Eigen values (Lapack) " << (ret_test ?
"failed" :
"succeed") << std::endl;
451 save_time(
"Eigen values (Lapack): ", verbose, use_plot_file, of, time, error);
454 std::cout <<
"Result after iteration " << iter <<
": " << (ret ?
"failed" :
"succeed") << std::endl;
458 return (ret == EXIT_SUCCESS);
461 int main(
int argc,
const char *argv[])
464 #if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_OPENCV)
465 unsigned int nb_matrices = 100;
466 unsigned int nb_iterations = 10;
467 unsigned int nb_rows = 6;
468 unsigned int nb_cols = 6;
469 bool verbose =
false;
470 std::string plotfile(
"plot-svd.csv");
471 bool use_plot_file =
false;
475 if (getOptions(argc, argv, nb_matrices, nb_iterations, use_plot_file, plotfile, nb_rows, nb_cols, verbose) ==
481 of.open(plotfile.c_str());
485 #if defined(VISP_HAVE_LAPACK)
486 of <<
"\"SVD Lapack\""
489 #if defined(VISP_HAVE_EIGEN3)
490 of <<
"\"SVD Eigen3\""
493 #if defined(VISP_HAVE_OPENCV)
494 of <<
"\"SVD OpenCV\""
500 std::string test_case;
501 test_case =
"Test case: Square matrices";
502 std::cout <<
"\n== " << test_case <<
": " << nb_rows <<
" x " << nb_cols <<
" ==" << std::endl;
503 bool defaultSuccess = testAllSvds(test_case, nb_matrices, nb_iterations, nb_rows, nb_cols,
504 true, verbose, use_plot_file, of);
505 std::cout <<
"=> " << test_case <<
": " << (defaultSuccess ?
"succeed" :
"failed") << std::endl;
507 test_case =
"Test case: More rows than columns";
508 std::cout <<
"\n== " << test_case <<
": " << nb_cols * 2 <<
" x " << nb_cols <<
" ==" << std::endl;
509 bool rowsSuccess = testAllSvds(test_case, nb_matrices, nb_iterations, nb_cols * 2, nb_cols,
510 false, verbose, use_plot_file, of);
511 std::cout <<
"=> " << test_case <<
": " << (rowsSuccess ?
"succeed" :
"failed") << std::endl;
513 test_case =
"Test case: More columns than rows";
514 std::cout <<
"\n== " << test_case <<
": " << nb_rows <<
" x " << nb_rows * 2 <<
" ==" << std::endl;
515 bool colsSuccess = testAllSvds(test_case, nb_matrices, nb_iterations, nb_rows, nb_rows * 2,
516 false, verbose, use_plot_file, of);
517 std::cout <<
"=> " << test_case <<
": " << (colsSuccess ?
"succeed" :
"failed") << std::endl;
519 std::cout <<
"\nResume:" << std::endl;
520 std::cout <<
"- Square matrices (" << nb_rows <<
"x" << nb_cols <<
"): " << (defaultSuccess ?
"succeed" :
"failed") << std::endl;
522 std::cout <<
"- More rows case (" << nb_cols * 2 <<
"x" << nb_cols <<
"): " << (rowsSuccess ?
"succeed" :
"failed") << std::endl;
524 std::cout <<
"- More columns case (" << nb_rows <<
"x" << nb_rows * 2 <<
"): " << (colsSuccess ?
"succeed" :
"failed") << std::endl;
526 success = defaultSuccess && rowsSuccess && colsSuccess;
530 std::cout <<
"Result saved in " << plotfile << std::endl;
534 std::cout <<
"Test succeed" << std::endl;
537 std::cout <<
"Test failed" << std::endl;
540 return success ? EXIT_SUCCESS : EXIT_FAILURE;
544 std::cout <<
"Test does nothing since you dont't have Lapack, Eigen3 or OpenCV 3rd party" << std::endl;
unsigned int getCols() const
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
unsigned int getRows() const
Implementation of column vector and the associated operations.
double frobeniusNorm() const
error that can be emitted by ViSP classes.
const std::string & getStringMessage() const
Implementation of a matrix and operations on matrices.
void diag(const double &val=1.0)
double frobeniusNorm() const
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
VISP_EXPORT double measureTimeMs()