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
56void usage(
const char *name,
const char *badparam);
57bool getOptions(
int argc,
const char **argv,
unsigned int &nb_matrices,
unsigned int &nb_iterations,
58 bool &use_plot_file, std::string &plotfile,
unsigned int &nbrows,
unsigned int &nbcols,
bool &verbose);
61vpMatrix make_random_matrix(
unsigned int nbrows,
unsigned int nbcols);
62vpMatrix make_random_symmetric_matrix(
unsigned int nbrows);
63void create_bench_random_matrix(
unsigned int nb_matrices,
unsigned int nb_rows,
unsigned int nb_cols,
bool verbose,
64 std::vector<vpMatrix> &bench);
65void create_bench_random_symmetric_matrix(
unsigned int nb_matrices,
unsigned int nb_rows,
bool verbose,
66 std::vector<vpMatrix> &bench);
67int test_svd(std::vector<vpMatrix> M, std::vector<vpMatrix> U, std::vector<vpColVector> s, std::vector<vpMatrix> V,
double &error);
68int test_eigen_values(std::vector<vpMatrix> M, std::vector<vpColVector> e, std::vector<vpMatrix> V,
69 std::vector<vpColVector> e2);
70void save_time(
const std::string &method,
bool verbose,
bool use_plot_file, std::ofstream &of,
double time,
double error);
71#if defined(VISP_HAVE_EIGEN3)
72int test_svd_eigen3(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time,
double &error);
74#if defined(VISP_HAVE_LAPACK)
75int test_svd_lapack(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time,
double &error);
76int test_eigen_values_lapack(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time);
78#if defined(VISP_HAVE_OPENCV)
79int test_svd_opencv(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time,
double &error);
88void usage(
const char *name,
const char *badparam)
91Test matrix inversions\n\
92using LU, QR and Cholesky methods as well as Pseudo-inverse.\n\
93Outputs a comparison of these methods.\n\
96 %s [-n <number of matrices>] [-f <plot filename>]\n\
97 [-R <number of rows>] [-C <number of columns>]\n\
98 [-i <number of iterations>] [-p] [-h]\n",
103 -n <number of matrices> \n\
104 Number of matrices inverted during each test loop.\n\
106 -i <number of iterations> \n\
107 Number of iterations of the test.\n\
109 -f <plot filename> \n\
110 Set output path for plot output.\n\
111 The plot logs the times of \n\
112 the different inversion methods: \n\
113 QR,LU,Cholesky and Pseudo-inverse.\n\
115 -R <number of rows>\n\
116 Number of rows of the automatically generated matrices \n\
119 -C <number of columns>\n\
120 Number of colums of the automatically generated matrices \n\
124 Plot into filename in the gnuplot format. \n\
125 If this option is used, tests results will be logged \n\
126 into a filename specified with -f.\n\
129 Print the help.\n\n");
132 fprintf(stderr,
"ERROR: \n");
133 fprintf(stderr,
"\nBad parameter [%s]\n", badparam);
144bool getOptions(
int argc,
const char **argv,
unsigned int &nb_matrices,
unsigned int &nb_iterations,
145 bool &use_plot_file, std::string &plotfile,
unsigned int &nbrows,
unsigned int &nbcols,
bool &verbose)
153 usage(argv[0],
nullptr);
156 nb_matrices =
static_cast<unsigned int>(atoi(optarg_));
159 nb_iterations =
static_cast<unsigned int>(atoi(optarg_));
163 use_plot_file =
true;
166 use_plot_file =
true;
169 nbrows =
static_cast<unsigned int>(atoi(optarg_));
172 nbcols =
static_cast<unsigned int>(atoi(optarg_));
183 usage(argv[0], optarg_);
188 if ((c == 1) || (c == -1)) {
190 usage(argv[0],
nullptr);
191 std::cerr <<
"ERROR: " << std::endl;
192 std::cerr <<
" Bad argument " << optarg_ << std::endl << std::endl;
199vpMatrix make_random_matrix(
unsigned int nbrows,
unsigned int nbcols)
204 for (
unsigned int i = 0;
i < A.
getRows();
i++) {
205 for (
unsigned int j = 0;
j < A.
getCols();
j++) {
206 A[
i][
j] =
static_cast<double>(rand()) /
static_cast<double>(RAND_MAX);
213vpMatrix make_random_symmetric_matrix(
unsigned int nbrows)
218 for (
unsigned int i = 0;
i < A.
getRows();
i++) {
219 for (
unsigned int j = i;
j < A.
getCols();
j++) {
220 A[
i][
j] =
static_cast<double>(rand()) /
static_cast<double>(RAND_MAX);
230void create_bench_random_matrix(
unsigned int nb_matrices,
unsigned int nb_rows,
unsigned int nb_cols,
bool verbose,
231 std::vector<vpMatrix> &bench)
234 std::cout <<
"Create a bench of " << nb_matrices <<
" " << nb_rows <<
" by " << nb_cols <<
" matrices" << std::endl;
236 for (
unsigned int i = 0;
i < nb_matrices;
i++) {
252 M = make_random_matrix(nb_rows, nb_cols);
258void create_bench_random_symmetric_matrix(
unsigned int nb_matrices,
unsigned int nb_rows,
bool verbose,
259 std::vector<vpMatrix> &bench)
262 std::cout <<
"Create a bench of " << nb_matrices <<
" " << nb_rows <<
" by " << nb_rows <<
" symmetric matrices" << std::endl;
264 for (
unsigned int i = 0;
i < nb_matrices;
i++) {
280 M = make_random_symmetric_matrix(nb_rows);
286int test_svd(std::vector<vpMatrix> M, std::vector<vpMatrix> U, std::vector<vpColVector> s, std::vector<vpMatrix> V,
double &error)
288 for (
unsigned int i = 0;
i < M.size();
i++) {
293 error = D.frobeniusNorm();
295 std::cout <<
"SVD decomposition failed. Error: " <<
error << std::endl;
302int test_eigen_values(std::vector<vpMatrix> M, std::vector<vpColVector> e, std::vector<vpMatrix> V,
303 std::vector<vpColVector> e2)
305 for (
unsigned int i = 0;
i < M.size();
i++) {
308 std::cout <<
"Eigen values differ" << std::endl;
315 std::cout <<
"Eigen values/vector decomposition failed" << std::endl;
322#if defined(VISP_HAVE_EIGEN3)
323int test_svd_eigen3(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time,
double &error)
326 std::cout <<
"Test SVD using Eigen3 3rd party" << std::endl;
329 std::cout <<
" SVD on a " << bench[0].getRows() <<
"x" << bench[0].getCols() <<
" matrix" << std::endl;
331 std::vector<vpMatrix> U = bench;
332 std::vector<vpMatrix> V(bench.size());
333 std::vector<vpColVector>
s(bench.size());
336 for (
unsigned int i = 0;
i < bench.size();
i++) {
337 U[
i].svdEigen3(s[i], V[i]);
342 return test_svd(bench, U, s, V, error);
346#if defined(VISP_HAVE_LAPACK)
347int test_svd_lapack(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time,
double &error)
350 std::cout <<
"Test SVD using Lapack 3rd party" << std::endl;
353 std::cout <<
" SVD on a " << bench[0].getRows() <<
"x" << bench[0].getCols() <<
" matrix" << std::endl;
355 std::vector<vpMatrix> U = bench;
356 std::vector<vpMatrix> V(bench.size());
357 std::vector<vpColVector>
s(bench.size());
360 for (
unsigned int i = 0;
i < bench.size();
i++) {
361 U[
i].svdLapack(s[i], V[i]);
365 return test_svd(bench, U, s, V, error);
368int test_eigen_values_lapack(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
371 std::cout <<
"Test eigenValues() using Lapack 3rd party" << std::endl;
373 std::vector<vpColVector>
e(bench.size());
374 std::vector<vpColVector> e2(bench.size());
375 std::vector<vpMatrix> V(bench.size());
377 for (
unsigned int i = 0;
i < bench.size();
i++) {
378 e2[
i] = bench[
i].eigenValues();
383 for (
unsigned int i = 0;
i < bench.size();
i++) {
384 bench[
i].eigenValues(e[i], V[i]);
388 return test_eigen_values(bench, e, V, e2);
392#if defined(VISP_HAVE_OPENCV)
393int test_svd_opencv(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time,
double &error)
396 std::cout <<
"Test SVD using OpenCV 3rd party" << std::endl;
399 std::cout <<
" SVD on a " << bench[0].getRows() <<
"x" << bench[0].getCols() <<
" matrix" << std::endl;
401 std::vector<vpMatrix> U = bench;
402 std::vector<vpMatrix> V(bench.size());
403 std::vector<vpColVector>
s(bench.size());
406 for (
unsigned int i = 0;
i < bench.size();
i++) {
407 U[
i].svdOpenCV(s[i], V[i]);
411 return test_svd(bench, U, s, V, error);
415void save_time(
const std::string &method,
bool verbose,
bool use_plot_file, std::ofstream &of,
double time,
double error)
419 if (verbose || !use_plot_file) {
420 std::cout << method <<
"took " << time <<
"s, error = " <<
error << std::endl;
424bool testAllSvds(
const std::string &test_name,
unsigned nb_matrices,
unsigned nb_iterations,
425 unsigned nb_rows,
unsigned nb_cols,
426 bool doEigenValues,
bool verbose,
bool use_plot_file, std::ofstream &of)
428 int ret = EXIT_SUCCESS;
430 for (
unsigned int iter = 0;
iter < nb_iterations;
iter++) {
431 std::cout <<
"\n-> Iteration: " <<
iter << std::endl;
432 std::vector<vpMatrix> bench_random_matrices;
433 create_bench_random_matrix(nb_matrices, nb_rows, nb_cols, verbose, bench_random_matrices);
434 std::vector<vpMatrix> bench_random_symmetric_matrices;
435 create_bench_random_symmetric_matrix(nb_matrices, nb_rows, verbose, bench_random_symmetric_matrices);
438 of << test_name <<
iter <<
"\t";
442#if defined(VISP_HAVE_LAPACK)
443 std::cout <<
"\n-- Test SVD using lapack" << std::endl;
444 ret_test = test_svd_lapack(verbose, bench_random_matrices, time, error);
446 std::cout << test_name <<
": SVD (Lapack) " << (ret_test ?
"failed" :
"succeed") << std::endl;
447 save_time(
"SVD (Lapack): ", verbose, use_plot_file, of, time, error);
450#if defined(VISP_HAVE_EIGEN3)
451 std::cout <<
"\n-- Test SVD using eigen" << std::endl;
452 ret_test = test_svd_eigen3(verbose, bench_random_matrices, time, error);
454 std::cout << test_name <<
": SVD (Eigen) " << (ret_test ?
"failed" :
"succeed") << std::endl;
455 save_time(
"SVD (Eigen3): ", verbose, use_plot_file, of, time, error);
458#if defined(VISP_HAVE_OPENCV)
459 std::cout <<
"\n-- Test SVD using OpenCV" << std::endl;
460 ret_test = test_svd_opencv(verbose, bench_random_matrices, time, error);
462 std::cout << test_name <<
": SVD (OpenCV) " << (ret_test ?
"failed" :
"succeed") << std::endl;
463 save_time(
"SVD (OpenCV): ", verbose, use_plot_file, of, time, error);
466#if defined(VISP_HAVE_LAPACK)
468 std::cout <<
"\n-- Test Eigen Values using lapack" << std::endl;
469 ret_test = test_eigen_values_lapack(verbose, bench_random_symmetric_matrices, time);
471 std::cout <<
"Eigen values (Lapack) " << (ret_test ?
"failed" :
"succeed") << std::endl;
473 save_time(
"Eigen values (Lapack): ", verbose, use_plot_file, of, time, error);
476 std::cout <<
"Result after iteration " <<
iter <<
": " << (ret ?
"failed" :
"succeed") << std::endl;
480 return (ret == EXIT_SUCCESS);
483int main(
int argc,
const char *argv[])
486#if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_OPENCV)
487 unsigned int nb_matrices = 100;
488 unsigned int nb_iterations = 10;
489 unsigned int nb_rows = 6;
490 unsigned int nb_cols = 6;
491 bool verbose =
false;
492 std::string plotfile(
"plot-svd.csv");
493 bool use_plot_file =
false;
497 if (getOptions(argc, argv, nb_matrices, nb_iterations, use_plot_file, plotfile, nb_rows, nb_cols, verbose) ==
503 of.open(plotfile.c_str());
507#if defined(VISP_HAVE_LAPACK)
508 of <<
"\"SVD Lapack\""
511#if defined(VISP_HAVE_EIGEN3)
512 of <<
"\"SVD Eigen3\""
515#if defined(VISP_HAVE_OPENCV)
516 of <<
"\"SVD OpenCV\""
522 std::string test_case;
523 test_case =
"Test case: Square matrices";
524 std::cout <<
"\n== " << test_case <<
": " << nb_rows <<
" x " << nb_cols <<
" ==" << std::endl;
525 bool defaultSuccess = testAllSvds(test_case, nb_matrices, nb_iterations, nb_rows, nb_cols,
526 true, verbose, use_plot_file, of);
527 std::cout <<
"=> " << test_case <<
": " << (defaultSuccess ?
"succeed" :
"failed") << std::endl;
529 test_case =
"Test case: More rows than columns";
530 std::cout <<
"\n== " << test_case <<
": " << nb_cols * 2 <<
" x " << nb_cols <<
" ==" << std::endl;
531 bool rowsSuccess = testAllSvds(test_case, nb_matrices, nb_iterations, nb_cols * 2, nb_cols,
532 false, verbose, use_plot_file, of);
533 std::cout <<
"=> " << test_case <<
": " << (rowsSuccess ?
"succeed" :
"failed") << std::endl;
535 test_case =
"Test case: More columns than rows";
536 std::cout <<
"\n== " << test_case <<
": " << nb_rows <<
" x " << nb_rows * 2 <<
" ==" << std::endl;
537 bool colsSuccess = testAllSvds(test_case, nb_matrices, nb_iterations, nb_rows, nb_rows * 2,
538 false, verbose, use_plot_file, of);
539 std::cout <<
"=> " << test_case <<
": " << (colsSuccess ?
"succeed" :
"failed") << std::endl;
541 std::cout <<
"\nResume:" << std::endl;
542 std::cout <<
"- Square matrices (" << nb_rows <<
"x" << nb_cols <<
"): " << (defaultSuccess ?
"succeed" :
"failed") << std::endl;
544 std::cout <<
"- More rows case (" << nb_cols * 2 <<
"x" << nb_cols <<
"): " << (rowsSuccess ?
"succeed" :
"failed") << std::endl;
546 std::cout <<
"- More columns case (" << nb_rows <<
"x" << nb_rows * 2 <<
"): " << (colsSuccess ?
"succeed" :
"failed") << std::endl;
548 success = defaultSuccess && rowsSuccess && colsSuccess;
552 std::cout <<
"Result saved in " << plotfile << std::endl;
556 std::cout <<
"Test succeed" << std::endl;
559 std::cout <<
"Test failed" << std::endl;
562 return success ? EXIT_SUCCESS : EXIT_FAILURE;
566 std::cout <<
"Test does nothing since you dont't have Lapack, Eigen3 or OpenCV 3rd party" << std::endl;
571 std::cout <<
"Catch an exception: " <<
e.getStringMessage() << 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.
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()