38 #include <visp3/core/vpConfig.h>
40 #ifdef VISP_HAVE_CATCH2
41 #define CATCH_CONFIG_ENABLE_BENCHMARKING
42 #define CATCH_CONFIG_RUNNER
45 #include <visp3/core/vpMatrix.h>
47 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
48 #include <opencv2/core.hpp>
51 #ifdef VISP_HAVE_EIGEN3
52 #include <Eigen/Dense>
55 #ifdef ENABLE_VISP_NAMESPACE
62 bool runBenchmark =
false;
63 bool runBenchmarkAll =
false;
65 double getRandomValues(
double min,
double max) {
return (max - min) * ((double)rand() / (double)RAND_MAX) + min; }
67 vpMatrix generateRandomMatrix(
unsigned int rows,
unsigned int cols,
double min = -1,
double max = 1)
71 for (
unsigned int i = 0; i < M.getRows(); i++) {
72 for (
unsigned int j = 0; j < M.getCols(); j++) {
73 M[i][j] = getRandomValues(min, max);
80 vpColVector generateRandomVector(
unsigned int rows,
double min = -1,
double max = 1)
84 for (
unsigned int i = 0; i < v.getRows(); i++) {
85 v[i] = getRandomValues(min, max);
106 unsigned int BcolNum = B.
getCols();
107 unsigned int BrowNum = B.
getRows();
108 unsigned int i, j, k;
109 for (i = 0; i < A.
getRows(); i++) {
110 double *rowptri = A[i];
112 for (j = 0; j < BcolNum; j++) {
114 for (k = 0; k < BrowNum; k++) {
115 s += rowptri[k] * B[k][j];
130 for (
unsigned int i = 0; i < A.
getCols(); i++) {
132 for (
unsigned int j = 0; j < i; j++) {
133 double *ptr = A.
data;
135 for (
unsigned int k = 0; k < A.
getRows(); k++) {
136 s += (*(ptr + i)) * (*(ptr + j));
142 double *ptr = A.
data;
144 for (
unsigned int k = 0; k < A.
getRows(); k++) {
145 s += (*(ptr + i)) * (*(ptr + i));
161 for (
unsigned int i = 0; i < A.
getRows(); i++) {
162 for (
unsigned int j = i; j < A.
getRows(); j++) {
168 for (
unsigned int k = 0; k < A.
getCols(); k++)
169 ssum += *(pi++) * *(pj++);
191 for (
unsigned int j = 0; j < A.
getCols(); j++) {
193 for (
unsigned int i = 0; i < A.
getRows(); i++) {
194 w[i] += A[i][j] * vj;
207 for (
unsigned int i = 0; i < A.
getRows(); i++) {
208 for (
unsigned int j = 0; j < A.
getCols(); j++) {
220 TEST_CASE(
"Benchmark matrix-matrix multiplication",
"[benchmark]")
222 if (runBenchmark || runBenchmarkAll) {
223 std::vector<std::pair<int, int> > sizes = { {3, 3}, {6, 6}, {8, 8}, {10, 10}, {20, 20}, {6, 200},
224 {200, 6}, {207, 119}, {83, 201}, {600, 400}, {400, 600} };
226 for (
auto sz : sizes) {
227 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
228 vpMatrix B = generateRandomMatrix(sz.second, sz.first);
230 std::ostringstream oss;
233 BENCHMARK(oss.str().c_str())
235 C_true = dgemm_regular(A, B);
241 BENCHMARK(oss.str().c_str())
246 REQUIRE(equalMatrix(C, C_true));
248 if (runBenchmarkAll) {
249 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
250 cv::Mat matA(sz.first, sz.second, CV_64FC1);
251 cv::Mat matB(sz.second, sz.first, CV_64FC1);
253 for (
unsigned int i = 0; i < A.
getRows(); i++) {
254 for (
unsigned int j = 0; j < A.
getCols(); j++) {
255 matA.at<
double>(i, j) = A[i][j];
256 matB.at<
double>(j, i) = B[j][i];
261 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(" << matB.rows <<
"x" << matB.cols <<
") - OpenCV";
262 BENCHMARK(oss.str().c_str())
264 cv::Mat matC = matA * matB;
269 #ifdef VISP_HAVE_EIGEN3
270 Eigen::MatrixXd eigenA(sz.first, sz.second);
271 Eigen::MatrixXd eigenB(sz.second, sz.first);
273 for (
unsigned int i = 0; i < A.
getRows(); i++) {
274 for (
unsigned int j = 0; j < A.
getCols(); j++) {
275 eigenA(i, j) = A[i][j];
276 eigenB(j, i) = B[j][i];
281 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(" << eigenB.rows() <<
"x" << eigenB.cols()
283 BENCHMARK(oss.str().c_str())
285 Eigen::MatrixXd eigenC = eigenA * eigenB;
294 const unsigned int rows = 47, cols = 63;
295 vpMatrix A = generateRandomMatrix(rows, cols);
296 vpMatrix B = generateRandomMatrix(cols, rows);
298 vpMatrix C_true = dgemm_regular(A, B);
300 REQUIRE(equalMatrix(C, C_true));
304 TEST_CASE(
"Benchmark matrix-rotation matrix multiplication",
"[benchmark]")
306 if (runBenchmark || runBenchmarkAll) {
307 std::vector<std::pair<int, int> > sizes = { {3, 3} };
309 for (
auto sz : sizes) {
310 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
314 std::ostringstream oss;
317 BENCHMARK(oss.str().c_str())
319 AB_true = dgemm_regular(A,
static_cast<vpMatrix>(B));
325 BENCHMARK(oss.str().c_str())
330 REQUIRE(equalMatrix(AB, AB_true));
332 if (runBenchmarkAll) {
333 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
334 cv::Mat matA(sz.first, sz.second, CV_64FC1);
335 cv::Mat matB(3, 3, CV_64FC1);
337 for (
unsigned int i = 0; i < A.
getRows(); i++) {
338 for (
unsigned int j = 0; j < A.
getCols(); j++) {
339 matA.at<
double>(i, j) = A[i][j];
342 for (
unsigned int i = 0; i < B.
getRows(); i++) {
343 for (
unsigned int j = 0; j < B.
getCols(); j++) {
344 matB.at<
double>(j, i) = B[j][i];
349 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(" << matB.rows <<
"x" << matB.cols <<
") - OpenCV";
350 BENCHMARK(oss.str().c_str())
352 cv::Mat matC = matA * matB;
357 #ifdef VISP_HAVE_EIGEN3
358 Eigen::MatrixXd eigenA(sz.first, sz.second);
359 Eigen::MatrixXd eigenB(3, 3);
361 for (
unsigned int i = 0; i < A.
getRows(); i++) {
362 for (
unsigned int j = 0; j < A.
getCols(); j++) {
363 eigenA(i, j) = A[i][j];
366 for (
unsigned int i = 0; i < B.
getRows(); i++) {
367 for (
unsigned int j = 0; j < B.
getCols(); j++) {
368 eigenB(j, i) = B[j][i];
373 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(" << eigenB.rows() <<
"x" << eigenB.cols()
375 BENCHMARK(oss.str().c_str())
377 Eigen::MatrixXd eigenC = eigenA * eigenB;
386 const unsigned int rows = 3, cols = 3;
387 vpMatrix A = generateRandomMatrix(rows, cols);
393 REQUIRE(equalMatrix(AB, AB_true));
397 TEST_CASE(
"Benchmark matrix-homogeneous matrix multiplication",
"[benchmark]")
399 if (runBenchmark || runBenchmarkAll) {
400 std::vector<std::pair<int, int> > sizes = { {4, 4} };
402 for (
auto sz : sizes) {
403 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
408 std::ostringstream oss;
411 BENCHMARK(oss.str().c_str())
413 AB_true = dgemm_regular(A,
static_cast<vpMatrix>(B));
419 BENCHMARK(oss.str().c_str())
424 REQUIRE(equalMatrix(AB, AB_true));
426 if (runBenchmarkAll) {
427 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
428 cv::Mat matA(sz.first, sz.second, CV_64FC1);
429 cv::Mat matB(4, 4, CV_64FC1);
431 for (
unsigned int i = 0; i < A.
getRows(); i++) {
432 for (
unsigned int j = 0; j < A.
getCols(); j++) {
433 matA.at<
double>(i, j) = A[i][j];
436 for (
unsigned int i = 0; i < B.
getRows(); i++) {
437 for (
unsigned int j = 0; j < B.
getCols(); j++) {
438 matB.at<
double>(j, i) = B[j][i];
443 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(" << matB.rows <<
"x" << matB.cols <<
") - OpenCV";
444 BENCHMARK(oss.str().c_str())
446 cv::Mat matC = matA * matB;
451 #ifdef VISP_HAVE_EIGEN3
452 Eigen::MatrixXd eigenA(sz.first, sz.second);
453 Eigen::MatrixXd eigenB(4, 4);
455 for (
unsigned int i = 0; i < A.
getRows(); i++) {
456 for (
unsigned int j = 0; j < A.
getCols(); j++) {
457 eigenA(i, j) = A[i][j];
460 for (
unsigned int i = 0; i < B.
getRows(); i++) {
461 for (
unsigned int j = 0; j < B.
getCols(); j++) {
462 eigenB(j, i) = B[j][i];
467 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(" << eigenB.rows() <<
"x" << eigenB.cols()
469 BENCHMARK(oss.str().c_str())
471 Eigen::MatrixXd eigenC = eigenA * eigenB;
480 const unsigned int rows = 4, cols = 4;
481 vpMatrix A = generateRandomMatrix(rows, cols);
489 REQUIRE(equalMatrix(AB, AB_true));
493 TEST_CASE(
"Benchmark matrix-vector multiplication",
"[benchmark]")
495 if (runBenchmark || runBenchmarkAll) {
496 std::vector<std::pair<int, int> > sizes = { {3, 3}, {6, 6}, {8, 8}, {10, 10}, {20, 20}, {6, 200},
497 {200, 6}, {207, 119}, {83, 201}, {600, 400}, {400, 600} };
499 for (
auto sz : sizes) {
500 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
503 std::ostringstream oss;
506 BENCHMARK(oss.str().c_str())
508 C_true = dgemv_regular(A,
static_cast<vpColVector>(B));
514 BENCHMARK(oss.str().c_str())
519 REQUIRE(equalMatrix(
static_cast<vpMatrix>(C),
static_cast<vpMatrix>(C_true)));
521 if (runBenchmarkAll) {
522 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
523 cv::Mat matA(sz.first, sz.second, CV_64FC1);
524 cv::Mat matB(sz.second, 1, CV_64FC1);
526 for (
unsigned int i = 0; i < A.
getRows(); i++) {
527 for (
unsigned int j = 0; j < A.
getCols(); j++) {
528 matA.at<
double>(i, j) = A[i][j];
530 matB.at<
double>(j, 0) = B[j];
536 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(" << matB.rows <<
"x" << matB.cols <<
") - OpenCV";
537 BENCHMARK(oss.str().c_str())
539 cv::Mat matC = matA * matB;
544 #ifdef VISP_HAVE_EIGEN3
545 Eigen::MatrixXd eigenA(sz.first, sz.second);
546 Eigen::MatrixXd eigenB(sz.second, 1);
548 for (
unsigned int i = 0; i < A.
getRows(); i++) {
549 for (
unsigned int j = 0; j < A.
getCols(); j++) {
550 eigenA(i, j) = A[i][j];
558 oss <<
"(" << eigenA.
rows() <<
"x" << eigenA.cols() <<
")x(" << eigenB.
rows() <<
"x" << eigenB.cols()
560 BENCHMARK(oss.str().c_str())
562 Eigen::MatrixXd eigenC = eigenA * eigenB;
571 const unsigned int rows = 47, cols = 63;
572 vpMatrix A = generateRandomMatrix(rows, cols);
577 REQUIRE(equalMatrix(
static_cast<vpMatrix>(C),
static_cast<vpMatrix>(C_true)));
581 TEST_CASE(
"Benchmark AtA",
"[benchmark]")
583 if (runBenchmark || runBenchmarkAll) {
584 std::vector<std::pair<int, int> > sizes = { {3, 3}, {6, 6}, {8, 8}, {10, 10}, {20, 20}, {6, 200},
585 {200, 6}, {207, 119}, {83, 201}, {600, 400}, {400, 600} };
587 for (
auto sz : sizes) {
588 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
590 std::ostringstream oss;
591 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
") - Naive code";
593 BENCHMARK(oss.str().c_str())
595 AtA_true = AtA_regular(A);
601 BENCHMARK(oss.str().c_str())
606 REQUIRE(equalMatrix(AtA, AtA_true));
608 if (runBenchmarkAll) {
609 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
610 cv::Mat matA(sz.first, sz.second, CV_64FC1);
612 for (
unsigned int i = 0; i < A.
getRows(); i++) {
613 for (
unsigned int j = 0; j < A.
getCols(); j++) {
614 matA.at<
double>(i, j) = A[i][j];
619 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
") - OpenCV";
620 BENCHMARK(oss.str().c_str())
622 cv::Mat matAtA = matA.t() * matA;
627 #ifdef VISP_HAVE_EIGEN3
628 Eigen::MatrixXd eigenA(sz.first, sz.second);
630 for (
unsigned int i = 0; i < A.
getRows(); i++) {
631 for (
unsigned int j = 0; j < A.
getCols(); j++) {
632 eigenA(i, j) = A[i][j];
637 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
") - Eigen";
638 BENCHMARK(oss.str().c_str())
640 Eigen::MatrixXd eigenAtA = eigenA.
transpose() * eigenA;
649 const unsigned int rows = 47, cols = 63;
650 vpMatrix A = generateRandomMatrix(rows, cols);
654 REQUIRE(equalMatrix(AtA, AtA_true));
658 TEST_CASE(
"Benchmark AAt",
"[benchmark]")
660 if (runBenchmark || runBenchmarkAll) {
661 std::vector<std::pair<int, int> > sizes = {
662 {3, 3}, {6, 6}, {8, 8}, {10, 10},
663 {20, 20}, {6, 200}, {200, 6} };
665 for (
auto sz : sizes) {
666 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
668 std::ostringstream oss;
669 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
") - Naive code";
671 BENCHMARK(oss.str().c_str())
673 AAt_true = AAt_regular(A);
679 BENCHMARK(oss.str().c_str())
684 REQUIRE(equalMatrix(AAt, AAt_true));
686 if (runBenchmarkAll) {
687 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
688 cv::Mat matA(sz.first, sz.second, CV_64FC1);
690 for (
unsigned int i = 0; i < A.
getRows(); i++) {
691 for (
unsigned int j = 0; j < A.
getCols(); j++) {
692 matA.at<
double>(i, j) = A[i][j];
697 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
") - OpenCV";
698 BENCHMARK(oss.str().c_str())
700 cv::Mat matAAt = matA * matA.t();
705 #ifdef VISP_HAVE_EIGEN3
706 Eigen::MatrixXd eigenA(sz.first, sz.second);
708 for (
unsigned int i = 0; i < A.
getRows(); i++) {
709 for (
unsigned int j = 0; j < A.
getCols(); j++) {
710 eigenA(i, j) = A[i][j];
715 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
") - Eigen";
716 BENCHMARK(oss.str().c_str())
718 Eigen::MatrixXd eigenAAt = eigenA * eigenA.
transpose();
727 const unsigned int rows = 47, cols = 63;
728 vpMatrix A = generateRandomMatrix(rows, cols);
732 REQUIRE(equalMatrix(AAt, AAt_true));
736 TEST_CASE(
"Benchmark matrix-velocity twist multiplication",
"[benchmark]")
738 if (runBenchmark || runBenchmarkAll) {
739 std::vector<std::pair<int, int> > sizes = { {6, 6}, {20, 6}, {207, 6}, {600, 6}, {1201, 6} };
741 for (
auto sz : sizes) {
742 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
745 std::ostringstream oss;
746 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
")x(6x6) - Naive code";
748 BENCHMARK(oss.str().c_str())
750 AV_true = dgemm_regular(A,
static_cast<vpMatrix>(V));
755 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
")x(6x6) - ViSP";
756 BENCHMARK(oss.str().c_str())
761 REQUIRE(equalMatrix(AV, AV_true));
763 if (runBenchmarkAll) {
764 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
765 cv::Mat matA(sz.first, sz.second, CV_64FC1);
766 cv::Mat matV(6, 6, CV_64FC1);
768 for (
unsigned int i = 0; i < A.
getRows(); i++) {
769 for (
unsigned int j = 0; j < A.
getCols(); j++) {
770 matA.at<
double>(i, j) = A[i][j];
773 for (
unsigned int i = 0; i < V.getRows(); i++) {
774 for (
unsigned int j = 0; j < V.getCols(); j++) {
775 matV.at<
double>(i, j) = V[i][j];
780 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(6x6) - OpenCV";
781 BENCHMARK(oss.str().c_str())
783 cv::Mat matAV = matA * matV;
788 #ifdef VISP_HAVE_EIGEN3
789 Eigen::MatrixXd eigenA(sz.first, sz.second);
790 Eigen::MatrixXd eigenV(6, 6);
792 for (
unsigned int i = 0; i < A.
getRows(); i++) {
793 for (
unsigned int j = 0; j < A.
getCols(); j++) {
794 eigenA(i, j) = A[i][j];
797 for (
unsigned int i = 0; i < V.getRows(); i++) {
798 for (
unsigned int j = 0; j < V.getCols(); j++) {
799 eigenV(i, j) = V[i][j];
804 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(6x6) - Eigen";
805 BENCHMARK(oss.str().c_str())
807 Eigen::MatrixXd eigenAV = eigenA * eigenV;
816 const unsigned int rows = 47, cols = 6;
817 vpMatrix A = generateRandomMatrix(rows, cols);
822 REQUIRE(equalMatrix(AV, AV_true));
826 TEST_CASE(
"Benchmark matrix-force twist multiplication",
"[benchmark]")
828 if (runBenchmark || runBenchmarkAll) {
829 std::vector<std::pair<int, int> > sizes = { {6, 6}, {20, 6}, {207, 6}, {600, 6}, {1201, 6} };
831 for (
auto sz : sizes) {
832 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
835 std::ostringstream oss;
836 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
")x(6x6) - Naive code";
838 BENCHMARK(oss.str().c_str())
840 AV_true = dgemm_regular(A,
static_cast<vpMatrix>(V));
845 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
")x(6x6) - ViSP";
846 BENCHMARK(oss.str().c_str())
851 REQUIRE(equalMatrix(AV, AV_true));
853 if (runBenchmarkAll) {
854 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
855 cv::Mat matA(sz.first, sz.second, CV_64FC1);
856 cv::Mat matV(6, 6, CV_64FC1);
858 for (
unsigned int i = 0; i < A.
getRows(); i++) {
859 for (
unsigned int j = 0; j < A.
getCols(); j++) {
860 matA.at<
double>(i, j) = A[i][j];
863 for (
unsigned int i = 0; i < V.getRows(); i++) {
864 for (
unsigned int j = 0; j < V.getCols(); j++) {
865 matV.at<
double>(i, j) = V[i][j];
870 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(6x6) - OpenCV";
871 BENCHMARK(oss.str().c_str())
873 cv::Mat matAV = matA * matV;
878 #ifdef VISP_HAVE_EIGEN3
879 Eigen::MatrixXd eigenA(sz.first, sz.second);
880 Eigen::MatrixXd eigenV(6, 6);
882 for (
unsigned int i = 0; i < A.
getRows(); i++) {
883 for (
unsigned int j = 0; j < A.
getCols(); j++) {
884 eigenA(i, j) = A[i][j];
887 for (
unsigned int i = 0; i < V.getRows(); i++) {
888 for (
unsigned int j = 0; j < V.getCols(); j++) {
889 eigenV(i, j) = V[i][j];
894 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(6x6) - Eigen";
895 BENCHMARK(oss.str().c_str())
897 Eigen::MatrixXd eigenAV = eigenA * eigenV;
906 const unsigned int rows = 47, cols = 6;
907 vpMatrix A = generateRandomMatrix(rows, cols);
912 REQUIRE(equalMatrix(AV, AV_true));
916 int main(
int argc,
char *argv[])
923 Catch::Session session;
926 std::cout <<
"Default matrix/vector min size to enable Blas/Lapack optimization: " << lapackMinSize << std::endl;
928 using namespace Catch::clara;
929 auto cli = session.cli()
932 (
"run benchmark comparing naive code with ViSP implementation")
933 | Opt(runBenchmarkAll)
935 (
"run benchmark comparing naive code with ViSP, OpenCV, Eigen implementation")
937 | Opt(lapackMinSize,
"min size")
938 [
"--lapack-min-size"]
939 (
"matrix/vector min size to enable blas/lapack usage");
945 session.applyCommandLine(argc, argv);
951 int numFailed = session.run();
961 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.