Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpMatrix.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 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 * Matrix manipulation.
32 */
33
38
39#include <algorithm>
40#include <assert.h>
41#include <cmath> // std::fabs
42#include <fstream>
43#include <limits> // numeric_limits
44#include <sstream>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <string>
49#include <vector>
50
51#include <visp3/core/vpCPUFeatures.h>
52#include <visp3/core/vpColVector.h>
53#include <visp3/core/vpConfig.h>
54#include <visp3/core/vpException.h>
55#include <visp3/core/vpMath.h>
56#include <visp3/core/vpMatrix.h>
57#include <visp3/core/vpTranslationVector.h>
58
59#if defined(VISP_HAVE_SIMDLIB)
60#include <Simd/SimdLib.h>
61#endif
62
63#ifdef VISP_HAVE_LAPACK
64#ifdef VISP_HAVE_GSL
65#include <gsl/gsl_eigen.h>
66#include <gsl/gsl_linalg.h>
67#include <gsl/gsl_math.h>
68#elif defined(VISP_HAVE_MKL)
69#include <mkl.h>
70#endif
71#endif
72
74
75#ifdef VISP_HAVE_LAPACK
76#ifdef VISP_HAVE_GSL
77#elif defined(VISP_HAVE_MKL)
78typedef MKL_INT integer;
79
80void vpMatrix::blas_dsyev(char jobz, char uplo, unsigned int n_, double *a_data, unsigned int lda_, double *w_data,
81 double *work_data, int lwork_, int &info_)
82{
83 MKL_INT n = static_cast<MKL_INT>(n_);
84 MKL_INT lda = static_cast<MKL_INT>(lda_);
85 MKL_INT lwork = static_cast<MKL_INT>(lwork_);
86 MKL_INT info = static_cast<MKL_INT>(info_);
87
88 dsyev(&jobz, &uplo, &n, a_data, &lda, w_data, work_data, &lwork, &info);
89}
90
91#else
92#if defined(VISP_HAVE_LAPACK_BUILT_IN)
93typedef long int integer;
94#else
95typedef int integer;
96#endif
97extern "C" integer dsyev_(char *jobz, char *uplo, integer *n, double *a, integer *lda, double *w, double *WORK,
98 integer *lwork, integer *info);
99
100void vpMatrix::blas_dsyev(char jobz, char uplo, unsigned int n_, double *a_data, unsigned int lda_, double *w_data,
101 double *work_data, int lwork_, int &info_)
102{
103 integer n = static_cast<integer>(n_);
104 integer lda = static_cast<integer>(lda_);
105 integer lwork = static_cast<integer>(lwork_);
106 integer info = static_cast<integer>(info_);
107
108 dsyev_(&jobz, &uplo, &n, a_data, &lda, w_data, work_data, &lwork, &info);
109
110 lwork_ = static_cast<int>(lwork);
111 info_ = static_cast<int>(info);
112}
113#endif
114#endif
115
116#if !defined(VISP_USE_MSVC) || (defined(VISP_USE_MSVC) && !defined(VISP_BUILD_SHARED_LIBS))
117const unsigned int vpMatrix::m_lapack_min_size_default = 0;
118unsigned int vpMatrix::m_lapack_min_size = vpMatrix::m_lapack_min_size_default;
119#endif
120
121// Prototypes of specific functions
122vpMatrix subblock(const vpMatrix &M, unsigned int col, unsigned int row);
123
128vpMatrix::vpMatrix(const vpMatrix &M, unsigned int r, unsigned int c, unsigned int nrows, unsigned int ncols)
129 : vpArray2D<double>()
130{
131 if (((r + nrows) > M.rowNum) || ((c + ncols) > M.colNum)) {
132 throw(vpException(vpException::dimensionError,
133 "Cannot construct a sub matrix (%dx%d) starting at "
134 "position (%d,%d) that is not contained in the "
135 "original matrix (%dx%d)",
136 nrows, ncols, r, c, M.rowNum, M.colNum));
137 }
138
139 init(M, r, c, nrows, ncols);
140}
141
147{
148 *this = M;
149}
150
156{
157 *this = V;
158}
159
165{
166 *this = F;
167}
168
174{
175 *this = R;
176}
177
183{
184 *this = v;
185}
186
192{
193 *this = v;
194}
195
201{
202 *this = t;
203}
204
205#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
206vpMatrix::vpMatrix(vpMatrix &&A) : vpArray2D<double>(std::move(A))
207{ }
208
236vpMatrix::vpMatrix(const std::initializer_list<double> &list) : vpArray2D<double>(list) { }
237
265vpMatrix::vpMatrix(unsigned int nrows, unsigned int ncols, const std::initializer_list<double> &list)
266 : vpArray2D<double>(nrows, ncols, list)
267{ }
268
293vpMatrix::vpMatrix(const std::initializer_list<std::initializer_list<double> > &lists) : vpArray2D<double>(lists) { }
294#endif
295
307vpMatrix vpMatrix::view(double *raw_data, unsigned int rows, unsigned int cols)
308{
309 vpMatrix M;
310 vpArray2D<double>::view(M, raw_data, rows, cols);
311 return M;
312}
313
314void vpMatrix::view(vpMatrix &v, double *data, unsigned int rows, unsigned int cols)
315{
316 vpArray2D<double>::view(v, data, rows, cols);
317}
318
369void vpMatrix::init(const vpMatrix &M, unsigned int r, unsigned int c, unsigned int nrows, unsigned int ncols)
370{
371 unsigned int rnrows = r + nrows;
372 unsigned int cncols = c + ncols;
373
374 if (rnrows > M.getRows()) {
375 throw(vpException(vpException::dimensionError, "Bad row dimension (%d > %d) used to initialize vpMatrix", rnrows,
376 M.getRows()));
377 }
378 if (cncols > M.getCols()) {
379 throw(vpException(vpException::dimensionError, "Bad column dimension (%d > %d) used to initialize vpMatrix", cncols,
380 M.getCols()));
381 }
382 resize(nrows, ncols, false, false);
383
384 if (this->rowPtrs == nullptr) { // Fix coverity scan: explicit null dereferenced
385 return; // Noting to do
386 }
387 for (unsigned int i = 0; i < nrows; ++i) {
388 memcpy((*this)[i], &M[i + r][c], ncols * sizeof(double));
389 }
390}
391
436vpMatrix vpMatrix::extract(unsigned int r, unsigned int c, unsigned int nrows, unsigned int ncols) const
437{
438 unsigned int rnrows = r + nrows;
439 unsigned int cncols = c + ncols;
440
441 if (rnrows > getRows()) {
442 throw(vpException(vpException::dimensionError, "Bad row dimension (%d > %d) used to initialize vpMatrix", rnrows,
443 getRows()));
444 }
445 if (cncols > getCols()) {
446 throw(vpException(vpException::dimensionError, "Bad column dimension (%d > %d) used to initialize vpMatrix", cncols,
447 getCols()));
448 }
449
450 vpMatrix M;
451 M.resize(nrows, ncols, false, false);
452 for (unsigned int i = 0; i < nrows; ++i) {
453 memcpy(M[i], &(*this)[i + r][c], ncols * sizeof(double));
454 }
455
456 return M;
457}
458
504vpColVector vpMatrix::getCol(unsigned int j, unsigned int i_begin, unsigned int column_size) const
505{
506 if (((i_begin + column_size) > getRows()) || (j >= getCols())) {
507 throw(vpException(vpException::dimensionError, "Unable to extract column %u from the %ux%u matrix", j, getRows(),
508 getCols()));
509 }
510 vpColVector c(column_size);
511 for (unsigned int i = 0; i < column_size; ++i) {
512 c[i] = (*this)[i_begin + i][j];
513 }
514 return c;
515}
516
560vpColVector vpMatrix::getCol(unsigned int j) const { return getCol(j, 0, rowNum); }
561
602vpRowVector vpMatrix::getRow(unsigned int i) const { return getRow(i, 0, colNum); }
603
647vpRowVector vpMatrix::getRow(unsigned int i, unsigned int j_begin, unsigned int row_size) const
648{
649 if (((j_begin + row_size) > colNum) || (i >= rowNum)) {
650 throw(vpException(vpException::dimensionError, "Unable to extract a row vector from the matrix"));
651 }
652 vpRowVector r(row_size);
653 if ((r.data != nullptr) && (data != nullptr)) {
654 memcpy(r.data, (*this)[i] + j_begin, row_size * sizeof(double));
655 }
656
657 return r;
658}
659
700{
701 unsigned int min_size = std::min<unsigned int>(rowNum, colNum);
703
704 if (min_size > 0) {
705 diag.resize(min_size, false);
706
707 for (unsigned int i = 0; i < min_size; ++i) {
708 diag[i] = (*this)[i][i];
709 }
710 }
711
712 return diag;
713}
714
727vpMatrix vpMatrix::insert(const vpMatrix &A, const vpMatrix &B, unsigned int r, unsigned int c)
728{
730
731 vpArray2D<double>::insert(A, B, C, r, c);
732
733 return vpMatrix(C);
734}
735
749void vpMatrix::insert(const vpMatrix &A, const vpMatrix &B, vpMatrix &C, unsigned int r, unsigned int c)
750{
751 vpArray2D<double> C_array;
752
753 vpArray2D<double>::insert(A, B, C_array, r, c);
754
755 C = C_array;
756}
757
770{
771 vpMatrix C;
772
773 juxtaposeMatrices(A, B, C);
774
775 return C;
776}
777
791{
792 unsigned int nca = A.getCols();
793 unsigned int ncb = B.getCols();
794
795 if (nca != 0) {
796 if (A.getRows() != B.getRows()) {
797 throw(vpException(vpException::dimensionError, "Cannot juxtapose (%dx%d) matrix with (%dx%d) matrix", A.getRows(),
798 A.getCols(), B.getRows(), B.getCols()));
799 }
800 }
801
802 if ((B.getRows() == 0) || ((nca + ncb) == 0)) {
803 std::cerr << "B.getRows() == 0 || nca+ncb == 0" << std::endl;
804 return;
805 }
806
807 C.resize(B.getRows(), nca + ncb, false, false);
808
809 C.insert(A, 0, 0);
810 C.insert(B, 0, nca);
811}
812
813//--------------------------------------------------------------------
814// Output
815//--------------------------------------------------------------------
816
836int vpMatrix::print(std::ostream &s, unsigned int length, const std::string &intro) const
837{
838 typedef std::string::size_type size_type;
839
840 unsigned int m = getRows();
841 unsigned int n = getCols();
842
843 std::vector<std::string> values(m * n);
844 std::ostringstream oss;
845 std::ostringstream ossFixed;
846 std::ios_base::fmtflags original_flags = oss.flags();
847
848 ossFixed.setf(std::ios::fixed, std::ios::floatfield);
849
850 size_type maxBefore = 0; // the length of the integral part
851 size_type maxAfter = 0; // number of decimals plus
852 // one place for the decimal point
853 for (unsigned int i = 0; i < m; ++i) {
854 for (unsigned int j = 0; j < n; ++j) {
855 oss.str("");
856 oss << (*this)[i][j];
857 if (oss.str().find("e") != std::string::npos) {
858 ossFixed.str("");
859 ossFixed << (*this)[i][j];
860 oss.str(ossFixed.str());
861 }
862
863 values[(i * n) + j] = oss.str();
864 size_type thislen = values[(i * n) + j].size();
865 size_type p = values[(i * n) + j].find('.');
866
867 if (p == std::string::npos) {
868 maxBefore = vpMath::maximum(maxBefore, thislen);
869 // maxAfter remains the same
870 }
871 else {
872 maxBefore = vpMath::maximum(maxBefore, p);
873 maxAfter = vpMath::maximum(maxAfter, thislen - p);
874 }
875 }
876 }
877
878 size_type totalLength = length;
879 // increase totalLength according to maxBefore
880 totalLength = vpMath::maximum(totalLength, maxBefore);
881 // decrease maxAfter according to totalLength
882 maxAfter = std::min<size_type>(maxAfter, totalLength - maxBefore);
883
884 if (!intro.empty()) {
885 s << intro;
886 }
887 s << "[" << m << "," << n << "]=\n";
888
889 for (unsigned int i = 0; i < m; ++i) {
890 s << " ";
891 for (unsigned int j = 0; j < n; ++j) {
892 size_type p = values[(i * n) + j].find('.');
893 s.setf(std::ios::right, std::ios::adjustfield);
894 s.width(static_cast<std::streamsize>(maxBefore));
895 s << values[(i * n) + j].substr(0, p).c_str();
896
897 if (maxAfter > 0) {
898 s.setf(std::ios::left, std::ios::adjustfield);
899 if (p != std::string::npos) {
900 s.width(static_cast<std::streamsize>(maxAfter));
901 s << values[(i * n) + j].substr(p, maxAfter).c_str();
902 }
903 else {
904 s.width(static_cast<std::streamsize>(maxAfter));
905 s << ".0";
906 }
907 }
908
909 s << ' ';
910 }
911 s << std::endl;
912 }
913
914 s.flags(original_flags); // restore s to standard state
915
916 return static_cast<int>(maxBefore + maxAfter);
917}
918
959std::ostream &vpMatrix::matlabPrint(std::ostream &os) const
960{
961 unsigned int this_rows = this->getRows();
962 unsigned int this_col = this->getCols();
963 os << "[ ";
964 for (unsigned int i = 0; i < this_rows; ++i) {
965 for (unsigned int j = 0; j < this_col; ++j) {
966 os << (*this)[i][j] << ", ";
967 }
968 if (this->getRows() != (i + 1)) {
969 os << ";" << std::endl;
970 }
971 else {
972 os << "]" << std::endl;
973 }
974 }
975 return os;
976}
977
1010std::ostream &vpMatrix::maplePrint(std::ostream &os) const
1011{
1012 unsigned int this_rows = this->getRows();
1013 unsigned int this_col = this->getCols();
1014 os << "([ " << std::endl;
1015 for (unsigned int i = 0; i < this_rows; ++i) {
1016 os << "[";
1017 for (unsigned int j = 0; j < this_col; ++j) {
1018 os << (*this)[i][j] << ", ";
1019 }
1020 os << "]," << std::endl;
1021 }
1022 os << "])" << std::endl;
1023 return os;
1024}
1025
1057std::ostream &vpMatrix::csvPrint(std::ostream &os) const
1058{
1059 unsigned int this_rows = this->getRows();
1060 unsigned int this_col = this->getCols();
1061 for (unsigned int i = 0; i < this_rows; ++i) {
1062 for (unsigned int j = 0; j < this_col; ++j) {
1063 os << (*this)[i][j];
1064 if (!(j == (this->getCols() - 1))) {
1065 os << ", ";
1066 }
1067 }
1068 os << std::endl;
1069 }
1070 return os;
1071}
1072
1112std::ostream &vpMatrix::cppPrint(std::ostream &os, const std::string &matrixName, bool octet) const
1113{
1114 os << "vpMatrix " << matrixName << " (" << this->getRows() << ", " << this->getCols() << "); " << std::endl;
1115
1116 unsigned int this_rows = this->getRows();
1117 unsigned int this_col = this->getCols();
1118 for (unsigned int i = 0; i < this_rows; ++i) {
1119 for (unsigned int j = 0; j < this_col; ++j) {
1120 if (!octet) {
1121 os << matrixName << "[" << i << "][" << j << "] = " << (*this)[i][j] << "; " << std::endl;
1122 }
1123 else {
1124 for (unsigned int k = 0; k < sizeof(double); ++k) {
1125 os << "((unsigned char*)&(" << matrixName << "[" << i << "][" << j << "]) )[" << k << "] = 0x" << std::hex
1126 << static_cast<unsigned int>(((unsigned char *)&((*this)[i][j]))[k]) << "; " << std::endl;
1127 }
1128 }
1129 }
1130 os << std::endl;
1131 }
1132 return os;
1133}
1134
1145void vpMatrix::insert(const vpMatrix &A, unsigned int r, unsigned int c)
1146{
1147 if (((r + A.getRows()) <= rowNum) && ((c + A.getCols()) <= colNum)) {
1148 if ((A.colNum == colNum) && (data != nullptr) && (A.data != nullptr) && (A.data != data)) {
1149 memcpy(data + (r * colNum), A.data, sizeof(double) * A.size());
1150 }
1151 else if ((data != nullptr) && (A.data != nullptr) && (A.data != data)) {
1152 unsigned int a_rows = A.getRows();
1153 for (unsigned int i = r; i < (r + a_rows); ++i) {
1154 memcpy(data + (i * colNum) + c, A.data + ((i - r) * A.colNum), sizeof(double) * A.colNum);
1155 }
1156 }
1157 }
1158 else {
1159 throw vpException(vpException::dimensionError, "Cannot insert (%dx%d) matrix in (%dx%d) matrix at position (%d,%d)",
1160 A.getRows(), A.getCols(), rowNum, colNum, r, c);
1161 }
1162}
1163
1205{
1206 vpColVector evalue(rowNum); // Eigen values
1207
1208 if (rowNum != colNum) {
1209 throw(vpException(vpException::dimensionError, "Cannot compute eigen values on a non square matrix (%dx%d)", rowNum,
1210 colNum));
1211 }
1212
1213 // Check if the matrix is symmetric: At - A = 0
1214 vpMatrix At_A = (*this).t() - (*this);
1215 for (unsigned int i = 0; i < rowNum; ++i) {
1216 for (unsigned int j = 0; j < rowNum; ++j) {
1217 // in comment: if (At_A[i][j] != 0) {
1218 if (std::fabs(At_A[i][j]) > std::numeric_limits<double>::epsilon()) {
1219 throw(vpException(vpException::fatalError, "Cannot compute eigen values on a non symmetric matrix"));
1220 }
1221 }
1222 }
1223
1224#if defined(VISP_HAVE_LAPACK)
1225#if defined(VISP_HAVE_GSL) /* be careful of the copy below */
1226 {
1227 gsl_vector *eval = gsl_vector_alloc(rowNum);
1228 gsl_matrix *evec = gsl_matrix_alloc(rowNum, colNum);
1229
1230 gsl_eigen_symmv_workspace *w = gsl_eigen_symmv_alloc(rowNum);
1231 gsl_matrix *m = gsl_matrix_alloc(rowNum, colNum);
1232
1233 unsigned int Atda = static_cast<unsigned int>(m->tda);
1234 for (unsigned int i = 0; i < rowNum; i++) {
1235 unsigned int k = i * Atda;
1236 for (unsigned int j = 0; j < colNum; j++)
1237 m->data[k + j] = (*this)[i][j];
1238 }
1239 gsl_eigen_symmv(m, eval, evec, w);
1240
1241 gsl_eigen_symmv_sort(eval, evec, GSL_EIGEN_SORT_ABS_ASC);
1242
1243 for (unsigned int i = 0; i < rowNum; i++) {
1244 evalue[i] = gsl_vector_get(eval, i);
1245 }
1246
1247 gsl_eigen_symmv_free(w);
1248 gsl_vector_free(eval);
1249 gsl_matrix_free(m);
1250 gsl_matrix_free(evec);
1251 }
1252#else
1253 {
1254 const char jobz = 'N';
1255 const char uplo = 'U';
1256 vpMatrix A = (*this);
1257 vpColVector WORK;
1258 int lwork = -1;
1259 int info = 0;
1260 double wkopt;
1261 vpMatrix::blas_dsyev(jobz, uplo, rowNum, A.data, colNum, evalue.data, &wkopt, lwork, info);
1262 lwork = static_cast<int>(wkopt);
1263 WORK.resize(lwork);
1264 vpMatrix::blas_dsyev(jobz, uplo, rowNum, A.data, colNum, evalue.data, WORK.data, lwork, info);
1265 }
1266#endif
1267#else
1268 throw(vpException(vpException::functionNotImplementedError, "Eigen values computation is not implemented. "
1269 "You should install Lapack 3rd party"));
1270#endif
1271 return evalue;
1272}
1273
1327void vpMatrix::eigenValues(vpColVector &evalue, vpMatrix &evector) const
1328{
1329 if (rowNum != colNum) {
1330 throw(vpException(vpException::dimensionError, "Cannot compute eigen values on a non square matrix (%dx%d)", rowNum,
1331 colNum));
1332 }
1333
1334 // Check if the matrix is symmetric: At - A = 0
1335 vpMatrix At_A = (*this).t() - (*this);
1336 for (unsigned int i = 0; i < rowNum; ++i) {
1337 for (unsigned int j = 0; j < rowNum; ++j) {
1338 // -- in comment: if (At_A[i][j] != 0) {
1339 if (std::fabs(At_A[i][j]) > std::numeric_limits<double>::epsilon()) {
1340 throw(vpException(vpException::fatalError, "Cannot compute eigen values on a non symmetric matrix"));
1341 }
1342 }
1343 }
1344
1345 // Resize the output matrices
1346 evalue.resize(rowNum);
1347 evector.resize(rowNum, colNum);
1348
1349#if defined(VISP_HAVE_LAPACK)
1350#if defined(VISP_HAVE_GSL) /* be careful of the copy below */
1351 {
1352 gsl_vector *eval = gsl_vector_alloc(rowNum);
1353 gsl_matrix *evec = gsl_matrix_alloc(rowNum, colNum);
1354
1355 gsl_eigen_symmv_workspace *w = gsl_eigen_symmv_alloc(rowNum);
1356 gsl_matrix *m = gsl_matrix_alloc(rowNum, colNum);
1357
1358 unsigned int Atda = static_cast<unsigned int>(m->tda);
1359 for (unsigned int i = 0; i < rowNum; i++) {
1360 unsigned int k = i * Atda;
1361 for (unsigned int j = 0; j < colNum; j++)
1362 m->data[k + j] = (*this)[i][j];
1363 }
1364 gsl_eigen_symmv(m, eval, evec, w);
1365
1366 gsl_eigen_symmv_sort(eval, evec, GSL_EIGEN_SORT_ABS_ASC);
1367
1368 for (unsigned int i = 0; i < rowNum; i++) {
1369 evalue[i] = gsl_vector_get(eval, i);
1370 }
1371 Atda = static_cast<unsigned int>(evec->tda);
1372 for (unsigned int i = 0; i < rowNum; i++) {
1373 unsigned int k = i * Atda;
1374 for (unsigned int j = 0; j < rowNum; j++) {
1375 evector[i][j] = evec->data[k + j];
1376 }
1377 }
1378
1379 gsl_eigen_symmv_free(w);
1380 gsl_vector_free(eval);
1381 gsl_matrix_free(m);
1382 gsl_matrix_free(evec);
1383 }
1384#else // defined(VISP_HAVE_GSL)
1385 {
1386 const char jobz = 'V';
1387 const char uplo = 'U';
1388 vpMatrix A = (*this);
1389 vpColVector WORK;
1390 int lwork = -1;
1391 int info = 0;
1392 double wkopt;
1393 vpMatrix::blas_dsyev(jobz, uplo, rowNum, A.data, colNum, evalue.data, &wkopt, lwork, info);
1394 lwork = static_cast<int>(wkopt);
1395 WORK.resize(lwork);
1396 vpMatrix::blas_dsyev(jobz, uplo, rowNum, A.data, colNum, evalue.data, WORK.data, lwork, info);
1397 evector = A.t();
1398 }
1399#endif // defined(VISP_HAVE_GSL)
1400#else
1401 throw(vpException(vpException::functionNotImplementedError, "Eigen values computation is not implemented. "
1402 "You should install Lapack 3rd party"));
1403#endif
1404}
1405
1424unsigned int vpMatrix::kernel(vpMatrix &kerAt, double svThreshold) const
1425{
1426 unsigned int nbline = getRows();
1427 unsigned int nbcol = getCols();
1428
1429 vpMatrix U, V; // Copy of the matrix, SVD function is destructive
1430 vpColVector sv;
1431 sv.resize(nbcol, false); // singular values
1432 V.resize(nbcol, nbcol, false); // V matrix of singular value decomposition
1433
1434 // Copy and resize matrix to have at least as many rows as columns
1435 // kernel is computed in svd method only if the matrix has more rows than
1436 // columns
1437
1438 if (nbline < nbcol) {
1439 U.resize(nbcol, nbcol, true);
1440 }
1441 else {
1442 U.resize(nbline, nbcol, false);
1443 }
1444
1445 U.insert(*this, 0, 0);
1446
1447 U.svd(sv, V);
1448
1449 // Compute the highest singular value and rank of the matrix
1450 double maxsv = 0;
1451 for (unsigned int i = 0; i < nbcol; ++i) {
1452 if (sv[i] > maxsv) {
1453 maxsv = sv[i];
1454 }
1455 }
1456
1457 unsigned int rank = 0;
1458 for (unsigned int i = 0; i < nbcol; ++i) {
1459 if (sv[i] >(maxsv * svThreshold)) {
1460 ++rank;
1461 }
1462 }
1463
1464 kerAt.resize(nbcol - rank, nbcol);
1465 if (rank != nbcol) {
1466 unsigned int k = 0;
1467 for (unsigned int j = 0; j < nbcol; ++j) {
1468 // if( v.col(j) in kernel and non zero )
1469 if ((sv[j] <= (maxsv * svThreshold)) &&
1470 (std::fabs(V.getCol(j).sumSquare()) > std::numeric_limits<double>::epsilon())) {
1471 unsigned int v_rows = V.getRows();
1472 for (unsigned int i = 0; i < v_rows; ++i) {
1473 kerAt[k][i] = V[i][j];
1474 }
1475 ++k;
1476 }
1477 }
1478 }
1479
1480 return rank;
1481}
1482
1499unsigned int vpMatrix::nullSpace(vpMatrix &kerA, double svThreshold) const
1500{
1501 unsigned int nbrow = getRows();
1502 unsigned int nbcol = getCols();
1503
1504 vpMatrix U, V; // Copy of the matrix, SVD function is destructive
1505 vpColVector sv;
1506 sv.resize(nbcol, false); // singular values
1507 V.resize(nbcol, nbcol, false); // V matrix of singular value decomposition
1508
1509 // Copy and resize matrix to have at least as many rows as columns
1510 // kernel is computed in svd method only if the matrix has more rows than
1511 // columns
1512
1513 if (nbrow < nbcol) {
1514 U.resize(nbcol, nbcol, true);
1515 }
1516 else {
1517 U.resize(nbrow, nbcol, false);
1518 }
1519
1520 U.insert(*this, 0, 0);
1521
1522 U.svd(sv, V);
1523
1524 // Compute the highest singular value and rank of the matrix
1525 double maxsv = sv[0];
1526
1527 unsigned int rank = 0;
1528 for (unsigned int i = 0; i < nbcol; ++i) {
1529 if (sv[i] >(maxsv * svThreshold)) {
1530 ++rank;
1531 }
1532 }
1533
1534 kerA.resize(nbcol, nbcol - rank);
1535 if (rank != nbcol) {
1536 unsigned int k = 0;
1537 for (unsigned int j = 0; j < nbcol; ++j) {
1538 // if( v.col(j) in kernel and non zero )
1539 if (sv[j] <= (maxsv * svThreshold)) {
1540 for (unsigned int i = 0; i < nbcol; ++i) {
1541 kerA[i][k] = V[i][j];
1542 }
1543 ++k;
1544 }
1545 }
1546 }
1547
1548 return (nbcol - rank);
1549}
1550
1567unsigned int vpMatrix::nullSpace(vpMatrix &kerA, int dim) const
1568{
1569 unsigned int nbrow = getRows();
1570 unsigned int nbcol = getCols();
1571 unsigned int dim_ = static_cast<unsigned int>(dim);
1572
1573 vpMatrix U, V; // Copy of the matrix, SVD function is destructive
1574 vpColVector sv;
1575 sv.resize(nbcol, false); // singular values
1576 V.resize(nbcol, nbcol, false); // V matrix of singular value decomposition
1577
1578 // Copy and resize matrix to have at least as many rows as columns
1579 // kernel is computed in svd method only if the matrix has more rows than
1580 // columns
1581
1582 if (nbrow < nbcol) {
1583 U.resize(nbcol, nbcol, true);
1584 }
1585 else {
1586 U.resize(nbrow, nbcol, false);
1587 }
1588
1589 U.insert(*this, 0, 0);
1590
1591 U.svd(sv, V);
1592
1593 kerA.resize(nbcol, dim_);
1594 if (dim_ != 0) {
1595 unsigned int rank = nbcol - dim_;
1596 for (unsigned int k = 0; k < dim_; ++k) {
1597 unsigned int j = k + rank;
1598 for (unsigned int i = 0; i < nbcol; ++i) {
1599 kerA[i][k] = V[i][j];
1600 }
1601 }
1602 }
1603
1604 double maxsv = sv[0];
1605 unsigned int rank = 0;
1606 for (unsigned int i = 0; i < nbcol; ++i) {
1607 if (sv[i] >(maxsv * 1e-6)) {
1608 ++rank;
1609 }
1610 }
1611 return (nbcol - rank);
1612}
1613
1649double vpMatrix::det(vpDetMethod method) const
1650{
1651 double det = 0.;
1652
1653 if (method == LU_DECOMPOSITION) {
1654 det = this->detByLU();
1655 }
1656
1657 return det;
1658}
1659
1661{
1662#if defined(VISP_HAVE_EIGEN3)
1663 return choleskyByEigen3();
1664#elif defined(VISP_HAVE_LAPACK)
1665 return choleskyByLapack();
1666#elif defined(VISP_HAVE_OPENCV)
1667 return choleskyByOpenCV();
1668#else
1669 throw(vpException(vpException::fatalError, "Cannot compute matrix Chloesky decomposition. "
1670 "Install Lapack, Eigen3 or OpenCV 3rd party"));
1671#endif
1672}
1673
1682{
1683 if (colNum != rowNum) {
1684 throw(vpException(vpException::dimensionError, "Cannot compute the exponential of a non square (%dx%d) matrix",
1685 rowNum, colNum));
1686 }
1687 else {
1688#ifdef VISP_HAVE_GSL
1689 size_t size_ = rowNum * colNum;
1690 double *b = new double[size_];
1691 for (size_t i = 0; i < size_; i++)
1692 b[i] = 0.;
1693 gsl_matrix_view m = gsl_matrix_view_array(this->data, rowNum, colNum);
1694 gsl_matrix_view em = gsl_matrix_view_array(b, rowNum, colNum);
1695 gsl_linalg_exponential_ss(&m.matrix, &em.matrix, 0);
1696 // gsl_matrix_fprintf(stdout, &em.matrix, "%g");
1697 vpMatrix expA;
1698 expA.resize(rowNum, colNum, false);
1699 memcpy(expA.data, b, size_ * sizeof(double));
1700
1701 delete[] b;
1702 return expA;
1703#else
1704 vpMatrix v_expE(rowNum, colNum, false);
1705 vpMatrix v_expD(rowNum, colNum, false);
1706 vpMatrix v_expX(rowNum, colNum, false);
1707 vpMatrix v_expcX(rowNum, colNum, false);
1708 vpMatrix v_eye(rowNum, colNum, false);
1709
1710 v_eye.eye();
1711 vpMatrix exp(*this);
1712
1713 // -- in comment: double f;
1714 int e;
1715 double c = 0.5;
1716 int q = 6;
1717 int p = 1;
1718
1719 double nA = 0;
1720 for (unsigned int i = 0; i < rowNum; ++i) {
1721 double sum = 0;
1722 for (unsigned int j = 0; j < colNum; ++j) {
1723 sum += fabs((*this)[i][j]);
1724 }
1725 if ((sum > nA) || (i == 0)) {
1726 nA = sum;
1727 }
1728 }
1729
1730 /* f = */ frexp(nA, &e);
1731 // -- in comment: double s = (0 > e+1)?0:e+1;
1732 double s = e + 1;
1733
1734 double sca = 1.0 / pow(2.0, s);
1735 exp = sca * exp;
1736 v_expX = *this;
1737 v_expE = (c * exp) + v_eye;
1738 v_expD = (-c * exp) + v_eye;
1739 for (int k = 2; k <= q; ++k) {
1740 c = (c * (static_cast<double>((q - k) + 1))) / (static_cast<double>(k * (((2.0 * q) - k) + 1)));
1741 v_expcX = exp * v_expX;
1742 v_expX = v_expcX;
1743 v_expcX = c * v_expX;
1744 v_expE = v_expE + v_expcX;
1745 if (p) {
1746 v_expD = v_expD + v_expcX;
1747 }
1748 else {
1749 v_expD = v_expD - v_expcX;
1750 }
1751 p = !p;
1752 }
1753 v_expX = v_expD.inverseByLU();
1754 exp = v_expX * v_expE;
1755 for (int k = 1; k <= s; ++k) {
1756 v_expE = exp * exp;
1757 exp = v_expE;
1758 }
1759 return exp;
1760#endif
1761 }
1762}
1763
1764// Specific functions
1765
1766/*
1767 input:: matrix M(nCols,nRows), nCols > 3, nRows > 3 , nCols == nRows.
1768
1769 output:: the complement matrix of the element (rowNo,colNo).
1770 This is the matrix obtained from M after elimenating the row rowNo and column
1771 colNo
1772
1773 example:
1774 1 2 3
1775 M = 4 5 6
1776 7 8 9
1777 1 3
1778 subblock(M, 1, 1) give the matrix 7 9
1779*/
1780vpMatrix subblock(const vpMatrix &M, unsigned int col, unsigned int row)
1781{
1782 vpMatrix M_comp;
1783 M_comp.resize(M.getRows() - 1, M.getCols() - 1, false);
1784
1785 unsigned int m_rows = M.getRows();
1786 unsigned int m_col = M.getCols();
1787 for (unsigned int i = 0; i < col; ++i) {
1788 for (unsigned int j = 0; j < row; ++j) {
1789 M_comp[i][j] = M[i][j];
1790 }
1791 for (unsigned int j = row + 1; j < m_rows; ++j) {
1792 M_comp[i][j - 1] = M[i][j];
1793 }
1794 }
1795 for (unsigned int i = col + 1; i < m_col; ++i) {
1796 for (unsigned int j = 0; j < row; ++j) {
1797 M_comp[i - 1][j] = M[i][j];
1798 }
1799 for (unsigned int j = row + 1; j < m_rows; ++j) {
1800 M_comp[i - 1][j - 1] = M[i][j];
1801 }
1802 }
1803 return M_comp;
1804}
1805
1815double vpMatrix::cond(double svThreshold) const
1816{
1817 unsigned int nbline = getRows();
1818 unsigned int nbcol = getCols();
1819
1820 vpMatrix U, V; // Copy of the matrix, SVD function is destructive
1821 vpColVector sv;
1822 sv.resize(nbcol); // singular values
1823 V.resize(nbcol, nbcol, false); // V matrix of singular value decomposition
1824
1825 // Copy and resize matrix to have at least as many rows as columns
1826 // kernel is computed in svd method only if the matrix has more rows than
1827 // columns
1828
1829 if (nbline < nbcol) {
1830 U.resize(nbcol, nbcol, true);
1831 }
1832 else {
1833 U.resize(nbline, nbcol, false);
1834 }
1835
1836 U.insert(*this, 0, 0);
1837
1838 U.svd(sv, V);
1839
1840 // Compute the highest singular value
1841 double maxsv = 0;
1842 for (unsigned int i = 0; i < nbcol; ++i) {
1843 if (sv[i] > maxsv) {
1844 maxsv = sv[i];
1845 }
1846 }
1847
1848 // Compute the rank of the matrix
1849 unsigned int rank = 0;
1850 for (unsigned int i = 0; i < nbcol; ++i) {
1851 if (sv[i] >(maxsv * svThreshold)) {
1852 ++rank;
1853 }
1854 }
1855
1856 // Compute the lowest singular value
1857 double minsv = maxsv;
1858 for (unsigned int i = 0; i < rank; ++i) {
1859 if (sv[i] < minsv) {
1860 minsv = sv[i];
1861 }
1862 }
1863
1864 if (std::fabs(minsv) > std::numeric_limits<double>::epsilon()) {
1865 return maxsv / minsv;
1866 }
1867 else {
1868#if defined(VISP_HAVE_FAST_MATH)
1869 return std::numeric_limits<double>::max();
1870#else
1871 return std::numeric_limits<double>::infinity();
1872#endif
1873 }
1874}
1875
1882void vpMatrix::computeHLM(const vpMatrix &H, const double &alpha, vpMatrix &HLM)
1883{
1884 if (H.getCols() != H.getRows()) {
1885 throw(vpException(vpException::dimensionError, "Cannot compute HLM on a non square matrix (%dx%d)", H.getRows(),
1886 H.getCols()));
1887 }
1888
1889 HLM = H;
1890 unsigned int h_col = H.getCols();
1891 for (unsigned int i = 0; i < h_col; ++i) {
1892 HLM[i][i] += alpha * H[i][i];
1893 }
1894}
1895
1904{
1905 double norm = 0.0;
1906 for (unsigned int i = 0; i < dsize; ++i) {
1907 double x = *(data + i);
1908 norm += x * x;
1909 }
1910
1911 return sqrt(norm);
1912}
1913
1923{
1924 if (this->dsize != 0) {
1925 vpMatrix v;
1926 vpColVector w;
1927
1928 vpMatrix M = *this;
1929
1930 M.svd(w, v);
1931
1932 double max = w[0];
1933 unsigned int maxRank = std::min<unsigned int>(this->getCols(), this->getRows());
1934 // The maximum reachable rank is either the number of columns or the number of rows
1935 // of the matrix.
1936 unsigned int boundary = std::min<unsigned int>(maxRank, w.size());
1937 // boundary is here to ensure that the number of singular values used for the com-
1938 // putation of the euclidean norm of the matrix is not greater than the maximum
1939 // reachable rank. Indeed, some svd library pad the singular values vector with 0s
1940 // if the input matrix is non-square.
1941 for (unsigned int i = 0; i < boundary; ++i) {
1942 if (max < w[i]) {
1943 max = w[i];
1944 }
1945 }
1946 return max;
1947 }
1948 else {
1949 return 0.;
1950 }
1951}
1952
1964{
1965 double norm = 0.0;
1966 for (unsigned int i = 0; i < rowNum; ++i) {
1967 double x = 0;
1968 for (unsigned int j = 0; j < colNum; ++j) {
1969 x += fabs(*(*(rowPtrs + i) + j));
1970 }
1971 if (x > norm) {
1972 norm = x;
1973 }
1974 }
1975 return norm;
1976}
1977
1985{
1986 double sum_square = 0.0;
1987 double x;
1988
1989 for (unsigned int i = 0; i < rowNum; ++i) {
1990 for (unsigned int j = 0; j < colNum; ++j) {
1991 x = rowPtrs[i][j];
1992 sum_square += x * x;
1993 }
1994 }
1995
1996 return sum_square;
1997}
1998#if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
2008double vpMatrix::euclideanNorm() const { return frobeniusNorm(); }
2009
2029{
2030 vpRowVector c(getCols());
2031
2032 for (unsigned int j = 0; j < getCols(); ++j) {
2033 c[j] = (*this)[i - 1][j];
2034 }
2035 return c;
2036}
2037
2056{
2057 vpColVector c(getRows());
2058
2059 for (unsigned int i = 0; i < getRows(); ++i) {
2060 c[i] = (*this)[i][j - 1];
2061 }
2062 return c;
2063}
2064
2071void vpMatrix::setIdentity(const double &val)
2072{
2073 for (unsigned int i = 0; i < rowNum; ++i) {
2074 for (unsigned int j = 0; j < colNum; ++j) {
2075 if (i == j) {
2076 (*this)[i][j] = val;
2077 }
2078 else {
2079 (*this)[i][j] = 0;
2080 }
2081 }
2082 }
2083}
2084
2085#endif //#if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
2086
2087END_VISP_NAMESPACE
unsigned int getCols() const
Definition vpArray2D.h:423
void insert(const vpArray2D< Type > &A, unsigned int r, unsigned int c)
Definition vpArray2D.h:586
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
Definition vpArray2D.h:448
static vpArray2D< Type > view(const vpArray2D< Type > &A)
Creates a view of the Matrix A. A view shares the same underlying memory as the original array....
Definition vpArray2D.h:324
unsigned int rowNum
Number of rows in the array.
Definition vpArray2D.h:1201
unsigned int dsize
Definition vpArray2D.h:1207
unsigned int size() const
Definition vpArray2D.h:435
unsigned int getRows() const
Definition vpArray2D.h:433
unsigned int colNum
Number of columns in the array.
Definition vpArray2D.h:1203
Implementation of column vector and the associated operations.
double sumSquare() const
void resize(unsigned int i, bool flagNullify=true)
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ functionNotImplementedError
Function not implemented.
Definition vpException.h:66
@ dimensionError
Bad dimension.
Definition vpException.h:71
@ fatalError
Fatal error.
Definition vpException.h:72
Implementation of an homogeneous matrix and operations on such kind of matrices.
static Type maximum(const Type &a, const Type &b)
Definition vpMath.h:257
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
vpColVector eigenValues() const
std::ostream & cppPrint(std::ostream &os, const std::string &matrixName="A", bool octet=false) const
double cond(double svThreshold=1e-6) const
vpMatrix expm() const
VP_DEPRECATED void setIdentity(const double &val=1.0)
int print(std::ostream &s, unsigned int length, const std::string &intro="") const
Definition vpMatrix.cpp:836
std::ostream & maplePrint(std::ostream &os) const
void init(const vpMatrix &M, unsigned int r, unsigned int c, unsigned int nrows, unsigned int ncols)
Definition vpMatrix.cpp:369
vpMatrix cholesky() const
unsigned int kernel(vpMatrix &kerAt, double svThreshold=1e-6) const
vpMatrix inverseByLU() const
static vpMatrix juxtaposeMatrices(const vpMatrix &A, const vpMatrix &B)
Definition vpMatrix.cpp:769
VP_DEPRECATED double euclideanNorm() const
VP_DEPRECATED vpColVector column(unsigned int j)
void svd(vpColVector &w, vpMatrix &V)
double sum() const
void diag(const double &val=1.0)
vpRowVector getRow(unsigned int i) const
Definition vpMatrix.cpp:602
vpMatrix choleskyByOpenCV() const
Compute the Cholesky decomposition of a Hermitian positive-definite matrix using OpenCV library.
vpMatrix choleskyByEigen3() const
Compute the Cholesky decomposition of a Hermitian positive-definite matrix using Eigen3 library.
double inducedL2Norm() const
double infinityNorm() const
double frobeniusNorm() const
vpColVector getDiag() const
Definition vpMatrix.cpp:699
static void computeHLM(const vpMatrix &H, const double &alpha, vpMatrix &HLM)
VP_DEPRECATED vpRowVector row(unsigned int i)
vpColVector getCol(unsigned int j) const
Definition vpMatrix.cpp:560
double detByLU() const
vpMatrix choleskyByLapack() const
Compute the Cholesky decomposition of a Hermitian positive-definite matrix using Lapack library.
double det(vpDetMethod method=LU_DECOMPOSITION) const
double sumSquare() const
void insert(const vpMatrix &A, unsigned int r, unsigned int c)
VP_DEPRECATED void init()
Definition vpMatrix.h:1094
@ LU_DECOMPOSITION
Definition vpMatrix.h:183
vpMatrix t() const
std::ostream & csvPrint(std::ostream &os) const
static vpMatrix view(double *data, unsigned int rows, unsigned int cols)
Create a matrix view of a raw data array. The view can modify the contents of the raw data array,...
Definition vpMatrix.cpp:307
unsigned int nullSpace(vpMatrix &kerA, double svThreshold=1e-6) const
std::ostream & matlabPrint(std::ostream &os) const
Definition vpMatrix.cpp:959
vpMatrix extract(unsigned int r, unsigned int c, unsigned int nrows, unsigned int ncols) const
Definition vpMatrix.cpp:436
Implementation of a rotation matrix and operations on such kind of matrices.
Implementation of row vector and the associated operations.
Class that consider the case of a translation vector.