Visual Servoing Platform  version 3.6.1 under development (2024-10-18)
vpMatrix_operators.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Stack matrix.
32  */
33 
34 #include <visp3/core/vpConfig.h>
35 #include <visp3/core/vpMatrix.h>
36 
37 #if defined(VISP_HAVE_SIMDLIB)
38 #include <Simd/SimdLib.h>
39 #endif
40 
41 BEGIN_VISP_NAMESPACE
42 
60 {
61  resize(A.getRows(), A.getCols(), false, false);
62 
63  if ((data != nullptr) && (A.data != nullptr) && (data != A.data)) {
64  memcpy(data, A.data, dsize * sizeof(double));
65  }
66 
67  return *this;
68 }
69 
83 {
84  resize(M.getRows(), M.getCols(), false, false);
85 
86  if ((data != nullptr) && (M.data != nullptr) && (data != M.data)) {
87  memcpy(data, M.data, dsize * sizeof(double));
88  }
89 
90  return *this;
91 }
92 
106 {
107  resize(R.getRows(), R.getCols(), false, false);
108 
109  if ((data != nullptr) && (R.data != nullptr) && (data != R.data)) {
110  memcpy(data, R.data, dsize * sizeof(double));
111  }
112 
113  return *this;
114 }
115 
129 {
130  resize(V.getRows(), V.getCols(), false, false);
131 
132  if ((data != nullptr) && (V.data != nullptr) && (data != V.data)) {
133  memcpy(data, V.data, dsize * sizeof(double));
134  }
135 
136  return *this;
137 }
138 
152 {
153  resize(F.getRows(), F.getCols(), false, false);
154 
155  if ((data != nullptr) && (F.data != nullptr) && (data != F.data)) {
156  memcpy(data, F.data, dsize * sizeof(double));
157  }
158 
159  return *this;
160 }
161 
175 {
176  resize(v.getRows(), v.getCols(), false, false);
177 
178  if ((data != nullptr) && (v.data != nullptr) && (data != v.data)) {
179  memcpy(data, v.data, dsize * sizeof(double));
180  }
181 
182  return *this;
183 }
184 
198 {
199  resize(v.getRows(), v.getCols(), false, false);
200 
201  if ((data != nullptr) && (v.data != nullptr) && (data != v.data)) {
202  memcpy(data, v.data, dsize * sizeof(double));
203  }
204 
205  return *this;
206 }
207 
221 {
222  resize(t.getRows(), t.getCols(), false, false);
223 
224  if ((data != nullptr) && (t.data != nullptr) && (data != t.data)) {
225  memcpy(data, t.data, dsize * sizeof(double));
226  }
227 
228  return *this;
229 }
230 
232 {
233  resize(A.getRows(), A.getCols(), false, false);
234 
235  if ((data != nullptr) && (A.data != nullptr) && (data != A.data)) {
236  memcpy(data, A.data, dsize * sizeof(double));
237  }
238 
239  return *this;
240 }
241 
242 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
244 {
245  if (this != &other) {
246  if (data) {
247  free(data);
248  }
249  if (rowPtrs) {
250  free(rowPtrs);
251  }
252 
253  rowNum = other.rowNum;
254  colNum = other.colNum;
255  rowPtrs = other.rowPtrs;
256  dsize = other.dsize;
257  data = other.data;
258 
259  other.rowNum = 0;
260  other.colNum = 0;
261  other.rowPtrs = nullptr;
262  other.dsize = 0;
263  other.data = nullptr;
264  }
265 
266  return *this;
267 }
268 
299 vpMatrix &vpMatrix::operator=(const std::initializer_list<double> &list)
300 {
301  if (dsize != static_cast<unsigned int>(list.size())) {
302  resize(1, static_cast<unsigned int>(list.size()), false, false);
303  }
304 
305  std::copy(list.begin(), list.end(), data);
306 
307  return *this;
308 }
309 
337 vpMatrix &vpMatrix::operator=(const std::initializer_list<std::initializer_list<double> > &lists)
338 {
339  unsigned int nrows = static_cast<unsigned int>(lists.size()), ncols = 0;
340  for (auto &l : lists) {
341  if (static_cast<unsigned int>(l.size()) > ncols) {
342  ncols = static_cast<unsigned int>(l.size());
343  }
344  }
345 
346  resize(nrows, ncols, false, false);
347  auto it = lists.begin();
348  for (unsigned int i = 0; i < rowNum; ++i, ++it) {
349  std::copy(it->begin(), it->end(), rowPtrs[i]);
350  }
351 
352  return *this;
353 }
354 #endif
355 
358 {
359  std::fill(data, data + (rowNum * colNum), x);
360  return *this;
361 }
362 
369 {
370  for (unsigned int i = 0; i < rowNum; ++i) {
371  for (unsigned int j = 0; j < colNum; ++j) {
372  rowPtrs[i][j] = *x++;
373  }
374  }
375  return *this;
376 }
377 
379 {
380  resize(1, 1, false, false);
381  rowPtrs[0][0] = val;
382  return *this;
383 }
384 
386 {
387  resize(1, colNum + 1, false, false);
388  rowPtrs[0][colNum - 1] = val;
389  return *this;
390 }
391 
397 {
398  vpTranslationVector t_out;
399 
400  if ((rowNum != 3) || (colNum != 3)) {
401  throw(vpException(vpException::dimensionError, "Cannot multiply a (%dx%d) matrix by a (%dx%d) translation vector",
402  rowNum, colNum, tv.getRows(), tv.getCols()));
403  }
404 
405  const unsigned int val_3 = 3;
406  for (unsigned int j = 0; j < val_3; ++j) {
407  t_out[j] = 0;
408  }
409 
410  for (unsigned int j = 0; j < val_3; ++j) {
411  double tj = tv[j]; // optimization em 5/12/2006
412  for (unsigned int i = 0; i < val_3; ++i) {
413  t_out[i] += rowPtrs[i][j] * tj;
414  }
415  }
416  return t_out;
417 }
418 
424 {
425  vpColVector v_out;
426  vpMatrix::multMatrixVector(*this, v, v_out);
427  return v_out;
428 }
429 
435 {
436  vpMatrix C;
437 
438  vpMatrix::mult2Matrices(*this, B, C);
439 
440  return C;
441 }
442 
448 {
449  if (colNum != R.getRows()) {
450  throw(vpException(vpException::dimensionError, "Cannot multiply (%dx%d) matrix by (3x3) rotation matrix", rowNum,
451  colNum));
452  }
453  vpMatrix C;
454  C.resize(rowNum, 3, false, false);
455 
456  unsigned int RcolNum = R.getCols();
457  unsigned int RrowNum = R.getRows();
458  for (unsigned int i = 0; i < rowNum; ++i) {
459  double *rowptri = rowPtrs[i];
460  double *ci = C[i];
461  for (unsigned int j = 0; j < RcolNum; ++j) {
462  double s = 0;
463  for (unsigned int k = 0; k < RrowNum; ++k) {
464  s += rowptri[k] * R[k][j];
465  }
466  ci[j] = s;
467  }
468  }
469 
470  return C;
471 }
472 
478 {
479  if (colNum != M.getRows()) {
480  throw(vpException(vpException::dimensionError, "Cannot multiply (%dx%d) matrix by (3x3) rotation matrix", rowNum,
481  colNum));
482  }
483  vpMatrix C;
484  C.resize(rowNum, 4, false, false);
485 
486  const unsigned int McolNum = M.getCols();
487  const unsigned int MrowNum = M.getRows();
488  for (unsigned int i = 0; i < rowNum; ++i) {
489  const double *rowptri = rowPtrs[i];
490  double *ci = C[i];
491  for (unsigned int j = 0; j < McolNum; ++j) {
492  double s = 0;
493  for (unsigned int k = 0; k < MrowNum; ++k) {
494  s += rowptri[k] * M[k][j];
495  }
496  ci[j] = s;
497  }
498  }
499 
500  return C;
501 }
502 
503 
509 {
510  if (colNum != V.getRows()) {
511  throw(vpException(vpException::dimensionError, "Cannot multiply (%dx%d) matrix by (6x6) velocity twist matrix",
512  rowNum, colNum));
513  }
514  vpMatrix M;
515  M.resize(rowNum, 6, false, false);
516 
517  // Considering perfMatrixMultiplication.cpp benchmark,
518  // using either MKL, OpenBLAS, or Netlib can slow down this function with respect to the naive code.
519  // Lapack usage needs to be validated again.
520  // If available use Lapack only for large matrices.
521  // Speed up obtained using SSE2.
522  bool useLapack = ((rowNum > vpMatrix::m_lapack_min_size) || (colNum > vpMatrix::m_lapack_min_size) ||
523  (V.colNum > vpMatrix::m_lapack_min_size));
524 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
525  useLapack = false;
526 #endif
527 
528  if (useLapack) {
529 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
530  const double alpha = 1.0;
531  const double beta = 0.0;
532  const char trans = 'n';
533  vpMatrix::blas_dgemm(trans, trans, V.colNum, rowNum, colNum, alpha, V.data, V.colNum, data, colNum, beta, M.data,
534  M.colNum);
535 #endif
536  }
537  else {
538 #if defined(VISP_HAVE_SIMDLIB)
539  SimdMatMulTwist(data, rowNum, V.data, M.data);
540 #else
541  unsigned int VcolNum = V.getCols();
542  unsigned int VrowNum = V.getRows();
543  for (unsigned int i = 0; i < rowNum; ++i) {
544  double *rowptri = rowPtrs[i];
545  double *ci = M[i];
546  for (unsigned int j = 0; j < VcolNum; ++j) {
547  double s = 0;
548  for (unsigned int k = 0; k < VrowNum; ++k) {
549  s += rowptri[k] * V[k][j];
550  }
551  ci[j] = s;
552  }
553  }
554 #endif
555  }
556 
557  return M;
558 }
559 
565 {
566  if (colNum != V.getRows()) {
567  throw(vpException(vpException::dimensionError, "Cannot multiply (%dx%d) matrix by (6x6) force/torque twist matrix",
568  rowNum, colNum));
569  }
570  vpMatrix M;
571  M.resize(rowNum, 6, false, false);
572 
573  // Considering perfMatrixMultiplication.cpp benchmark,
574  // using either MKL, OpenBLAS, or Netlib can slow down this function with respect to the naive code.
575  // Lapack usage needs to be validated again.
576  // If available use Lapack only for large matrices.
577  // Speed up obtained using SSE2.
578  bool useLapack = ((rowNum > vpMatrix::m_lapack_min_size) || (colNum > vpMatrix::m_lapack_min_size) ||
579  (V.getCols() > vpMatrix::m_lapack_min_size));
580 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
581  useLapack = false;
582 #endif
583 
584  if (useLapack) {
585 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
586  const double alpha = 1.0;
587  const double beta = 0.0;
588  const char trans = 'n';
589  vpMatrix::blas_dgemm(trans, trans, V.getCols(), rowNum, colNum, alpha, V.data, V.getCols(), data, colNum, beta,
590  M.data, M.colNum);
591 #endif
592  }
593  else {
594 #if defined(VISP_HAVE_SIMDLIB)
595  SimdMatMulTwist(data, rowNum, V.data, M.data);
596 #else
597  unsigned int VcolNum = V.getCols();
598  unsigned int VrowNum = V.getRows();
599  for (unsigned int i = 0; i < rowNum; ++i) {
600  double *rowptri = rowPtrs[i];
601  double *ci = M[i];
602  for (unsigned int j = 0; j < VcolNum; ++j) {
603  double s = 0;
604  for (unsigned int k = 0; k < VrowNum; ++k) {
605  s += rowptri[k] * V[k][j];
606  }
607  ci[j] = s;
608  }
609  }
610 #endif
611  }
612 
613  return M;
614 }
615 
621 {
622  vpMatrix C;
623  vpMatrix::add2Matrices(*this, B, C);
624  return C;
625 }
626 
632 {
633  vpMatrix C;
634  vpMatrix::sub2Matrices(*this, B, C);
635  return C;
636 }
637 
639 
641 {
642  if ((colNum != B.getCols()) || (rowNum != B.getRows())) {
643  throw(vpException(vpException::dimensionError, "Cannot add (%dx%d) matrix to (%dx%d) matrix", rowNum, colNum,
644  B.getRows(), B.getCols()));
645  }
646 
647  double **BrowPtrs = B.rowPtrs;
648 
649  for (unsigned int i = 0; i < rowNum; ++i) {
650  for (unsigned int j = 0; j < colNum; ++j) {
651  rowPtrs[i][j] += BrowPtrs[i][j];
652  }
653  }
654 
655  return *this;
656 }
657 
660 {
661  if ((colNum != B.getCols()) || (rowNum != B.getRows())) {
662  throw(vpException(vpException::dimensionError, "Cannot subtract (%dx%d) matrix to (%dx%d) matrix", rowNum, colNum,
663  B.getRows(), B.getCols()));
664  }
665 
666  double **BrowPtrs = B.rowPtrs;
667  for (unsigned int i = 0; i < rowNum; ++i) {
668  for (unsigned int j = 0; j < colNum; ++j) {
669  rowPtrs[i][j] -= BrowPtrs[i][j];
670  }
671  }
672 
673  return *this;
674 }
675 
680 vpMatrix vpMatrix::operator-() const // negate
681 {
682  vpMatrix C;
683  vpMatrix::negateMatrix(*this, C);
684  return C;
685 }
686 
687 double vpMatrix::sum() const
688 {
689  double s = 0.0;
690  for (unsigned int i = 0; i < rowNum; ++i) {
691  for (unsigned int j = 0; j < colNum; ++j) {
692  s += rowPtrs[i][j];
693  }
694  }
695 
696  return s;
697 }
698 
704 {
705  if (std::fabs(x - 1.) < std::numeric_limits<double>::epsilon()) {
706  return *this;
707  }
708 
709  vpMatrix M;
710  M.resize(rowNum, colNum, false, false);
711 
712  for (unsigned int i = 0; i < rowNum; ++i) {
713  for (unsigned int j = 0; j < colNum; ++j) {
714  M[i][j] = rowPtrs[i][j] * x;
715  }
716  }
717 
718  return M;
719 }
720 
721 
724 {
725  if (std::fabs(x - 1.) < std::numeric_limits<double>::epsilon()) {
726  return *this;
727  }
728 
729  if (std::fabs(x) < std::numeric_limits<double>::epsilon()) {
730  throw vpException(vpException::divideByZeroError, "Divide matrix by zero scalar");
731  }
732 
733  vpMatrix C;
734  C.resize(rowNum, colNum, false, false);
735 
736  double xinv = 1 / x;
737 
738  for (unsigned int i = 0; i < rowNum; ++i) {
739  for (unsigned int j = 0; j < colNum; ++j) {
740  C[i][j] = rowPtrs[i][j] * xinv;
741  }
742  }
743 
744  return C;
745 }
746 
749 {
750  for (unsigned int i = 0; i < rowNum; ++i) {
751  for (unsigned int j = 0; j < colNum; ++j) {
752  rowPtrs[i][j] += x;
753  }
754  }
755 
756  return *this;
757 }
758 
761 {
762  for (unsigned int i = 0; i < rowNum; ++i) {
763  for (unsigned int j = 0; j < colNum; ++j) {
764  rowPtrs[i][j] -= x;
765  }
766  }
767 
768  return *this;
769 }
770 
776 {
777  if (std::fabs(x - 1.) < std::numeric_limits<double>::epsilon()) {
778  return *this;
779  }
780 
781  for (unsigned int i = 0; i < rowNum; ++i) {
782  for (unsigned int j = 0; j < colNum; ++j) {
783  rowPtrs[i][j] *= x;
784  }
785  }
786 
787  return *this;
788 }
789 
792 {
793  if (std::fabs(x - 1.) < std::numeric_limits<double>::epsilon()) {
794  return *this;
795  }
796 
797  if (std::fabs(x) < std::numeric_limits<double>::epsilon()) {
798  throw vpException(vpException::divideByZeroError, "Divide matrix by zero scalar");
799  }
800 
801  double xinv = 1 / x;
802 
803  for (unsigned int i = 0; i < rowNum; ++i) {
804  for (unsigned int j = 0; j < colNum; ++j) {
805  rowPtrs[i][j] *= xinv;
806  }
807  }
808 
809  return *this;
810 }
811 
816 vpMatrix operator*(const double &x, const vpMatrix &B)
817 {
818  if (std::fabs(x - 1.) < std::numeric_limits<double>::epsilon()) {
819  return B;
820  }
821 
822  unsigned int Brow = B.getRows();
823  unsigned int Bcol = B.getCols();
824 
825  VISP_NAMESPACE_ADDRESSING vpMatrix C;
826  C.resize(Brow, Bcol, false, false);
827 
828  for (unsigned int i = 0; i < Brow; ++i) {
829  for (unsigned int j = 0; j < Bcol; ++j) {
830  C[i][j] = B[i][j] * x;
831  }
832  }
833 
834  return C;
835 }
836 
837 END_VISP_NAMESPACE
unsigned int getCols() const
Definition: vpArray2D.h:337
double * data
Address of the first element of the data array.
Definition: vpArray2D.h:148
double ** rowPtrs
Address of the first element of each rows.
Definition: vpArray2D.h:1102
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition: vpArray2D.h:362
unsigned int rowNum
Number of rows in the array.
Definition: vpArray2D.h:1098
unsigned int dsize
Current array size (rowNum * colNum)
Definition: vpArray2D.h:1104
unsigned int getRows() const
Definition: vpArray2D.h:347
unsigned int colNum
Number of columns in the array.
Definition: vpArray2D.h:1100
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ dimensionError
Bad dimension.
Definition: vpException.h:71
@ divideByZeroError
Division by zero.
Definition: vpException.h:70
Implementation of an homogeneous matrix and operations on such kind of matrices.
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:169
vpMatrix operator-() const
vpMatrix & operator/=(double x)
Divide all the element of the matrix by x : Aij = Aij / x.
vpMatrix operator*(const vpMatrix &B) const
vpMatrix operator/(double x) const
Cij = Aij / x (A is unchanged)
vpMatrix & operator-=(const vpMatrix &B)
Operation A = A - B.
vpMatrix & operator*=(double x)
Multiply all the element of the matrix by x : Aij = Aij * x.
vpMatrix operator*(const double &x, const vpMatrix &B)
vpMatrix & operator<<(double *p)
static void sub2Matrices(const vpMatrix &A, const vpMatrix &B, vpMatrix &C)
vpMatrix operator+(const vpMatrix &B) const
double sum() const
vpMatrix & operator+=(const vpMatrix &B)
Operation A = A + B.
vpMatrix & operator,(double val)
static void multMatrixVector(const vpMatrix &A, const vpColVector &v, vpColVector &w)
vpMatrix & operator=(const vpArray2D< double > &A)
static void add2Matrices(const vpMatrix &A, const vpMatrix &B, vpMatrix &C)
static void mult2Matrices(const vpMatrix &A, const vpMatrix &B, vpMatrix &C)
static void negateMatrix(const vpMatrix &A, vpMatrix &C)
vpMatrix t() const
Implementation of a rotation matrix and operations on such kind of matrices.
Implementation of row vector and the associated operations.
Definition: vpRowVector.h:124
Class that consider the case of a translation vector.