36 #include <visp3/core/vpConfig.h>
38 #ifdef VISP_HAVE_CATCH2
39 #define CATCH_CONFIG_ENABLE_BENCHMARKING
40 #define CATCH_CONFIG_RUNNER
43 #include <visp3/core/vpMatrix.h>
45 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
46 #include <opencv2/core.hpp>
49 #ifdef VISP_HAVE_EIGEN3
50 #include <Eigen/Dense>
56 bool runBenchmark =
false;
57 bool runBenchmarkAll =
false;
59 double getRandomValues(
double min,
double max) {
return (max - min) * ((double)rand() / (double)RAND_MAX) + min; }
61 vpMatrix generateRandomMatrix(
unsigned int rows,
unsigned int cols,
double min = -1,
double max = 1)
65 for (
unsigned int i = 0; i < M.getRows(); i++) {
66 for (
unsigned int j = 0; j < M.getCols(); j++) {
67 M[i][j] = getRandomValues(min, max);
74 vpColVector generateRandomVector(
unsigned int rows,
double min = -1,
double max = 1)
78 for (
unsigned int i = 0; i < v.getRows(); i++) {
79 v[i] = getRandomValues(min, max);
100 unsigned int BcolNum = B.
getCols();
101 unsigned int BrowNum = B.
getRows();
102 unsigned int i, j, k;
103 for (i = 0; i < A.
getRows(); i++) {
104 double *rowptri = A[i];
106 for (j = 0; j < BcolNum; j++) {
108 for (k = 0; k < BrowNum; k++) {
109 s += rowptri[k] * B[k][j];
124 for (
unsigned int i = 0; i < A.
getCols(); i++) {
126 for (
unsigned int j = 0; j < i; j++) {
127 double *ptr = A.
data;
129 for (
unsigned int k = 0; k < A.
getRows(); k++) {
130 s += (*(ptr + i)) * (*(ptr + j));
136 double *ptr = A.
data;
138 for (
unsigned int k = 0; k < A.
getRows(); k++) {
139 s += (*(ptr + i)) * (*(ptr + i));
155 for (
unsigned int i = 0; i < A.
getRows(); i++) {
156 for (
unsigned int j = i; j < A.
getRows(); j++) {
162 for (
unsigned int k = 0; k < A.
getCols(); k++)
163 ssum += *(pi++) * *(pj++);
185 for (
unsigned int j = 0; j < A.
getCols(); j++) {
187 for (
unsigned int i = 0; i < A.
getRows(); i++) {
188 w[i] += A[i][j] * vj;
201 for (
unsigned int i = 0; i < A.
getRows(); i++) {
202 for (
unsigned int j = 0; j < A.
getCols(); j++) {
214 TEST_CASE(
"Benchmark matrix-matrix multiplication",
"[benchmark]")
216 if (runBenchmark || runBenchmarkAll) {
217 std::vector<std::pair<int, int> > sizes = {{3, 3}, {6, 6}, {8, 8}, {10, 10}, {20, 20}, {6, 200},
218 {200, 6}, {207, 119}, {83, 201}, {600, 400}, {400, 600}};
220 for (
auto sz : sizes) {
221 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
222 vpMatrix B = generateRandomMatrix(sz.second, sz.first);
224 std::ostringstream oss;
227 BENCHMARK(oss.str().c_str())
229 C_true = dgemm_regular(A, B);
235 BENCHMARK(oss.str().c_str())
240 REQUIRE(equalMatrix(C, C_true));
242 if (runBenchmarkAll) {
243 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
244 cv::Mat matA(sz.first, sz.second, CV_64FC1);
245 cv::Mat matB(sz.second, sz.first, CV_64FC1);
247 for (
unsigned int i = 0; i < A.
getRows(); i++) {
248 for (
unsigned int j = 0; j < A.
getCols(); j++) {
249 matA.at<
double>(i, j) = A[i][j];
250 matB.at<
double>(j, i) = B[j][i];
255 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(" << matB.rows <<
"x" << matB.cols <<
") - OpenCV";
256 BENCHMARK(oss.str().c_str())
258 cv::Mat matC = matA * matB;
263 #ifdef VISP_HAVE_EIGEN3
264 Eigen::MatrixXd eigenA(sz.first, sz.second);
265 Eigen::MatrixXd eigenB(sz.second, sz.first);
267 for (
unsigned int i = 0; i < A.
getRows(); i++) {
268 for (
unsigned int j = 0; j < A.
getCols(); j++) {
269 eigenA(i, j) = A[i][j];
270 eigenB(j, i) = B[j][i];
275 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(" << eigenB.rows() <<
"x" << eigenB.cols()
277 BENCHMARK(oss.str().c_str())
279 Eigen::MatrixXd eigenC = eigenA * eigenB;
288 const unsigned int rows = 47, cols = 63;
289 vpMatrix A = generateRandomMatrix(rows, cols);
290 vpMatrix B = generateRandomMatrix(cols, rows);
292 vpMatrix C_true = dgemm_regular(A, B);
294 REQUIRE(equalMatrix(C, C_true));
298 TEST_CASE(
"Benchmark matrix-rotation matrix multiplication",
"[benchmark]")
300 if (runBenchmark || runBenchmarkAll) {
301 std::vector<std::pair<int, int> > sizes = {{3, 3}};
303 for (
auto sz : sizes) {
304 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
308 std::ostringstream oss;
311 BENCHMARK(oss.str().c_str())
313 AB_true = dgemm_regular(A, B);
319 BENCHMARK(oss.str().c_str())
324 REQUIRE(equalMatrix(AB, AB_true));
326 if (runBenchmarkAll) {
327 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
328 cv::Mat matA(sz.first, sz.second, CV_64FC1);
329 cv::Mat matB(3, 3, CV_64FC1);
331 for (
unsigned int i = 0; i < A.
getRows(); i++) {
332 for (
unsigned int j = 0; j < A.
getCols(); j++) {
333 matA.at<
double>(i, j) = A[i][j];
336 for (
unsigned int i = 0; i < B.
getRows(); i++) {
337 for (
unsigned int j = 0; j < B.
getCols(); j++) {
338 matB.at<
double>(j, i) = B[j][i];
343 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(" << matB.rows <<
"x" << matB.cols <<
") - OpenCV";
344 BENCHMARK(oss.str().c_str())
346 cv::Mat matC = matA * matB;
351 #ifdef VISP_HAVE_EIGEN3
352 Eigen::MatrixXd eigenA(sz.first, sz.second);
353 Eigen::MatrixXd eigenB(3, 3);
355 for (
unsigned int i = 0; i < A.
getRows(); i++) {
356 for (
unsigned int j = 0; j < A.
getCols(); j++) {
357 eigenA(i, j) = A[i][j];
360 for (
unsigned int i = 0; i < B.
getRows(); i++) {
361 for (
unsigned int j = 0; j < B.
getCols(); j++) {
362 eigenB(j, i) = B[j][i];
367 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(" << eigenB.rows() <<
"x" << eigenB.cols()
369 BENCHMARK(oss.str().c_str())
371 Eigen::MatrixXd eigenC = eigenA * eigenB;
380 const unsigned int rows = 3, cols = 3;
381 vpMatrix A = generateRandomMatrix(rows, cols);
385 vpMatrix AB_true = dgemm_regular(A, B);
387 REQUIRE(equalMatrix(AB, AB_true));
391 TEST_CASE(
"Benchmark matrix-homogeneous matrix multiplication",
"[benchmark]")
393 if (runBenchmark || runBenchmarkAll) {
394 std::vector<std::pair<int, int> > sizes = {{4, 4}};
396 for (
auto sz : sizes) {
397 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
402 std::ostringstream oss;
405 BENCHMARK(oss.str().c_str())
407 AB_true = dgemm_regular(A, B);
413 BENCHMARK(oss.str().c_str())
418 REQUIRE(equalMatrix(AB, AB_true));
420 if (runBenchmarkAll) {
421 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
422 cv::Mat matA(sz.first, sz.second, CV_64FC1);
423 cv::Mat matB(4, 4, CV_64FC1);
425 for (
unsigned int i = 0; i < A.
getRows(); i++) {
426 for (
unsigned int j = 0; j < A.
getCols(); j++) {
427 matA.at<
double>(i, j) = A[i][j];
430 for (
unsigned int i = 0; i < B.
getRows(); i++) {
431 for (
unsigned int j = 0; j < B.
getCols(); j++) {
432 matB.at<
double>(j, i) = B[j][i];
437 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(" << matB.rows <<
"x" << matB.cols <<
") - OpenCV";
438 BENCHMARK(oss.str().c_str())
440 cv::Mat matC = matA * matB;
445 #ifdef VISP_HAVE_EIGEN3
446 Eigen::MatrixXd eigenA(sz.first, sz.second);
447 Eigen::MatrixXd eigenB(4, 4);
449 for (
unsigned int i = 0; i < A.
getRows(); i++) {
450 for (
unsigned int j = 0; j < A.
getCols(); j++) {
451 eigenA(i, j) = A[i][j];
454 for (
unsigned int i = 0; i < B.
getRows(); i++) {
455 for (
unsigned int j = 0; j < B.
getCols(); j++) {
456 eigenB(j, i) = B[j][i];
461 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(" << eigenB.rows() <<
"x" << eigenB.cols()
463 BENCHMARK(oss.str().c_str())
465 Eigen::MatrixXd eigenC = eigenA * eigenB;
474 const unsigned int rows = 4, cols = 4;
475 vpMatrix A = generateRandomMatrix(rows, cols);
480 vpMatrix AB_true = dgemm_regular(A, B);
483 REQUIRE(equalMatrix(AB, AB_true));
487 TEST_CASE(
"Benchmark matrix-vector multiplication",
"[benchmark]")
489 if (runBenchmark || runBenchmarkAll) {
490 std::vector<std::pair<int, int> > sizes = {{3, 3}, {6, 6}, {8, 8}, {10, 10}, {20, 20}, {6, 200},
491 {200, 6}, {207, 119}, {83, 201}, {600, 400}, {400, 600}};
493 for (
auto sz : sizes) {
494 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
497 std::ostringstream oss;
500 BENCHMARK(oss.str().c_str())
502 C_true = dgemv_regular(A, B);
508 BENCHMARK(oss.str().c_str())
513 REQUIRE(equalMatrix(C, C_true));
515 if (runBenchmarkAll) {
516 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
517 cv::Mat matA(sz.first, sz.second, CV_64FC1);
518 cv::Mat matB(sz.second, 1, CV_64FC1);
520 for (
unsigned int i = 0; i < A.
getRows(); i++) {
521 for (
unsigned int j = 0; j < A.
getCols(); j++) {
522 matA.at<
double>(i, j) = A[i][j];
524 matB.at<
double>(j, 0) = B[j];
530 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(" << matB.rows <<
"x" << matB.cols <<
") - OpenCV";
531 BENCHMARK(oss.str().c_str())
533 cv::Mat matC = matA * matB;
538 #ifdef VISP_HAVE_EIGEN3
539 Eigen::MatrixXd eigenA(sz.first, sz.second);
540 Eigen::MatrixXd eigenB(sz.second, 1);
542 for (
unsigned int i = 0; i < A.
getRows(); i++) {
543 for (
unsigned int j = 0; j < A.
getCols(); j++) {
544 eigenA(i, j) = A[i][j];
552 oss <<
"(" << eigenA.
rows() <<
"x" << eigenA.cols() <<
")x(" << eigenB.
rows() <<
"x" << eigenB.cols()
554 BENCHMARK(oss.str().c_str())
556 Eigen::MatrixXd eigenC = eigenA * eigenB;
565 const unsigned int rows = 47, cols = 63;
566 vpMatrix A = generateRandomMatrix(rows, cols);
571 REQUIRE(equalMatrix(C, C_true));
575 TEST_CASE(
"Benchmark AtA",
"[benchmark]")
577 if (runBenchmark || runBenchmarkAll) {
578 std::vector<std::pair<int, int> > sizes = {{3, 3}, {6, 6}, {8, 8}, {10, 10}, {20, 20}, {6, 200},
579 {200, 6}, {207, 119}, {83, 201}, {600, 400}, {400, 600}};
581 for (
auto sz : sizes) {
582 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
584 std::ostringstream oss;
585 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
") - Naive code";
587 BENCHMARK(oss.str().c_str())
589 AtA_true = AtA_regular(A);
595 BENCHMARK(oss.str().c_str())
600 REQUIRE(equalMatrix(AtA, AtA_true));
602 if (runBenchmarkAll) {
603 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
604 cv::Mat matA(sz.first, sz.second, CV_64FC1);
606 for (
unsigned int i = 0; i < A.
getRows(); i++) {
607 for (
unsigned int j = 0; j < A.
getCols(); j++) {
608 matA.at<
double>(i, j) = A[i][j];
613 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
") - OpenCV";
614 BENCHMARK(oss.str().c_str())
616 cv::Mat matAtA = matA.t() * matA;
621 #ifdef VISP_HAVE_EIGEN3
622 Eigen::MatrixXd eigenA(sz.first, sz.second);
624 for (
unsigned int i = 0; i < A.
getRows(); i++) {
625 for (
unsigned int j = 0; j < A.
getCols(); j++) {
626 eigenA(i, j) = A[i][j];
631 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
") - Eigen";
632 BENCHMARK(oss.str().c_str())
634 Eigen::MatrixXd eigenAtA = eigenA.
transpose() * eigenA;
643 const unsigned int rows = 47, cols = 63;
644 vpMatrix A = generateRandomMatrix(rows, cols);
648 REQUIRE(equalMatrix(AtA, AtA_true));
652 TEST_CASE(
"Benchmark AAt",
"[benchmark]")
654 if (runBenchmark || runBenchmarkAll) {
655 std::vector<std::pair<int, int> > sizes = {
656 {3, 3}, {6, 6}, {8, 8}, {10, 10},
657 {20, 20}, {6, 200}, {200, 6}};
659 for (
auto sz : sizes) {
660 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
662 std::ostringstream oss;
663 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
") - Naive code";
665 BENCHMARK(oss.str().c_str())
667 AAt_true = AAt_regular(A);
673 BENCHMARK(oss.str().c_str())
678 REQUIRE(equalMatrix(AAt, AAt_true));
680 if (runBenchmarkAll) {
681 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
682 cv::Mat matA(sz.first, sz.second, CV_64FC1);
684 for (
unsigned int i = 0; i < A.
getRows(); i++) {
685 for (
unsigned int j = 0; j < A.
getCols(); j++) {
686 matA.at<
double>(i, j) = A[i][j];
691 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
") - OpenCV";
692 BENCHMARK(oss.str().c_str())
694 cv::Mat matAAt = matA * matA.t();
699 #ifdef VISP_HAVE_EIGEN3
700 Eigen::MatrixXd eigenA(sz.first, sz.second);
702 for (
unsigned int i = 0; i < A.
getRows(); i++) {
703 for (
unsigned int j = 0; j < A.
getCols(); j++) {
704 eigenA(i, j) = A[i][j];
709 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
") - Eigen";
710 BENCHMARK(oss.str().c_str())
712 Eigen::MatrixXd eigenAAt = eigenA * eigenA.
transpose();
721 const unsigned int rows = 47, cols = 63;
722 vpMatrix A = generateRandomMatrix(rows, cols);
726 REQUIRE(equalMatrix(AAt, AAt_true));
730 TEST_CASE(
"Benchmark matrix-velocity twist multiplication",
"[benchmark]")
732 if (runBenchmark || runBenchmarkAll) {
733 std::vector<std::pair<int, int> > sizes = {{6, 6}, {20, 6}, {207, 6}, {600, 6}, {1201, 6}};
735 for (
auto sz : sizes) {
736 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
739 std::ostringstream oss;
740 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
")x(6x6) - Naive code";
742 BENCHMARK(oss.str().c_str())
744 AV_true = dgemm_regular(A, V);
749 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
")x(6x6) - ViSP";
750 BENCHMARK(oss.str().c_str())
755 REQUIRE(equalMatrix(AV, AV_true));
757 if (runBenchmarkAll) {
758 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
759 cv::Mat matA(sz.first, sz.second, CV_64FC1);
760 cv::Mat matV(6, 6, CV_64FC1);
762 for (
unsigned int i = 0; i < A.
getRows(); i++) {
763 for (
unsigned int j = 0; j < A.
getCols(); j++) {
764 matA.at<
double>(i, j) = A[i][j];
767 for (
unsigned int i = 0; i < V.getRows(); i++) {
768 for (
unsigned int j = 0; j < V.getCols(); j++) {
769 matV.at<
double>(i, j) = V[i][j];
774 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(6x6) - OpenCV";
775 BENCHMARK(oss.str().c_str())
777 cv::Mat matAV = matA * matV;
782 #ifdef VISP_HAVE_EIGEN3
783 Eigen::MatrixXd eigenA(sz.first, sz.second);
784 Eigen::MatrixXd eigenV(6, 6);
786 for (
unsigned int i = 0; i < A.
getRows(); i++) {
787 for (
unsigned int j = 0; j < A.
getCols(); j++) {
788 eigenA(i, j) = A[i][j];
791 for (
unsigned int i = 0; i < V.getRows(); i++) {
792 for (
unsigned int j = 0; j < V.getCols(); j++) {
793 eigenV(i, j) = V[i][j];
798 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(6x6) - Eigen";
799 BENCHMARK(oss.str().c_str())
801 Eigen::MatrixXd eigenAV = eigenA * eigenV;
810 const unsigned int rows = 47, cols = 6;
811 vpMatrix A = generateRandomMatrix(rows, cols);
814 vpMatrix AV_true = dgemm_regular(A, V);
816 REQUIRE(equalMatrix(AV, AV_true));
820 TEST_CASE(
"Benchmark matrix-force twist multiplication",
"[benchmark]")
822 if (runBenchmark || runBenchmarkAll) {
823 std::vector<std::pair<int, int> > sizes = {{6, 6}, {20, 6}, {207, 6}, {600, 6}, {1201, 6}};
825 for (
auto sz : sizes) {
826 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
829 std::ostringstream oss;
830 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
")x(6x6) - Naive code";
832 BENCHMARK(oss.str().c_str())
834 AV_true = dgemm_regular(A, V);
839 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
")x(6x6) - ViSP";
840 BENCHMARK(oss.str().c_str())
845 REQUIRE(equalMatrix(AV, AV_true));
847 if (runBenchmarkAll) {
848 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
849 cv::Mat matA(sz.first, sz.second, CV_64FC1);
850 cv::Mat matV(6, 6, CV_64FC1);
852 for (
unsigned int i = 0; i < A.
getRows(); i++) {
853 for (
unsigned int j = 0; j < A.
getCols(); j++) {
854 matA.at<
double>(i, j) = A[i][j];
857 for (
unsigned int i = 0; i < V.getRows(); i++) {
858 for (
unsigned int j = 0; j < V.getCols(); j++) {
859 matV.at<
double>(i, j) = V[i][j];
864 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(6x6) - OpenCV";
865 BENCHMARK(oss.str().c_str())
867 cv::Mat matAV = matA * matV;
872 #ifdef VISP_HAVE_EIGEN3
873 Eigen::MatrixXd eigenA(sz.first, sz.second);
874 Eigen::MatrixXd eigenV(6, 6);
876 for (
unsigned int i = 0; i < A.
getRows(); i++) {
877 for (
unsigned int j = 0; j < A.
getCols(); j++) {
878 eigenA(i, j) = A[i][j];
881 for (
unsigned int i = 0; i < V.getRows(); i++) {
882 for (
unsigned int j = 0; j < V.getCols(); j++) {
883 eigenV(i, j) = V[i][j];
888 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(6x6) - Eigen";
889 BENCHMARK(oss.str().c_str())
891 Eigen::MatrixXd eigenAV = eigenA * eigenV;
900 const unsigned int rows = 47, cols = 6;
901 vpMatrix A = generateRandomMatrix(rows, cols);
904 vpMatrix AV_true = dgemm_regular(A, V);
906 REQUIRE(equalMatrix(AV, AV_true));
910 int main(
int argc,
char *argv[])
917 Catch::Session session;
920 std::cout <<
"Default matrix/vector min size to enable Blas/Lapack optimization: " << lapackMinSize << std::endl;
922 using namespace Catch::clara;
923 auto cli = session.cli()
926 (
"run benchmark comparing naive code with ViSP implementation")
927 | Opt(runBenchmarkAll)
929 (
"run benchmark comparing naive code with ViSP, OpenCV, Eigen implementation")
931 | Opt(lapackMinSize,
"min size")
932 [
"--lapack-min-size"]
933 (
"matrix/vector min size to enable blas/lapack usage");
939 session.applyCommandLine(argc, argv);
945 int numFailed = session.run();
955 int main() {
return EXIT_SUCCESS; }
unsigned int getCols() const
Type * data
Address of the first element of the data array.
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.
vp_deprecated vpColVector rows(unsigned int first_row, unsigned int last_row) const
void resize(unsigned int i, bool flagNullify=true)
error that can be emitted by ViSP classes.
@ dimensionError
Bad dimension.
Implementation of an homogeneous matrix and operations on such kind of matrices.
static bool equal(double x, double y, double threshold=0.001)
static double deg(double rad)
Implementation of a matrix and operations on matrices.
static void setLapackMatrixMinSize(unsigned int min_size)
static unsigned int getLapackMatrixMinSize()
vpMatrix transpose() const
static void mult2Matrices(const vpMatrix &A, const vpMatrix &B, vpMatrix &C)
Implementation of a rotation matrix and operations on such kind of matrices.
Implementation of a rotation vector as axis-angle minimal representation.
Class that consider the case of a translation vector.