Visual Servoing Platform  version 3.6.1 under development (2024-12-17)
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  const unsigned int val_3 = 3;
401  if ((rowNum != val_3) || (colNum != val_3)) {
402  throw(vpException(vpException::dimensionError, "Cannot multiply a (%dx%d) matrix by a (%dx%d) translation vector",
403  rowNum, colNum, tv.getRows(), tv.getCols()));
404  }
405 
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  const unsigned int val_3 = 3;
455  C.resize(rowNum, val_3, false, false);
456 
457  unsigned int RcolNum = R.getCols();
458  unsigned int RrowNum = R.getRows();
459  for (unsigned int i = 0; i < rowNum; ++i) {
460  double *rowptri = rowPtrs[i];
461  double *ci = C[i];
462  for (unsigned int j = 0; j < RcolNum; ++j) {
463  double s = 0;
464  for (unsigned int k = 0; k < RrowNum; ++k) {
465  s += rowptri[k] * R[k][j];
466  }
467  ci[j] = s;
468  }
469  }
470 
471  return C;
472 }
473 
479 {
480  if (colNum != M.getRows()) {
481  throw(vpException(vpException::dimensionError, "Cannot multiply (%dx%d) matrix by (3x3) rotation matrix", rowNum,
482  colNum));
483  }
484  vpMatrix C;
485  const unsigned int val_4 = 4;
486  C.resize(rowNum, val_4, false, false);
487 
488  const unsigned int McolNum = M.getCols();
489  const unsigned int MrowNum = M.getRows();
490  for (unsigned int i = 0; i < rowNum; ++i) {
491  const double *rowptri = rowPtrs[i];
492  double *ci = C[i];
493  for (unsigned int j = 0; j < McolNum; ++j) {
494  double s = 0;
495  for (unsigned int k = 0; k < MrowNum; ++k) {
496  s += rowptri[k] * M[k][j];
497  }
498  ci[j] = s;
499  }
500  }
501 
502  return C;
503 }
504 
505 
511 {
512  if (colNum != V.getRows()) {
513  throw(vpException(vpException::dimensionError, "Cannot multiply (%dx%d) matrix by (6x6) velocity twist matrix",
514  rowNum, colNum));
515  }
516  vpMatrix M;
517  const unsigned int val_6 = 6;
518  M.resize(rowNum, val_6, false, false);
519 
520  // Considering perfMatrixMultiplication.cpp benchmark,
521  // using either MKL, OpenBLAS, or Netlib can slow down this function with respect to the naive code.
522  // Lapack usage needs to be validated again.
523  // If available use Lapack only for large matrices.
524  // Speed up obtained using SSE2.
525  bool useLapack = ((rowNum > vpMatrix::m_lapack_min_size) || (colNum > vpMatrix::m_lapack_min_size) ||
526  (V.colNum > vpMatrix::m_lapack_min_size));
527 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
528  useLapack = false;
529 #endif
530 
531  if (useLapack) {
532 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
533  const double alpha = 1.0;
534  const double beta = 0.0;
535  const char trans = 'n';
536  vpMatrix::blas_dgemm(trans, trans, V.colNum, rowNum, colNum, alpha, V.data, V.colNum, data, colNum, beta, M.data,
537  M.colNum);
538 #endif
539  }
540  else {
541 #if defined(VISP_HAVE_SIMDLIB)
542  SimdMatMulTwist(data, rowNum, V.data, M.data);
543 #else
544  unsigned int VcolNum = V.getCols();
545  unsigned int VrowNum = V.getRows();
546  for (unsigned int i = 0; i < rowNum; ++i) {
547  double *rowptri = rowPtrs[i];
548  double *ci = M[i];
549  for (unsigned int j = 0; j < VcolNum; ++j) {
550  double s = 0;
551  for (unsigned int k = 0; k < VrowNum; ++k) {
552  s += rowptri[k] * V[k][j];
553  }
554  ci[j] = s;
555  }
556  }
557 #endif
558  }
559 
560  return M;
561 }
562 
568 {
569  if (colNum != V.getRows()) {
570  throw(vpException(vpException::dimensionError, "Cannot multiply (%dx%d) matrix by (6x6) force/torque twist matrix",
571  rowNum, colNum));
572  }
573  vpMatrix M;
574  const unsigned int val_6 = 6;
575  M.resize(rowNum, val_6, false, false);
576 
577  // Considering perfMatrixMultiplication.cpp benchmark,
578  // using either MKL, OpenBLAS, or Netlib can slow down this function with respect to the naive code.
579  // Lapack usage needs to be validated again.
580  // If available use Lapack only for large matrices.
581  // Speed up obtained using SSE2.
582  bool useLapack = ((rowNum > vpMatrix::m_lapack_min_size) || (colNum > vpMatrix::m_lapack_min_size) ||
583  (V.getCols() > vpMatrix::m_lapack_min_size));
584 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
585  useLapack = false;
586 #endif
587 
588  if (useLapack) {
589 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
590  const double alpha = 1.0;
591  const double beta = 0.0;
592  const char trans = 'n';
593  vpMatrix::blas_dgemm(trans, trans, V.getCols(), rowNum, colNum, alpha, V.data, V.getCols(), data, colNum, beta,
594  M.data, M.colNum);
595 #endif
596  }
597  else {
598 #if defined(VISP_HAVE_SIMDLIB)
599  SimdMatMulTwist(data, rowNum, V.data, M.data);
600 #else
601  unsigned int VcolNum = V.getCols();
602  unsigned int VrowNum = V.getRows();
603  for (unsigned int i = 0; i < rowNum; ++i) {
604  double *rowptri = rowPtrs[i];
605  double *ci = M[i];
606  for (unsigned int j = 0; j < VcolNum; ++j) {
607  double s = 0;
608  for (unsigned int k = 0; k < VrowNum; ++k) {
609  s += rowptri[k] * V[k][j];
610  }
611  ci[j] = s;
612  }
613  }
614 #endif
615  }
616 
617  return M;
618 }
619 
625 {
626  vpMatrix C;
627  vpMatrix::add2Matrices(*this, B, C);
628  return C;
629 }
630 
636 {
637  vpMatrix C;
638  vpMatrix::sub2Matrices(*this, B, C);
639  return C;
640 }
641 
643 
645 {
646  if ((colNum != B.getCols()) || (rowNum != B.getRows())) {
647  throw(vpException(vpException::dimensionError, "Cannot add (%dx%d) matrix to (%dx%d) matrix", rowNum, colNum,
648  B.getRows(), B.getCols()));
649  }
650 
651  double **BrowPtrs = B.rowPtrs;
652 
653  for (unsigned int i = 0; i < rowNum; ++i) {
654  for (unsigned int j = 0; j < colNum; ++j) {
655  rowPtrs[i][j] += BrowPtrs[i][j];
656  }
657  }
658 
659  return *this;
660 }
661 
664 {
665  if ((colNum != B.getCols()) || (rowNum != B.getRows())) {
666  throw(vpException(vpException::dimensionError, "Cannot subtract (%dx%d) matrix to (%dx%d) matrix", rowNum, colNum,
667  B.getRows(), B.getCols()));
668  }
669 
670  double **BrowPtrs = B.rowPtrs;
671  for (unsigned int i = 0; i < rowNum; ++i) {
672  for (unsigned int j = 0; j < colNum; ++j) {
673  rowPtrs[i][j] -= BrowPtrs[i][j];
674  }
675  }
676 
677  return *this;
678 }
679 
684 vpMatrix vpMatrix::operator-() const // negate
685 {
686  vpMatrix C;
687  vpMatrix::negateMatrix(*this, C);
688  return C;
689 }
690 
691 double vpMatrix::sum() const
692 {
693  double s = 0.0;
694  for (unsigned int i = 0; i < rowNum; ++i) {
695  for (unsigned int j = 0; j < colNum; ++j) {
696  s += rowPtrs[i][j];
697  }
698  }
699 
700  return s;
701 }
702 
708 {
709  if (std::fabs(x - 1.) < std::numeric_limits<double>::epsilon()) {
710  return *this;
711  }
712 
713  vpMatrix M;
714  M.resize(rowNum, colNum, false, false);
715 
716  for (unsigned int i = 0; i < rowNum; ++i) {
717  for (unsigned int j = 0; j < colNum; ++j) {
718  M[i][j] = rowPtrs[i][j] * x;
719  }
720  }
721 
722  return M;
723 }
724 
725 
728 {
729  if (std::fabs(x - 1.) < std::numeric_limits<double>::epsilon()) {
730  return *this;
731  }
732 
733  if (std::fabs(x) < std::numeric_limits<double>::epsilon()) {
734  throw vpException(vpException::divideByZeroError, "Divide matrix by zero scalar");
735  }
736 
737  vpMatrix C;
738  C.resize(rowNum, colNum, false, false);
739 
740  double xinv = 1 / x;
741 
742  for (unsigned int i = 0; i < rowNum; ++i) {
743  for (unsigned int j = 0; j < colNum; ++j) {
744  C[i][j] = rowPtrs[i][j] * xinv;
745  }
746  }
747 
748  return C;
749 }
750 
753 {
754  for (unsigned int i = 0; i < rowNum; ++i) {
755  for (unsigned int j = 0; j < colNum; ++j) {
756  rowPtrs[i][j] += x;
757  }
758  }
759 
760  return *this;
761 }
762 
765 {
766  for (unsigned int i = 0; i < rowNum; ++i) {
767  for (unsigned int j = 0; j < colNum; ++j) {
768  rowPtrs[i][j] -= x;
769  }
770  }
771 
772  return *this;
773 }
774 
780 {
781  if (std::fabs(x - 1.) < std::numeric_limits<double>::epsilon()) {
782  return *this;
783  }
784 
785  for (unsigned int i = 0; i < rowNum; ++i) {
786  for (unsigned int j = 0; j < colNum; ++j) {
787  rowPtrs[i][j] *= x;
788  }
789  }
790 
791  return *this;
792 }
793 
796 {
797  if (std::fabs(x - 1.) < std::numeric_limits<double>::epsilon()) {
798  return *this;
799  }
800 
801  if (std::fabs(x) < std::numeric_limits<double>::epsilon()) {
802  throw vpException(vpException::divideByZeroError, "Divide matrix by zero scalar");
803  }
804 
805  double xinv = 1 / x;
806 
807  for (unsigned int i = 0; i < rowNum; ++i) {
808  for (unsigned int j = 0; j < colNum; ++j) {
809  rowPtrs[i][j] *= xinv;
810  }
811  }
812 
813  return *this;
814 }
815 
820 vpMatrix operator*(const double &x, const vpMatrix &B)
821 {
822  if (std::fabs(x - 1.) < std::numeric_limits<double>::epsilon()) {
823  return B;
824  }
825 
826  unsigned int Brow = B.getRows();
827  unsigned int Bcol = B.getCols();
828 
829  VISP_NAMESPACE_ADDRESSING vpMatrix C;
830  C.resize(Brow, Bcol, false, false);
831 
832  for (unsigned int i = 0; i < Brow; ++i) {
833  for (unsigned int j = 0; j < Bcol; ++j) {
834  C[i][j] = B[i][j] * x;
835  }
836  }
837 
838  return C;
839 }
840 
841 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:1105
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:1101
unsigned int dsize
Current array size (rowNum * colNum)
Definition: vpArray2D.h:1107
unsigned int getRows() const
Definition: vpArray2D.h:347
unsigned int colNum
Number of columns in the array.
Definition: vpArray2D.h:1103
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.