45 #include <visp3/core/vpColVector.h>
46 #include <visp3/core/vpMatrix.h>
47 #include <visp3/core/vpTime.h>
48 #include <visp3/io/vpParseArgv.h>
51 #define GETOPTARGS "cdn:i:pf:R:C:vh"
61 void usage(
const char *name,
const char *badparam)
64 Test matrix inversions\n\
65 using LU, QR and Cholesky methods as well as Pseudo-inverse.\n\
66 Outputs a comparison of these methods.\n\
69 %s [-n <number of matrices>] [-f <plot filename>]\n\
70 [-R <number of rows>] [-C <number of columns>]\n\
71 [-i <number of iterations>] [-p] [-h]\n",
76 -n <number of matrices> \n\
77 Number of matrices inverted during each test loop.\n\
79 -i <number of iterations> \n\
80 Number of iterations of the test.\n\
82 -f <plot filename> \n\
83 Set output path for plot output.\n\
84 The plot logs the times of \n\
85 the different inversion methods: \n\
86 QR,LU,Cholesky and Pseudo-inverse.\n\
88 -R <number of rows>\n\
89 Number of rows of the automatically generated matrices \n\
92 -C <number of columns>\n\
93 Number of colums of the automatically generated matrices \n\
97 Plot into filename in the gnuplot format. \n\
98 If this option is used, tests results will be logged \n\
99 into a filename specified with -f.\n\
102 Print the help.\n\n");
105 fprintf(stderr,
"ERROR: \n");
106 fprintf(stderr,
"\nBad parameter [%s]\n", badparam);
117 bool getOptions(
int argc,
const char **argv,
unsigned int &nb_matrices,
unsigned int &nb_iterations,
118 bool &use_plot_file, std::string &plotfile,
unsigned int &nbrows,
unsigned int &nbcols,
bool &verbose)
126 usage(argv[0],
nullptr);
130 nb_matrices = (
unsigned int)atoi(optarg_);
133 nb_iterations = (
unsigned int)atoi(optarg_);
137 use_plot_file =
true;
140 use_plot_file =
true;
143 nbrows = (
unsigned int)atoi(optarg_);
146 nbcols = (
unsigned int)atoi(optarg_);
157 usage(argv[0], optarg_);
163 if ((c == 1) || (c == -1)) {
165 usage(argv[0],
nullptr);
166 std::cerr <<
"ERROR: " << std::endl;
167 std::cerr <<
" Bad argument " << optarg_ << std::endl << std::endl;
174 vpMatrix make_random_matrix(
unsigned int nbrows,
unsigned int nbcols)
179 for (
unsigned int i = 0; i < A.
getRows(); i++) {
180 for (
unsigned int j = 0; j < A.
getCols(); j++) {
181 A[i][j] =
static_cast<double>(rand()) /
static_cast<double>(RAND_MAX);
188 vpMatrix make_random_symmetric_matrix(
unsigned int nbrows)
193 for (
unsigned int i = 0; i < A.
getRows(); i++) {
194 for (
unsigned int j = i; j < A.
getCols(); j++) {
195 A[i][j] =
static_cast<double>(rand()) /
static_cast<double>(RAND_MAX);
205 void create_bench_random_matrix(
unsigned int nb_matrices,
unsigned int nb_rows,
unsigned int nb_cols,
bool verbose,
206 std::vector<vpMatrix> &bench)
209 std::cout <<
"Create a bench of " << nb_matrices <<
" " << nb_rows <<
" by " << nb_cols <<
" matrices" << std::endl;
211 for (
unsigned int i = 0; i < nb_matrices; i++) {
227 M = make_random_matrix(nb_rows, nb_cols);
233 void create_bench_random_symmetric_matrix(
unsigned int nb_matrices,
unsigned int nb_rows,
bool verbose,
234 std::vector<vpMatrix> &bench)
237 std::cout <<
"Create a bench of " << nb_matrices <<
" " << nb_rows <<
" by " << nb_rows <<
" symmetric matrices" << std::endl;
239 for (
unsigned int i = 0; i < nb_matrices; i++) {
255 M = make_random_symmetric_matrix(nb_rows);
261 int test_svd(std::vector<vpMatrix> M, std::vector<vpMatrix> U, std::vector<vpColVector> s, std::vector<vpMatrix> V,
double &error)
263 for (
unsigned int i = 0; i < M.size(); i++) {
268 error = D.frobeniusNorm();
270 std::cout <<
"SVD decomposition failed. Error: " << error << std::endl;
277 int test_eigen_values(std::vector<vpMatrix> M, std::vector<vpColVector> e, std::vector<vpMatrix> V,
278 std::vector<vpColVector> e2)
280 for (
unsigned int i = 0; i < M.size(); i++) {
283 std::cout <<
"Eigen values differ" << std::endl;
288 vpMatrix MV_VD = M[i] * V[i] - V[i] * D;
290 std::cout <<
"Eigen values/vector decomposition failed" << std::endl;
297 #if defined(VISP_HAVE_EIGEN3)
298 int test_svd_eigen3(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time,
double &error)
301 std::cout <<
"Test SVD using Eigen3 3rd party" << std::endl;
304 std::cout <<
" SVD on a " << bench[0].getRows() <<
"x" << bench[0].getCols() <<
" matrix" << std::endl;
306 std::vector<vpMatrix> U = bench;
307 std::vector<vpMatrix> V(bench.size());
308 std::vector<vpColVector> s(bench.size());
311 for (
unsigned int i = 0; i < bench.size(); i++) {
312 U[i].svdEigen3(s[i], V[i]);
317 return test_svd(bench, U, s, V, error);
321 #if defined(VISP_HAVE_LAPACK)
322 int test_svd_lapack(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time,
double &error)
325 std::cout <<
"Test SVD using Lapack 3rd party" << std::endl;
328 std::cout <<
" SVD on a " << bench[0].getRows() <<
"x" << bench[0].getCols() <<
" matrix" << std::endl;
330 std::vector<vpMatrix> U = bench;
331 std::vector<vpMatrix> V(bench.size());
332 std::vector<vpColVector> s(bench.size());
335 for (
unsigned int i = 0; i < bench.size(); i++) {
336 U[i].svdLapack(s[i], V[i]);
340 return test_svd(bench, U, s, V, error);
343 int test_eigen_values_lapack(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time)
346 std::cout <<
"Test eigenValues() using Lapack 3rd party" << std::endl;
348 std::vector<vpColVector> e(bench.size());
349 std::vector<vpColVector> e2(bench.size());
350 std::vector<vpMatrix> V(bench.size());
352 for (
unsigned int i = 0; i < bench.size(); i++) {
353 e2[i] = bench[i].eigenValues();
358 for (
unsigned int i = 0; i < bench.size(); i++) {
359 bench[i].eigenValues(e[i], V[i]);
363 return test_eigen_values(bench, e, V, e2);
367 #if defined(VISP_HAVE_OPENCV)
368 int test_svd_opencv(
bool verbose,
const std::vector<vpMatrix> &bench,
double &time,
double &error)
371 std::cout <<
"Test SVD using OpenCV 3rd party" << std::endl;
374 std::cout <<
" SVD on a " << bench[0].getRows() <<
"x" << bench[0].getCols() <<
" matrix" << std::endl;
376 std::vector<vpMatrix> U = bench;
377 std::vector<vpMatrix> V(bench.size());
378 std::vector<vpColVector> s(bench.size());
381 for (
unsigned int i = 0; i < bench.size(); i++) {
382 U[i].svdOpenCV(s[i], V[i]);
386 return test_svd(bench, U, s, V, error);
390 void save_time(
const std::string &method,
bool verbose,
bool use_plot_file, std::ofstream &of,
double time,
double error)
394 if (verbose || !use_plot_file) {
395 std::cout << method <<
"took " << time <<
"s, error = " << error << std::endl;
399 bool testAllSvds(
const std::string &test_name,
unsigned nb_matrices,
unsigned nb_iterations,
400 unsigned nb_rows,
unsigned nb_cols,
401 bool doEigenValues,
bool verbose,
bool use_plot_file, std::ofstream &of)
403 int ret = EXIT_SUCCESS;
405 for (
unsigned int iter = 0; iter < nb_iterations; iter++) {
406 std::cout <<
"\n-> Iteration: " << iter << std::endl;
407 std::vector<vpMatrix> bench_random_matrices;
408 create_bench_random_matrix(nb_matrices, nb_rows, nb_cols, verbose, bench_random_matrices);
409 std::vector<vpMatrix> bench_random_symmetric_matrices;
410 create_bench_random_symmetric_matrix(nb_matrices, nb_rows, verbose, bench_random_symmetric_matrices);
413 of << test_name << iter <<
"\t";
417 #if defined(VISP_HAVE_LAPACK)
418 std::cout <<
"\n-- Test SVD using lapack" << std::endl;
419 ret_test = test_svd_lapack(verbose, bench_random_matrices, time, error);
421 std::cout << test_name <<
": SVD (Lapack) " << (ret_test ?
"failed" :
"succeed") << std::endl;
422 save_time(
"SVD (Lapack): ", verbose, use_plot_file, of, time, error);
425 #if defined(VISP_HAVE_EIGEN3)
426 std::cout <<
"\n-- Test SVD using eigen" << std::endl;
427 ret_test = test_svd_eigen3(verbose, bench_random_matrices, time, error);
429 std::cout << test_name <<
": SVD (Eigen) " << (ret_test ?
"failed" :
"succeed") << std::endl;
430 save_time(
"SVD (Eigen3): ", verbose, use_plot_file, of, time, error);
433 #if defined(VISP_HAVE_OPENCV)
434 std::cout <<
"\n-- Test SVD using OpenCV" << std::endl;
435 ret_test = test_svd_opencv(verbose, bench_random_matrices, time, error);
437 std::cout << test_name <<
": SVD (OpenCV) " << (ret_test ?
"failed" :
"succeed") << std::endl;
438 save_time(
"SVD (OpenCV): ", verbose, use_plot_file, of, time, error);
441 #if defined(VISP_HAVE_LAPACK)
443 std::cout <<
"\n-- Test Eigen Values using lapack" << std::endl;
444 ret_test = test_eigen_values_lapack(verbose, bench_random_symmetric_matrices, time);
446 std::cout <<
"Eigen values (Lapack) " << (ret_test ?
"failed" :
"succeed") << std::endl;
448 save_time(
"Eigen values (Lapack): ", verbose, use_plot_file, of, time, error);
451 std::cout <<
"Result after iteration " << iter <<
": " << (ret ?
"failed" :
"succeed") << std::endl;
455 return (ret == EXIT_SUCCESS);
458 int main(
int argc,
const char *argv[])
461 #if defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_OPENCV)
462 unsigned int nb_matrices = 100;
463 unsigned int nb_iterations = 10;
464 unsigned int nb_rows = 6;
465 unsigned int nb_cols = 6;
466 bool verbose =
false;
467 std::string plotfile(
"plot-svd.csv");
468 bool use_plot_file =
false;
472 if (getOptions(argc, argv, nb_matrices, nb_iterations, use_plot_file, plotfile, nb_rows, nb_cols, verbose) ==
478 of.open(plotfile.c_str());
482 #if defined(VISP_HAVE_LAPACK)
483 of <<
"\"SVD Lapack\""
486 #if defined(VISP_HAVE_EIGEN3)
487 of <<
"\"SVD Eigen3\""
490 #if defined(VISP_HAVE_OPENCV)
491 of <<
"\"SVD OpenCV\""
497 std::string test_case;
498 test_case =
"Test case: Square matrices";
499 std::cout <<
"\n== " << test_case <<
": " << nb_rows <<
" x " << nb_cols <<
" ==" << std::endl;
500 bool defaultSuccess = testAllSvds(test_case, nb_matrices, nb_iterations, nb_rows, nb_cols,
501 true, verbose, use_plot_file, of);
502 std::cout <<
"=> " << test_case <<
": " << (defaultSuccess ?
"succeed" :
"failed") << std::endl;
504 test_case =
"Test case: More rows than columns";
505 std::cout <<
"\n== " << test_case <<
": " << nb_cols * 2 <<
" x " << nb_cols <<
" ==" << std::endl;
506 bool rowsSuccess = testAllSvds(test_case, nb_matrices, nb_iterations, nb_cols * 2, nb_cols,
507 false, verbose, use_plot_file, of);
508 std::cout <<
"=> " << test_case <<
": " << (rowsSuccess ?
"succeed" :
"failed") << std::endl;
510 test_case =
"Test case: More columns than rows";
511 std::cout <<
"\n== " << test_case <<
": " << nb_rows <<
" x " << nb_rows * 2 <<
" ==" << std::endl;
512 bool colsSuccess = testAllSvds(test_case, nb_matrices, nb_iterations, nb_rows, nb_rows * 2,
513 false, verbose, use_plot_file, of);
514 std::cout <<
"=> " << test_case <<
": " << (colsSuccess ?
"succeed" :
"failed") << std::endl;
516 std::cout <<
"\nResume:" << std::endl;
517 std::cout <<
"- Square matrices (" << nb_rows <<
"x" << nb_cols <<
"): " << (defaultSuccess ?
"succeed" :
"failed") << std::endl;
519 std::cout <<
"- More rows case (" << nb_cols * 2 <<
"x" << nb_cols <<
"): " << (rowsSuccess ?
"succeed" :
"failed") << std::endl;
521 std::cout <<
"- More columns case (" << nb_rows <<
"x" << nb_rows * 2 <<
"): " << (colsSuccess ?
"succeed" :
"failed") << std::endl;
523 success = defaultSuccess && rowsSuccess && colsSuccess;
527 std::cout <<
"Result saved in " << plotfile << std::endl;
531 std::cout <<
"Test succeed" << std::endl;
534 std::cout <<
"Test failed" << std::endl;
537 return success ? EXIT_SUCCESS : EXIT_FAILURE;
541 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()