38 #include <visp3/core/vpConfig.h>
40 #if defined(VISP_HAVE_CATCH2)
42 #include <catch_amalgamated.hpp>
44 #include <visp3/core/vpMatrix.h>
46 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
47 #include <opencv2/core.hpp>
50 #ifdef VISP_HAVE_EIGEN3
51 #include <Eigen/Dense>
54 #ifdef ENABLE_VISP_NAMESPACE
61 bool runBenchmark =
false;
62 bool runBenchmarkAll =
false;
64 double getRandomValues(
double min,
double max) {
return (max - min) * ((double)rand() / (double)RAND_MAX) + min; }
66 vpMatrix generateRandomMatrix(
unsigned int rows,
unsigned int cols,
double min = -1,
double max = 1)
70 for (
unsigned int i = 0; i < M.getRows(); i++) {
71 for (
unsigned int j = 0; j < M.getCols(); j++) {
72 M[i][j] = getRandomValues(min, max);
79 vpColVector generateRandomVector(
unsigned int rows,
double min = -1,
double max = 1)
83 for (
unsigned int i = 0; i < v.getRows(); i++) {
84 v[i] = getRandomValues(min, max);
105 unsigned int BcolNum = B.
getCols();
106 unsigned int BrowNum = B.
getRows();
107 unsigned int i, j, k;
108 for (i = 0; i < A.
getRows(); i++) {
109 double *rowptri = A[i];
111 for (j = 0; j < BcolNum; j++) {
113 for (k = 0; k < BrowNum; k++) {
114 s += rowptri[k] * B[k][j];
129 for (
unsigned int i = 0; i < A.
getCols(); i++) {
131 for (
unsigned int j = 0; j < i; j++) {
132 double *ptr = A.
data;
134 for (
unsigned int k = 0; k < A.
getRows(); k++) {
135 s += (*(ptr + i)) * (*(ptr + j));
141 double *ptr = A.
data;
143 for (
unsigned int k = 0; k < A.
getRows(); k++) {
144 s += (*(ptr + i)) * (*(ptr + i));
160 for (
unsigned int i = 0; i < A.
getRows(); i++) {
161 for (
unsigned int j = i; j < A.
getRows(); j++) {
167 for (
unsigned int k = 0; k < A.
getCols(); k++)
168 ssum += *(pi++) * *(pj++);
190 for (
unsigned int j = 0; j < A.
getCols(); j++) {
192 for (
unsigned int i = 0; i < A.
getRows(); i++) {
193 w[i] += A[i][j] * vj;
206 for (
unsigned int i = 0; i < A.
getRows(); i++) {
207 for (
unsigned int j = 0; j < A.
getCols(); j++) {
219 TEST_CASE(
"Benchmark matrix-matrix multiplication",
"[benchmark]")
221 if (runBenchmark || runBenchmarkAll) {
222 std::vector<std::pair<int, int> > sizes = { {3, 3}, {6, 6}, {8, 8}, {10, 10}, {20, 20}, {6, 200},
223 {200, 6}, {207, 119}, {83, 201}, {600, 400}, {400, 600} };
225 for (
auto sz : sizes) {
226 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
227 vpMatrix B = generateRandomMatrix(sz.second, sz.first);
229 std::ostringstream oss;
232 BENCHMARK(oss.str().c_str())
234 C_true = dgemm_regular(A, B);
240 BENCHMARK(oss.str().c_str())
245 REQUIRE(equalMatrix(C, C_true));
247 if (runBenchmarkAll) {
248 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
249 cv::Mat matA(sz.first, sz.second, CV_64FC1);
250 cv::Mat matB(sz.second, sz.first, CV_64FC1);
252 for (
unsigned int i = 0; i < A.
getRows(); i++) {
253 for (
unsigned int j = 0; j < A.
getCols(); j++) {
254 matA.at<
double>(i, j) = A[i][j];
255 matB.at<
double>(j, i) = B[j][i];
260 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(" << matB.rows <<
"x" << matB.cols <<
") - OpenCV";
261 BENCHMARK(oss.str().c_str())
263 cv::Mat matC = matA * matB;
268 #ifdef VISP_HAVE_EIGEN3
269 Eigen::MatrixXd eigenA(sz.first, sz.second);
270 Eigen::MatrixXd eigenB(sz.second, sz.first);
272 for (
unsigned int i = 0; i < A.
getRows(); i++) {
273 for (
unsigned int j = 0; j < A.
getCols(); j++) {
274 eigenA(i, j) = A[i][j];
275 eigenB(j, i) = B[j][i];
280 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(" << eigenB.rows() <<
"x" << eigenB.cols()
282 BENCHMARK(oss.str().c_str())
284 Eigen::MatrixXd eigenC = eigenA * eigenB;
293 const unsigned int rows = 47, cols = 63;
294 vpMatrix A = generateRandomMatrix(rows, cols);
295 vpMatrix B = generateRandomMatrix(cols, rows);
297 vpMatrix C_true = dgemm_regular(A, B);
299 REQUIRE(equalMatrix(C, C_true));
303 TEST_CASE(
"Benchmark matrix-rotation matrix multiplication",
"[benchmark]")
305 if (runBenchmark || runBenchmarkAll) {
306 std::vector<std::pair<int, int> > sizes = { {3, 3} };
308 for (
auto sz : sizes) {
309 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
313 std::ostringstream oss;
316 BENCHMARK(oss.str().c_str())
318 AB_true = dgemm_regular(A,
static_cast<vpMatrix>(B));
324 BENCHMARK(oss.str().c_str())
329 REQUIRE(equalMatrix(AB, AB_true));
331 if (runBenchmarkAll) {
332 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
333 cv::Mat matA(sz.first, sz.second, CV_64FC1);
334 cv::Mat matB(3, 3, CV_64FC1);
336 for (
unsigned int i = 0; i < A.
getRows(); i++) {
337 for (
unsigned int j = 0; j < A.
getCols(); j++) {
338 matA.at<
double>(i, j) = A[i][j];
341 for (
unsigned int i = 0; i < B.
getRows(); i++) {
342 for (
unsigned int j = 0; j < B.
getCols(); j++) {
343 matB.at<
double>(j, i) = B[j][i];
348 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(" << matB.rows <<
"x" << matB.cols <<
") - OpenCV";
349 BENCHMARK(oss.str().c_str())
351 cv::Mat matC = matA * matB;
356 #ifdef VISP_HAVE_EIGEN3
357 Eigen::MatrixXd eigenA(sz.first, sz.second);
358 Eigen::MatrixXd eigenB(3, 3);
360 for (
unsigned int i = 0; i < A.
getRows(); i++) {
361 for (
unsigned int j = 0; j < A.
getCols(); j++) {
362 eigenA(i, j) = A[i][j];
365 for (
unsigned int i = 0; i < B.
getRows(); i++) {
366 for (
unsigned int j = 0; j < B.
getCols(); j++) {
367 eigenB(j, i) = B[j][i];
372 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(" << eigenB.rows() <<
"x" << eigenB.cols()
374 BENCHMARK(oss.str().c_str())
376 Eigen::MatrixXd eigenC = eigenA * eigenB;
385 const unsigned int rows = 3, cols = 3;
386 vpMatrix A = generateRandomMatrix(rows, cols);
392 REQUIRE(equalMatrix(AB, AB_true));
396 TEST_CASE(
"Benchmark matrix-homogeneous matrix multiplication",
"[benchmark]")
398 if (runBenchmark || runBenchmarkAll) {
399 std::vector<std::pair<int, int> > sizes = { {4, 4} };
401 for (
auto sz : sizes) {
402 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
407 std::ostringstream oss;
410 BENCHMARK(oss.str().c_str())
412 AB_true = dgemm_regular(A,
static_cast<vpMatrix>(B));
418 BENCHMARK(oss.str().c_str())
423 REQUIRE(equalMatrix(AB, AB_true));
425 if (runBenchmarkAll) {
426 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
427 cv::Mat matA(sz.first, sz.second, CV_64FC1);
428 cv::Mat matB(4, 4, CV_64FC1);
430 for (
unsigned int i = 0; i < A.
getRows(); i++) {
431 for (
unsigned int j = 0; j < A.
getCols(); j++) {
432 matA.at<
double>(i, j) = A[i][j];
435 for (
unsigned int i = 0; i < B.
getRows(); i++) {
436 for (
unsigned int j = 0; j < B.
getCols(); j++) {
437 matB.at<
double>(j, i) = B[j][i];
442 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(" << matB.rows <<
"x" << matB.cols <<
") - OpenCV";
443 BENCHMARK(oss.str().c_str())
445 cv::Mat matC = matA * matB;
450 #ifdef VISP_HAVE_EIGEN3
451 Eigen::MatrixXd eigenA(sz.first, sz.second);
452 Eigen::MatrixXd eigenB(4, 4);
454 for (
unsigned int i = 0; i < A.
getRows(); i++) {
455 for (
unsigned int j = 0; j < A.
getCols(); j++) {
456 eigenA(i, j) = A[i][j];
459 for (
unsigned int i = 0; i < B.
getRows(); i++) {
460 for (
unsigned int j = 0; j < B.
getCols(); j++) {
461 eigenB(j, i) = B[j][i];
466 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(" << eigenB.rows() <<
"x" << eigenB.cols()
468 BENCHMARK(oss.str().c_str())
470 Eigen::MatrixXd eigenC = eigenA * eigenB;
479 const unsigned int rows = 4, cols = 4;
480 vpMatrix A = generateRandomMatrix(rows, cols);
488 REQUIRE(equalMatrix(AB, AB_true));
492 TEST_CASE(
"Benchmark matrix-vector multiplication",
"[benchmark]")
494 if (runBenchmark || runBenchmarkAll) {
495 std::vector<std::pair<int, int> > sizes = { {3, 3}, {6, 6}, {8, 8}, {10, 10}, {20, 20}, {6, 200},
496 {200, 6}, {207, 119}, {83, 201}, {600, 400}, {400, 600} };
498 for (
auto sz : sizes) {
499 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
502 std::ostringstream oss;
505 BENCHMARK(oss.str().c_str())
507 C_true = dgemv_regular(A,
static_cast<vpColVector>(B));
513 BENCHMARK(oss.str().c_str())
518 REQUIRE(equalMatrix(
static_cast<vpMatrix>(C),
static_cast<vpMatrix>(C_true)));
520 if (runBenchmarkAll) {
521 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
522 cv::Mat matA(sz.first, sz.second, CV_64FC1);
523 cv::Mat matB(sz.second, 1, CV_64FC1);
525 for (
unsigned int i = 0; i < A.
getRows(); i++) {
526 for (
unsigned int j = 0; j < A.
getCols(); j++) {
527 matA.at<
double>(i, j) = A[i][j];
529 matB.at<
double>(j, 0) = B[j];
535 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(" << matB.rows <<
"x" << matB.cols <<
") - OpenCV";
536 BENCHMARK(oss.str().c_str())
538 cv::Mat matC = matA * matB;
543 #ifdef VISP_HAVE_EIGEN3
544 Eigen::MatrixXd eigenA(sz.first, sz.second);
545 Eigen::MatrixXd eigenB(sz.second, 1);
547 for (
unsigned int i = 0; i < A.
getRows(); i++) {
548 for (
unsigned int j = 0; j < A.
getCols(); j++) {
549 eigenA(i, j) = A[i][j];
557 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(" << eigenB.rows() <<
"x" << eigenB.cols()
559 BENCHMARK(oss.str().c_str())
561 Eigen::MatrixXd eigenC = eigenA * eigenB;
570 const unsigned int rows = 47, cols = 63;
571 vpMatrix A = generateRandomMatrix(rows, cols);
576 REQUIRE(equalMatrix(
static_cast<vpMatrix>(C),
static_cast<vpMatrix>(C_true)));
580 TEST_CASE(
"Benchmark AtA",
"[benchmark]")
582 if (runBenchmark || runBenchmarkAll) {
583 std::vector<std::pair<int, int> > sizes = { {3, 3}, {6, 6}, {8, 8}, {10, 10}, {20, 20}, {6, 200},
584 {200, 6}, {207, 119}, {83, 201}, {600, 400}, {400, 600} };
586 for (
auto sz : sizes) {
587 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
589 std::ostringstream oss;
590 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
") - Naive code";
592 BENCHMARK(oss.str().c_str())
594 AtA_true = AtA_regular(A);
600 BENCHMARK(oss.str().c_str())
605 REQUIRE(equalMatrix(AtA, AtA_true));
607 if (runBenchmarkAll) {
608 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
609 cv::Mat matA(sz.first, sz.second, CV_64FC1);
611 for (
unsigned int i = 0; i < A.
getRows(); i++) {
612 for (
unsigned int j = 0; j < A.
getCols(); j++) {
613 matA.at<
double>(i, j) = A[i][j];
618 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
") - OpenCV";
619 BENCHMARK(oss.str().c_str())
621 cv::Mat matAtA = matA.t() * matA;
626 #ifdef VISP_HAVE_EIGEN3
627 Eigen::MatrixXd eigenA(sz.first, sz.second);
629 for (
unsigned int i = 0; i < A.
getRows(); i++) {
630 for (
unsigned int j = 0; j < A.
getCols(); j++) {
631 eigenA(i, j) = A[i][j];
636 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
") - Eigen";
637 BENCHMARK(oss.str().c_str())
639 Eigen::MatrixXd eigenAtA = eigenA.
transpose() * eigenA;
648 const unsigned int rows = 47, cols = 63;
649 vpMatrix A = generateRandomMatrix(rows, cols);
653 REQUIRE(equalMatrix(AtA, AtA_true));
657 TEST_CASE(
"Benchmark AAt",
"[benchmark]")
659 if (runBenchmark || runBenchmarkAll) {
660 std::vector<std::pair<int, int> > sizes = {
661 {3, 3}, {6, 6}, {8, 8}, {10, 10},
662 {20, 20}, {6, 200}, {200, 6} };
664 for (
auto sz : sizes) {
665 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
667 std::ostringstream oss;
668 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
") - Naive code";
670 BENCHMARK(oss.str().c_str())
672 AAt_true = AAt_regular(A);
678 BENCHMARK(oss.str().c_str())
683 REQUIRE(equalMatrix(AAt, AAt_true));
685 if (runBenchmarkAll) {
686 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
687 cv::Mat matA(sz.first, sz.second, CV_64FC1);
689 for (
unsigned int i = 0; i < A.
getRows(); i++) {
690 for (
unsigned int j = 0; j < A.
getCols(); j++) {
691 matA.at<
double>(i, j) = A[i][j];
696 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
") - OpenCV";
697 BENCHMARK(oss.str().c_str())
699 cv::Mat matAAt = matA * matA.t();
704 #ifdef VISP_HAVE_EIGEN3
705 Eigen::MatrixXd eigenA(sz.first, sz.second);
707 for (
unsigned int i = 0; i < A.
getRows(); i++) {
708 for (
unsigned int j = 0; j < A.
getCols(); j++) {
709 eigenA(i, j) = A[i][j];
714 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
") - Eigen";
715 BENCHMARK(oss.str().c_str())
717 Eigen::MatrixXd eigenAAt = eigenA * eigenA.
transpose();
726 const unsigned int rows = 47, cols = 63;
727 vpMatrix A = generateRandomMatrix(rows, cols);
731 REQUIRE(equalMatrix(AAt, AAt_true));
735 TEST_CASE(
"Benchmark matrix-velocity twist multiplication",
"[benchmark]")
737 if (runBenchmark || runBenchmarkAll) {
738 std::vector<std::pair<int, int> > sizes = { {6, 6}, {20, 6}, {207, 6}, {600, 6}, {1201, 6} };
740 for (
auto sz : sizes) {
741 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
744 std::ostringstream oss;
745 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
")x(6x6) - Naive code";
747 BENCHMARK(oss.str().c_str())
749 AV_true = dgemm_regular(A,
static_cast<vpMatrix>(V));
754 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
")x(6x6) - ViSP";
755 BENCHMARK(oss.str().c_str())
760 REQUIRE(equalMatrix(AV, AV_true));
762 if (runBenchmarkAll) {
763 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
764 cv::Mat matA(sz.first, sz.second, CV_64FC1);
765 cv::Mat matV(6, 6, CV_64FC1);
767 for (
unsigned int i = 0; i < A.
getRows(); i++) {
768 for (
unsigned int j = 0; j < A.
getCols(); j++) {
769 matA.at<
double>(i, j) = A[i][j];
772 for (
unsigned int i = 0; i < V.getRows(); i++) {
773 for (
unsigned int j = 0; j < V.getCols(); j++) {
774 matV.at<
double>(i, j) = V[i][j];
779 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(6x6) - OpenCV";
780 BENCHMARK(oss.str().c_str())
782 cv::Mat matAV = matA * matV;
787 #ifdef VISP_HAVE_EIGEN3
788 Eigen::MatrixXd eigenA(sz.first, sz.second);
789 Eigen::MatrixXd eigenV(6, 6);
791 for (
unsigned int i = 0; i < A.
getRows(); i++) {
792 for (
unsigned int j = 0; j < A.
getCols(); j++) {
793 eigenA(i, j) = A[i][j];
796 for (
unsigned int i = 0; i < V.getRows(); i++) {
797 for (
unsigned int j = 0; j < V.getCols(); j++) {
798 eigenV(i, j) = V[i][j];
803 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(6x6) - Eigen";
804 BENCHMARK(oss.str().c_str())
806 Eigen::MatrixXd eigenAV = eigenA * eigenV;
815 const unsigned int rows = 47, cols = 6;
816 vpMatrix A = generateRandomMatrix(rows, cols);
821 REQUIRE(equalMatrix(AV, AV_true));
825 TEST_CASE(
"Benchmark matrix-force twist multiplication",
"[benchmark]")
827 if (runBenchmark || runBenchmarkAll) {
828 std::vector<std::pair<int, int> > sizes = { {6, 6}, {20, 6}, {207, 6}, {600, 6}, {1201, 6} };
830 for (
auto sz : sizes) {
831 vpMatrix A = generateRandomMatrix(sz.first, sz.second);
834 std::ostringstream oss;
835 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
")x(6x6) - Naive code";
837 BENCHMARK(oss.str().c_str())
839 AV_true = dgemm_regular(A,
static_cast<vpMatrix>(V));
844 oss <<
"(" << A.
getRows() <<
"x" << A.
getCols() <<
")x(6x6) - ViSP";
845 BENCHMARK(oss.str().c_str())
850 REQUIRE(equalMatrix(AV, AV_true));
852 if (runBenchmarkAll) {
853 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
854 cv::Mat matA(sz.first, sz.second, CV_64FC1);
855 cv::Mat matV(6, 6, CV_64FC1);
857 for (
unsigned int i = 0; i < A.
getRows(); i++) {
858 for (
unsigned int j = 0; j < A.
getCols(); j++) {
859 matA.at<
double>(i, j) = A[i][j];
862 for (
unsigned int i = 0; i < V.getRows(); i++) {
863 for (
unsigned int j = 0; j < V.getCols(); j++) {
864 matV.at<
double>(i, j) = V[i][j];
869 oss <<
"(" << matA.rows <<
"x" << matA.cols <<
")x(6x6) - OpenCV";
870 BENCHMARK(oss.str().c_str())
872 cv::Mat matAV = matA * matV;
877 #ifdef VISP_HAVE_EIGEN3
878 Eigen::MatrixXd eigenA(sz.first, sz.second);
879 Eigen::MatrixXd eigenV(6, 6);
881 for (
unsigned int i = 0; i < A.
getRows(); i++) {
882 for (
unsigned int j = 0; j < A.
getCols(); j++) {
883 eigenA(i, j) = A[i][j];
886 for (
unsigned int i = 0; i < V.getRows(); i++) {
887 for (
unsigned int j = 0; j < V.getCols(); j++) {
888 eigenV(i, j) = V[i][j];
893 oss <<
"(" << eigenA.rows() <<
"x" << eigenA.cols() <<
")x(6x6) - Eigen";
894 BENCHMARK(oss.str().c_str())
896 Eigen::MatrixXd eigenAV = eigenA * eigenV;
905 const unsigned int rows = 47, cols = 6;
906 vpMatrix A = generateRandomMatrix(rows, cols);
911 REQUIRE(equalMatrix(AV, AV_true));
915 int main(
int argc,
char *argv[])
922 Catch::Session session;
925 std::cout <<
"Default matrix/vector min size to enable Blas/Lapack optimization: " << lapackMinSize << std::endl;
927 auto cli = session.cli()
928 | Catch::Clara::Opt(runBenchmark)[
"--benchmark"](
"run benchmark comparing naive code with ViSP implementation")
929 | Catch::Clara::Opt(runBenchmarkAll)[
"--benchmark-all"](
"run benchmark comparing naive code with ViSP, OpenCV, Eigen implementation")
930 | Catch::Clara::Opt(lapackMinSize,
"min size")[
"--lapack-min-size"](
"matrix/vector min size to enable blas/lapack usage");
933 session.applyCommandLine(argc, argv);
939 int numFailed = session.run();
946 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.
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.