1 /****************************************************************************
2 *
3 * ViSP, open source Visual Servoing Platform software.
4 * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5 *
6 * This software is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 * See the file LICENSE.txt at the root directory of this source
11 * distribution for additional information about the GNU GPL.
12 *
13 * For using ViSP with software that can not be combined with the GNU
14 * GPL, please contact Inria about acquiring a ViSP Professional
15 * Edition License.
16 *
17 * See http://visp.inria.fr for more information.
18 *
19 * This software was developed at:
20 * Inria Rennes - Bretagne Atlantique
21 * Campus Universitaire de Beaulieu
22 * 35042 Rennes Cedex
23 * France
24 *
25 * If you have questions regarding the use of this file, please contact
26 * Inria at visp@inria.fr
27 *
28 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30 *
31 * Description:
32 * Matrix manipulation.
33 *
34 * Authors:
35 * Eric Marchand
36 *
37 *****************************************************************************/
38 /*!
39 \file vpMatrix.cpp
40 \brief Definition of the vpMatrix class
41 */
42
43 #include <algorithm>
44 #include <assert.h>
45 #include <cmath> // std::fabs
46 #include <fstream>
47 #include <limits> // numeric_limits
48 #include <sstream>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <string>
53 #include <vector>
54
55 #include <visp3/core/vpConfig.h>
56 #include <visp3/core/vpCPUFeatures.h>
57 #include <visp3/core/vpColVector.h>
58 #include <visp3/core/vpDebug.h>
59 #include <visp3/core/vpException.h>
60 #include <visp3/core/vpMath.h>
61 #include <visp3/core/vpMatrix.h>
62 #include <visp3/core/vpTranslationVector.h>
63
64 #include <Simd/SimdLib.hpp>
65
66 #ifdef VISP_HAVE_LAPACK
67 # ifdef VISP_HAVE_GSL
68 # include <gsl/gsl_eigen.h>
69 # include <gsl/gsl_math.h>
70 # include <gsl/gsl_linalg.h>
71 # elif defined(VISP_HAVE_MKL)
72 # include <mkl.h>
73 typedef MKL_INT integer;
74
blas_dsyev(char jobz,char uplo,unsigned int n_,double * a_data,unsigned int lda_,double * w_data,double * work_data,int lwork_,int & info_)75 void vpMatrix::blas_dsyev(char jobz, char uplo, unsigned int n_, double *a_data, unsigned int lda_,
76 double *w_data, double *work_data, int lwork_, int &info_)
77 {
78 MKL_INT n = static_cast<MKL_INT>(n_);
79 MKL_INT lda = static_cast<MKL_INT>(lda_);
80 MKL_INT lwork = static_cast<MKL_INT>(lwork_);
81 MKL_INT info = static_cast<MKL_INT>(info_);
82
83 dsyev(&jobz, &uplo, &n, a_data, &lda, w_data, work_data, &lwork, &info);
84 }
85
86 # else
87 # if defined(VISP_HAVE_LAPACK_BUILT_IN)
88 typedef long int integer;
89 # else
90 typedef int integer;
91 # endif
92 extern "C" integer dsyev_(char *jobz, char *uplo, integer *n, double *a, integer *lda,
93 double *w, double *WORK, integer *lwork, integer *info);
94
blas_dsyev(char jobz,char uplo,unsigned int n_,double * a_data,unsigned int lda_,double * w_data,double * work_data,int lwork_,int & info_)95 void vpMatrix::blas_dsyev(char jobz, char uplo, unsigned int n_, double *a_data, unsigned int lda_,
96 double *w_data, double *work_data, int lwork_, int &info_)
97 {
98 integer n = static_cast<integer>(n_);
99 integer lda = static_cast<integer>(lda_);
100 integer lwork = static_cast<integer>(lwork_);
101 integer info = static_cast<integer>(info_);
102
103 dsyev_(&jobz, &uplo, &n, a_data, &lda, w_data, work_data, &lwork, &info);
104
105 lwork_ = static_cast<int>(lwork);
106 info_ = static_cast<int>(info);
107 }
108 # endif
109 #endif
110
111 #if !defined(VISP_USE_MSVC) || (defined(VISP_USE_MSVC) && !defined(VISP_BUILD_SHARED_LIBS))
112 const unsigned int vpMatrix::m_lapack_min_size_default = 0;
113 unsigned int vpMatrix::m_lapack_min_size = vpMatrix::m_lapack_min_size_default;
114 #endif
115
116 // Prototypes of specific functions
117 vpMatrix subblock(const vpMatrix &, unsigned int, unsigned int);
118
compute_pseudo_inverse(const vpMatrix & U,const vpColVector & sv,const vpMatrix & V,unsigned int nrows,unsigned int ncols,double svThreshold,vpMatrix & Ap,int & rank_out,int * rank_in,vpMatrix * imA,vpMatrix * imAt,vpMatrix * kerAt)119 void compute_pseudo_inverse(const vpMatrix &U, const vpColVector &sv, const vpMatrix &V, unsigned int nrows,
120 unsigned int ncols, double svThreshold, vpMatrix &Ap, int &rank_out,
121 int *rank_in, vpMatrix *imA, vpMatrix *imAt, vpMatrix *kerAt)
122 {
123 Ap.resize(ncols, nrows, true, false);
124
125 // compute the highest singular value and the rank of h
126 double maxsv = sv[0];
127
128 rank_out = 0;
129
130 for (unsigned int i = 0; i < ncols; i++) {
131 if (sv[i] > maxsv * svThreshold) {
132 rank_out++;
133 }
134 }
135
136 unsigned int rank = static_cast<unsigned int>(rank_out);
137 if (rank_in) {
138 rank = static_cast<unsigned int>(*rank_in);
139 }
140
141 for (unsigned int i = 0; i < ncols; i++) {
142 for (unsigned int j = 0; j < nrows; j++) {
143 for (unsigned int k = 0; k < rank; k++) {
144 Ap[i][j] += V[i][k] * U[j][k] / sv[k];
145 }
146 }
147 }
148
149 // Compute im(A)
150 if (imA) {
151 imA->resize(nrows, rank);
152
153 for (unsigned int i = 0; i < nrows; i++) {
154 for (unsigned int j = 0; j < rank; j++) {
155 (*imA)[i][j] = U[i][j];
156 }
157 }
158 }
159
160 // Compute im(At)
161 if (imAt) {
162 imAt->resize(ncols, rank);
163 for (unsigned int i = 0; i < ncols; i++) {
164 for (unsigned int j = 0; j < rank; j++) {
165 (*imAt)[i][j] = V[i][j];
166 }
167 }
168 }
169
170 // Compute ker(At)
171 if (kerAt) {
172 kerAt->resize(ncols - rank, ncols);
173 if (rank != ncols) {
174 for (unsigned int k = 0; k < (ncols - rank); k++) {
175 unsigned j = k + rank;
176 for (unsigned int i = 0; i < V.getRows(); i++) {
177 (*kerAt)[k][i] = V[i][j];
178 }
179 }
180 }
181 }
182 }
183
184 /*!
185 Construct a matrix as a sub-matrix of the input matrix \e M.
186 \sa init(const vpMatrix &M, unsigned int r, unsigned int c, unsigned int
187 nrows, unsigned int ncols)
188 */
vpMatrix(const vpMatrix & M,unsigned int r,unsigned int c,unsigned int nrows,unsigned int ncols)189 vpMatrix::vpMatrix(const vpMatrix &M, unsigned int r, unsigned int c, unsigned int nrows, unsigned int ncols)
190 : vpArray2D<double>()
191 {
192 if (((r + nrows) > M.rowNum) || ((c + ncols) > M.colNum)) {
193 throw(vpException(vpException::dimensionError,
194 "Cannot construct a sub matrix (%dx%d) starting at "
195 "position (%d,%d) that is not contained in the "
196 "original matrix (%dx%d)",
197 nrows, ncols, r, c, M.rowNum, M.colNum));
198 }
199
200 init(M, r, c, nrows, ncols);
201 }
202
203 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
vpMatrix(vpMatrix && A)204 vpMatrix::vpMatrix(vpMatrix &&A) : vpArray2D<double>()
205 {
206 rowNum = A.rowNum;
207 colNum = A.colNum;
208 rowPtrs = A.rowPtrs;
209 dsize = A.dsize;
210 data = A.data;
211
212 A.rowNum = 0;
213 A.colNum = 0;
214 A.rowPtrs = NULL;
215 A.dsize = 0;
216 A.data = NULL;
217 }
218
219 /*!
220 Construct a matrix from a list of double values.
221 \param list : List of double.
222
223 The following code shows how to use this constructor to initialize a 2-by-3 matrix using reshape() function:
224
225 \code
226 #include <visp3/core/vpMatrix.h>
227
228 int main()
229 {
230 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
231 vpMatrix M( {-1, -2, -3, 4, 5.5, 6.0f} );
232 M.reshape(2, 3);
233 std::cout << "M:\n" << M << std::endl;
234 #endif
235 }
236 \endcode
237 It produces the following output:
238 \code
239 M:
240 -1 -2 -3
241 4 5.5 6
242 \endcode
243 */
vpMatrix(const std::initializer_list<double> & list)244 vpMatrix::vpMatrix(const std::initializer_list<double> &list) : vpArray2D<double>(list) { }
245
246
247 /*!
248 Construct a matrix from a list of double values.
249 \param ncols, nrows : Matrix size.
250 \param list : List of double.
251
252 The following code shows how to use this constructor to initialize a 2-by-3 matrix:
253 \code
254 #include <visp3/core/vpMatrix.h>
255
256 int main()
257 {
258 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
259 vpMatrix M(2, 3, {-1, -2, -3, 4, 5.5, 6});
260 std::cout << "M:\n" << M << std::endl;
261 #endif
262 }
263 \endcode
264 It produces the following output:
265 \code
266 M:
267 -1 -2 -3
268 4 5.5 6
269 \endcode
270 */
vpMatrix(unsigned int nrows,unsigned int ncols,const std::initializer_list<double> & list)271 vpMatrix::vpMatrix(unsigned int nrows, unsigned int ncols, const std::initializer_list<double> &list)
272 : vpArray2D<double>(nrows, ncols, list) {}
273
274 /*!
275 Construct a matrix from a list of double values.
276 \param lists : List of double.
277 The following code shows how to use this constructor to initialize a 2-by-3 matrix function:
278 \code
279 #include <visp3/core/vpMatrix.h>
280
281 int main()
282 {
283 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
284 vpMatrix M( { {-1, -2, -3}, {4, 5.5, 6} } );
285 std::cout << "M:\n" << M << std::endl;
286 #endif
287 }
288 \endcode
289 It produces the following output:
290 \code
291 M:
292 -1 -2 -3
293 4 5.5 6
294 \endcode
295 */
vpMatrix(const std::initializer_list<std::initializer_list<double>> & lists)296 vpMatrix::vpMatrix(const std::initializer_list<std::initializer_list<double> > &lists) : vpArray2D<double>(lists) { }
297
298 #endif
299
300 /*!
301 Initialize the matrix from a part of an input matrix \e M.
302
303 \param M : Input matrix used for initialization.
304 \param r : row index in matrix M.
305 \param c : column index in matrix M.
306 \param nrows : Number of rows of the matrix that should be initialized.
307 \param ncols : Number of columns of the matrix that should be initialized.
308
309 The sub-matrix starting from M[r][c] element and ending on
310 M[r+nrows-1][c+ncols-1] element is used to initialize the matrix.
311
312 The following code shows how to use this function:
313 \code
314 #include <visp3/core/vpMatrix.h>
315
316 int main()
317 {
318 vpMatrix M(4,5);
319 int val = 0;
320 for(size_t i=0; i<M.getRows(); i++) {
321 for(size_t j=0; j<M.getCols(); j++) {
322 M[i][j] = val++;
323 }
324 }
325 M.print (std::cout, 4, "M ");
326
327 vpMatrix N;
328 N.init(M, 0, 1, 2, 3);
329 N.print (std::cout, 4, "N ");
330 }
331 \endcode
332 It produces the following output:
333 \code
334 M [4,5]=
335 0 1 2 3 4
336 5 6 7 8 9
337 10 11 12 13 14
338 15 16 17 18 19
339 N [2,3]=
340 1 2 3
341 6 7 8
342 \endcode
343
344 \sa extract()
345 */
init(const vpMatrix & M,unsigned int r,unsigned int c,unsigned int nrows,unsigned int ncols)346 void vpMatrix::init(const vpMatrix &M, unsigned int r, unsigned int c, unsigned int nrows, unsigned int ncols)
347 {
348 unsigned int rnrows = r + nrows;
349 unsigned int cncols = c + ncols;
350
351 if (rnrows > M.getRows())
352 throw(vpException(vpException::dimensionError, "Bad row dimension (%d > %d) used to initialize vpMatrix", rnrows,
353 M.getRows()));
354 if (cncols > M.getCols())
355 throw(vpException(vpException::dimensionError, "Bad column dimension (%d > %d) used to initialize vpMatrix", cncols,
356 M.getCols()));
357 resize(nrows, ncols, false, false);
358
359 if (this->rowPtrs == NULL) // Fix coverity scan: explicit null dereferenced
360 return; // Noting to do
361 for (unsigned int i = 0; i < nrows; i++) {
362 memcpy((*this)[i], &M[i + r][c], ncols * sizeof(double));
363 }
364 }
365
366 /*!
367 Extract a sub matrix from a matrix \e M.
368
369 \param r : row index in matrix \e M.
370 \param c : column index in matrix \e M.
371 \param nrows : Number of rows of the matrix that should be extracted.
372 \param ncols : Number of columns of the matrix that should be extracted.
373
374 The following code shows how to use this function:
375 \code
376 #include <visp3/core/vpMatrix.h>
377
378 int main()
379 {
380 vpMatrix M(4,5);
381 int val = 0;
382 for(size_t i=0; i<M.getRows(); i++) {
383 for(size_t j=0; j<M.getCols(); j++) {
384 M[i][j] = val++;
385 }
386 }
387 M.print (std::cout, 4, "M ");
388 vpMatrix N = M.extract(0, 1, 2, 3);
389 N.print (std::cout, 4, "N ");
390 }
391 \endcode
392 It produces the following output:
393 \code
394 M [4,5]=
395 0 1 2 3 4
396 5 6 7 8 9
397 10 11 12 13 14
398 15 16 17 18 19
399 N [2,3]=
400 1 2 3
401 6 7 8
402 \endcode
403
404 \sa init(const vpMatrix &, unsigned int, unsigned int, unsigned int,
405 unsigned int)
406 */
extract(unsigned int r,unsigned int c,unsigned int nrows,unsigned int ncols) const407 vpMatrix vpMatrix::extract(unsigned int r, unsigned int c, unsigned int nrows, unsigned int ncols) const
408 {
409 unsigned int rnrows = r + nrows;
410 unsigned int cncols = c + ncols;
411
412 if (rnrows > getRows())
413 throw(vpException(vpException::dimensionError, "Bad row dimension (%d > %d) used to initialize vpMatrix", rnrows,
414 getRows()));
415 if (cncols > getCols())
416 throw(vpException(vpException::dimensionError, "Bad column dimension (%d > %d) used to initialize vpMatrix", cncols,
417 getCols()));
418
419 vpMatrix M;
420 M.resize(nrows, ncols, false, false);
421 for (unsigned int i = 0; i < nrows; i++) {
422 memcpy(M[i], &(*this)[i + r][c], ncols * sizeof(double));
423 }
424
425 return M;
426 }
427
428 /*!
429 Set an n-by-n matrix to identity with ones on the diagonal and zeros
430 else where.
431 */
eye(unsigned int n)432 void vpMatrix::eye(unsigned int n) { eye(n, n); }
433
434 /*!
435 Set an m-by-n matrix to identity with ones on the diagonal and zeros
436 else where.
437 */
eye(unsigned int m,unsigned int n)438 void vpMatrix::eye(unsigned int m, unsigned int n)
439 {
440 resize(m, n);
441
442 eye();
443 }
444
445 /*!
446 Set an m-by-n matrix to identity with ones on the diagonal and zeros
447 else where.
448 */
eye()449 void vpMatrix::eye()
450 {
451 for (unsigned int i = 0; i < rowNum; i++) {
452 for (unsigned int j = 0; j < colNum; j++) {
453 if (i == j)
454 (*this)[i][j] = 1.0;
455 else
456 (*this)[i][j] = 0;
457 }
458 }
459 }
460
461 /*!
462 Compute and return the transpose of the matrix.
463 */
t() const464 vpMatrix vpMatrix::t() const
465 {
466 return transpose();
467 }
468
469 /*!
470 Compute and return the transpose of the matrix.
471
472 \sa t()
473 */
transpose() const474 vpMatrix vpMatrix::transpose() const
475 {
476 vpMatrix At;
477 transpose(At);
478 return At;
479 }
480
481 /*!
482 Compute \e At the transpose of the matrix.
483 \param At (output) : Resulting transpose matrix.
484 \sa t()
485 */
transpose(vpMatrix & At) const486 void vpMatrix::transpose(vpMatrix &At) const
487 {
488 At.resize(colNum, rowNum, false, false);
489
490 if (rowNum <= 16 || colNum <= 16) {
491 for (unsigned int i = 0; i < rowNum; i++) {
492 for (unsigned int j = 0; j < colNum; j++) {
493 At[j][i] = (*this)[i][j];
494 }
495 }
496 }
497 else {
498 SimdMatTranspose(data, rowNum, colNum, At.data);
499 }
500 }
501
502 /*!
503 Computes the \f$AA^T\f$ operation \f$B = A*A^T\f$
504 \return \f$A*A^T\f$
505 \sa AAt(vpMatrix &) const
506 */
AAt() const507 vpMatrix vpMatrix::AAt() const
508 {
509 vpMatrix B;
510
511 AAt(B);
512
513 return B;
514 }
515
516 /*!
517 Compute the AAt operation such as \f$B = A*A^T\f$.
518
519 The result is placed in the parameter \e B and not returned.
520
521 A new matrix won't be allocated for every use of the function. This
522 results in a speed gain if used many times with the same result
523 matrix size.
524
525 \sa AAt()
526 */
AAt(vpMatrix & B) const527 void vpMatrix::AAt(vpMatrix &B) const
528 {
529 if ((B.rowNum != rowNum) || (B.colNum != rowNum))
530 B.resize(rowNum, rowNum, false, false);
531
532 // If available use Lapack only for large matrices
533 bool useLapack = (rowNum > vpMatrix::m_lapack_min_size || colNum > vpMatrix::m_lapack_min_size);
534 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
535 useLapack = false;
536 #endif
537
538 if (useLapack) {
539 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
540 const double alpha = 1.0;
541 const double beta = 0.0;
542 const char transa = 't';
543 const char transb = 'n';
544
545 vpMatrix::blas_dgemm(transa, transb, rowNum, rowNum, colNum, alpha, data, colNum, data, colNum, beta, B.data, rowNum);
546 #endif
547 }
548 else {
549 // compute A*A^T
550 for (unsigned int i = 0; i < rowNum; i++) {
551 for (unsigned int j = i; j < rowNum; j++) {
552 double *pi = rowPtrs[i]; // row i
553 double *pj = rowPtrs[j]; // row j
554
555 // sum (row i .* row j)
556 double ssum = 0;
557 for (unsigned int k = 0; k < colNum; k++)
558 ssum += *(pi++) * *(pj++);
559
560 B[i][j] = ssum; // upper triangle
561 if (i != j)
562 B[j][i] = ssum; // lower triangle
563 }
564 }
565 }
566 }
567
568 /*!
569 Compute the AtA operation such as \f$B = A^T*A\f$.
570
571 The result is placed in the parameter \e B and not returned.
572
573 A new matrix won't be allocated for every use of the function. This
574 results in a speed gain if used many times with the same result matrix
575 size.
576
577 \sa AtA()
578 */
AtA(vpMatrix & B) const579 void vpMatrix::AtA(vpMatrix &B) const
580 {
581 if ((B.rowNum != colNum) || (B.colNum != colNum))
582 B.resize(colNum, colNum, false, false);
583
584 // If available use Lapack only for large matrices
585 bool useLapack = (rowNum > vpMatrix::m_lapack_min_size || colNum > vpMatrix::m_lapack_min_size);
586 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
587 useLapack = false;
588 #endif
589
590 if (useLapack) {
591 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
592 const double alpha = 1.0;
593 const double beta = 0.0;
594 const char transa = 'n';
595 const char transb = 't';
596
597 vpMatrix::blas_dgemm(transa, transb, colNum, colNum, rowNum, alpha, data, colNum, data, colNum, beta, B.data, colNum);
598 #endif
599 }
600 else {
601 for (unsigned int i = 0; i < colNum; i++) {
602 double *Bi = B[i];
603 for (unsigned int j = 0; j < i; j++) {
604 double *ptr = data;
605 double s = 0;
606 for (unsigned int k = 0; k < rowNum; k++) {
607 s += (*(ptr + i)) * (*(ptr + j));
608 ptr += colNum;
609 }
610 *Bi++ = s;
611 B[j][i] = s;
612 }
613 double *ptr = data;
614 double s = 0;
615 for (unsigned int k = 0; k < rowNum; k++) {
616 s += (*(ptr + i)) * (*(ptr + i));
617 ptr += colNum;
618 }
619 *Bi = s;
620 }
621 }
622 }
623
624 /*!
625 Compute the AtA operation such as \f$B = A^T*A\f$
626 \return \f$A^T*A\f$
627 \sa AtA(vpMatrix &) const
628 */
AtA() const629 vpMatrix vpMatrix::AtA() const
630 {
631 vpMatrix B;
632
633 AtA(B);
634
635 return B;
636 }
637
638 /*!
639 Copy operator that allows to convert on of the following container that
640 inherit from vpArray2D such as vpMatrix, vpRotationMatrix,
641 vpHomogeneousMatrix, vpPoseVector, vpColVector, vpRowVector... into a
642 vpMatrix.
643
644 \param A : 2D array to be copied.
645
646 The following example shows how to create a matrix from an homogeneous
647 matrix:
648 \code
649 vpRotationMatrix R;
650 vpMatrix M = R;
651 \endcode
652
653 */
operator =(const vpArray2D<double> & A)654 vpMatrix &vpMatrix::operator=(const vpArray2D<double> &A)
655 {
656 resize(A.getRows(), A.getCols(), false, false);
657
658 if (data != NULL && A.data != NULL && data != A.data) {
659 memcpy(data, A.data, dsize * sizeof(double));
660 }
661
662 return *this;
663 }
664
665 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
operator =(const vpMatrix & A)666 vpMatrix &vpMatrix::operator=(const vpMatrix &A)
667 {
668 resize(A.getRows(), A.getCols(), false, false);
669
670 if (data != NULL && A.data != NULL && data != A.data) {
671 memcpy(data, A.data, dsize * sizeof(double));
672 }
673
674 return *this;
675 }
676
operator =(vpMatrix && other)677 vpMatrix &vpMatrix::operator=(vpMatrix &&other)
678 {
679 if (this != &other) {
680 free(data);
681 free(rowPtrs);
682
683 rowNum = other.rowNum;
684 colNum = other.colNum;
685 rowPtrs = other.rowPtrs;
686 dsize = other.dsize;
687 data = other.data;
688
689 other.rowNum = 0;
690 other.colNum = 0;
691 other.rowPtrs = NULL;
692 other.dsize = 0;
693 other.data = NULL;
694 }
695
696 return *this;
697 }
698
699 /*!
700 Set matrix elements from a list of values.
701 \param list : List of double. Matrix size (number of columns multiplied by number of columns) should match the number of elements.
702 \return The modified Matrix.
703 The following example shows how to set each element of a 2-by-3 matrix.
704 \code
705 #include <visp3/core/vpMatrix.h>
706
707 int main()
708 {
709 vpMatrix M;
710 M = { -1, -2, -3, -4, -5, -6 };
711 M.reshape(2, 3);
712 std::cout << "M:\n" << M << std::endl;
713 }
714 \endcode
715 It produces the following printings:
716 \code
717 M:
718 -1 -2 -3
719 -4 -5 -6
720 \endcode
721 \sa operator<<()
722 */
operator =(const std::initializer_list<double> & list)723 vpMatrix& vpMatrix::operator=(const std::initializer_list<double> &list)
724 {
725 if (dsize != static_cast<unsigned int>(list.size())) {
726 resize(1, static_cast<unsigned int>(list.size()), false, false);
727 }
728
729 std::copy(list.begin(), list.end(), data);
730
731 return *this;
732 }
733
734 /*!
735 Set matrix elements from a list of values.
736 \param lists : List of double.
737 \return The modified Matrix.
738 The following example shows how to set each element of a 2-by-3 matrix.
739 \code
740 #include <visp3/core/vpMatrix.h>
741
742 int main()
743 {
744 vpMatrix M;
745 M = { {-1, -2, -3}, {-4, -5, -6} };
746 std::cout << "M:\n" << M << std::endl;
747 }
748 \endcode
749 It produces the following printings:
750 \code
751 M:
752 -1 -2 -3
753 -4 -5 -6
754 \endcode
755 \sa operator<<()
756 */
operator =(const std::initializer_list<std::initializer_list<double>> & lists)757 vpMatrix& vpMatrix::operator=(const std::initializer_list<std::initializer_list<double> > &lists)
758 {
759 unsigned int nrows = static_cast<unsigned int>(lists.size()), ncols = 0;
760 for (auto& l : lists) {
761 if (static_cast<unsigned int>(l.size()) > ncols) {
762 ncols = static_cast<unsigned int>(l.size());
763 }
764 }
765
766 resize(nrows, ncols, false, false);
767 auto it = lists.begin();
768 for (unsigned int i = 0; i < rowNum; i++, ++it) {
769 std::copy(it->begin(), it->end(), rowPtrs[i]);
770 }
771
772 return *this;
773 }
774 #endif
775
776 //! Set all the element of the matrix A to \e x.
operator =(double x)777 vpMatrix &vpMatrix::operator=(double x)
778 {
779 std::fill(data, data + rowNum*colNum, x);
780 return *this;
781 }
782
783 /*!
784 Assigment from an array of double. This method has to be used carefully
785 since the array allocated behind \e x pointer should have the same dimension
786 than the matrix.
787 */
operator <<(double * x)788 vpMatrix &vpMatrix::operator<<(double *x)
789 {
790 for (unsigned int i = 0; i < rowNum; i++) {
791 for (unsigned int j = 0; j < colNum; j++) {
792 rowPtrs[i][j] = *x++;
793 }
794 }
795 return *this;
796 }
797
operator <<(double val)798 vpMatrix& vpMatrix::operator<<(double val)
799 {
800 resize(1, 1, false, false);
801 rowPtrs[0][0] = val;
802 return *this;
803 }
804
operator ,(double val)805 vpMatrix& vpMatrix::operator,(double val)
806 {
807 resize(1, colNum + 1, false, false);
808 rowPtrs[0][colNum - 1] = val;
809 return *this;
810 }
811
812 /*!
813 Create a diagonal matrix with the element of a vector.
814
815 \param A : Vector which element will be put in the diagonal.
816
817 \sa createDiagonalMatrix()
818
819 \code
820 #include <iostream>
821
822 #include <visp3/core/vpColVector.h>
823 #include <visp3/core/vpMatrix.h>
824
825 int main()
826 {
827 vpMatrix A;
828 vpColVector v(3);
829
830 v[0] = 1;
831 v[1] = 2;
832 v[2] = 3;
833
834 A.diag(v);
835
836 std::cout << "A:\n" << A << std::endl;
837 }
838 \endcode
839
840 Matrix A is now equal to:
841 \code
842 1 0 0
843 0 2 0
844 0 0 3
845 \endcode
846 */
diag(const vpColVector & A)847 void vpMatrix::diag(const vpColVector &A)
848 {
849 unsigned int rows = A.getRows();
850 this->resize(rows, rows);
851
852 (*this) = 0;
853 for (unsigned int i = 0; i < rows; i++)
854 (*this)[i][i] = A[i];
855 }
856
857 /*!
858 Set the matrix as a diagonal matrix where each element on the diagonal is
859 set to \e val. Elements that are not on the diagonal are set to 0.
860
861 \param val : Value to set.
862
863 \sa eye()
864
865 \code
866 #include <iostream>
867
868 #include <visp3/core/vpMatrix.h>
869
870 int main()
871 {
872 vpMatrix A(3, 4);
873
874 A.diag(2);
875
876 std::cout << "A:\n" << A << std::endl;
877 }
878 \endcode
879
880 Matrix A is now equal to:
881 \code
882 2 0 0 0
883 0 2 0 0
884 0 0 2 0
885 \endcode
886 */
diag(const double & val)887 void vpMatrix::diag(const double &val)
888 {
889 (*this) = 0;
890 unsigned int min_ = (rowNum < colNum) ? rowNum : colNum;
891 for (unsigned int i = 0; i < min_; i++)
892 (*this)[i][i] = val;
893 }
894
895 /*!
896
897 Create a diagonal matrix with the element of a vector \f$ DA_{ii} = A_i \f$.
898
899 \param A : Vector which element will be put in the diagonal.
900
901 \param DA : Diagonal matrix DA[i][i] = A[i]
902
903 \sa diag()
904 */
905
createDiagonalMatrix(const vpColVector & A,vpMatrix & DA)906 void vpMatrix::createDiagonalMatrix(const vpColVector &A, vpMatrix &DA)
907 {
908 unsigned int rows = A.getRows();
909 DA.resize(rows, rows, true);
910
911 for (unsigned int i = 0; i < rows; i++)
912 DA[i][i] = A[i];
913 }
914
915 /*!
916 Operator that allows to multiply a matrix by a translation vector.
917 The matrix should be of dimension (3x3)
918 */
operator *(const vpTranslationVector & tv) const919 vpTranslationVector vpMatrix::operator*(const vpTranslationVector &tv) const
920 {
921 vpTranslationVector t_out;
922
923 if (rowNum != 3 || colNum != 3) {
924 throw(vpException(vpException::dimensionError, "Cannot multiply a (%dx%d) matrix by a (%dx%d) translation vector",
925 rowNum, colNum, tv.getRows(), tv.getCols()));
926 }
927
928 for (unsigned int j = 0; j < 3; j++)
929 t_out[j] = 0;
930
931 for (unsigned int j = 0; j < 3; j++) {
932 double tj = tv[j]; // optimization em 5/12/2006
933 for (unsigned int i = 0; i < 3; i++) {
934 t_out[i] += rowPtrs[i][j] * tj;
935 }
936 }
937 return t_out;
938 }
939
940 /*!
941 Operation w = A * v (matrix A is unchanged, v and w are column vectors).
942 \sa multMatrixVector() to avoid matrix allocation for each use.
943 */
operator *(const vpColVector & v) const944 vpColVector vpMatrix::operator*(const vpColVector &v) const
945 {
946 vpColVector v_out;
947 vpMatrix::multMatrixVector(*this, v, v_out);
948 return v_out;
949 }
950
951 /*!
952 Operation w = A * v (v and w are vectors).
953
954 A new matrix won't be allocated for every use of the function
955 (Speed gain if used many times with the same result matrix size).
956
957 \sa operator*(const vpColVector &v) const
958 */
multMatrixVector(const vpMatrix & A,const vpColVector & v,vpColVector & w)959 void vpMatrix::multMatrixVector(const vpMatrix &A, const vpColVector &v, vpColVector &w)
960 {
961 if (A.colNum != v.getRows()) {
962 throw(vpException(vpException::dimensionError, "Cannot multiply a (%dx%d) matrix by a (%d) column vector",
963 A.getRows(), A.getCols(), v.getRows()));
964 }
965
966 if (A.rowNum != w.rowNum)
967 w.resize(A.rowNum, false);
968
969 // If available use Lapack only for large matrices
970 bool useLapack = (A.rowNum > vpMatrix::m_lapack_min_size || A.colNum > vpMatrix::m_lapack_min_size);
971 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
972 useLapack = false;
973 #endif
974
975 if (useLapack) {
976 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
977 double alpha = 1.0;
978 double beta = 0.0;
979 char trans = 't';
980 int incr = 1;
981
982 vpMatrix::blas_dgemv(trans, A.colNum, A.rowNum, alpha, A.data, A.colNum, v.data, incr, beta, w.data, incr);
983 #endif
984 }
985 else {
986 w = 0.0;
987 for (unsigned int j = 0; j < A.colNum; j++) {
988 double vj = v[j]; // optimization em 5/12/2006
989 for (unsigned int i = 0; i < A.rowNum; i++) {
990 w[i] += A.rowPtrs[i][j] * vj;
991 }
992 }
993 }
994 }
995
996 //---------------------------------
997 // Matrix operations.
998 //---------------------------------
999
1000 /*!
1001 Operation C = A * B.
1002
1003 The result is placed in the third parameter C and not returned.
1004 A new matrix won't be allocated for every use of the function
1005 (speed gain if used many times with the same result matrix size).
1006
1007 \sa operator*()
1008 */
mult2Matrices(const vpMatrix & A,const vpMatrix & B,vpMatrix & C)1009 void vpMatrix::mult2Matrices(const vpMatrix &A, const vpMatrix &B, vpMatrix &C)
1010 {
1011 if ((A.rowNum != C.rowNum) || (B.colNum != C.colNum))
1012 C.resize(A.rowNum, B.colNum, false, false);
1013
1014 if (A.colNum != B.rowNum) {
1015 throw(vpException(vpException::dimensionError, "Cannot multiply (%dx%d) matrix by (%dx%d) matrix", A.getRows(),
1016 A.getCols(), B.getRows(), B.getCols()));
1017 }
1018
1019 // If available use Lapack only for large matrices
1020 bool useLapack = (A.rowNum > vpMatrix::m_lapack_min_size || A.colNum > vpMatrix::m_lapack_min_size || B.colNum > vpMatrix::m_lapack_min_size);
1021 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
1022 useLapack = false;
1023 #endif
1024
1025 if (useLapack) {
1026 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
1027 const double alpha = 1.0;
1028 const double beta = 0.0;
1029 const char trans = 'n';
1030 vpMatrix::blas_dgemm(trans, trans, B.colNum, A.rowNum, A.colNum, alpha, B.data, B.colNum, A.data, A.colNum, beta,
1031 C.data, B.colNum);
1032 #endif
1033 }
1034 else {
1035 // 5/12/06 some "very" simple optimization to avoid indexation
1036 const unsigned int BcolNum = B.colNum;
1037 const unsigned int BrowNum = B.rowNum;
1038 double **BrowPtrs = B.rowPtrs;
1039 for (unsigned int i = 0; i < A.rowNum; i++) {
1040 const double *rowptri = A.rowPtrs[i];
1041 double *ci = C[i];
1042 for (unsigned int j = 0; j < BcolNum; j++) {
1043 double s = 0;
1044 for (unsigned int k = 0; k < BrowNum; k++)
1045 s += rowptri[k] * BrowPtrs[k][j];
1046 ci[j] = s;
1047 }
1048 }
1049 }
1050 }
1051
1052 /*!
1053 \warning This function is provided for compat with previous releases. You
1054 should rather use the functionalities provided in vpRotationMatrix class.
1055
1056 Operation C = A * B.
1057
1058 The result is placed in the third parameter C and not returned.
1059 A new matrix won't be allocated for every use of the function
1060 (speed gain if used many times with the same result matrix size).
1061
1062 \exception vpException::dimensionError If matrices are not 3-by-3 dimension.
1063
1064 */
mult2Matrices(const vpMatrix & A,const vpMatrix & B,vpRotationMatrix & C)1065 void vpMatrix::mult2Matrices(const vpMatrix &A, const vpMatrix &B, vpRotationMatrix &C)
1066 {
1067 if (A.colNum != 3 || A.rowNum != 3 || B.colNum != 3 || B.rowNum != 3) {
1068 throw(vpException(vpException::dimensionError,
1069 "Cannot multiply (%dx%d) matrix by (%dx%d) matrix as a "
1070 "rotation matrix",
1071 A.getRows(), A.getCols(), B.getRows(), B.getCols()));
1072 }
1073 // 5/12/06 some "very" simple optimization to avoid indexation
1074 const unsigned int BcolNum = B.colNum;
1075 const unsigned int BrowNum = B.rowNum;
1076 double **BrowPtrs = B.rowPtrs;
1077 for (unsigned int i = 0; i < A.rowNum; i++) {
1078 const double *rowptri = A.rowPtrs[i];
1079 double *ci = C[i];
1080 for (unsigned int j = 0; j < BcolNum; j++) {
1081 double s = 0;
1082 for (unsigned int k = 0; k < BrowNum; k++)
1083 s += rowptri[k] * BrowPtrs[k][j];
1084 ci[j] = s;
1085 }
1086 }
1087 }
1088
1089 /*!
1090 \warning This function is provided for compat with previous releases. You
1091 should rather use the functionalities provided in vpHomogeneousMatrix class.
1092
1093 Operation C = A * B.
1094
1095 The result is placed in the third parameter C and not returned.
1096 A new matrix won't be allocated for every use of the function
1097 (speed gain if used many times with the same result matrix size).
1098
1099 \exception vpException::dimensionError If matrices are not 4-by-4 dimension.
1100
1101 */
mult2Matrices(const vpMatrix & A,const vpMatrix & B,vpHomogeneousMatrix & C)1102 void vpMatrix::mult2Matrices(const vpMatrix &A, const vpMatrix &B, vpHomogeneousMatrix &C)
1103 {
1104 if (A.colNum != 4 || A.rowNum != 4 || B.colNum != 4 || B.rowNum != 4) {
1105 throw(vpException(vpException::dimensionError,
1106 "Cannot multiply (%dx%d) matrix by (%dx%d) matrix as a "
1107 "rotation matrix",
1108 A.getRows(), A.getCols(), B.getRows(), B.getCols()));
1109 }
1110 // Considering perfMatrixMultiplication.cpp benchmark,
1111 // using either MKL, OpenBLAS, or Netlib can slow down this function with respect to the naive code.
1112 // Lapack usage needs to be validated again.
1113 // If available use Lapack only for large matrices.
1114 // Using SSE2 doesn't speed up.
1115 bool useLapack = (A.rowNum > vpMatrix::m_lapack_min_size || A.colNum > vpMatrix::m_lapack_min_size || B.colNum > vpMatrix::m_lapack_min_size);
1116 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
1117 useLapack = false;
1118 #endif
1119
1120 if (useLapack) {
1121 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
1122 const double alpha = 1.0;
1123 const double beta = 0.0;
1124 const char trans = 'n';
1125 vpMatrix::blas_dgemm(trans, trans, B.colNum, A.rowNum, A.colNum, alpha, B.data, B.colNum, A.data, A.colNum, beta,
1126 C.data, B.colNum);
1127 #endif
1128 }
1129 else {
1130 // 5/12/06 some "very" simple optimization to avoid indexation
1131 const unsigned int BcolNum = B.colNum;
1132 const unsigned int BrowNum = B.rowNum;
1133 double **BrowPtrs = B.rowPtrs;
1134 for (unsigned int i = 0; i < A.rowNum; i++) {
1135 const double *rowptri = A.rowPtrs[i];
1136 double *ci = C[i];
1137 for (unsigned int j = 0; j < BcolNum; j++) {
1138 double s = 0;
1139 for (unsigned int k = 0; k < BrowNum; k++)
1140 s += rowptri[k] * BrowPtrs[k][j];
1141 ci[j] = s;
1142 }
1143 }
1144 }
1145 }
1146
1147 /*!
1148 \warning This function is provided for compat with previous releases. You
1149 should rather use multMatrixVector() that is more explicit.
1150
1151 Operation C = A * B.
1152
1153 The result is placed in the third parameter C and not returned.
1154 A new matrix won't be allocated for every use of the function
1155 (speed gain if used many times with the same result matrix size).
1156
1157 \sa multMatrixVector()
1158 */
mult2Matrices(const vpMatrix & A,const vpColVector & B,vpColVector & C)1159 void vpMatrix::mult2Matrices(const vpMatrix &A, const vpColVector &B, vpColVector &C)
1160 {
1161 vpMatrix::multMatrixVector(A, B, C);
1162 }
1163
1164 /*!
1165 Operation C = A * B (A is unchanged).
1166 \sa mult2Matrices() to avoid matrix allocation for each use.
1167 */
operator *(const vpMatrix & B) const1168 vpMatrix vpMatrix::operator*(const vpMatrix &B) const
1169 {
1170 vpMatrix C;
1171
1172 vpMatrix::mult2Matrices(*this, B, C);
1173
1174 return C;
1175 }
1176
1177 /*!
1178 Operator that allow to multiply a matrix by a rotation matrix.
1179 The matrix should be of dimension m-by-3.
1180 */
operator *(const vpRotationMatrix & R) const1181 vpMatrix vpMatrix::operator*(const vpRotationMatrix &R) const
1182 {
1183 if (colNum != R.getRows()) {
1184 throw(vpException(vpException::dimensionError, "Cannot multiply (%dx%d) matrix by (3x3) rotation matrix", rowNum,
1185 colNum));
1186 }
1187 vpMatrix C;
1188 C.resize(rowNum, 3, false, false);
1189
1190 unsigned int RcolNum = R.getCols();
1191 unsigned int RrowNum = R.getRows();
1192 for (unsigned int i = 0; i < rowNum; i++) {
1193 double *rowptri = rowPtrs[i];
1194 double *ci = C[i];
1195 for (unsigned int j = 0; j < RcolNum; j++) {
1196 double s = 0;
1197 for (unsigned int k = 0; k < RrowNum; k++)
1198 s += rowptri[k] * R[k][j];
1199 ci[j] = s;
1200 }
1201 }
1202
1203 return C;
1204 }
1205
1206 /*!
1207 Operator that allow to multiply a matrix by a homogeneous matrix.
1208 The matrix should be of dimension m-by-4.
1209 */
operator *(const vpHomogeneousMatrix & M) const1210 vpMatrix vpMatrix::operator*(const vpHomogeneousMatrix &M) const
1211 {
1212 if (colNum != M.getRows()) {
1213 throw(vpException(vpException::dimensionError, "Cannot multiply (%dx%d) matrix by (3x3) rotation matrix", rowNum,
1214 colNum));
1215 }
1216 vpMatrix C;
1217 C.resize(rowNum, 4, false, false);
1218
1219 const unsigned int McolNum = M.getCols();
1220 const unsigned int MrowNum = M.getRows();
1221 for (unsigned int i = 0; i < rowNum; i++) {
1222 const double *rowptri = rowPtrs[i];
1223 double *ci = C[i];
1224 for (unsigned int j = 0; j < McolNum; j++) {
1225 double s = 0;
1226 for (unsigned int k = 0; k < MrowNum; k++)
1227 s += rowptri[k] * M[k][j];
1228 ci[j] = s;
1229 }
1230 }
1231
1232 return C;
1233 }
1234
1235 /*!
1236 Operator that allow to multiply a matrix by a velocity twist matrix.
1237 The matrix should be of dimension m-by-6.
1238 */
operator *(const vpVelocityTwistMatrix & V) const1239 vpMatrix vpMatrix::operator*(const vpVelocityTwistMatrix &V) const
1240 {
1241 if (colNum != V.getRows()) {
1242 throw(vpException(vpException::dimensionError, "Cannot multiply (%dx%d) matrix by (6x6) velocity twist matrix",
1243 rowNum, colNum));
1244 }
1245 vpMatrix M;
1246 M.resize(rowNum, 6, false, false);
1247
1248 // Considering perfMatrixMultiplication.cpp benchmark,
1249 // using either MKL, OpenBLAS, or Netlib can slow down this function with respect to the naive code.
1250 // Lapack usage needs to be validated again.
1251 // If available use Lapack only for large matrices.
1252 // Speed up obtained using SSE2.
1253 bool useLapack = (rowNum > vpMatrix::m_lapack_min_size || colNum > vpMatrix::m_lapack_min_size || V.colNum > vpMatrix::m_lapack_min_size);
1254 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
1255 useLapack = false;
1256 #endif
1257
1258 if (useLapack) {
1259 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
1260 const double alpha = 1.0;
1261 const double beta = 0.0;
1262 const char trans = 'n';
1263 vpMatrix::blas_dgemm(trans, trans, V.colNum, rowNum, colNum, alpha, V.data, V.colNum, data, colNum, beta,
1264 M.data, M.colNum);
1265 #endif
1266 }
1267 else {
1268 SimdMatMulTwist(data, rowNum, V.data, M.data);
1269 }
1270
1271 return M;
1272 }
1273
1274 /*!
1275 Operator that allow to multiply a matrix by a force/torque twist matrix.
1276 The matrix should be of dimension m-by-6.
1277 */
operator *(const vpForceTwistMatrix & V) const1278 vpMatrix vpMatrix::operator*(const vpForceTwistMatrix &V) const
1279 {
1280 if (colNum != V.getRows()) {
1281 throw(vpException(vpException::dimensionError, "Cannot multiply (%dx%d) matrix by (6x6) force/torque twist matrix",
1282 rowNum, colNum));
1283 }
1284 vpMatrix M;
1285 M.resize(rowNum, 6, false, false);
1286
1287 // Considering perfMatrixMultiplication.cpp benchmark,
1288 // using either MKL, OpenBLAS, or Netlib can slow down this function with respect to the naive code.
1289 // Lapack usage needs to be validated again.
1290 // If available use Lapack only for large matrices.
1291 // Speed up obtained using SSE2.
1292 bool useLapack = (rowNum > vpMatrix::m_lapack_min_size || colNum > vpMatrix::m_lapack_min_size || V.getCols() > vpMatrix::m_lapack_min_size);
1293 #if !(defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL))
1294 useLapack = false;
1295 #endif
1296
1297 if (useLapack) {
1298 #if defined(VISP_HAVE_LAPACK) && !defined(VISP_HAVE_LAPACK_BUILT_IN) && !defined(VISP_HAVE_GSL)
1299 const double alpha = 1.0;
1300 const double beta = 0.0;
1301 const char trans = 'n';
1302 vpMatrix::blas_dgemm(trans, trans, V.getCols(), rowNum, colNum, alpha, V.data, V.getCols(), data, colNum, beta,
1303 M.data, M.colNum);
1304 #endif
1305 }
1306 else {
1307 SimdMatMulTwist(data, rowNum, V.data, M.data);
1308 }
1309
1310 return M;
1311 }
1312
1313 /*!
1314 Operation C = A*wA + B*wB
1315
1316 The result is placed in the third parameter C and not returned.
1317 A new matrix won't be allocated for every use of the function
1318 (Speed gain if used many times with the same result matrix size).
1319
1320 \sa operator+()
1321 */
1322
add2WeightedMatrices(const vpMatrix & A,const double & wA,const vpMatrix & B,const double & wB,vpMatrix & C)1323 void vpMatrix::add2WeightedMatrices(const vpMatrix &A, const double &wA, const vpMatrix &B, const double &wB,
1324 vpMatrix &C)
1325 {
1326 if ((A.rowNum != C.rowNum) || (B.colNum != C.colNum))
1327 C.resize(A.rowNum, B.colNum, false, false);
1328
1329 if ((A.colNum != B.getCols()) || (A.rowNum != B.getRows())) {
1330 throw(vpException(vpException::dimensionError, "Cannot add (%dx%d) matrix with (%dx%d) matrix", A.getRows(),
1331 A.getCols(), B.getRows(), B.getCols()));
1332 }
1333
1334 double **ArowPtrs = A.rowPtrs;
1335 double **BrowPtrs = B.rowPtrs;
1336 double **CrowPtrs = C.rowPtrs;
1337
1338 for (unsigned int i = 0; i < A.rowNum; i++)
1339 for (unsigned int j = 0; j < A.colNum; j++)
1340 CrowPtrs[i][j] = wB * BrowPtrs[i][j] + wA * ArowPtrs[i][j];
1341 }
1342
1343 /*!
1344 Operation C = A + B.
1345
1346 The result is placed in the third parameter C and not returned.
1347 A new matrix won't be allocated for every use of the function
1348 (speed gain if used many times with the same result matrix size).
1349
1350 \sa operator+()
1351 */
add2Matrices(const vpMatrix & A,const vpMatrix & B,vpMatrix & C)1352 void vpMatrix::add2Matrices(const vpMatrix &A, const vpMatrix &B, vpMatrix &C)
1353 {
1354 if ((A.rowNum != C.rowNum) || (B.colNum != C.colNum))
1355 C.resize(A.rowNum, B.colNum, false, false);
1356
1357 if ((A.colNum != B.getCols()) || (A.rowNum != B.getRows())) {
1358 throw(vpException(vpException::dimensionError, "Cannot add (%dx%d) matrix with (%dx%d) matrix", A.getRows(),
1359 A.getCols(), B.getRows(), B.getCols()));
1360 }
1361
1362 double **ArowPtrs = A.rowPtrs;
1363 double **BrowPtrs = B.rowPtrs;
1364 double **CrowPtrs = C.rowPtrs;
1365
1366 for (unsigned int i = 0; i < A.rowNum; i++) {
1367 for (unsigned int j = 0; j < A.colNum; j++) {
1368 CrowPtrs[i][j] = BrowPtrs[i][j] + ArowPtrs[i][j];
1369 }
1370 }
1371 }
1372
1373 /*!
1374 \warning This function is provided for compat with previous releases. You
1375 should rather use the functionalities provided in vpColVector class.
1376
1377 Operation C = A + B.
1378
1379 The result is placed in the third parameter C and not returned.
1380 A new vector won't be allocated for every use of the function
1381 (speed gain if used many times with the same result matrix size).
1382
1383 \sa vpColVector::operator+()
1384 */
add2Matrices(const vpColVector & A,const vpColVector & B,vpColVector & C)1385 void vpMatrix::add2Matrices(const vpColVector &A, const vpColVector &B, vpColVector &C)
1386 {
1387 if ((A.rowNum != C.rowNum) || (B.colNum != C.colNum))
1388 C.resize(A.rowNum);
1389
1390 if ((A.colNum != B.getCols()) || (A.rowNum != B.getRows())) {
1391 throw(vpException(vpException::dimensionError, "Cannot add (%dx%d) matrix with (%dx%d) matrix", A.getRows(),
1392 A.getCols(), B.getRows(), B.getCols()));
1393 }
1394
1395 double **ArowPtrs = A.rowPtrs;
1396 double **BrowPtrs = B.rowPtrs;
1397 double **CrowPtrs = C.rowPtrs;
1398
1399 for (unsigned int i = 0; i < A.rowNum; i++) {
1400 for (unsigned int j = 0; j < A.colNum; j++) {
1401 CrowPtrs[i][j] = BrowPtrs[i][j] + ArowPtrs[i][j];
1402 }
1403 }
1404 }
1405
1406 /*!
1407 Operation C = A + B (A is unchanged).
1408 \sa add2Matrices() to avoid matrix allocation for each use.
1409 */
operator +(const vpMatrix & B) const1410 vpMatrix vpMatrix::operator+(const vpMatrix &B) const
1411 {
1412 vpMatrix C;
1413 vpMatrix::add2Matrices(*this, B, C);
1414 return C;
1415 }
1416
1417 /*!
1418 \warning This function is provided for compat with previous releases. You
1419 should rather use the functionalities provided in vpColVector class.
1420
1421 Operation C = A - B on column vectors.
1422
1423 The result is placed in the third parameter C and not returned.
1424 A new vector won't be allocated for every use of the function
1425 (speed gain if used many times with the same result matrix size).
1426
1427 \exception vpException::dimensionError If A and B vectors have not the same
1428 size.
1429
1430 \sa vpColVector::operator-()
1431 */
sub2Matrices(const vpColVector & A,const vpColVector & B,vpColVector & C)1432 void vpMatrix::sub2Matrices(const vpColVector &A, const vpColVector &B, vpColVector &C)
1433 {
1434 if ((A.rowNum != C.rowNum) || (A.colNum != C.colNum))
1435 C.resize(A.rowNum);
1436
1437 if ((A.colNum != B.getCols()) || (A.rowNum != B.getRows())) {
1438 throw(vpException(vpException::dimensionError, "Cannot substract (%dx%d) matrix to (%dx%d) matrix", A.getRows(),
1439 A.getCols(), B.getRows(), B.getCols()));
1440 }
1441
1442 double **ArowPtrs = A.rowPtrs;
1443 double **BrowPtrs = B.rowPtrs;
1444 double **CrowPtrs = C.rowPtrs;
1445
1446 for (unsigned int i = 0; i < A.rowNum; i++) {
1447 for (unsigned int j = 0; j < A.colNum; j++) {
1448 CrowPtrs[i][j] = ArowPtrs[i][j] - BrowPtrs[i][j];
1449 }
1450 }
1451 }
1452
1453 /*!
1454 Operation C = A - B.
1455
1456 The result is placed in the third parameter C and not returned.
1457 A new matrix won't be allocated for every use of the function
1458 (speed gain if used many times with the same result matrix size).
1459
1460 \exception vpException::dimensionError If A and B matrices have not the same
1461 size.
1462
1463 \sa operator-()
1464 */
sub2Matrices(const vpMatrix & A,const vpMatrix & B,vpMatrix & C)1465 void vpMatrix::sub2Matrices(const vpMatrix &A, const vpMatrix &B, vpMatrix &C)
1466 {
1467 if ((A.rowNum != C.rowNum) || (A.colNum != C.colNum))
1468 C.resize(A.rowNum, A.colNum, false, false);
1469
1470 if ((A.colNum != B.getCols()) || (A.rowNum != B.getRows())) {
1471 throw(vpException(vpException::dimensionError, "Cannot substract (%dx%d) matrix to (%dx%d) matrix", A.getRows(),
1472 A.getCols(), B.getRows(), B.getCols()));
1473 }
1474
1475 double **ArowPtrs = A.rowPtrs;
1476 double **BrowPtrs = B.rowPtrs;
1477 double **CrowPtrs = C.rowPtrs;
1478
1479 for (unsigned int i = 0; i < A.rowNum; i++) {
1480 for (unsigned int j = 0; j < A.colNum; j++) {
1481 CrowPtrs[i][j] = ArowPtrs[i][j] - BrowPtrs[i][j];
1482 }
1483 }
1484 }
1485
1486 /*!
1487 Operation C = A - B (A is unchanged).
1488 \sa sub2Matrices() to avoid matrix allocation for each use.
1489 */
operator -(const vpMatrix & B) const1490 vpMatrix vpMatrix::operator-(const vpMatrix &B) const
1491 {
1492 vpMatrix C;
1493 vpMatrix::sub2Matrices(*this, B, C);
1494 return C;
1495 }
1496
1497 //! Operation A = A + B
1498
operator +=(const vpMatrix & B)1499 vpMatrix &vpMatrix::operator+=(const vpMatrix &B)
1500 {
1501 if ((colNum != B.getCols()) || (rowNum != B.getRows())) {
1502 throw(vpException(vpException::dimensionError, "Cannot add (%dx%d) matrix to (%dx%d) matrix", rowNum, colNum,
1503 B.getRows(), B.getCols()));
1504 }
1505
1506 double **BrowPtrs = B.rowPtrs;
1507
1508 for (unsigned int i = 0; i < rowNum; i++)
1509 for (unsigned int j = 0; j < colNum; j++)
1510 rowPtrs[i][j] += BrowPtrs[i][j];
1511
1512 return *this;
1513 }
1514
1515 //! Operation A = A - B
operator -=(const vpMatrix & B)1516 vpMatrix &vpMatrix::operator-=(const vpMatrix &B)
1517 {
1518 if ((colNum != B.getCols()) || (rowNum != B.getRows())) {
1519 throw(vpException(vpException::dimensionError, "Cannot substract (%dx%d) matrix to (%dx%d) matrix", rowNum, colNum,
1520 B.getRows(), B.getCols()));
1521 }
1522
1523 double **BrowPtrs = B.rowPtrs;
1524 for (unsigned int i = 0; i < rowNum; i++)
1525 for (unsigned int j = 0; j < colNum; j++)
1526 rowPtrs[i][j] -= BrowPtrs[i][j];
1527
1528 return *this;
1529 }
1530
1531 /*!
1532 Operation C = -A.
1533
1534 The result is placed in the second parameter C and not returned.
1535 A new matrix won't be allocated for every use of the function
1536 (Speed gain if used many times with the same result matrix size).
1537
1538 \sa operator-(void)
1539 */
negateMatrix(const vpMatrix & A,vpMatrix & C)1540 void vpMatrix::negateMatrix(const vpMatrix &A, vpMatrix &C)
1541 {
1542 if ((A.rowNum != C.rowNum) || (A.colNum != C.colNum))
1543 C.resize(A.rowNum, A.colNum, false, false);
1544
1545 double **ArowPtrs = A.rowPtrs;
1546 double **CrowPtrs = C.rowPtrs;
1547
1548 // t0=vpTime::measureTimeMicros();
1549 for (unsigned int i = 0; i < A.rowNum; i++)
1550 for (unsigned int j = 0; j < A.colNum; j++)
1551 CrowPtrs[i][j] = -ArowPtrs[i][j];
1552 }
1553
1554 /*!
1555 Operation C = -A (A is unchanged).
1556 \sa negateMatrix() to avoid matrix allocation for each use.
1557 */
operator -() const1558 vpMatrix vpMatrix::operator-() const // negate
1559 {
1560 vpMatrix C;
1561 vpMatrix::negateMatrix(*this, C);
1562 return C;
1563 }
1564
sum() const1565 double vpMatrix::sum() const
1566 {
1567 double s = 0.0;
1568 for (unsigned int i = 0; i < rowNum; i++) {
1569 for (unsigned int j = 0; j < colNum; j++) {
1570 s += rowPtrs[i][j];
1571 }
1572 }
1573
1574 return s;
1575 }
1576
1577 //---------------------------------
1578 // Matrix/vector operations.
1579 //---------------------------------
1580
1581 //---------------------------------
1582 // Matrix/real operations.
1583 //---------------------------------
1584
1585 /*!
1586 \relates vpMatrix
1587 Allow to multiply a scalar by a matrix.
1588 */
operator *(const double & x,const vpMatrix & B)1589 vpMatrix operator*(const double &x, const vpMatrix &B)
1590 {
1591 if (std::fabs(x - 1.) < std::numeric_limits<double>::epsilon()) {
1592 return B;
1593 }
1594
1595 unsigned int Brow = B.getRows();
1596 unsigned int Bcol = B.getCols();
1597
1598 vpMatrix C;
1599 C.resize(Brow, Bcol, false, false);
1600
1601 for (unsigned int i = 0; i < Brow; i++)
1602 for (unsigned int j = 0; j < Bcol; j++)
1603 C[i][j] = B[i][j] * x;
1604
1605 return C;
1606 }
1607
1608 /*!
1609 Operator that allows to multiply all the elements of a matrix
1610 by a scalar.
1611 */
operator *(double x) const1612 vpMatrix vpMatrix::operator*(double x) const
1613 {
1614 if (std::fabs(x - 1.) < std::numeric_limits<double>::epsilon()) {
1615 return (*this);
1616 }
1617
1618 vpMatrix M;
1619 M.resize(rowNum, colNum, false, false);
1620
1621 for (unsigned int i = 0; i < rowNum; i++)
1622 for (unsigned int j = 0; j < colNum; j++)
1623 M[i][j] = rowPtrs[i][j] * x;
1624
1625 return M;
1626 }
1627
1628 //! Cij = Aij / x (A is unchanged)
operator /(double x) const1629 vpMatrix vpMatrix::operator/(double x) const
1630 {
1631 if (std::fabs(x - 1.) < std::numeric_limits<double>::epsilon()) {
1632 return (*this);
1633 }
1634
1635 if (std::fabs(x) < std::numeric_limits<double>::epsilon()) {
1636 throw vpException(vpException::divideByZeroError, "Divide matrix by zero scalar");
1637 }
1638
1639 vpMatrix C;
1640 C.resize(rowNum, colNum, false, false);
1641
1642 double xinv = 1 / x;
1643
1644 for (unsigned int i = 0; i < rowNum; i++)
1645 for (unsigned int j = 0; j < colNum; j++)
1646 C[i][j] = rowPtrs[i][j] * xinv;
1647
1648 return C;
1649 }
1650
1651 //! Add x to all the element of the matrix : Aij = Aij + x
operator +=(double x)1652 vpMatrix &vpMatrix::operator+=(double x)
1653 {
1654 for (unsigned int i = 0; i < rowNum; i++)
1655 for (unsigned int j = 0; j < colNum; j++)
1656 rowPtrs[i][j] += x;
1657
1658 return *this;
1659 }
1660
1661 //! Substract x to all the element of the matrix : Aij = Aij - x
operator -=(double x)1662 vpMatrix &vpMatrix::operator-=(double x)
1663 {
1664 for (unsigned int i = 0; i < rowNum; i++)
1665 for (unsigned int j = 0; j < colNum; j++)
1666 rowPtrs[i][j] -= x;
1667
1668 return *this;
1669 }
1670
1671 /*!
1672 Operator that allows to multiply all the elements of a matrix
1673 by a scalar.
1674 */
operator *=(double x)1675 vpMatrix &vpMatrix::operator*=(double x)
1676 {
1677 if (std::fabs(x - 1.) < std::numeric_limits<double>::epsilon()) {
1678 return *this;
1679 }
1680
1681 for (unsigned int i = 0; i < rowNum; i++)
1682 for (unsigned int j = 0; j < colNum; j++)
1683 rowPtrs[i][j] *= x;
1684
1685 return *this;
1686 }
1687
1688 //! Divide all the element of the matrix by x : Aij = Aij / x
operator /=(double x)1689 vpMatrix &vpMatrix::operator/=(double x)
1690 {
1691 if (std::fabs(x - 1.) < std::numeric_limits<double>::epsilon()) {
1692 return *this;
1693 }
1694
1695 if (std::fabs(x) < std::numeric_limits<double>::epsilon())
1696 throw vpException(vpException::divideByZeroError, "Divide matrix by zero scalar");
1697
1698 double xinv = 1 / x;
1699
1700 for (unsigned int i = 0; i < rowNum; i++)
1701 for (unsigned int j = 0; j < colNum; j++)
1702 rowPtrs[i][j] *= xinv;
1703
1704 return *this;
1705 }
1706
1707 //----------------------------------------------------------------
1708 // Matrix Operation
1709 //----------------------------------------------------------------
1710
1711 /*!
1712 Stacks columns of a matrix in a vector.
1713 \param out : a vpColVector.
1714 */
stackColumns(vpColVector & out)1715 void vpMatrix::stackColumns(vpColVector &out)
1716 {
1717 if ((out.rowNum != colNum * rowNum) || (out.colNum != 1))
1718 out.resize(colNum * rowNum, false, false);
1719
1720 double *optr = out.data;
1721 for (unsigned int j = 0; j < colNum; j++) {
1722 for (unsigned int i = 0; i < rowNum; i++) {
1723 *(optr++) = rowPtrs[i][j];
1724 }
1725 }
1726 }
1727
1728 /*!
1729 Stacks columns of a matrix in a vector.
1730 \return a vpColVector.
1731 */
stackColumns()1732 vpColVector vpMatrix::stackColumns()
1733 {
1734 vpColVector out(colNum * rowNum);
1735 stackColumns(out);
1736 return out;
1737 }
1738
1739 /*!
1740 Stacks rows of a matrix in a vector
1741 \param out : a vpRowVector.
1742 */
stackRows(vpRowVector & out)1743 void vpMatrix::stackRows(vpRowVector &out)
1744 {
1745 if ((out.getRows() != 1) || (out.getCols() != colNum * rowNum))
1746 out.resize(colNum * rowNum, false, false);
1747
1748 memcpy(out.data, data, sizeof(double)*out.getCols());
1749 }
1750 /*!
1751 Stacks rows of a matrix in a vector.
1752 \return a vpRowVector.
1753 */
stackRows()1754 vpRowVector vpMatrix::stackRows()
1755 {
1756 vpRowVector out(colNum * rowNum);
1757 stackRows(out);
1758 return out;
1759 }
1760
1761 /*!
1762 Compute the Hadamard product (element wise matrix multiplication).
1763 \param m : Second matrix;
1764 \return m1.hadamard(m2) The Hadamard product :
1765 \f$ m1 \circ m2 = (m1 \circ m2)_{i,j} = (m1)_{i,j} (m2)_{i,j} \f$
1766 */
hadamard(const vpMatrix & m) const1767 vpMatrix vpMatrix::hadamard(const vpMatrix &m) const
1768 {
1769 if (m.getRows() != rowNum || m.getCols() != colNum) {
1770 throw(vpException(vpException::dimensionError, "In Hadamard product: bad dimension of input matrix"));
1771 }
1772
1773 vpMatrix out;
1774 out.resize(rowNum, colNum, false, false);
1775
1776 SimdVectorHadamard(data, m.data, dsize, out.data);
1777
1778 return out;
1779 }
1780
1781 /*!
1782 Compute Kronecker product matrix.
1783 \param m1 : vpMatrix;
1784 \param m2 : vpMatrix;
1785 \param out : The kronecker product : \f$ m1 \otimes m2 \f$
1786 */
kron(const vpMatrix & m1,const vpMatrix & m2,vpMatrix & out)1787 void vpMatrix::kron(const vpMatrix &m1, const vpMatrix &m2, vpMatrix &out)
1788 {
1789 unsigned int r1 = m1.getRows();
1790 unsigned int c1 = m1.getCols();
1791 unsigned int r2 = m2.getRows();
1792 unsigned int c2 = m2.getCols();
1793
1794 out.resize(r1*r2, c1*c2, false, false);
1795
1796 for (unsigned int r = 0; r < r1; r++) {
1797 for (unsigned int c = 0; c < c1; c++) {
1798 double alpha = m1[r][c];
1799 double *m2ptr = m2[0];
1800 unsigned int roffset = r * r2;
1801 unsigned int coffset = c * c2;
1802 for (unsigned int rr = 0; rr < r2; rr++) {
1803 for (unsigned int cc = 0; cc < c2; cc++) {
1804 out[roffset + rr][coffset + cc] = alpha * *(m2ptr++);
1805 }
1806 }
1807 }
1808 }
1809 }
1810
1811 /*!
1812 Compute Kronecker product matrix.
1813 \param m : vpMatrix.
1814 \param out : If m1.kron(m2) out contains the kronecker product's result :
1815 \f$ m1 \otimes m2 \f$.
1816 */
kron(const vpMatrix & m,vpMatrix & out) const1817 void vpMatrix::kron(const vpMatrix &m, vpMatrix &out) const { kron(*this, m, out); }
1818
1819 /*!
1820 Compute Kronecker product matrix.
1821 \param m1 : vpMatrix;
1822 \param m2 : vpMatrix;
1823 \return The kronecker product : \f$ m1 \otimes m2 \f$
1824 */
kron(const vpMatrix & m1,const vpMatrix & m2)1825 vpMatrix vpMatrix::kron(const vpMatrix &m1, const vpMatrix &m2)
1826 {
1827 unsigned int r1 = m1.getRows();
1828 unsigned int c1 = m1.getCols();
1829 unsigned int r2 = m2.getRows();
1830 unsigned int c2 = m2.getCols();
1831
1832 vpMatrix out;
1833 out.resize(r1 * r2, c1 * c2, false, false);
1834
1835 for (unsigned int r = 0; r < r1; r++) {
1836 for (unsigned int c = 0; c < c1; c++) {
1837 double alpha = m1[r][c];
1838 double *m2ptr = m2[0];
1839 unsigned int roffset = r * r2;
1840 unsigned int coffset = c * c2;
1841 for (unsigned int rr = 0; rr < r2; rr++) {
1842 for (unsigned int cc = 0; cc < c2; cc++) {
1843 out[roffset + rr][coffset + cc] = alpha * *(m2ptr++);
1844 }
1845 }
1846 }
1847 }
1848 return out;
1849 }
1850
1851 /*!
1852 Compute Kronecker product matrix.
1853 \param m : vpMatrix;
1854 \return m1.kron(m2) The kronecker product : \f$ m1 \otimes m2 \f$
1855 */
kron(const vpMatrix & m) const1856 vpMatrix vpMatrix::kron(const vpMatrix &m) const { return kron(*this, m); }
1857
1858 /*!
1859
1860 Solve a linear system \f$ A X = B \f$ using Singular Value
1861 Decomposition (SVD).
1862
1863 Non destructive wrt. A and B.
1864
1865 \param b : Vector\f$ B \f$.
1866
1867 \param x : Vector \f$ X \f$.
1868
1869 Here an example:
1870 \code
1871 #include <visp3/core/vpColVector.h>
1872 #include <visp3/core/vpMatrix.h>
1873
1874 int main()
1875 {
1876 vpMatrix A(3,3);
1877
1878 A[0][0] = 4.64;
1879 A[0][1] = 0.288;
1880 A[0][2] = -0.384;
1881
1882 A[1][0] = 0.288;
1883 A[1][1] = 7.3296;
1884 A[1][2] = 2.2272;
1885
1886 A[2][0] = -0.384;
1887 A[2][1] = 2.2272;
1888 A[2][2] = 6.0304;
1889
1890 vpColVector X(3), B(3);
1891 B[0] = 1;
1892 B[1] = 2;
1893 B[2] = 3;
1894
1895 A.solveBySVD(B, X);
1896
1897 // Obtained values of X
1898 // X[0] = 0.2468;
1899 // X[1] = 0.120782;
1900 // X[2] = 0.468587;
1901
1902 std::cout << "X:\n" << X << std::endl;
1903 }
1904 \endcode
1905
1906 \sa solveBySVD(const vpColVector &)
1907 */
solveBySVD(const vpColVector & b,vpColVector & x) const1908 void vpMatrix::solveBySVD(const vpColVector &b, vpColVector &x) const { x = pseudoInverse(1e-6) * b; }
1909
1910 /*!
1911
1912 Solve a linear system \f$ A X = B \f$ using Singular Value
1913 Decomposition (SVD).
1914
1915 Non destructive wrt. A and B.
1916
1917 \param B : Vector\f$ B \f$.
1918
1919 \return Vector \f$ X \f$.
1920
1921 Here an example:
1922 \code
1923 #include <visp3/core/vpColVector.h>
1924 #include <visp3/core/vpMatrix.h>
1925
1926 int main()
1927 {
1928 vpMatrix A(3,3);
1929
1930 A[0][0] = 4.64;
1931 A[0][1] = 0.288;
1932 A[0][2] = -0.384;
1933
1934 A[1][0] = 0.288;
1935 A[1][1] = 7.3296;
1936 A[1][2] = 2.2272;
1937
1938 A[2][0] = -0.384;
1939 A[2][1] = 2.2272;
1940 A[2][2] = 6.0304;
1941
1942 vpColVector X(3), B(3);
1943 B[0] = 1;
1944 B[1] = 2;
1945 B[2] = 3;
1946
1947 X = A.solveBySVD(B);
1948 // Obtained values of X
1949 // X[0] = 0.2468;
1950 // X[1] = 0.120782;
1951 // X[2] = 0.468587;
1952
1953 std::cout << "X:\n" << X << std::endl;
1954 }
1955 \endcode
1956
1957 \sa solveBySVD(const vpColVector &, vpColVector &)
1958 */
solveBySVD(const vpColVector & B) const1959 vpColVector vpMatrix::solveBySVD(const vpColVector &B) const
1960 {
1961 vpColVector X(colNum);
1962
1963 solveBySVD(B, X);
1964 return X;
1965 }
1966
1967 /*!
1968
1969 Matrix singular value decomposition (SVD).
1970
1971 This function calls the first following function that is available:
1972 - svdLapack() if Lapack 3rd party is installed
1973 - svdEigen3() if Eigen3 3rd party is installed
1974 - svdOpenCV() if OpenCV 3rd party is installed.
1975
1976 If none of these previous 3rd parties is installed, we use by default
1977 svdLapack() with a Lapack built-in version.
1978
1979 Given matrix \f$M\f$, this function computes it singular value decomposition
1980 such as
1981
1982 \f[ M = U \Sigma V^{\top} \f]
1983
1984 \warning This method is destructive wrt. to the matrix \f$ M \f$ to
1985 decompose. You should make a COPY of that matrix if needed.
1986
1987 \param w : Vector of singular values: \f$ \Sigma = diag(w) \f$.
1988
1989 \param V : Matrix \f$ V \f$.
1990
1991 \return Matrix \f$ U \f$.
1992
1993 \note The singular values are ordered in decreasing
1994 fashion in \e w. It means that the highest singular value is in \e w[0].
1995
1996 Here an example of SVD decomposition of a non square Matrix M.
1997
1998 \code
1999 #include <visp3/core/vpMatrix.h>
2000
2001 int main()
2002 {
2003 vpMatrix M(3,2);
2004 M[0][0] = 1; M[0][1] = 6;
2005 M[1][0] = 2; M[1][1] = 8;
2006 M[2][0] = 0.5; M[2][1] = 9;
2007
2008 vpColVector w;
2009 vpMatrix V, Sigma, U = M;
2010
2011 U.svd(w, V);
2012
2013 // Construct the diagonal matrix from the singular values
2014 Sigma.diag(w);
2015
2016 // Reconstruct the initial matrix using the decomposition
2017 vpMatrix Mrec = U * Sigma * V.t();
2018
2019 // Here, Mrec is obtained equal to the initial value of M
2020 // Mrec[0][0] = 1; Mrec[0][1] = 6;
2021 // Mrec[1][0] = 2; Mrec[1][1] = 8;
2022 // Mrec[2][0] = 0.5; Mrec[2][1] = 9;
2023
2024 std::cout << "Reconstructed M matrix: \n" << Mrec << std::endl;
2025 }
2026 \endcode
2027
2028 \sa svdLapack(), svdEigen3(), svdOpenCV()
2029 */
svd(vpColVector & w,vpMatrix & V)2030 void vpMatrix::svd(vpColVector &w, vpMatrix &V)
2031 {
2032 #if defined(VISP_HAVE_LAPACK)
2033 svdLapack(w, V);
2034 #elif defined(VISP_HAVE_EIGEN3)
2035 svdEigen3(w, V);
2036 #elif (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
2037 svdOpenCV(w, V);
2038 #else
2039 (void)w;
2040 (void)V;
2041 throw(vpException(vpException::fatalError, "Cannot compute SVD. Install Lapack, Eigen3 or OpenCV 3rd party"));
2042 #endif
2043 }
2044
2045 /*!
2046 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
2047 A\f$ and return the rank of the matrix.
2048
2049 \note By default, this function uses Lapack 3rd party. It is also possible
2050 to use a specific 3rd party suffixing this function name with one of the
2051 following 3rd party names (Lapack, Eigen3 or OpenCV).
2052
2053 \warning To inverse a square n-by-n matrix, you have to use rather one of
2054 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
2055 are kwown as faster.
2056
2057 \param Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
2058
2059 \param svThreshold : Threshold used to test the singular values. If
2060 a singular value is lower than this threshold we consider that the
2061 matrix is not full rank.
2062
2063 \return The rank of the matrix.
2064
2065 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
2066
2067 \code
2068 #include <visp3/core/vpMatrix.h>
2069
2070 int main()
2071 {
2072 vpMatrix A(2, 3);
2073
2074 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
2075 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
2076
2077 A.print(std::cout, 10, "A: ");
2078
2079 vpMatrix A_p;
2080 unsigned int rank = A.pseudoInverse(A_p);
2081
2082 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
2083 std::cout << "Rank: " << rank << std::endl;
2084 }
2085 \endcode
2086
2087 Once build, the previous example produces the following output:
2088 \code
2089 A: [2,3]=
2090 2 3 5
2091 -4 2 3
2092 A^+ (pseudo-inverse): [3,2]=
2093 0.117899 -0.190782
2094 0.065380 0.039657
2095 0.113612 0.052518
2096 Rank: 2
2097 \endcode
2098 */
pseudoInverse(vpMatrix & Ap,double svThreshold) const2099 unsigned int vpMatrix::pseudoInverse(vpMatrix &Ap, double svThreshold) const
2100 {
2101 #if defined(VISP_HAVE_LAPACK)
2102 return pseudoInverseLapack(Ap, svThreshold);
2103 #elif defined(VISP_HAVE_EIGEN3)
2104 return pseudoInverseEigen3(Ap, svThreshold);
2105 #elif (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
2106 return pseudoInverseOpenCV(Ap, svThreshold);
2107 #else
2108 (void)Ap;
2109 (void)svThreshold;
2110 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
2111 "Install Lapack, Eigen3 or OpenCV 3rd party"));
2112 #endif
2113 }
2114
2115 /*!
2116 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
2117 A\f$ and return the rank of the matrix.
2118
2119 \note By default, this function uses Lapack 3rd party. It is also possible
2120 to use a specific 3rd party suffixing this function name with one of the
2121 following 3rd party names (Lapack, Eigen3 or OpenCV).
2122
2123 \warning To inverse a square n-by-n matrix, you have to use rather one of
2124 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
2125 are kwown as faster.
2126
2127 \param Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
2128
2129 \param[in] rank_in : Known rank of the matrix.
2130
2131 \return The rank of the matrix.
2132
2133 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
2134
2135 \code
2136 #include <visp3/core/vpMatrix.h>
2137
2138 int main()
2139 {
2140 vpMatrix A(2, 3);
2141
2142 // This matrix rank is 2
2143 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
2144 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
2145
2146 A.print(std::cout, 10, "A: ");
2147
2148 vpMatrix A_p;
2149 int rank_in = 2;
2150 int rank_out = A.pseudoInverse(A_p, rank_in);
2151 if (rank_out != rank_in) {
2152 std::cout << "There is a possibility that the pseudo-inverse in wrong." << std::endl;
2153 std::cout << "Are you sure that the matrix rank is " << rank_in << std::endl;
2154 }
2155
2156 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
2157 std::cout << "Rank in : " << rank_in << std::endl;
2158 std::cout << "Rank out: " << rank_out << std::endl;
2159 }
2160 \endcode
2161
2162 Once build, the previous example produces the following output:
2163 \code
2164 A: [2,3]=
2165 2 3 5
2166 -4 2 3
2167 A^+ (pseudo-inverse): [3,2]=
2168 0.117899 -0.190782
2169 0.065380 0.039657
2170 0.113612 0.052518
2171 Rank in : 2
2172 Rank out: 2
2173 \endcode
2174 */
pseudoInverse(vpMatrix & Ap,int rank_in) const2175 int vpMatrix::pseudoInverse(vpMatrix &Ap, int rank_in) const
2176 {
2177 #if defined(VISP_HAVE_LAPACK)
2178 return pseudoInverseLapack(Ap, rank_in);
2179 #elif defined(VISP_HAVE_EIGEN3)
2180 return pseudoInverseEigen3(Ap, rank_in);
2181 #elif (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
2182 return pseudoInverseOpenCV(Ap, rank_in);
2183 #else
2184 (void)Ap;
2185 (void)svThreshold;
2186 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
2187 "Install Lapack, Eigen3 or OpenCV 3rd party"));
2188 #endif
2189 }
2190
2191 /*!
2192 Compute and return the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n
2193 matrix \f$\bf A\f$.
2194
2195 \note By default, this function uses Lapack 3rd party. It is also possible
2196 to use a specific 3rd party suffixing this function name with one of the
2197 following 3rd party names (Lapack, Eigen3 or OpenCV).
2198
2199 \warning To inverse a square n-by-n matrix, you have to use rather one of
2200 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
2201 are kwown as faster.
2202
2203 \param svThreshold : Threshold used to test the singular values. If
2204 a singular value is lower than this threshold we consider that the
2205 matrix is not full rank.
2206
2207 \return The Moore-Penros pseudo inverse \f$ A^+ \f$.
2208
2209 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
2210
2211 \code
2212 #include <visp3/core/vpMatrix.h>
2213
2214 int main()
2215 {
2216 vpMatrix A(2, 3);
2217
2218 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
2219 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
2220
2221 A.print(std::cout, 10, "A: ");
2222
2223 vpMatrix A_p = A.pseudoInverse();
2224
2225 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
2226 }
2227 \endcode
2228
2229 Once build, the previous example produces the following output:
2230 \code
2231 A: [2,3]=
2232 2 3 5
2233 -4 2 3
2234 A^+ (pseudo-inverse): [3,2]=
2235 0.117899 -0.190782
2236 0.065380 0.039657
2237 0.113612 0.052518
2238 \endcode
2239
2240 */
pseudoInverse(double svThreshold) const2241 vpMatrix vpMatrix::pseudoInverse(double svThreshold) const
2242 {
2243 #if defined(VISP_HAVE_LAPACK)
2244 return pseudoInverseLapack(svThreshold);
2245 #elif defined(VISP_HAVE_EIGEN3)
2246 return pseudoInverseEigen3(svThreshold);
2247 #elif (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
2248 return pseudoInverseOpenCV(svThreshold);
2249 #else
2250 (void)svThreshold;
2251 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
2252 "Install Lapack, Eigen3 or OpenCV 3rd party"));
2253 #endif
2254 }
2255
2256 /*!
2257 Compute and return the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n
2258 matrix \f$\bf A\f$.
2259
2260 \note By default, this function uses Lapack 3rd party. It is also possible
2261 to use a specific 3rd party suffixing this function name with one of the
2262 following 3rd party names (Lapack, Eigen3 or OpenCV).
2263
2264 \warning To inverse a square n-by-n matrix, you have to use rather one of
2265 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
2266 are kwown as faster.
2267
2268 \param[in] rank_in : Known rank of the matrix.
2269
2270 \return The Moore-Penros pseudo inverse \f$ A^+ \f$.
2271
2272 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
2273
2274 \code
2275 #include <visp3/core/vpMatrix.h>
2276
2277 int main()
2278 {
2279 vpMatrix A(2, 3);
2280
2281 // This matrix rank is 2
2282 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
2283 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
2284
2285 A.print(std::cout, 10, "A: ");
2286
2287 int rank_in = 2;
2288 vpMatrix A_p = A.pseudoInverseLapack(rank_in);
2289
2290 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
2291 }
2292 \endcode
2293
2294 Once build, the previous example produces the following output:
2295 \code
2296 A: [2,3]=
2297 2 3 5
2298 -4 2 3
2299 A^+ (pseudo-inverse): [3,2]=
2300 0.117899 -0.190782
2301 0.065380 0.039657
2302 0.113612 0.052518
2303 \endcode
2304
2305 */
pseudoInverse(int rank_in) const2306 vpMatrix vpMatrix::pseudoInverse(int rank_in) const
2307 {
2308 #if defined(VISP_HAVE_LAPACK)
2309 return pseudoInverseLapack(rank_in);
2310 #elif defined(VISP_HAVE_EIGEN3)
2311 return pseudoInverseEigen3(rank_in);
2312 #elif (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
2313 return pseudoInverseOpenCV(rank_in);
2314 #else
2315 (void)svThreshold;
2316 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
2317 "Install Lapack, Eigen3 or OpenCV 3rd party"));
2318 #endif
2319 }
2320
2321 #ifndef DOXYGEN_SHOULD_SKIP_THIS
2322 #if defined(VISP_HAVE_LAPACK)
2323 /*!
2324 Compute and return the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n
2325 matrix \f$\bf A\f$ using Lapack 3rd party.
2326
2327 \warning To inverse a square n-by-n matrix, you have to use rather one of
2328 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
2329 are kwown as faster.
2330
2331 \param svThreshold : Threshold used to test the singular values. If
2332 a singular value is lower than this threshold we consider that the
2333 matrix is not full rank.
2334
2335 \return The Moore-Penros pseudo inverse \f$ A^+ \f$.
2336
2337 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
2338
2339 \code
2340 #include <visp3/core/vpMatrix.h>
2341
2342 int main()
2343 {
2344 vpMatrix A(2, 3);
2345
2346 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
2347 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
2348
2349 A.print(std::cout, 10, "A: ");
2350
2351 vpMatrix A_p = A.pseudoInverseLapack();
2352
2353 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
2354 }
2355 \endcode
2356
2357 \sa pseudoInverse(double) const
2358 */
pseudoInverseLapack(double svThreshold) const2359 vpMatrix vpMatrix::pseudoInverseLapack(double svThreshold) const
2360 {
2361 unsigned int nrows = getRows();
2362 unsigned int ncols = getCols();
2363 int rank_out;
2364
2365 vpMatrix U, V, Ap;
2366 vpColVector sv;
2367
2368 Ap.resize(ncols, nrows, false, false);
2369
2370 if (nrows < ncols) {
2371 U.resize(ncols, ncols, true);
2372 sv.resize(nrows, false);
2373 } else {
2374 U.resize(nrows, ncols, false);
2375 sv.resize(ncols, false);
2376 }
2377
2378 U.insert(*this, 0, 0);
2379 U.svdLapack(sv, V);
2380
2381 compute_pseudo_inverse(U, sv, V, nrows, ncols, svThreshold, Ap, rank_out, NULL, NULL, NULL, NULL);
2382
2383 return Ap;
2384 }
2385
2386 /*!
2387 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
2388 A\f$ and return the rank of the matrix using Lapack 3rd party.
2389
2390 \warning To inverse a square n-by-n matrix, you have to use rather one of
2391 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
2392 are kwown as faster.
2393
2394 \param Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
2395
2396 \param svThreshold : Threshold used to test the singular values. If
2397 a singular value is lower than this threshold we consider that the
2398 matrix is not full rank.
2399
2400 \return The rank of the matrix.
2401
2402 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
2403
2404 \code
2405 #include <visp3/core/vpMatrix.h>
2406
2407 int main()
2408 {
2409 vpMatrix A(2, 3);
2410
2411 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
2412 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
2413
2414 A.print(std::cout, 10, "A: ");
2415
2416 vpMatrix A_p;
2417 unsigned int rank = A.pseudoInverseLapack(A_p);
2418
2419 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
2420 std::cout << "Rank: " << rank << std::endl;
2421 }
2422 \endcode
2423
2424 \sa pseudoInverse(vpMatrix &, double) const
2425 */
pseudoInverseLapack(vpMatrix & Ap,double svThreshold) const2426 unsigned int vpMatrix::pseudoInverseLapack(vpMatrix &Ap, double svThreshold) const
2427 {
2428 unsigned int nrows = getRows();
2429 unsigned int ncols = getCols();
2430 int rank_out;
2431
2432 vpMatrix U, V;
2433 vpColVector sv;
2434
2435 Ap.resize(ncols, nrows, false, false);
2436
2437 if (nrows < ncols) {
2438 U.resize(ncols, ncols, true);
2439 sv.resize(nrows, false);
2440 } else {
2441 U.resize(nrows, ncols, false);
2442 sv.resize(ncols, false);
2443 }
2444
2445 U.insert(*this, 0, 0);
2446 U.svdLapack(sv, V);
2447
2448 compute_pseudo_inverse(U, sv, V, nrows, ncols, svThreshold, Ap, rank_out, NULL, NULL, NULL, NULL);
2449
2450 return static_cast<unsigned int>(rank_out);
2451 }
2452 /*!
2453 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
2454 A\f$ along with singular values and return the rank of the matrix using
2455 Lapack 3rd party.
2456
2457 \warning To inverse a square n-by-n matrix, you have to use rather one of
2458 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
2459 are kwown as faster.
2460
2461 \param Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
2462
2463 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
2464 of this vector is equal to min(m, n).
2465
2466 \param svThreshold : Threshold used to test the singular values. If
2467 a singular value is lower than this threshold we consider that the
2468 matrix is not full rank.
2469
2470 \return The rank of the matrix \f$\bf A\f$.
2471
2472 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
2473
2474 \code
2475 #include <visp3/core/vpMatrix.h>
2476
2477 int main()
2478 {
2479 vpMatrix A(2, 3);
2480
2481 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
2482 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
2483
2484 A.print(std::cout, 10, "A: ");
2485
2486 vpMatrix A_p;
2487 vpColVector sv;
2488 unsigned int rank = A.pseudoInverseLapack(A_p, sv);
2489
2490 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
2491
2492 std::cout << "Rank: " << rank << std::endl;
2493 std::cout << "Singular values: " << sv.t() << std::endl;
2494 }
2495 \endcode
2496
2497 \sa pseudoInverse(vpMatrix &, vpColVector &, double) const
2498 */
pseudoInverseLapack(vpMatrix & Ap,vpColVector & sv,double svThreshold) const2499 unsigned int vpMatrix::pseudoInverseLapack(vpMatrix &Ap, vpColVector &sv, double svThreshold) const
2500 {
2501 unsigned int nrows = getRows();
2502 unsigned int ncols = getCols();
2503 int rank_out;
2504
2505 vpMatrix U, V;
2506 vpColVector sv_;
2507
2508 Ap.resize(ncols, nrows, false, false);
2509
2510 if (nrows < ncols) {
2511 U.resize(ncols, ncols, true);
2512 sv.resize(nrows, false);
2513 } else {
2514 U.resize(nrows, ncols, false);
2515 sv.resize(ncols, false);
2516 }
2517
2518 U.insert(*this, 0, 0);
2519 U.svdLapack(sv_, V);
2520
2521 compute_pseudo_inverse(U, sv_, V, nrows, ncols, svThreshold, Ap, rank_out, NULL, NULL, NULL, NULL);
2522
2523 // Remove singular values equal to the one that corresponds to the lines of 0
2524 // introduced when m < n
2525 memcpy(sv.data, sv_.data, sv.size() * sizeof(double));
2526
2527 return static_cast<unsigned int>(rank_out);
2528 }
2529
2530 /*!
2531 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
2532 A\f$ along with singular values, \f$\mbox{Im}(A)\f$, \f$\mbox{Im}(A^T)\f$ and
2533 \f$\mbox{Ker}(A)\f$ and return the rank of the matrix using Lapack 3rd
2534 party.
2535
2536 \warning To inverse a square n-by-n matrix, you have to use rather
2537 inverseByLU(), inverseByCholesky(), or inverseByQR() that are kwown as faster.
2538
2539 Using singular value decomposition, we have:
2540
2541 \f[
2542 {\bf A}_{m\times n} = {\bf U}_{m\times m} \; {\bf S}_{m\times n} \; {\bf
2543 V^\top}_{n\times n} \f] \f[
2544 {\bf A}_{m\times n} = \left[\begin{array}{ccc}\mbox{Im} ({\bf A}) & | &
2545 \mbox{Ker} ({\bf A}^\top) \end{array} \right] {\bf S}_{m\times n}
2546 \left[
2547 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
2548 \\
2549 \hline \\
2550 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
2551 \f]
2552
2553 where the diagonal of \f${\bf S}_{m\times n}\f$ corresponds to the matrix
2554 \f$A\f$ singular values.
2555
2556 This equation could be reformulated in a minimal way:
2557 \f[
2558 {\bf A}_{m\times n} = \mbox{Im} ({\bf A}) \; {\bf S}_{r\times n}
2559 \left[
2560 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
2561 \\
2562 \hline \\
2563 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
2564 \f]
2565
2566 where the diagonal of \f${\bf S}_{r\times n}\f$ corresponds to the matrix
2567 \f$A\f$ first r singular values.
2568
2569 The null space of a matrix \f$\bf A\f$ is defined as \f$\mbox{Ker}({\bf A})
2570 = { {\bf X} : {\bf A}*{\bf X} = {\bf 0}}\f$.
2571
2572 \param Ap: The Moore-Penros pseudo inverse \f$ {\bf A}^+ \f$.
2573
2574 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
2575 of this vector is equal to min(m, n).
2576
2577 \param svThreshold: Threshold used to test the singular values. If
2578 a singular value is lower than this threshold we consider that the
2579 matrix is not full rank.
2580
2581 \param imA: \f$\mbox{Im}({\bf A})\f$ that is a m-by-r matrix.
2582
2583 \param imAt: \f$\mbox{Im}({\bf A}^T)\f$ that is n-by-r matrix.
2584
2585 \param kerAt: The matrix that contains the null space (kernel) of \f$\bf
2586 A\f$ defined by the matrix \f${\bf X}^T\f$. If matrix \f$\bf A\f$ is full
2587 rank, the dimension of \c kerAt is (0, n), otherwise the dimension is (n-r,
2588 n). This matrix is thus the transpose of \f$\mbox{Ker}({\bf A})\f$.
2589
2590 \return The rank of the matrix \f$\bf A\f$.
2591
2592 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
2593
2594 \code
2595 #include <visp3/core/vpMatrix.h>
2596
2597 int main()
2598 {
2599 vpMatrix A(2, 3);
2600
2601 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
2602 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
2603
2604 A.print(std::cout, 10, "A: ");
2605
2606 vpColVector sv;
2607 vpMatrix A_p, imA, imAt, kerAt;
2608 unsigned int rank = A.pseudoInverseLapack(A_p, sv, 1e-6, imA, imAt, kerAt);
2609
2610 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
2611 std::cout << "Rank: " << rank << std::endl;
2612 std::cout << "Singular values: " << sv.t() << std::endl;
2613 imA.print(std::cout, 10, "Im(A): ");
2614 imAt.print(std::cout, 10, "Im(A^T): ");
2615
2616 if (kerAt.size()) {
2617 kerAt.t().print(std::cout, 10, "Ker(A): ");
2618 }
2619 else {
2620 std::cout << "Ker(A) empty " << std::endl;
2621 }
2622
2623 // Reconstruct matrix A from ImA, ImAt, KerAt
2624 vpMatrix S(rank, A.getCols());
2625 for(unsigned int i = 0; i< rank; i++)
2626 S[i][i] = sv[i];
2627 vpMatrix Vt(A.getCols(), A.getCols());
2628 Vt.insert(imAt.t(), 0, 0);
2629 Vt.insert(kerAt, rank, 0);
2630 (imA * S * Vt).print(std::cout, 10, "Im(A) * S * [Im(A^T) | Ker(A)]^T:");
2631 }
2632 \endcode
2633
2634 \sa pseudoInverse(vpMatrix &, vpColVector &, double, vpMatrix &, vpMatrix &, vpMatrix &) const
2635 */
pseudoInverseLapack(vpMatrix & Ap,vpColVector & sv,double svThreshold,vpMatrix & imA,vpMatrix & imAt,vpMatrix & kerAt) const2636 unsigned int vpMatrix::pseudoInverseLapack(vpMatrix &Ap, vpColVector &sv, double svThreshold, vpMatrix &imA,
2637 vpMatrix &imAt, vpMatrix &kerAt) const
2638 {
2639 unsigned int nrows = getRows();
2640 unsigned int ncols = getCols();
2641 int rank_out;
2642 vpMatrix U, V;
2643 vpColVector sv_;
2644
2645 if (nrows < ncols) {
2646 U.resize(ncols, ncols, true);
2647 sv.resize(nrows, false);
2648 } else {
2649 U.resize(nrows, ncols, false);
2650 sv.resize(ncols, false);
2651 }
2652
2653 U.insert(*this, 0, 0);
2654 U.svdLapack(sv_, V);
2655
2656 compute_pseudo_inverse(U, sv_, V, nrows, ncols, svThreshold, Ap, rank_out, NULL, &imA, &imAt, &kerAt);
2657
2658 // Remove singular values equal to the one that corresponds to the lines of 0
2659 // introduced when m < n
2660 memcpy(sv.data, sv_.data, sv.size() * sizeof(double));
2661
2662 return static_cast<unsigned int>(rank_out);
2663 }
2664
2665 /*!
2666 Compute and return the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n
2667 matrix \f$\bf A\f$ using Lapack 3rd party.
2668
2669 \warning To inverse a square n-by-n matrix, you have to use rather one of
2670 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
2671 are kwown as faster.
2672
2673 \param[in] rank_in : Known rank of the matrix.
2674 \return The Moore-Penros pseudo inverse \f$ A^+ \f$.
2675
2676 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
2677
2678 \code
2679 #include <visp3/core/vpMatrix.h>
2680
2681 int main()
2682 {
2683 vpMatrix A(2, 3);
2684
2685 // This matrix rank is 2
2686 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
2687 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
2688
2689 A.print(std::cout, 10, "A: ");
2690
2691 int rank_in = 2;
2692 vpMatrix A_p = A.pseudoInverseLapack(rank_in);
2693
2694 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
2695 return 0;
2696 }
2697 \endcode
2698
2699 \sa pseudoInverse(int) const
2700 */
pseudoInverseLapack(int rank_in) const2701 vpMatrix vpMatrix::pseudoInverseLapack(int rank_in) const
2702 {
2703 unsigned int nrows = getRows();
2704 unsigned int ncols = getCols();
2705 int rank_out;
2706 double svThreshold = 1e-26;
2707
2708 vpMatrix U, V, Ap;
2709 vpColVector sv;
2710
2711 Ap.resize(ncols, nrows, false, false);
2712
2713 if (nrows < ncols) {
2714 U.resize(ncols, ncols, true);
2715 sv.resize(nrows, false);
2716 } else {
2717 U.resize(nrows, ncols, false);
2718 sv.resize(ncols, false);
2719 }
2720
2721 U.insert(*this, 0, 0);
2722 U.svdLapack(sv, V);
2723
2724 compute_pseudo_inverse(U, sv, V, nrows, ncols, svThreshold, Ap, rank_out, &rank_in, NULL, NULL, NULL);
2725
2726 return Ap;
2727 }
2728
2729 /*!
2730 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
2731 A\f$ and return the rank of the matrix using Lapack 3rd party.
2732
2733 \warning To inverse a square n-by-n matrix, you have to use rather one of
2734 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
2735 are kwown as faster.
2736
2737 \param[out] Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
2738
2739 \param[in] rank_in : Known rank of the matrix.
2740
2741 \return The computed rank of the matrix.
2742
2743 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
2744
2745 \code
2746 #include <visp3/core/vpMatrix.h>
2747
2748 int main()
2749 {
2750 vpMatrix A(2, 3);
2751
2752 // This matrix rank is 2
2753 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
2754 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
2755
2756 A.print(std::cout, 10, "A: ");
2757
2758 vpMatrix A_p;
2759 int rank_in = 2;
2760 int rank_out = A.pseudoInverseLapack(A_p, rank_in);
2761 if (rank_out != rank_in) {
2762 std::cout << "There is a possibility that the pseudo-inverse in wrong." << std::endl;
2763 std::cout << "Are you sure that the matrix rank is " << rank_in << std::endl;
2764 }
2765
2766 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
2767 std::cout << "Rank in : " << rank_in << std::endl;
2768 std::cout << "Rank out: " << rank_out << std::endl;
2769 return 0;
2770 }
2771 \endcode
2772
2773 \sa pseudoInverse(vpMatrix &, int) const
2774 */
pseudoInverseLapack(vpMatrix & Ap,int rank_in) const2775 int vpMatrix::pseudoInverseLapack(vpMatrix &Ap, int rank_in) const
2776 {
2777 unsigned int nrows = getRows();
2778 unsigned int ncols = getCols();
2779 int rank_out;
2780 double svThreshold = 1e-26;
2781
2782 vpMatrix U, V;
2783 vpColVector sv;
2784
2785 Ap.resize(ncols, nrows, false, false);
2786
2787 if (nrows < ncols) {
2788 U.resize(ncols, ncols, true);
2789 sv.resize(nrows, false);
2790 } else {
2791 U.resize(nrows, ncols, false);
2792 sv.resize(ncols, false);
2793 }
2794
2795 U.insert(*this, 0, 0);
2796 U.svdLapack(sv, V);
2797
2798 compute_pseudo_inverse(U, sv, V, nrows, ncols, svThreshold, Ap, rank_out, &rank_in, NULL, NULL, NULL);
2799
2800 return rank_out;
2801 }
2802
2803 /*!
2804 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
2805 A\f$ along with singular values and return the rank of the matrix using
2806 Lapack 3rd party.
2807
2808 \warning To inverse a square n-by-n matrix, you have to use rather one of
2809 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
2810 are kwown as faster.
2811
2812 \param Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
2813
2814 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
2815 of this vector is equal to min(m, n).
2816
2817 \param[in] rank_in : Known rank of the matrix.
2818
2819 \return The rank of the matrix \f$\bf A\f$.
2820
2821 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
2822
2823 \code
2824 #include <visp3/core/vpMatrix.h>
2825
2826 int main()
2827 {
2828 vpMatrix A(2, 3);
2829
2830 // This matrix rank is 2
2831 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
2832 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
2833
2834 A.print(std::cout, 10, "A: ");
2835
2836 vpMatrix A_p;
2837 vpColVector sv;
2838 int rank_in = 2;
2839
2840 int rank_out = A.pseudoInverseLapack(A_p, sv, rank_in);
2841 if (rank_out != rank_in) {
2842 std::cout << "There is a possibility that the pseudo-inverse in wrong." << std::endl;
2843 std::cout << "Are you sure that the matrix rank is " << rank_in << std::endl;
2844 }
2845
2846 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
2847 std::cout << "Rank in : " << rank_in << std::endl;
2848 std::cout << "Rank out: " << rank_out << std::endl;
2849 std::cout << "Singular values: " << sv.t() << std::endl;
2850 return 0;
2851 }
2852 \endcode
2853
2854 \sa pseudoInverse(vpMatrix &, vpColVector &, int) const
2855 */
pseudoInverseLapack(vpMatrix & Ap,vpColVector & sv,int rank_in) const2856 int vpMatrix::pseudoInverseLapack(vpMatrix &Ap, vpColVector &sv, int rank_in) const
2857 {
2858 unsigned int nrows = getRows();
2859 unsigned int ncols = getCols();
2860 int rank_out;
2861 double svThreshold = 1e-26;
2862
2863 vpMatrix U, V;
2864 vpColVector sv_;
2865
2866 Ap.resize(ncols, nrows, false, false);
2867
2868 if (nrows < ncols) {
2869 U.resize(ncols, ncols, true);
2870 sv.resize(nrows, false);
2871 } else {
2872 U.resize(nrows, ncols, false);
2873 sv.resize(ncols, false);
2874 }
2875
2876 U.insert(*this, 0, 0);
2877 U.svdLapack(sv_, V);
2878
2879 compute_pseudo_inverse(U, sv_, V, nrows, ncols, svThreshold, Ap, rank_out, &rank_in, NULL, NULL, NULL);
2880
2881 // Remove singular values equal to the one that corresponds to the lines of 0
2882 // introduced when m < n
2883 memcpy(sv.data, sv_.data, sv.size() * sizeof(double));
2884
2885 return rank_out;
2886 }
2887
2888 /*!
2889 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
2890 A\f$ along with singular values, \f$\mbox{Im}(A)\f$, \f$\mbox{Im}(A^T)\f$ and
2891 \f$\mbox{Ker}(A)\f$ and return the rank of the matrix using Lapack 3rd
2892 party.
2893
2894 \warning To inverse a square n-by-n matrix, you have to use rather
2895 inverseByLU(), inverseByCholesky(), or inverseByQR() that are kwown as faster.
2896
2897 Using singular value decomposition, we have:
2898
2899 \f[
2900 {\bf A}_{m\times n} = {\bf U}_{m\times m} \; {\bf S}_{m\times n} \; {\bf
2901 V^\top}_{n\times n} \f] \f[
2902 {\bf A}_{m\times n} = \left[\begin{array}{ccc}\mbox{Im} ({\bf A}) & | &
2903 \mbox{Ker} ({\bf A}^\top) \end{array} \right] {\bf S}_{m\times n}
2904 \left[
2905 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
2906 \\
2907 \hline \\
2908 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
2909 \f]
2910
2911 where the diagonal of \f${\bf S}_{m\times n}\f$ corresponds to the matrix
2912 \f$A\f$ singular values.
2913
2914 This equation could be reformulated in a minimal way:
2915 \f[
2916 {\bf A}_{m\times n} = \mbox{Im} ({\bf A}) \; {\bf S}_{r\times n}
2917 \left[
2918 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
2919 \\
2920 \hline \\
2921 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
2922 \f]
2923
2924 where the diagonal of \f${\bf S}_{r\times n}\f$ corresponds to the matrix
2925 \f$A\f$ first r singular values.
2926
2927 The null space of a matrix \f$\bf A\f$ is defined as \f$\mbox{Ker}({\bf A})
2928 = { {\bf X} : {\bf A}*{\bf X} = {\bf 0}}\f$.
2929
2930 \param Ap: The Moore-Penros pseudo inverse \f$ {\bf A}^+ \f$.
2931
2932 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
2933 of this vector is equal to min(m, n).
2934
2935 \param[in] rank_in : Known rank of the matrix.
2936
2937 \param imA: \f$\mbox{Im}({\bf A})\f$ that is a m-by-r matrix.
2938
2939 \param imAt: \f$\mbox{Im}({\bf A}^T)\f$ that is n-by-r matrix.
2940
2941 \param kerAt: The matrix that contains the null space (kernel) of \f$\bf
2942 A\f$ defined by the matrix \f${\bf X}^T\f$. If matrix \f$\bf A\f$ is full
2943 rank, the dimension of \c kerAt is (0, n), otherwise the dimension is (n-r,
2944 n). This matrix is thus the transpose of \f$\mbox{Ker}({\bf A})\f$.
2945
2946 \return The rank of the matrix \f$\bf A\f$.
2947
2948 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
2949
2950 \code
2951 #include <visp3/core/vpMatrix.h>
2952
2953 int main()
2954 {
2955 vpMatrix A(2, 3);
2956
2957 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
2958 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
2959
2960 A.print(std::cout, 10, "A: ");
2961
2962 vpColVector sv;
2963 vpMatrix A_p, imA, imAt, kerAt;
2964 int rank_in = 2;
2965 int rank_out = A.pseudoInverseLapack(A_p, sv, rank_in, imA, imAt, kerAt);
2966
2967 if (rank_out != rank_in) {
2968 std::cout << "There is a possibility that the pseudo-inverse in wrong." << std::endl;
2969 std::cout << "Are you sure that the matrix rank is " << rank_in << std::endl;
2970 }
2971
2972 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
2973 std::cout << "Rank in : " << rank_in << std::endl;
2974 std::cout << "Rank out: " << rank_out << std::endl;
2975 std::cout << "Singular values: " << sv.t() << std::endl;
2976 imA.print(std::cout, 10, "Im(A): ");
2977 imAt.print(std::cout, 10, "Im(A^T): ");
2978
2979 if (kerAt.size()) {
2980 kerAt.t().print(std::cout, 10, "Ker(A): ");
2981 }
2982 else {
2983 std::cout << "Ker(A) empty " << std::endl;
2984 }
2985
2986 // Reconstruct matrix A from ImA, ImAt, KerAt
2987 vpMatrix S(rank_in, A.getCols());
2988 for(unsigned int i = 0; i< rank_in; i++)
2989 S[i][i] = sv[i];
2990 vpMatrix Vt(A.getCols(), A.getCols());
2991 Vt.insert(imAt.t(), 0, 0);
2992 Vt.insert(kerAt, rank_in, 0);
2993 (imA * S * Vt).print(std::cout, 10, "Im(A) * S * [Im(A^T) | Ker(A)]^T:");
2994 }
2995 \endcode
2996
2997 \sa pseudoInverse(vpMatrix &, vpColVector &, int, vpMatrix &, vpMatrix &, vpMatrix &) const
2998 */
pseudoInverseLapack(vpMatrix & Ap,vpColVector & sv,int rank_in,vpMatrix & imA,vpMatrix & imAt,vpMatrix & kerAt) const2999 int vpMatrix::pseudoInverseLapack(vpMatrix &Ap, vpColVector &sv, int rank_in, vpMatrix &imA,
3000 vpMatrix &imAt, vpMatrix &kerAt) const
3001 {
3002 unsigned int nrows = getRows();
3003 unsigned int ncols = getCols();
3004 int rank_out;
3005 double svThreshold = 1e-26;
3006 vpMatrix U, V;
3007 vpColVector sv_;
3008
3009 if (nrows < ncols) {
3010 U.resize(ncols, ncols, true);
3011 sv.resize(nrows, false);
3012 } else {
3013 U.resize(nrows, ncols, false);
3014 sv.resize(ncols, false);
3015 }
3016
3017 U.insert(*this, 0, 0);
3018 U.svdLapack(sv_, V);
3019
3020 compute_pseudo_inverse(U, sv_, V, nrows, ncols, svThreshold, Ap, rank_out, &rank_in, &imA, &imAt, &kerAt);
3021
3022 // Remove singular values equal to the one that corresponds to the lines of 0
3023 // introduced when m < n
3024 memcpy(sv.data, sv_.data, sv.size() * sizeof(double));
3025
3026 return rank_out;
3027 }
3028
3029 #endif
3030 #if defined(VISP_HAVE_EIGEN3)
3031 /*!
3032 Compute and return the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n
3033 matrix \f$\bf A\f$ using Eigen3 3rd party.
3034
3035 \warning To inverse a square n-by-n matrix, you have to use rather one of
3036 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
3037 are kwown as faster.
3038
3039 \param svThreshold : Threshold used to test the singular values. If
3040 a singular value is lower than this threshold we consider that the
3041 matrix is not full rank.
3042
3043 \return The Moore-Penros pseudo inverse \f$ A^+ \f$.
3044
3045 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
3046
3047 \code
3048 #include <visp3/core/vpMatrix.h>
3049
3050 int main()
3051 {
3052 vpMatrix A(2, 3);
3053
3054 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
3055 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
3056
3057 A.print(std::cout, 10, "A: ");
3058
3059 vpMatrix A_p = A.pseudoInverseEigen3();
3060
3061 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
3062 }
3063 \endcode
3064
3065 \sa pseudoInverse(double)
3066 */
pseudoInverseEigen3(double svThreshold) const3067 vpMatrix vpMatrix::pseudoInverseEigen3(double svThreshold) const
3068 {
3069 unsigned int nrows = getRows();
3070 unsigned int ncols = getCols();
3071 int rank_out;
3072
3073 vpMatrix U, V, Ap;
3074 vpColVector sv;
3075
3076 Ap.resize(ncols, nrows, false, false);
3077
3078 if (nrows < ncols) {
3079 U.resize(ncols, ncols, true);
3080 sv.resize(nrows, false);
3081 } else {
3082 U.resize(nrows, ncols, false);
3083 sv.resize(ncols, false);
3084 }
3085
3086 U.insert(*this, 0, 0);
3087 U.svdEigen3(sv, V);
3088
3089 compute_pseudo_inverse(U, sv, V, nrows, ncols, svThreshold, Ap, rank_out, NULL, NULL, NULL, NULL);
3090
3091 return Ap;
3092 }
3093
3094 /*!
3095 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
3096 A\f$ and return the rank of the matrix using Eigen3 3rd party.
3097
3098 \warning To inverse a square n-by-n matrix, you have to use rather one of
3099 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
3100 are kwown as faster.
3101
3102 \param Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
3103
3104 \param svThreshold : Threshold used to test the singular values. If
3105 a singular value is lower than this threshold we consider that the
3106 matrix is not full rank.
3107
3108 \return The rank of the matrix.
3109
3110 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
3111
3112 \code
3113 #include <visp3/core/vpMatrix.h>
3114
3115 int main()
3116 {
3117 vpMatrix A(2, 3);
3118
3119 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
3120 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
3121
3122 A.print(std::cout, 10, "A: ");
3123
3124 vpMatrix A_p;
3125 unsigned int rank = A.pseudoInverseEigen3(A_p);
3126
3127 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
3128 std::cout << "Rank: " << rank << std::endl;
3129 }
3130 \endcode
3131
3132 \sa pseudoInverse(vpMatrix &, double) const
3133 */
pseudoInverseEigen3(vpMatrix & Ap,double svThreshold) const3134 unsigned int vpMatrix::pseudoInverseEigen3(vpMatrix &Ap, double svThreshold) const
3135 {
3136 unsigned int nrows = getRows();
3137 unsigned int ncols = getCols();
3138 int rank_out;
3139
3140 vpMatrix U, V;
3141 vpColVector sv;
3142
3143 Ap.resize(ncols, nrows, false, false);
3144
3145 if (nrows < ncols) {
3146 U.resize(ncols, ncols, true);
3147 sv.resize(nrows, false);
3148 } else {
3149 U.resize(nrows, ncols, false);
3150 sv.resize(ncols, false);
3151 }
3152
3153 U.insert(*this, 0, 0);
3154 U.svdEigen3(sv, V);
3155
3156 compute_pseudo_inverse(U, sv, V, nrows, ncols, svThreshold, Ap, rank_out, NULL, NULL, NULL, NULL);
3157
3158 return static_cast<unsigned int>(rank_out);
3159 }
3160 /*!
3161 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
3162 A\f$ along with singular values and return the rank of the matrix using
3163 Eigen3 3rd party.
3164
3165 \warning To inverse a square n-by-n matrix, you have to use rather one of
3166 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
3167 are kwown as faster.
3168
3169 \param Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
3170
3171 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
3172 of this vector is equal to min(m, n).
3173
3174 \param svThreshold : Threshold used to test the singular values. If
3175 a singular value is lower than this threshold we consider that the
3176 matrix is not full rank.
3177
3178 \return The rank of the matrix \f$\bf A\f$.
3179
3180 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
3181
3182 \code
3183 #include <visp3/core/vpMatrix.h>
3184
3185 int main()
3186 {
3187 vpMatrix A(2, 3);
3188
3189 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
3190 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
3191
3192 A.print(std::cout, 10, "A: ");
3193
3194 vpMatrix A_p;
3195 vpColVector sv;
3196 unsigned int rank = A.pseudoInverseEigen3(A_p, sv);
3197
3198 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
3199
3200 std::cout << "Rank: " << rank << std::endl;
3201 std::cout << "Singular values: " << sv.t() << std::endl;
3202 }
3203 \endcode
3204
3205 \sa pseudoInverse(vpMatrix &, vpColVector &, double) const
3206 */
pseudoInverseEigen3(vpMatrix & Ap,vpColVector & sv,double svThreshold) const3207 unsigned int vpMatrix::pseudoInverseEigen3(vpMatrix &Ap, vpColVector &sv, double svThreshold) const
3208 {
3209 unsigned int nrows = getRows();
3210 unsigned int ncols = getCols();
3211 int rank_out;
3212
3213 vpMatrix U, V;
3214 vpColVector sv_;
3215
3216 Ap.resize(ncols, nrows, false, false);
3217
3218 if (nrows < ncols) {
3219 U.resize(ncols, ncols, true);
3220 sv.resize(nrows, false);
3221 } else {
3222 U.resize(nrows, ncols, false);
3223 sv.resize(ncols, false);
3224 }
3225
3226 U.insert(*this, 0, 0);
3227 U.svdEigen3(sv_, V);
3228
3229 compute_pseudo_inverse(U, sv_, V, nrows, ncols, svThreshold, Ap, rank_out, NULL, NULL, NULL, NULL);
3230
3231 // Remove singular values equal to the one that corresponds to the lines of 0
3232 // introduced when m < n
3233 memcpy(sv.data, sv_.data, sv.size() * sizeof(double));
3234
3235 return static_cast<unsigned int>(rank_out);
3236 }
3237
3238 /*!
3239 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
3240 A\f$ along with singular values, \f$\mbox{Im}(A)\f$, \f$\mbox{Im}(A^T)\f$ and
3241 \f$\mbox{Ker}(A)\f$ and return the rank of the matrix using Eigen3 3rd
3242 party.
3243
3244 \warning To inverse a square n-by-n matrix, you have to use rather
3245 inverseByLU(), inverseByCholesky(), or inverseByQR() that are kwown as faster.
3246
3247 Using singular value decomposition, we have:
3248
3249 \f[
3250 {\bf A}_{m\times n} = {\bf U}_{m\times m} \; {\bf S}_{m\times n} \; {\bf
3251 V^\top}_{n\times n} \f] \f[
3252 {\bf A}_{m\times n} = \left[\begin{array}{ccc}\mbox{Im} ({\bf A}) & | &
3253 \mbox{Ker} ({\bf A}^\top) \end{array} \right] {\bf S}_{m\times n}
3254 \left[
3255 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
3256 \\
3257 \hline \\
3258 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
3259 \f]
3260
3261 where the diagonal of \f${\bf S}_{m\times n}\f$ corresponds to the matrix
3262 \f$A\f$ singular values.
3263
3264 This equation could be reformulated in a minimal way:
3265 \f[
3266 {\bf A}_{m\times n} = \mbox{Im} ({\bf A}) \; {\bf S}_{r\times n}
3267 \left[
3268 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
3269 \\
3270 \hline \\
3271 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
3272 \f]
3273
3274 where the diagonal of \f${\bf S}_{r\times n}\f$ corresponds to the matrix
3275 \f$A\f$ first r singular values.
3276
3277 The null space of a matrix \f$\bf A\f$ is defined as \f$\mbox{Ker}({\bf A})
3278 = { {\bf X} : {\bf A}*{\bf X} = {\bf 0}}\f$.
3279
3280 \param Ap: The Moore-Penros pseudo inverse \f$ {\bf A}^+ \f$.
3281
3282 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
3283 of this vector is equal to min(m, n).
3284
3285 \param svThreshold: Threshold used to test the singular values. If
3286 a singular value is lower than this threshold we consider that the
3287 matrix is not full rank.
3288
3289 \param imA: \f$\mbox{Im}({\bf A})\f$ that is a m-by-r matrix.
3290
3291 \param imAt: \f$\mbox{Im}({\bf A}^T)\f$ that is n-by-r matrix.
3292
3293 \param kerAt: The matrix that contains the null space (kernel) of \f$\bf
3294 A\f$ defined by the matrix \f${\bf X}^T\f$. If matrix \f$\bf A\f$ is full
3295 rank, the dimension of \c kerAt is (0, n), otherwise the dimension is (n-r,
3296 n). This matrix is thus the transpose of \f$\mbox{Ker}({\bf A})\f$.
3297
3298 \return The rank of the matrix \f$\bf A\f$.
3299
3300 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
3301
3302 \code
3303 #include <visp3/core/vpMatrix.h>
3304
3305 int main()
3306 {
3307 vpMatrix A(2, 3);
3308
3309 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
3310 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
3311
3312 A.print(std::cout, 10, "A: ");
3313
3314 vpColVector sv;
3315 vpMatrix A_p, imA, imAt, kerAt;
3316 unsigned int rank = A.pseudoInverseEigen3(A_p, sv, 1e-6, imA, imAt, kerAt);
3317
3318 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
3319 std::cout << "Rank: " << rank << std::endl;
3320 std::cout << "Singular values: " << sv.t() << std::endl;
3321 imA.print(std::cout, 10, "Im(A): ");
3322 imAt.print(std::cout, 10, "Im(A^T): ");
3323
3324 if (kerAt.size()) {
3325 kerAt.t().print(std::cout, 10, "Ker(A): ");
3326 }
3327 else {
3328 std::cout << "Ker(A) empty " << std::endl;
3329 }
3330
3331 // Reconstruct matrix A from ImA, ImAt, KerAt
3332 vpMatrix S(rank, A.getCols());
3333 for(unsigned int i = 0; i< rank; i++)
3334 S[i][i] = sv[i];
3335 vpMatrix Vt(A.getCols(), A.getCols());
3336 Vt.insert(imAt.t(), 0, 0);
3337 Vt.insert(kerAt, rank, 0);
3338 (imA * S * Vt).print(std::cout, 10, "Im(A) * S * [Im(A^T) | Ker(A)]^T:");
3339 }
3340 \endcode
3341
3342 \sa pseudoInverse(vpMatrix &, vpColVector &, double, vpMatrix &, vpMatrix &, vpMatrix &) const
3343 */
pseudoInverseEigen3(vpMatrix & Ap,vpColVector & sv,double svThreshold,vpMatrix & imA,vpMatrix & imAt,vpMatrix & kerAt) const3344 unsigned int vpMatrix::pseudoInverseEigen3(vpMatrix &Ap, vpColVector &sv, double svThreshold, vpMatrix &imA,
3345 vpMatrix &imAt, vpMatrix &kerAt) const
3346 {
3347 unsigned int nrows = getRows();
3348 unsigned int ncols = getCols();
3349 int rank_out;
3350 vpMatrix U, V;
3351 vpColVector sv_;
3352
3353 if (nrows < ncols) {
3354 U.resize(ncols, ncols, true);
3355 sv.resize(nrows, false);
3356 } else {
3357 U.resize(nrows, ncols, false);
3358 sv.resize(ncols, false);
3359 }
3360
3361 U.insert(*this, 0, 0);
3362 U.svdEigen3(sv_, V);
3363
3364 compute_pseudo_inverse(U, sv_, V, nrows, ncols, svThreshold, Ap, rank_out, NULL, &imA, &imAt, &kerAt);
3365
3366 // Remove singular values equal to the one that corresponds to the lines of 0
3367 // introduced when m < n
3368 memcpy(sv.data, sv_.data, sv.size() * sizeof(double));
3369
3370 return static_cast<unsigned int>(rank_out);
3371 }
3372
3373 /*!
3374 Compute and return the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n
3375 matrix \f$\bf A\f$ using Eigen3 3rd party.
3376
3377 \warning To inverse a square n-by-n matrix, you have to use rather one of
3378 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
3379 are kwown as faster.
3380
3381 \param[in] rank_in : Known rank of the matrix.
3382 \return The Moore-Penros pseudo inverse \f$ A^+ \f$.
3383
3384 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
3385
3386 \code
3387 #include <visp3/core/vpMatrix.h>
3388
3389 int main()
3390 {
3391 vpMatrix A(2, 3);
3392
3393 // This matrix rank is 2
3394 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
3395 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
3396
3397 A.print(std::cout, 10, "A: ");
3398
3399 int rank_in = 2;
3400 vpMatrix A_p = A.pseudoInverseEigen3(rank_in);
3401
3402 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
3403 return 0;
3404 }
3405 \endcode
3406
3407 \sa pseudoInverse(int) const
3408 */
pseudoInverseEigen3(int rank_in) const3409 vpMatrix vpMatrix::pseudoInverseEigen3(int rank_in) const
3410 {
3411 unsigned int nrows = getRows();
3412 unsigned int ncols = getCols();
3413 int rank_out;
3414 double svThreshold = 1e-26;
3415
3416 vpMatrix U, V, Ap;
3417 vpColVector sv;
3418
3419 Ap.resize(ncols, nrows, false, false);
3420
3421 if (nrows < ncols) {
3422 U.resize(ncols, ncols, true);
3423 sv.resize(nrows, false);
3424 } else {
3425 U.resize(nrows, ncols, false);
3426 sv.resize(ncols, false);
3427 }
3428
3429 U.insert(*this, 0, 0);
3430 U.svdEigen3(sv, V);
3431
3432 compute_pseudo_inverse(U, sv, V, nrows, ncols, svThreshold, Ap, rank_out, &rank_in, NULL, NULL, NULL);
3433
3434 return Ap;
3435 }
3436
3437 /*!
3438 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
3439 A\f$ and return the rank of the matrix using Eigen3 3rd party.
3440
3441 \warning To inverse a square n-by-n matrix, you have to use rather one of
3442 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
3443 are kwown as faster.
3444
3445 \param[out] Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
3446
3447 \param[in] rank_in : Known rank of the matrix.
3448
3449 \return The computed rank of the matrix.
3450
3451 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
3452
3453 \code
3454 #include <visp3/core/vpMatrix.h>
3455
3456 int main()
3457 {
3458 vpMatrix A(2, 3);
3459
3460 // This matrix rank is 2
3461 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
3462 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
3463
3464 A.print(std::cout, 10, "A: ");
3465
3466 vpMatrix A_p;
3467 int rank_in = 2;
3468 int rank_out = A.pseudoInverseEigen3(A_p, rank_in);
3469 if (rank_out != rank_in) {
3470 std::cout << "There is a possibility that the pseudo-inverse in wrong." << std::endl;
3471 std::cout << "Are you sure that the matrix rank is " << rank_in << std::endl;
3472 }
3473
3474 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
3475 std::cout << "Rank in : " << rank_in << std::endl;
3476 std::cout << "Rank out: " << rank_out << std::endl;
3477 return 0;
3478 }
3479 \endcode
3480
3481 \sa pseudoInverse(vpMatrix &, int) const
3482 */
pseudoInverseEigen3(vpMatrix & Ap,int rank_in) const3483 int vpMatrix::pseudoInverseEigen3(vpMatrix &Ap, int rank_in) const
3484 {
3485 unsigned int nrows = getRows();
3486 unsigned int ncols = getCols();
3487 int rank_out;
3488 double svThreshold = 1e-26;
3489
3490 vpMatrix U, V;
3491 vpColVector sv;
3492
3493 Ap.resize(ncols, nrows, false, false);
3494
3495 if (nrows < ncols) {
3496 U.resize(ncols, ncols, true);
3497 sv.resize(nrows, false);
3498 } else {
3499 U.resize(nrows, ncols, false);
3500 sv.resize(ncols, false);
3501 }
3502
3503 U.insert(*this, 0, 0);
3504 U.svdEigen3(sv, V);
3505
3506 compute_pseudo_inverse(U, sv, V, nrows, ncols, svThreshold, Ap, rank_out, &rank_in, NULL, NULL, NULL);
3507
3508 return rank_out;
3509 }
3510
3511 /*!
3512 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
3513 A\f$ along with singular values and return the rank of the matrix using
3514 Eigen3 3rd party.
3515
3516 \warning To inverse a square n-by-n matrix, you have to use rather one of
3517 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
3518 are kwown as faster.
3519
3520 \param Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
3521
3522 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
3523 of this vector is equal to min(m, n).
3524
3525 \param[in] rank_in : Known rank of the matrix.
3526
3527 \return The rank of the matrix \f$\bf A\f$.
3528
3529 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
3530
3531 \code
3532 #include <visp3/core/vpMatrix.h>
3533
3534 int main()
3535 {
3536 vpMatrix A(2, 3);
3537
3538 // This matrix rank is 2
3539 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
3540 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
3541
3542 A.print(std::cout, 10, "A: ");
3543
3544 vpMatrix A_p;
3545 vpColVector sv;
3546 int rank_in = 2;
3547
3548 int rank_out = A.pseudoInverseEigen3(A_p, sv, rank_in);
3549 if (rank_out != rank_in) {
3550 std::cout << "There is a possibility that the pseudo-inverse in wrong." << std::endl;
3551 std::cout << "Are you sure that the matrix rank is " << rank_in << std::endl;
3552 }
3553
3554 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
3555 std::cout << "Rank in : " << rank_in << std::endl;
3556 std::cout << "Rank out: " << rank_out << std::endl;
3557 std::cout << "Singular values: " << sv.t() << std::endl;
3558 return 0;
3559 }
3560 \endcode
3561
3562 \sa pseudoInverse(vpMatrix &, vpColVector &, int) const
3563 */
pseudoInverseEigen3(vpMatrix & Ap,vpColVector & sv,int rank_in) const3564 int vpMatrix::pseudoInverseEigen3(vpMatrix &Ap, vpColVector &sv, int rank_in) const
3565 {
3566 unsigned int nrows = getRows();
3567 unsigned int ncols = getCols();
3568 int rank_out;
3569 double svThreshold = 1e-26;
3570
3571 vpMatrix U, V;
3572 vpColVector sv_;
3573
3574 Ap.resize(ncols, nrows, false, false);
3575
3576 if (nrows < ncols) {
3577 U.resize(ncols, ncols, true);
3578 sv.resize(nrows, false);
3579 } else {
3580 U.resize(nrows, ncols, false);
3581 sv.resize(ncols, false);
3582 }
3583
3584 U.insert(*this, 0, 0);
3585 U.svdEigen3(sv_, V);
3586
3587 compute_pseudo_inverse(U, sv_, V, nrows, ncols, svThreshold, Ap, rank_out, &rank_in, NULL, NULL, NULL);
3588
3589 // Remove singular values equal to the one that corresponds to the lines of 0
3590 // introduced when m < n
3591 memcpy(sv.data, sv_.data, sv.size() * sizeof(double));
3592
3593 return rank_out;
3594 }
3595
3596 /*!
3597 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
3598 A\f$ along with singular values, \f$\mbox{Im}(A)\f$, \f$\mbox{Im}(A^T)\f$ and
3599 \f$\mbox{Ker}(A)\f$ and return the rank of the matrix using Eigen3 3rd
3600 party.
3601
3602 \warning To inverse a square n-by-n matrix, you have to use rather
3603 inverseByLU(), inverseByCholesky(), or inverseByQR() that are kwown as faster.
3604
3605 Using singular value decomposition, we have:
3606
3607 \f[
3608 {\bf A}_{m\times n} = {\bf U}_{m\times m} \; {\bf S}_{m\times n} \; {\bf
3609 V^\top}_{n\times n} \f] \f[
3610 {\bf A}_{m\times n} = \left[\begin{array}{ccc}\mbox{Im} ({\bf A}) & | &
3611 \mbox{Ker} ({\bf A}^\top) \end{array} \right] {\bf S}_{m\times n}
3612 \left[
3613 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
3614 \\
3615 \hline \\
3616 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
3617 \f]
3618
3619 where the diagonal of \f${\bf S}_{m\times n}\f$ corresponds to the matrix
3620 \f$A\f$ singular values.
3621
3622 This equation could be reformulated in a minimal way:
3623 \f[
3624 {\bf A}_{m\times n} = \mbox{Im} ({\bf A}) \; {\bf S}_{r\times n}
3625 \left[
3626 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
3627 \\
3628 \hline \\
3629 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
3630 \f]
3631
3632 where the diagonal of \f${\bf S}_{r\times n}\f$ corresponds to the matrix
3633 \f$A\f$ first r singular values.
3634
3635 The null space of a matrix \f$\bf A\f$ is defined as \f$\mbox{Ker}({\bf A})
3636 = { {\bf X} : {\bf A}*{\bf X} = {\bf 0}}\f$.
3637
3638 \param Ap: The Moore-Penros pseudo inverse \f$ {\bf A}^+ \f$.
3639
3640 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
3641 of this vector is equal to min(m, n).
3642
3643 \param[in] rank_in : Known rank of the matrix.
3644
3645 \param imA: \f$\mbox{Im}({\bf A})\f$ that is a m-by-r matrix.
3646
3647 \param imAt: \f$\mbox{Im}({\bf A}^T)\f$ that is n-by-r matrix.
3648
3649 \param kerAt: The matrix that contains the null space (kernel) of \f$\bf
3650 A\f$ defined by the matrix \f${\bf X}^T\f$. If matrix \f$\bf A\f$ is full
3651 rank, the dimension of \c kerAt is (0, n), otherwise the dimension is (n-r,
3652 n). This matrix is thus the transpose of \f$\mbox{Ker}({\bf A})\f$.
3653
3654 \return The rank of the matrix \f$\bf A\f$.
3655
3656 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
3657
3658 \code
3659 #include <visp3/core/vpMatrix.h>
3660
3661 int main()
3662 {
3663 vpMatrix A(2, 3);
3664
3665 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
3666 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
3667
3668 A.print(std::cout, 10, "A: ");
3669
3670 vpColVector sv;
3671 vpMatrix A_p, imA, imAt, kerAt;
3672 int rank_in = 2;
3673 int rank_out = A.pseudoInverseEigen3(A_p, sv, rank_in, imA, imAt, kerAt);
3674
3675 if (rank_out != rank_in) {
3676 std::cout << "There is a possibility that the pseudo-inverse in wrong." << std::endl;
3677 std::cout << "Are you sure that the matrix rank is " << rank_in << std::endl;
3678 }
3679
3680 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
3681 std::cout << "Rank in : " << rank_in << std::endl;
3682 std::cout << "Rank out: " << rank_out << std::endl;
3683 std::cout << "Singular values: " << sv.t() << std::endl;
3684 imA.print(std::cout, 10, "Im(A): ");
3685 imAt.print(std::cout, 10, "Im(A^T): ");
3686
3687 if (kerAt.size()) {
3688 kerAt.t().print(std::cout, 10, "Ker(A): ");
3689 }
3690 else {
3691 std::cout << "Ker(A) empty " << std::endl;
3692 }
3693
3694 // Reconstruct matrix A from ImA, ImAt, KerAt
3695 vpMatrix S(rank_in, A.getCols());
3696 for(unsigned int i = 0; i< rank_in; i++)
3697 S[i][i] = sv[i];
3698 vpMatrix Vt(A.getCols(), A.getCols());
3699 Vt.insert(imAt.t(), 0, 0);
3700 Vt.insert(kerAt, rank_in, 0);
3701 (imA * S * Vt).print(std::cout, 10, "Im(A) * S * [Im(A^T) | Ker(A)]^T:");
3702 }
3703 \endcode
3704
3705 \sa pseudoInverse(vpMatrix &, vpColVector &, int, vpMatrix &, vpMatrix &, vpMatrix &) const
3706 */
pseudoInverseEigen3(vpMatrix & Ap,vpColVector & sv,int rank_in,vpMatrix & imA,vpMatrix & imAt,vpMatrix & kerAt) const3707 int vpMatrix::pseudoInverseEigen3(vpMatrix &Ap, vpColVector &sv, int rank_in, vpMatrix &imA,
3708 vpMatrix &imAt, vpMatrix &kerAt) const
3709 {
3710 unsigned int nrows = getRows();
3711 unsigned int ncols = getCols();
3712 int rank_out;
3713 double svThreshold = 1e-26;
3714 vpMatrix U, V;
3715 vpColVector sv_;
3716
3717 if (nrows < ncols) {
3718 U.resize(ncols, ncols, true);
3719 sv.resize(nrows, false);
3720 } else {
3721 U.resize(nrows, ncols, false);
3722 sv.resize(ncols, false);
3723 }
3724
3725 U.insert(*this, 0, 0);
3726 U.svdEigen3(sv_, V);
3727
3728 compute_pseudo_inverse(U, sv_, V, nrows, ncols, svThreshold, Ap, rank_out, &rank_in, &imA, &imAt, &kerAt);
3729
3730 // Remove singular values equal to the one that corresponds to the lines of 0
3731 // introduced when m < n
3732 memcpy(sv.data, sv_.data, sv.size() * sizeof(double));
3733
3734 return rank_out;
3735 }
3736
3737 #endif
3738 #if (VISP_HAVE_OPENCV_VERSION >= 0x020101)
3739 /*!
3740 Compute and return the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n
3741 matrix \f$\bf A\f$ using OpenCV 3rd party.
3742
3743 \warning To inverse a square n-by-n matrix, you have to use rather one of
3744 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
3745 are kwown as faster.
3746
3747 \param svThreshold : Threshold used to test the singular values. If
3748 a singular value is lower than this threshold we consider that the
3749 matrix is not full rank.
3750
3751 \return The Moore-Penros pseudo inverse \f$ A^+ \f$.
3752
3753 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
3754
3755 \code
3756 #include <visp3/core/vpMatrix.h>
3757
3758 int main()
3759 {
3760 vpMatrix A(2, 3);
3761
3762 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
3763 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
3764
3765 A.print(std::cout, 10, "A: ");
3766
3767 vpMatrix A_p = A.pseudoInverseEigen3();
3768
3769 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
3770 }
3771 \endcode
3772
3773 \sa pseudoInverse(double) const
3774 */
pseudoInverseOpenCV(double svThreshold) const3775 vpMatrix vpMatrix::pseudoInverseOpenCV(double svThreshold) const
3776 {
3777 unsigned int nrows = getRows();
3778 unsigned int ncols = getCols();
3779 int rank_out;
3780
3781 vpMatrix U, V, Ap;
3782 vpColVector sv;
3783
3784 Ap.resize(ncols, nrows, false, false);
3785
3786 if (nrows < ncols) {
3787 U.resize(ncols, ncols, true);
3788 sv.resize(nrows, false);
3789 } else {
3790 U.resize(nrows, ncols, false);
3791 sv.resize(ncols, false);
3792 }
3793
3794 U.insert(*this, 0, 0);
3795 U.svdOpenCV(sv, V);
3796
3797 compute_pseudo_inverse(U, sv, V, nrows, ncols, svThreshold, Ap, rank_out, NULL, NULL, NULL, NULL);
3798
3799 return Ap;
3800 }
3801
3802 /*!
3803 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
3804 A\f$ and return the rank of the matrix using OpenCV 3rd party.
3805
3806 \warning To inverse a square n-by-n matrix, you have to use rather one of
3807 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
3808 are kwown as faster.
3809
3810 \param Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
3811
3812 \param svThreshold : Threshold used to test the singular values. If
3813 a singular value is lower than this threshold we consider that the
3814 matrix is not full rank.
3815
3816 \return The rank of the matrix.
3817
3818 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
3819
3820 \code
3821 #include <visp3/core/vpMatrix.h>
3822
3823 int main()
3824 {
3825 vpMatrix A(2, 3);
3826
3827 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
3828 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
3829
3830 A.print(std::cout, 10, "A: ");
3831
3832 vpMatrix A_p;
3833 unsigned int rank = A.pseudoInverseOpenCV(A_p);
3834
3835 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
3836 std::cout << "Rank: " << rank << std::endl;
3837 }
3838 \endcode
3839
3840 \sa pseudoInverse(vpMatrix &, double) const
3841 */
pseudoInverseOpenCV(vpMatrix & Ap,double svThreshold) const3842 unsigned int vpMatrix::pseudoInverseOpenCV(vpMatrix &Ap, double svThreshold) const
3843 {
3844 unsigned int nrows = getRows();
3845 unsigned int ncols = getCols();
3846 int rank_out;
3847
3848 vpMatrix U, V;
3849 vpColVector sv;
3850
3851 Ap.resize(ncols, nrows, false, false);
3852
3853 if (nrows < ncols) {
3854 U.resize(ncols, ncols, true);
3855 sv.resize(nrows, false);
3856 } else {
3857 U.resize(nrows, ncols, false);
3858 sv.resize(ncols, false);
3859 }
3860
3861 U.insert(*this, 0, 0);
3862 U.svdOpenCV(sv, V);
3863
3864 compute_pseudo_inverse(U, sv, V, nrows, ncols, svThreshold, Ap, rank_out, NULL, NULL, NULL, NULL);
3865
3866 return static_cast<unsigned int>(rank_out);
3867 }
3868 /*!
3869 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
3870 A\f$ along with singular values and return the rank of the matrix using
3871 OpenCV 3rd party.
3872
3873 \warning To inverse a square n-by-n matrix, you have to use rather one of
3874 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
3875 are kwown as faster.
3876
3877 \param Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
3878
3879 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
3880 of this vector is equal to min(m, n).
3881
3882 \param svThreshold : Threshold used to test the singular values. If
3883 a singular value is lower than this threshold we consider that the
3884 matrix is not full rank.
3885
3886 \return The rank of the matrix \f$\bf A\f$.
3887
3888 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
3889
3890 \code
3891 #include <visp3/core/vpMatrix.h>
3892
3893 int main()
3894 {
3895 vpMatrix A(2, 3);
3896
3897 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
3898 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
3899
3900 A.print(std::cout, 10, "A: ");
3901
3902 vpMatrix A_p;
3903 vpColVector sv;
3904 unsigned int rank = A.pseudoInverseOpenCV(A_p, sv);
3905
3906 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
3907
3908 std::cout << "Rank: " << rank << std::endl;
3909 std::cout << "Singular values: " << sv.t() << std::endl;
3910 }
3911 \endcode
3912
3913 \sa pseudoInverse(vpMatrix &, vpColVector &, double) const
3914 */
pseudoInverseOpenCV(vpMatrix & Ap,vpColVector & sv,double svThreshold) const3915 unsigned int vpMatrix::pseudoInverseOpenCV(vpMatrix &Ap, vpColVector &sv, double svThreshold) const
3916 {
3917 unsigned int nrows = getRows();
3918 unsigned int ncols = getCols();
3919 int rank_out;
3920
3921 vpMatrix U, V;
3922 vpColVector sv_;
3923
3924 Ap.resize(ncols, nrows, false, false);
3925
3926 if (nrows < ncols) {
3927 U.resize(ncols, ncols, true);
3928 sv.resize(nrows, false);
3929 } else {
3930 U.resize(nrows, ncols, false);
3931 sv.resize(ncols, false);
3932 }
3933
3934 U.insert(*this, 0, 0);
3935 U.svdOpenCV(sv_, V);
3936
3937 compute_pseudo_inverse(U, sv_, V, nrows, ncols, svThreshold, Ap, rank_out, NULL, NULL, NULL, NULL);
3938
3939 // Remove singular values equal to the one that corresponds to the lines of 0
3940 // introduced when m < n
3941 memcpy(sv.data, sv_.data, sv.size() * sizeof(double));
3942
3943 return static_cast<unsigned int>(rank_out);
3944 }
3945
3946 /*!
3947 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
3948 A\f$ along with singular values, \f$\mbox{Im}(A)\f$, \f$\mbox{Im}(A^T)\f$ and
3949 \f$\mbox{Ker}(A)\f$ and return the rank of the matrix using OpenCV 3rd
3950 party.
3951
3952 \warning To inverse a square n-by-n matrix, you have to use rather
3953 inverseByLU(), inverseByCholesky(), or inverseByQR() that are kwown as faster.
3954
3955 Using singular value decomposition, we have:
3956
3957 \f[
3958 {\bf A}_{m\times n} = {\bf U}_{m\times m} \; {\bf S}_{m\times n} \; {\bf
3959 V^\top}_{n\times n} \f] \f[
3960 {\bf A}_{m\times n} = \left[\begin{array}{ccc}\mbox{Im} ({\bf A}) & | &
3961 \mbox{Ker} ({\bf A}^\top) \end{array} \right] {\bf S}_{m\times n}
3962 \left[
3963 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
3964 \\
3965 \hline \\
3966 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
3967 \f]
3968
3969 where the diagonal of \f${\bf S}_{m\times n}\f$ corresponds to the matrix
3970 \f$A\f$ singular values.
3971
3972 This equation could be reformulated in a minimal way:
3973 \f[
3974 {\bf A}_{m\times n} = \mbox{Im} ({\bf A}) \; {\bf S}_{r\times n}
3975 \left[
3976 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
3977 \\
3978 \hline \\
3979 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
3980 \f]
3981
3982 where the diagonal of \f${\bf S}_{r\times n}\f$ corresponds to the matrix
3983 \f$A\f$ first r singular values.
3984
3985 The null space of a matrix \f$\bf A\f$ is defined as \f$\mbox{Ker}({\bf A})
3986 = { {\bf X} : {\bf A}*{\bf X} = {\bf 0}}\f$.
3987
3988 \param Ap: The Moore-Penros pseudo inverse \f$ {\bf A}^+ \f$.
3989
3990 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
3991 of this vector is equal to min(m, n).
3992
3993 \param svThreshold: Threshold used to test the singular values. If
3994 a singular value is lower than this threshold we consider that the
3995 matrix is not full rank.
3996
3997 \param imA: \f$\mbox{Im}({\bf A})\f$ that is a m-by-r matrix.
3998
3999 \param imAt: \f$\mbox{Im}({\bf A}^T)\f$ that is n-by-r matrix.
4000
4001 \param kerAt: The matrix that contains the null space (kernel) of \f$\bf
4002 A\f$ defined by the matrix \f${\bf X}^T\f$. If matrix \f$\bf A\f$ is full
4003 rank, the dimension of \c kerAt is (0, n), otherwise the dimension is (n-r,
4004 n). This matrix is thus the transpose of \f$\mbox{Ker}({\bf A})\f$.
4005
4006 \return The rank of the matrix \f$\bf A\f$.
4007
4008 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
4009
4010 \code
4011 #include <visp3/core/vpMatrix.h>
4012
4013 int main()
4014 {
4015 vpMatrix A(2, 3);
4016
4017 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
4018 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
4019
4020 A.print(std::cout, 10, "A: ");
4021
4022 vpColVector sv;
4023 vpMatrix A_p, imA, imAt, kerAt;
4024 unsigned int rank = A.pseudoInverseOpenCV(A_p, sv, 1e-6, imA, imAt, kerAt);
4025
4026 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
4027 std::cout << "Rank: " << rank << std::endl;
4028 std::cout << "Singular values: " << sv.t() << std::endl;
4029 imA.print(std::cout, 10, "Im(A): ");
4030 imAt.print(std::cout, 10, "Im(A^T): ");
4031
4032 if (kerAt.size()) {
4033 kerAt.t().print(std::cout, 10, "Ker(A): ");
4034 }
4035 else {
4036 std::cout << "Ker(A) empty " << std::endl;
4037 }
4038
4039 // Reconstruct matrix A from ImA, ImAt, KerAt
4040 vpMatrix S(rank, A.getCols());
4041 for(unsigned int i = 0; i< rank; i++)
4042 S[i][i] = sv[i];
4043 vpMatrix Vt(A.getCols(), A.getCols());
4044 Vt.insert(imAt.t(), 0, 0);
4045 Vt.insert(kerAt, rank, 0);
4046 (imA * S * Vt).print(std::cout, 10, "Im(A) * S * [Im(A^T) | Ker(A)]^T:");
4047 }
4048 \endcode
4049
4050 \sa pseudoInverse(vpMatrix &, vpColVector &, double, vpMatrix &, vpMatrix &, vpMatrix &) const
4051 */
pseudoInverseOpenCV(vpMatrix & Ap,vpColVector & sv,double svThreshold,vpMatrix & imA,vpMatrix & imAt,vpMatrix & kerAt) const4052 unsigned int vpMatrix::pseudoInverseOpenCV(vpMatrix &Ap, vpColVector &sv, double svThreshold, vpMatrix &imA,
4053 vpMatrix &imAt, vpMatrix &kerAt) const
4054 {
4055 unsigned int nrows = getRows();
4056 unsigned int ncols = getCols();
4057 int rank_out;
4058 vpMatrix U, V;
4059 vpColVector sv_;
4060
4061 if (nrows < ncols) {
4062 U.resize(ncols, ncols, true);
4063 sv.resize(nrows, false);
4064 } else {
4065 U.resize(nrows, ncols, false);
4066 sv.resize(ncols, false);
4067 }
4068
4069 U.insert(*this, 0, 0);
4070 U.svdOpenCV(sv_, V);
4071
4072 compute_pseudo_inverse(U, sv_, V, nrows, ncols, svThreshold, Ap, rank_out, NULL, &imA, &imAt, &kerAt);
4073
4074 // Remove singular values equal to the one that corresponds to the lines of 0
4075 // introduced when m < n
4076 memcpy(sv.data, sv_.data, sv.size() * sizeof(double));
4077
4078 return static_cast<unsigned int>(rank_out);
4079 }
4080
4081 /*!
4082 Compute and return the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n
4083 matrix \f$\bf A\f$ using OpenCV 3rd party.
4084
4085 \warning To inverse a square n-by-n matrix, you have to use rather one of
4086 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
4087 are kwown as faster.
4088
4089 \param[in] rank_in : Known rank of the matrix.
4090 \return The Moore-Penros pseudo inverse \f$ A^+ \f$.
4091
4092 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
4093
4094 \code
4095 #include <visp3/core/vpMatrix.h>
4096
4097 int main()
4098 {
4099 vpMatrix A(2, 3);
4100
4101 // This matrix rank is 2
4102 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
4103 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
4104
4105 A.print(std::cout, 10, "A: ");
4106
4107 int rank_in = 2;
4108 vpMatrix A_p = A.pseudoInverseOpenCV(rank_in);
4109
4110 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
4111 return 0;
4112 }
4113 \endcode
4114
4115 \sa pseudoInverse(int) const
4116 */
pseudoInverseOpenCV(int rank_in) const4117 vpMatrix vpMatrix::pseudoInverseOpenCV(int rank_in) const
4118 {
4119 unsigned int nrows = getRows();
4120 unsigned int ncols = getCols();
4121 int rank_out;
4122 double svThreshold = 1e-26;
4123
4124 vpMatrix U, V, Ap;
4125 vpColVector sv;
4126
4127 Ap.resize(ncols, nrows, false, false);
4128
4129 if (nrows < ncols) {
4130 U.resize(ncols, ncols, true);
4131 sv.resize(nrows, false);
4132 } else {
4133 U.resize(nrows, ncols, false);
4134 sv.resize(ncols, false);
4135 }
4136
4137 U.insert(*this, 0, 0);
4138 U.svdOpenCV(sv, V);
4139
4140 compute_pseudo_inverse(U, sv, V, nrows, ncols, svThreshold, Ap, rank_out, &rank_in, NULL, NULL, NULL);
4141
4142 return Ap;
4143 }
4144
4145 /*!
4146 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
4147 A\f$ and return the rank of the matrix using OpenCV 3rd party.
4148
4149 \warning To inverse a square n-by-n matrix, you have to use rather one of
4150 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
4151 are kwown as faster.
4152
4153 \param[out] Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
4154
4155 \param[in] rank_in : Known rank of the matrix.
4156
4157 \return The computed rank of the matrix.
4158
4159 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
4160
4161 \code
4162 #include <visp3/core/vpMatrix.h>
4163
4164 int main()
4165 {
4166 vpMatrix A(2, 3);
4167
4168 // This matrix rank is 2
4169 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
4170 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
4171
4172 A.print(std::cout, 10, "A: ");
4173
4174 vpMatrix A_p;
4175 int rank_in = 2;
4176 int rank_out = A.pseudoInverseOpenCV(A_p, rank_in);
4177 if (rank_out != rank_in) {
4178 std::cout << "There is a possibility that the pseudo-inverse in wrong." << std::endl;
4179 std::cout << "Are you sure that the matrix rank is " << rank_in << std::endl;
4180 }
4181
4182 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
4183 std::cout << "Rank in : " << rank_in << std::endl;
4184 std::cout << "Rank out: " << rank_out << std::endl;
4185 return 0;
4186 }
4187 \endcode
4188
4189 \sa pseudoInverse(vpMatrix &, int) const
4190 */
pseudoInverseOpenCV(vpMatrix & Ap,int rank_in) const4191 int vpMatrix::pseudoInverseOpenCV(vpMatrix &Ap, int rank_in) const
4192 {
4193 unsigned int nrows = getRows();
4194 unsigned int ncols = getCols();
4195 int rank_out;
4196 double svThreshold = 1e-26;
4197
4198 vpMatrix U, V;
4199 vpColVector sv;
4200
4201 Ap.resize(ncols, nrows, false, false);
4202
4203 if (nrows < ncols) {
4204 U.resize(ncols, ncols, true);
4205 sv.resize(nrows, false);
4206 } else {
4207 U.resize(nrows, ncols, false);
4208 sv.resize(ncols, false);
4209 }
4210
4211 U.insert(*this, 0, 0);
4212 U.svdOpenCV(sv, V);
4213
4214 compute_pseudo_inverse(U, sv, V, nrows, ncols, svThreshold, Ap, rank_out, &rank_in, NULL, NULL, NULL);
4215
4216 return rank_out;
4217 }
4218
4219 /*!
4220 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
4221 A\f$ along with singular values and return the rank of the matrix using
4222 OpenCV 3rd party.
4223
4224 \warning To inverse a square n-by-n matrix, you have to use rather one of
4225 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
4226 are kwown as faster.
4227
4228 \param Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
4229
4230 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
4231 of this vector is equal to min(m, n).
4232
4233 \param[in] rank_in : Known rank of the matrix.
4234
4235 \return The rank of the matrix \f$\bf A\f$.
4236
4237 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
4238
4239 \code
4240 #include <visp3/core/vpMatrix.h>
4241
4242 int main()
4243 {
4244 vpMatrix A(2, 3);
4245
4246 // This matrix rank is 2
4247 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
4248 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
4249
4250 A.print(std::cout, 10, "A: ");
4251
4252 vpMatrix A_p;
4253 vpColVector sv;
4254 int rank_in = 2;
4255
4256 int rank_out = A.pseudoInverseOpenCV(A_p, sv, rank_in);
4257 if (rank_out != rank_in) {
4258 std::cout << "There is a possibility that the pseudo-inverse in wrong." << std::endl;
4259 std::cout << "Are you sure that the matrix rank is " << rank_in << std::endl;
4260 }
4261
4262 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
4263 std::cout << "Rank in : " << rank_in << std::endl;
4264 std::cout << "Rank out: " << rank_out << std::endl;
4265 std::cout << "Singular values: " << sv.t() << std::endl;
4266 return 0;
4267 }
4268 \endcode
4269
4270 \sa pseudoInverse(vpMatrix &, vpColVector &, int) const
4271 */
pseudoInverseOpenCV(vpMatrix & Ap,vpColVector & sv,int rank_in) const4272 int vpMatrix::pseudoInverseOpenCV(vpMatrix &Ap, vpColVector &sv, int rank_in) const
4273 {
4274 unsigned int nrows = getRows();
4275 unsigned int ncols = getCols();
4276 int rank_out;
4277 double svThreshold = 1e-26;
4278
4279 vpMatrix U, V;
4280 vpColVector sv_;
4281
4282 Ap.resize(ncols, nrows, false, false);
4283
4284 if (nrows < ncols) {
4285 U.resize(ncols, ncols, true);
4286 sv.resize(nrows, false);
4287 } else {
4288 U.resize(nrows, ncols, false);
4289 sv.resize(ncols, false);
4290 }
4291
4292 U.insert(*this, 0, 0);
4293 U.svdOpenCV(sv_, V);
4294
4295 compute_pseudo_inverse(U, sv_, V, nrows, ncols, svThreshold, Ap, rank_out, &rank_in, NULL, NULL, NULL);
4296
4297 // Remove singular values equal to the one that corresponds to the lines of 0
4298 // introduced when m < n
4299 memcpy(sv.data, sv_.data, sv.size() * sizeof(double));
4300
4301 return rank_out;
4302 }
4303
4304 /*!
4305 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
4306 A\f$ along with singular values, \f$\mbox{Im}(A)\f$, \f$\mbox{Im}(A^T)\f$ and
4307 \f$\mbox{Ker}(A)\f$ and return the rank of the matrix using OpenCV 3rd
4308 party.
4309
4310 \warning To inverse a square n-by-n matrix, you have to use rather
4311 inverseByLU(), inverseByCholesky(), or inverseByQR() that are kwown as faster.
4312
4313 Using singular value decomposition, we have:
4314
4315 \f[
4316 {\bf A}_{m\times n} = {\bf U}_{m\times m} \; {\bf S}_{m\times n} \; {\bf
4317 V^\top}_{n\times n} \f] \f[
4318 {\bf A}_{m\times n} = \left[\begin{array}{ccc}\mbox{Im} ({\bf A}) & | &
4319 \mbox{Ker} ({\bf A}^\top) \end{array} \right] {\bf S}_{m\times n}
4320 \left[
4321 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
4322 \\
4323 \hline \\
4324 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
4325 \f]
4326
4327 where the diagonal of \f${\bf S}_{m\times n}\f$ corresponds to the matrix
4328 \f$A\f$ singular values.
4329
4330 This equation could be reformulated in a minimal way:
4331 \f[
4332 {\bf A}_{m\times n} = \mbox{Im} ({\bf A}) \; {\bf S}_{r\times n}
4333 \left[
4334 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
4335 \\
4336 \hline \\
4337 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
4338 \f]
4339
4340 where the diagonal of \f${\bf S}_{r\times n}\f$ corresponds to the matrix
4341 \f$A\f$ first r singular values.
4342
4343 The null space of a matrix \f$\bf A\f$ is defined as \f$\mbox{Ker}({\bf A})
4344 = { {\bf X} : {\bf A}*{\bf X} = {\bf 0}}\f$.
4345
4346 \param Ap: The Moore-Penros pseudo inverse \f$ {\bf A}^+ \f$.
4347
4348 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
4349 of this vector is equal to min(m, n).
4350
4351 \param[in] rank_in : Known rank of the matrix.
4352
4353 \param imA: \f$\mbox{Im}({\bf A})\f$ that is a m-by-r matrix.
4354
4355 \param imAt: \f$\mbox{Im}({\bf A}^T)\f$ that is n-by-r matrix.
4356
4357 \param kerAt: The matrix that contains the null space (kernel) of \f$\bf
4358 A\f$ defined by the matrix \f${\bf X}^T\f$. If matrix \f$\bf A\f$ is full
4359 rank, the dimension of \c kerAt is (0, n), otherwise the dimension is (n-r,
4360 n). This matrix is thus the transpose of \f$\mbox{Ker}({\bf A})\f$.
4361
4362 \return The rank of the matrix \f$\bf A\f$.
4363
4364 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
4365
4366 \code
4367 #include <visp3/core/vpMatrix.h>
4368
4369 int main()
4370 {
4371 vpMatrix A(2, 3);
4372
4373 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
4374 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
4375
4376 A.print(std::cout, 10, "A: ");
4377
4378 vpColVector sv;
4379 vpMatrix A_p, imA, imAt, kerAt;
4380 int rank_in = 2;
4381 int rank_out = A.pseudoInverseOpenCV(A_p, sv, rank_in, imA, imAt, kerAt);
4382
4383 if (rank_out != rank_in) {
4384 std::cout << "There is a possibility that the pseudo-inverse in wrong." << std::endl;
4385 std::cout << "Are you sure that the matrix rank is " << rank_in << std::endl;
4386 }
4387
4388 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
4389 std::cout << "Rank in : " << rank_in << std::endl;
4390 std::cout << "Rank out: " << rank_out << std::endl;
4391 std::cout << "Singular values: " << sv.t() << std::endl;
4392 imA.print(std::cout, 10, "Im(A): ");
4393 imAt.print(std::cout, 10, "Im(A^T): ");
4394
4395 if (kerAt.size()) {
4396 kerAt.t().print(std::cout, 10, "Ker(A): ");
4397 }
4398 else {
4399 std::cout << "Ker(A) empty " << std::endl;
4400 }
4401
4402 // Reconstruct matrix A from ImA, ImAt, KerAt
4403 vpMatrix S(rank_in, A.getCols());
4404 for(unsigned int i = 0; i< rank_in; i++)
4405 S[i][i] = sv[i];
4406 vpMatrix Vt(A.getCols(), A.getCols());
4407 Vt.insert(imAt.t(), 0, 0);
4408 Vt.insert(kerAt, rank_in, 0);
4409 (imA * S * Vt).print(std::cout, 10, "Im(A) * S * [Im(A^T) | Ker(A)]^T:");
4410 }
4411 \endcode
4412
4413 \sa pseudoInverse(vpMatrix &, vpColVector &, int, vpMatrix &, vpMatrix &, vpMatrix &) const
4414 */
pseudoInverseOpenCV(vpMatrix & Ap,vpColVector & sv,int rank_in,vpMatrix & imA,vpMatrix & imAt,vpMatrix & kerAt) const4415 int vpMatrix::pseudoInverseOpenCV(vpMatrix &Ap, vpColVector &sv, int rank_in, vpMatrix &imA,
4416 vpMatrix &imAt, vpMatrix &kerAt) const
4417 {
4418 unsigned int nrows = getRows();
4419 unsigned int ncols = getCols();
4420 int rank_out;
4421 double svThreshold = 1e-26;
4422 vpMatrix U, V;
4423 vpColVector sv_;
4424
4425 if (nrows < ncols) {
4426 U.resize(ncols, ncols, true);
4427 sv.resize(nrows, false);
4428 } else {
4429 U.resize(nrows, ncols, false);
4430 sv.resize(ncols, false);
4431 }
4432
4433 U.insert(*this, 0, 0);
4434 U.svdOpenCV(sv_, V);
4435
4436 compute_pseudo_inverse(U, sv_, V, nrows, ncols, svThreshold, Ap, rank_out, &rank_in, &imA, &imAt, &kerAt);
4437
4438 // Remove singular values equal to the one that corresponds to the lines of 0
4439 // introduced when m < n
4440 memcpy(sv.data, sv_.data, sv.size() * sizeof(double));
4441
4442 return rank_out;
4443 }
4444
4445 #endif
4446 #endif // #ifndef DOXYGEN_SHOULD_SKIP_THIS
4447
4448 /*!
4449 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
4450 A\f$ along with singular values and return the rank of the matrix.
4451
4452 \note By default, this function uses Lapack 3rd party. It is also possible
4453 to use a specific 3rd party suffixing this function name with one of the
4454 following 3rd party names (Lapack, Eigen3 or OpenCV).
4455
4456 \warning To inverse a square n-by-n matrix, you have to use rather one of
4457 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
4458 are kwown as faster.
4459
4460 \param Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
4461
4462 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
4463 of this vector is equal to min(m, n).
4464
4465 \param svThreshold : Threshold used to test the singular values. If
4466 a singular value is lower than this threshold we consider that the
4467 matrix is not full rank.
4468
4469 \return The rank of the matrix \f$\bf A\f$.
4470
4471 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
4472
4473 \code
4474 #include <visp3/core/vpMatrix.h>
4475
4476 int main()
4477 {
4478 vpMatrix A(2, 3);
4479
4480 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
4481 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
4482
4483 A.print(std::cout, 10, "A: ");
4484
4485 vpMatrix A_p;
4486 vpColVector sv;
4487 unsigned int rank = A.pseudoInverse(A_p, sv);
4488
4489 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
4490
4491 std::cout << "Rank: " << rank << std::endl;
4492 std::cout << "Singular values: " << sv.t() << std::endl;
4493 }
4494 \endcode
4495
4496 Once build, the previous example produces the following output:
4497 \code
4498 A: [2,3]=
4499 2 3 5
4500 -4 2 3
4501 A^+ (pseudo-inverse): [3,2]=
4502 0.117899 -0.190782
4503 0.065380 0.039657
4504 0.113612 0.052518
4505 Rank: 2
4506 Singular values: 6.874359351 4.443330227
4507 \endcode
4508 */
pseudoInverse(vpMatrix & Ap,vpColVector & sv,double svThreshold) const4509 unsigned int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, double svThreshold) const
4510 {
4511 #if defined(VISP_HAVE_LAPACK)
4512 return pseudoInverseLapack(Ap, sv, svThreshold);
4513 #elif defined(VISP_HAVE_EIGEN3)
4514 return pseudoInverseEigen3(Ap, sv, svThreshold);
4515 #elif (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
4516 return pseudoInverseOpenCV(Ap, sv, svThreshold);
4517 #else
4518 (void)Ap;
4519 (void)sv;
4520 (void)svThreshold;
4521 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
4522 "Install Lapack, Eigen3 or OpenCV 3rd party"));
4523 #endif
4524 }
4525
4526 /*!
4527 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
4528 A\f$ along with singular values and return the rank of the matrix.
4529
4530 \note By default, this function uses Lapack 3rd party. It is also possible
4531 to use a specific 3rd party suffixing this function name with one of the
4532 following 3rd party names (Lapack, Eigen3 or OpenCV).
4533
4534 \warning To inverse a square n-by-n matrix, you have to use rather one of
4535 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
4536 are kwown as faster.
4537
4538 \param Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
4539
4540 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
4541 of this vector is equal to min(m, n).
4542
4543 \param[in] rank_in : Known rank of the matrix.
4544
4545 \return The rank of the matrix \f$\bf A\f$.
4546
4547 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
4548
4549 \code
4550 #include <visp3/core/vpMatrix.h>
4551
4552 int main()
4553 {
4554 vpMatrix A(2, 3);
4555
4556 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
4557 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
4558
4559 A.print(std::cout, 10, "A: ");
4560
4561 vpMatrix A_p;
4562 vpColVector sv;
4563 int rank_in = 2;
4564 int rank_out = A.pseudoInverse(A_p, sv, rank_in);
4565 if (rank_out != rank_in) {
4566 std::cout << "There is a possibility that the pseudo-inverse in wrong." << std::endl;
4567 std::cout << "Are you sure that the matrix rank is " << rank_in << std::endl;
4568 }
4569
4570 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
4571
4572 std::cout << "Rank in : " << rank_in << std::endl;
4573 std::cout << "Rank out: " << rank_out << std::endl;
4574 std::cout << "Singular values: " << sv.t() << std::endl;
4575 }
4576 \endcode
4577
4578 Once build, the previous example produces the following output:
4579 \code
4580 A: [2,3]=
4581 2 3 5
4582 -4 2 3
4583 A^+ (pseudo-inverse): [3,2]=
4584 0.117899 -0.190782
4585 0.065380 0.039657
4586 0.113612 0.052518
4587 Rank in : 2
4588 Rank out: 2
4589 Singular values: 6.874359351 4.443330227
4590 \endcode
4591 */
pseudoInverse(vpMatrix & Ap,vpColVector & sv,int rank_in) const4592 int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, int rank_in) const
4593 {
4594 #if defined(VISP_HAVE_LAPACK)
4595 return pseudoInverseLapack(Ap, sv, rank_in);
4596 #elif defined(VISP_HAVE_EIGEN3)
4597 return pseudoInverseEigen3(Ap, sv, rank_in);
4598 #elif (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
4599 return pseudoInverseOpenCV(Ap, sv, rank_in);
4600 #else
4601 (void)Ap;
4602 (void)sv;
4603 (void)svThreshold;
4604 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
4605 "Install Lapack, Eigen3 or OpenCV 3rd party"));
4606 #endif
4607 }
4608 /*!
4609 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
4610 A\f$ along with singular values, \f$\mbox{Im}(A)\f$ and \f$\mbox{Im}(A^T)\f$
4611 and return the rank of the matrix.
4612
4613 See pseudoInverse(vpMatrix &, vpColVector &, double, vpMatrix &, vpMatrix &, vpMatrix &) const
4614 for a complete description of this function.
4615
4616 \warning To inverse a square n-by-n matrix, you have to use rather one of
4617 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
4618 are kwown as faster.
4619
4620 \param Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
4621
4622 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
4623 of this vector is equal to min(m, n).
4624
4625 \param svThreshold : Threshold used to test the singular values. If
4626 a singular value is lower than this threshold we consider that the
4627 matrix is not full rank.
4628
4629 \param imA: \f$\mbox{Im}({\bf A})\f$ that is a m-by-r matrix.
4630
4631 \param imAt: \f$\mbox{Im}({\bf A}^T)\f$ that is n-by-r matrix.
4632
4633 \return The rank of the matrix \f$\bf A\f$.
4634
4635 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
4636
4637 \code
4638 #include <visp3/core/vpMatrix.h>
4639
4640 int main()
4641 {
4642 vpMatrix A(2, 3);
4643
4644 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
4645 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
4646
4647 A.print(std::cout, 10, "A: ");
4648
4649 vpMatrix A_p;
4650 vpColVector sv;
4651 vpMatrix imA, imAt;
4652 unsigned int rank = A.pseudoInverse(A_p, sv, 1e-6, imA, imAt);
4653
4654 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
4655 std::cout << "Rank: " << rank << std::endl;
4656 std::cout << "Singular values: " << sv.t() << std::endl;
4657 imA.print(std::cout, 10, "Im(A): ");
4658 imAt.print(std::cout, 10, "Im(A^T): ");
4659 }
4660 \endcode
4661
4662 Once build, the previous example produces the following output:
4663 \code
4664 A: [2,3]=
4665 2 3 5
4666 -4 2 3
4667 A^+ (pseudo-inverse): [3,2]=
4668 0.117899 -0.190782
4669 0.065380 0.039657
4670 0.113612 0.052518
4671 Rank: 2
4672 Singular values: 6.874359351 4.443330227
4673 Im(A): [2,2]=
4674 0.81458 -0.58003
4675 0.58003 0.81458
4676 Im(A^T): [3,2]=
4677 -0.100515 -0.994397
4678 0.524244 -0.024967
4679 0.845615 -0.102722
4680 \endcode
4681 */
pseudoInverse(vpMatrix & Ap,vpColVector & sv,double svThreshold,vpMatrix & imA,vpMatrix & imAt) const4682 unsigned int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, double svThreshold, vpMatrix &imA, vpMatrix &imAt) const
4683 {
4684 vpMatrix kerAt;
4685 return pseudoInverse(Ap, sv, svThreshold, imA, imAt, kerAt);
4686 }
4687
4688 /*!
4689 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
4690 A\f$ along with singular values, \f$\mbox{Im}(A)\f$ and \f$\mbox{Im}(A^T)\f$
4691 and return the rank of the matrix.
4692
4693 See pseudoInverse(vpMatrix &, vpColVector &, double, vpMatrix &, vpMatrix &, vpMatrix &) const
4694 for a complete description of this function.
4695
4696 \warning To inverse a square n-by-n matrix, you have to use rather one of
4697 the following functions inverseByLU(), inverseByQR(), inverseByCholesky() that
4698 are kwown as faster.
4699
4700 \param Ap : The Moore-Penros pseudo inverse \f$ A^+ \f$.
4701
4702 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
4703 of this vector is equal to min(m, n).
4704
4705 \param[in] rank_in : Known rank of the matrix.
4706
4707 \param imA: \f$\mbox{Im}({\bf A})\f$ that is a m-by-r matrix.
4708
4709 \param imAt: \f$\mbox{Im}({\bf A}^T)\f$ that is n-by-r matrix.
4710
4711 \return The rank of the matrix \f$\bf A\f$.
4712
4713 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
4714
4715 \code
4716 #include <visp3/core/vpMatrix.h>
4717
4718 int main()
4719 {
4720 vpMatrix A(2, 3);
4721
4722 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
4723 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
4724
4725 A.print(std::cout, 10, "A: ");
4726
4727 vpMatrix A_p;
4728 vpColVector sv;
4729 vpMatrix imA, imAt;
4730 int rank_in = 2;
4731 int rank_out = A.pseudoInverse(A_p, sv, rank_in, imA, imAt);
4732 if (rank_out != rank_in) {
4733 std::cout << "There is a possibility that the pseudo-inverse in wrong." << std::endl;
4734 std::cout << "Are you sure that the matrix rank is " << rank_in << std::endl;
4735 }
4736
4737 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
4738 std::cout << "Rank in : " << rank_in << std::endl;
4739 std::cout << "Rank out: " << rank_in << std::endl;
4740 std::cout << "Singular values: " << sv.t() << std::endl;
4741 imA.print(std::cout, 10, "Im(A): ");
4742 imAt.print(std::cout, 10, "Im(A^T): ");
4743 }
4744 \endcode
4745
4746 Once build, the previous example produces the following output:
4747 \code
4748 A: [2,3]=
4749 2 3 5
4750 -4 2 3
4751 A^+ (pseudo-inverse): [3,2]=
4752 0.117899 -0.190782
4753 0.065380 0.039657
4754 0.113612 0.052518
4755 Rank: 2
4756 Singular values: 6.874359351 4.443330227
4757 Im(A): [2,2]=
4758 0.81458 -0.58003
4759 0.58003 0.81458
4760 Im(A^T): [3,2]=
4761 -0.100515 -0.994397
4762 0.524244 -0.024967
4763 0.845615 -0.102722
4764 \endcode
4765 */
pseudoInverse(vpMatrix & Ap,vpColVector & sv,int rank_in,vpMatrix & imA,vpMatrix & imAt) const4766 int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, int rank_in, vpMatrix &imA, vpMatrix &imAt) const
4767 {
4768 vpMatrix kerAt;
4769 return pseudoInverse(Ap, sv, rank_in, imA, imAt, kerAt);
4770 }
4771
4772 /*!
4773 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
4774 A\f$ along with singular values, \f$\mbox{Im}(A)\f$, \f$\mbox{Im}(A^T)\f$ and
4775 \f$\mbox{Ker}(A)\f$ and return the rank of the matrix.
4776
4777 \note By default, this function uses Lapack 3rd party. It is also possible
4778 to use a specific 3rd party suffixing this function name with one of the
4779 following 3rd party names (Lapack, Eigen3 or OpenCV).
4780
4781 \warning To inverse a square n-by-n matrix, you have to use rather
4782 inverseByLU(), inverseByCholesky(), or inverseByQR() that are kwown as faster.
4783
4784 Using singular value decomposition, we have:
4785
4786 \f[
4787 {\bf A}_{m\times n} = {\bf U}_{m\times m} \; {\bf S}_{m\times n} \; {\bf
4788 V^\top}_{n\times n} \f] \f[
4789 {\bf A}_{m\times n} = \left[\begin{array}{ccc}\mbox{Im} ({\bf A}) & | &
4790 \mbox{Ker} ({\bf A}^\top) \end{array} \right] {\bf S}_{m\times n}
4791 \left[
4792 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
4793 \\
4794 \hline \\
4795 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
4796 \f]
4797
4798 where the diagonal of \f${\bf S}_{m\times n}\f$ corresponds to the matrix
4799 \f$A\f$ singular values.
4800
4801 This equation could be reformulated in a minimal way:
4802 \f[
4803 {\bf A}_{m\times n} = \mbox{Im} ({\bf A}) \; {\bf S}_{r\times n}
4804 \left[
4805 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
4806 \\
4807 \hline \\
4808 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
4809 \f]
4810
4811 where the diagonal of \f${\bf S}_{r\times n}\f$ corresponds to the matrix
4812 \f$A\f$ first r singular values.
4813
4814 The null space of a matrix \f$\bf A\f$ is defined as \f$\mbox{Ker}({\bf A})
4815 = { {\bf X} : {\bf A}*{\bf X} = {\bf 0}}\f$.
4816
4817 \param Ap: The Moore-Penros pseudo inverse \f$ {\bf A}^+ \f$.
4818
4819 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
4820 of this vector is equal to min(m, n).
4821
4822 \param svThreshold: Threshold used to test the singular values. If
4823 a singular value is lower than this threshold we consider that the
4824 matrix is not full rank.
4825
4826 \param imA: \f$\mbox{Im}({\bf A})\f$ that is a m-by-r matrix.
4827
4828 \param imAt: \f$\mbox{Im}({\bf A}^T)\f$ that is n-by-r matrix.
4829
4830 \param kerAt: The matrix that contains the null space (kernel) of \f$\bf
4831 A\f$ defined by the matrix \f${\bf X}^T\f$. If matrix \f$\bf A\f$ is full
4832 rank, the dimension of \c kerAt is (0, n), otherwise the dimension is (n-r,
4833 n). This matrix is thus the transpose of \f$\mbox{Ker}({\bf A})\f$.
4834
4835 \return The rank of the matrix \f$\bf A\f$.
4836
4837 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
4838
4839 \code
4840 #include <visp3/core/vpMatrix.h>
4841
4842 int main()
4843 {
4844 vpMatrix A(2, 3);
4845
4846 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
4847 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
4848
4849 A.print(std::cout, 10, "A: ");
4850
4851 vpColVector sv;
4852 vpMatrix A_p, imA, imAt, kerAt;
4853 unsigned int rank = A.pseudoInverse(A_p, sv, 1e-6, imA, imAt, kerAt);
4854
4855 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
4856 std::cout << "Rank: " << rank << std::endl;
4857 std::cout << "Singular values: " << sv.t() << std::endl;
4858 imA.print(std::cout, 10, "Im(A): ");
4859 imAt.print(std::cout, 10, "Im(A^T): ");
4860
4861 if (kerAt.size()) {
4862 kerAt.t().print(std::cout, 10, "Ker(A): ");
4863 }
4864 else {
4865 std::cout << "Ker(A) empty " << std::endl;
4866 }
4867
4868 // Reconstruct matrix A from ImA, ImAt, KerAt
4869 vpMatrix S(rank, A.getCols());
4870 for(unsigned int i = 0; i< rank; i++)
4871 S[i][i] = sv[i];
4872 vpMatrix Vt(A.getCols(), A.getCols());
4873 Vt.insert(imAt.t(), 0, 0);
4874 Vt.insert(kerAt, rank, 0);
4875 (imA * S * Vt).print(std::cout, 10, "Im(A) * S * [Im(A^T) | Ker(A)]^T:");
4876 }
4877 \endcode
4878
4879 Once build, the previous example produces the following output:
4880 \code
4881 A: [2,3]=
4882 2 3 5
4883 -4 2 3
4884 A^+ (pseudo-inverse): [3,2]=
4885 0.117899 -0.190782
4886 0.065380 0.039657
4887 0.113612 0.052518
4888 Rank: 2
4889 Singular values: 6.874359351 4.443330227
4890 Im(A): [2,2]=
4891 0.81458 -0.58003
4892 0.58003 0.81458
4893 Im(A^T): [3,2]=
4894 -0.100515 -0.994397
4895 0.524244 -0.024967
4896 0.845615 -0.102722
4897 Ker(A): [3,1]=
4898 -0.032738
4899 -0.851202
4900 0.523816
4901 Im(A) * S * [Im(A^T) | Ker(A)]^T:[2,3]=
4902 2 3 5
4903 -4 2 3
4904 \endcode
4905 */
pseudoInverse(vpMatrix & Ap,vpColVector & sv,double svThreshold,vpMatrix & imA,vpMatrix & imAt,vpMatrix & kerAt) const4906 unsigned int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, double svThreshold, vpMatrix &imA, vpMatrix &imAt, vpMatrix &kerAt) const
4907 {
4908 #if defined(VISP_HAVE_LAPACK)
4909 return pseudoInverseLapack(Ap, sv, svThreshold, imA, imAt, kerAt);
4910 #elif defined(VISP_HAVE_EIGEN3)
4911 return pseudoInverseEigen3(Ap, sv, svThreshold, imA, imAt, kerAt);
4912 #elif (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
4913 return pseudoInverseOpenCV(Ap, sv, svThreshold, imA, imAt, kerAt);
4914 #else
4915 (void)Ap;
4916 (void)sv;
4917 (void)svThreshold;
4918 (void)imA;
4919 (void)imAt;
4920 (void)kerAt;
4921 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
4922 "Install Lapack, Eigen3 or OpenCV 3rd party"));
4923 #endif
4924 }
4925
4926 /*!
4927 Compute the Moore-Penros pseudo inverse \f$A^+\f$ of a m-by-n matrix \f$\bf
4928 A\f$ along with singular values, \f$\mbox{Im}(A)\f$, \f$\mbox{Im}(A^T)\f$ and
4929 \f$\mbox{Ker}(A)\f$ and return the rank of the matrix.
4930
4931 \note By default, this function uses Lapack 3rd party. It is also possible
4932 to use a specific 3rd party suffixing this function name with one of the
4933 following 3rd party names (Lapack, Eigen3 or OpenCV).
4934
4935 \warning To inverse a square n-by-n matrix, you have to use rather
4936 inverseByLU(), inverseByCholesky(), or inverseByQR() that are kwown as faster.
4937
4938 Using singular value decomposition, we have:
4939
4940 \f[
4941 {\bf A}_{m\times n} = {\bf U}_{m\times m} \; {\bf S}_{m\times n} \; {\bf
4942 V^\top}_{n\times n} \f] \f[
4943 {\bf A}_{m\times n} = \left[\begin{array}{ccc}\mbox{Im} ({\bf A}) & | &
4944 \mbox{Ker} ({\bf A}^\top) \end{array} \right] {\bf S}_{m\times n}
4945 \left[
4946 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
4947 \\
4948 \hline \\
4949 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
4950 \f]
4951
4952 where the diagonal of \f${\bf S}_{m\times n}\f$ corresponds to the matrix
4953 \f$A\f$ singular values.
4954
4955 This equation could be reformulated in a minimal way:
4956 \f[
4957 {\bf A}_{m\times n} = \mbox{Im} ({\bf A}) \; {\bf S}_{r\times n}
4958 \left[
4959 \begin{array}{c} \left[\mbox{Im} ({\bf A}^\top)\right]^\top \\
4960 \\
4961 \hline \\
4962 \left[\mbox{Ker}({\bf A})\right]^\top \end{array}\right]
4963 \f]
4964
4965 where the diagonal of \f${\bf S}_{r\times n}\f$ corresponds to the matrix
4966 \f$A\f$ first r singular values.
4967
4968 The null space of a matrix \f$\bf A\f$ is defined as \f$\mbox{Ker}({\bf A})
4969 = { {\bf X} : {\bf A}*{\bf X} = {\bf 0}}\f$.
4970
4971 \param Ap: The Moore-Penros pseudo inverse \f$ {\bf A}^+ \f$.
4972
4973 \param sv: Vector corresponding to matrix \f$A\f$ singular values. The size
4974 of this vector is equal to min(m, n).
4975
4976 \param[in] rank_in : Known rank of the matrix.
4977
4978 \param imA: \f$\mbox{Im}({\bf A})\f$ that is a m-by-r matrix.
4979
4980 \param imAt: \f$\mbox{Im}({\bf A}^T)\f$ that is n-by-r matrix.
4981
4982 \param kerAt: The matrix that contains the null space (kernel) of \f$\bf
4983 A\f$ defined by the matrix \f${\bf X}^T\f$. If matrix \f$\bf A\f$ is full
4984 rank, the dimension of \c kerAt is (0, n), otherwise the dimension is (n-r,
4985 n). This matrix is thus the transpose of \f$\mbox{Ker}({\bf A})\f$.
4986
4987 \return The rank of the matrix \f$\bf A\f$.
4988
4989 Here an example to compute the pseudo-inverse of a 2-by-3 matrix that is rank 2.
4990
4991 \code
4992 #include <visp3/core/vpMatrix.h>
4993
4994 int main()
4995 {
4996 vpMatrix A(2, 3);
4997
4998 A[0][0] = 2; A[0][1] = 3; A[0][2] = 5;
4999 A[1][0] = -4; A[1][1] = 2; A[1][2] = 3;
5000
5001 A.print(std::cout, 10, "A: ");
5002
5003 vpColVector sv;
5004 vpMatrix A_p, imA, imAt, kerAt;
5005 int rank_in = 2;
5006 int rank_out = A.pseudoInverse(A_p, sv, rank_in, imA, imAt, kerAt);
5007 if (rank_out != rank_in) {
5008 std::cout << "There is a possibility that the pseudo-inverse in wrong." << std::endl;
5009 std::cout << "Are you sure that the matrix rank is " << rank_in << std::endl;
5010 }
5011
5012 A_p.print(std::cout, 10, "A^+ (pseudo-inverse): ");
5013 std::cout << "Rank in : " << rank_in << std::endl;
5014 std::cout << "Rank out: " << rank_out << std::endl;
5015 std::cout << "Singular values: " << sv.t() << std::endl;
5016 imA.print(std::cout, 10, "Im(A): ");
5017 imAt.print(std::cout, 10, "Im(A^T): ");
5018
5019 if (kerAt.size()) {
5020 kerAt.t().print(std::cout, 10, "Ker(A): ");
5021 }
5022 else {
5023 std::cout << "Ker(A) empty " << std::endl;
5024 }
5025
5026 // Reconstruct matrix A from ImA, ImAt, KerAt
5027 vpMatrix S(rank, A.getCols());
5028 for(unsigned int i = 0; i< rank_in; i++)
5029 S[i][i] = sv[i];
5030 vpMatrix Vt(A.getCols(), A.getCols());
5031 Vt.insert(imAt.t(), 0, 0);
5032 Vt.insert(kerAt, rank, 0);
5033 (imA * S * Vt).print(std::cout, 10, "Im(A) * S * [Im(A^T) | Ker(A)]^T:");
5034 }
5035 \endcode
5036
5037 Once build, the previous example produces the following output:
5038 \code
5039 A: [2,3]=
5040 2 3 5
5041 -4 2 3
5042 A^+ (pseudo-inverse): [3,2]=
5043 0.117899 -0.190782
5044 0.065380 0.039657
5045 0.113612 0.052518
5046 Rank in : 2
5047 Rank out: 2
5048 Singular values: 6.874359351 4.443330227
5049 Im(A): [2,2]=
5050 0.81458 -0.58003
5051 0.58003 0.81458
5052 Im(A^T): [3,2]=
5053 -0.100515 -0.994397
5054 0.524244 -0.024967
5055 0.845615 -0.102722
5056 Ker(A): [3,1]=
5057 -0.032738
5058 -0.851202
5059 0.523816
5060 Im(A) * S * [Im(A^T) | Ker(A)]^T:[2,3]=
5061 2 3 5
5062 -4 2 3
5063 \endcode
5064 */
pseudoInverse(vpMatrix & Ap,vpColVector & sv,int rank_in,vpMatrix & imA,vpMatrix & imAt,vpMatrix & kerAt) const5065 int vpMatrix::pseudoInverse(vpMatrix &Ap, vpColVector &sv, int rank_in, vpMatrix &imA, vpMatrix &imAt, vpMatrix &kerAt) const
5066 {
5067 #if defined(VISP_HAVE_LAPACK)
5068 return pseudoInverseLapack(Ap, sv, rank_in, imA, imAt, kerAt);
5069 #elif defined(VISP_HAVE_EIGEN3)
5070 return pseudoInverseEigen3(Ap, sv, rank_in, imA, imAt, kerAt);
5071 #elif (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
5072 return pseudoInverseOpenCV(Ap, sv, rank_in, imA, imAt, kerAt);
5073 #else
5074 (void)Ap;
5075 (void)sv;
5076 (void)svThreshold;
5077 (void)imA;
5078 (void)imAt;
5079 (void)kerAt;
5080 throw(vpException(vpException::fatalError, "Cannot compute pseudo-inverse. "
5081 "Install Lapack, Eigen3 or OpenCV 3rd party"));
5082 #endif
5083 }
5084
5085 /*!
5086 Extract a column vector from a matrix.
5087 \warning All the indexes start from 0 in this function.
5088 \param j : Index of the column to extract. If col=0, the first column is extracted.
5089 \param i_begin : Index of the row that gives the location of the first element
5090 of the column vector to extract.
5091 \param column_size : Size of the column vector to extract.
5092 \return The extracted column vector.
5093
5094 The following example shows how to use this function:
5095 \code
5096 #include <visp3/core/vpColVector.h>
5097 #include <visp3/core/vpMatrix.h>
5098
5099 int main()
5100 {
5101 vpMatrix A(4,4);
5102
5103 for(unsigned int i=0; i < A.getRows(); i++)
5104 for(unsigned int j=0; j < A.getCols(); j++)
5105 A[i][j] = i*A.getCols()+j;
5106
5107 A.print(std::cout, 4);
5108
5109 vpColVector cv = A.getCol(1, 1, 3);
5110 std::cout << "Column vector: \n" << cv << std::endl;
5111 }
5112 \endcode
5113 It produces the following output:
5114 \code
5115 [4,4]=
5116 0 1 2 3
5117 4 5 6 7
5118 8 9 10 11
5119 12 13 14 15
5120 column vector:
5121 5
5122 9
5123 13
5124 \endcode
5125 */
getCol(unsigned int j,unsigned int i_begin,unsigned int column_size) const5126 vpColVector vpMatrix::getCol(unsigned int j, unsigned int i_begin, unsigned int column_size) const
5127 {
5128 if (i_begin + column_size > getRows() || j >= getCols())
5129 throw(vpException(vpException::dimensionError, "Unable to extract column %u from the %ux%u matrix", j, getRows(), getCols()));
5130 vpColVector c(column_size);
5131 for (unsigned int i = 0; i < column_size; i++)
5132 c[i] = (*this)[i_begin + i][j];
5133 return c;
5134 }
5135
5136 /*!
5137 Extract a column vector from a matrix.
5138 \warning All the indexes start from 0 in this function.
5139 \param j : Index of the column to extract. If j=0, the first column is extracted.
5140 \return The extracted column vector.
5141
5142 The following example shows how to use this function:
5143 \code
5144 #include <visp3/core/vpColVector.h>
5145 #include <visp3/core/vpMatrix.h>
5146
5147 int main()
5148 {
5149 vpMatrix A(4,4);
5150
5151 for(unsigned int i=0; i < A.getRows(); i++)
5152 for(unsigned int j=0; j < A.getCols(); j++)
5153 A[i][j] = i*A.getCols()+j;
5154
5155 A.print(std::cout, 4);
5156
5157 vpColVector cv = A.getCol(1);
5158 std::cout << "Column vector: \n" << cv << std::endl;
5159 }
5160 \endcode
5161 It produces the following output:
5162 \code
5163 [4,4]=
5164 0 1 2 3
5165 4 5 6 7
5166 8 9 10 11
5167 12 13 14 15
5168 column vector:
5169 1
5170 5
5171 9
5172 13
5173 \endcode
5174 */
getCol(unsigned int j) const5175 vpColVector vpMatrix::getCol(unsigned int j) const
5176 {
5177 return getCol(j, 0, rowNum);
5178 }
5179
5180 /*!
5181 Extract a row vector from a matrix.
5182 \warning All the indexes start from 0 in this function.
5183 \param i : Index of the row to extract. If i=0, the first row is extracted.
5184 \return The extracted row vector.
5185
5186 The following example shows how to use this function:
5187 \code
5188 #include <visp3/core/vpMatrix.h>
5189 #include <visp3/core/vpRowVector.h>
5190
5191 int main()
5192 {
5193 vpMatrix A(4,4);
5194
5195 for(unsigned int i=0; i < A.getRows(); i++)
5196 for(unsigned int j=0; j < A.getCols(); j++)
5197 A[i][j] = i*A.getCols()+j;
5198
5199 A.print(std::cout, 4);
5200
5201 vpRowVector rv = A.getRow(1);
5202 std::cout << "Row vector: \n" << rv << std::endl;
5203 } \endcode
5204 It produces the following output:
5205 \code
5206 [4,4]=
5207 0 1 2 3
5208 4 5 6 7
5209 8 9 10 11
5210 12 13 14 15
5211 Row vector:
5212 4 5 6 7
5213 \endcode
5214 */
getRow(unsigned int i) const5215 vpRowVector vpMatrix::getRow(unsigned int i) const
5216 {
5217 return getRow(i, 0, colNum);
5218 }
5219
5220 /*!
5221 Extract a row vector from a matrix.
5222 \warning All the indexes start from 0 in this function.
5223 \param i : Index of the row to extract. If i=0, the first row is extracted.
5224 \param j_begin : Index of the column that gives the location of the first
5225 element of the row vector to extract.
5226 \param row_size : Size of the row vector to extract.
5227 \return The extracted row vector.
5228
5229 The following example shows how to use this function:
5230 \code
5231 #include <visp3/core/vpMatrix.h>
5232 #include <visp3/core/vpRowVector.h>
5233
5234 int main()
5235 {
5236 vpMatrix A(4,4);
5237
5238 for(unsigned int i=0; i < A.getRows(); i++)
5239 for(unsigned int j=0; j < A.getCols(); j++)
5240 A[i][j] = i*A.getCols()+j;
5241
5242 A.print(std::cout, 4);
5243
5244 vpRowVector rv = A.getRow(1, 1, 3);
5245 std::cout << "Row vector: \n" << rv << std::endl;
5246 }
5247 \endcode
5248 It produces the following output:
5249 \code
5250 [4,4]=
5251 0 1 2 3
5252 4 5 6 7
5253 8 9 10 11
5254 12 13 14 15
5255 Row vector:
5256 5 6 7
5257 \endcode
5258 */
getRow(unsigned int i,unsigned int j_begin,unsigned int row_size) const5259 vpRowVector vpMatrix::getRow(unsigned int i, unsigned int j_begin, unsigned int row_size) const
5260 {
5261 if (j_begin + row_size > colNum || i >= rowNum)
5262 throw(vpException(vpException::dimensionError, "Unable to extract a row vector from the matrix"));
5263
5264 vpRowVector r(row_size);
5265 if (r.data != NULL && data != NULL) {
5266 memcpy(r.data, (*this)[i] + j_begin, row_size*sizeof(double));
5267 }
5268
5269 return r;
5270 }
5271
5272 /*!
5273 Extract a diagonal vector from a matrix.
5274
5275 \return The diagonal of the matrix.
5276
5277 \warning An empty vector is returned if the matrix is empty.
5278
5279 The following example shows how to use this function:
5280 \code
5281 #include <visp3/core/vpMatrix.h>
5282
5283 int main()
5284 {
5285 vpMatrix A(3,4);
5286
5287 for(unsigned int i=0; i < A.getRows(); i++)
5288 for(unsigned int j=0; j < A.getCols(); j++)
5289 A[i][j] = i*A.getCols()+j;
5290
5291 A.print(std::cout, 4);
5292
5293 vpColVector diag = A.getDiag();
5294 std::cout << "Diag vector: \n" << diag.t() << std::endl;
5295 }
5296 \endcode
5297 It produces the following output:
5298 \code
5299 [3,4]=
5300 0 1 2 3
5301 4 5 6 7
5302 8 9 10 11
5303 Diag vector:
5304 0 5 10
5305 \endcode
5306 */
getDiag() const5307 vpColVector vpMatrix::getDiag() const
5308 {
5309 unsigned int min_size = std::min(rowNum, colNum);
5310 vpColVector diag;
5311
5312 if (min_size > 0) {
5313 diag.resize(min_size, false);
5314
5315 for (unsigned int i = 0; i < min_size; i++) {
5316 diag[i] = (*this)[i][i];
5317 }
5318 }
5319
5320 return diag;
5321 }
5322
5323 /*!
5324 Stack matrix \e B to the end of matrix \e A and return the resulting matrix
5325 [ A B ]^T
5326
5327 \param A : Upper matrix.
5328 \param B : Lower matrix.
5329 \return Stacked matrix [ A B ]^T
5330
5331 \warning A and B must have the same number of columns.
5332 */
stack(const vpMatrix & A,const vpMatrix & B)5333 vpMatrix vpMatrix::stack(const vpMatrix &A, const vpMatrix &B)
5334 {
5335 vpMatrix C;
5336
5337 vpMatrix::stack(A, B, C);
5338
5339 return C;
5340 }
5341
5342 /*!
5343 Stack matrix \e B to the end of matrix \e A and return the resulting matrix
5344 in \e C.
5345
5346 \param A : Upper matrix.
5347 \param B : Lower matrix.
5348 \param C : Stacked matrix C = [ A B ]^T
5349
5350 \warning A and B must have the same number of columns. A and C, B and C must
5351 be two different objects.
5352 */
stack(const vpMatrix & A,const vpMatrix & B,vpMatrix & C)5353 void vpMatrix::stack(const vpMatrix &A, const vpMatrix &B, vpMatrix &C)
5354 {
5355 unsigned int nra = A.getRows();
5356 unsigned int nrb = B.getRows();
5357
5358 if (nra != 0) {
5359 if (A.getCols() != B.getCols()) {
5360 throw(vpException(vpException::dimensionError, "Cannot stack (%dx%d) matrix with (%dx%d) matrix", A.getRows(),
5361 A.getCols(), B.getRows(), B.getCols()));
5362 }
5363 }
5364
5365 if (A.data != NULL && A.data == C.data) {
5366 std::cerr << "A and C must be two different objects!" << std::endl;
5367 return;
5368 }
5369
5370 if (B.data != NULL && B.data == C.data) {
5371 std::cerr << "B and C must be two different objects!" << std::endl;
5372 return;
5373 }
5374
5375 C.resize(nra + nrb, B.getCols(), false, false);
5376
5377 if (C.data != NULL && A.data != NULL && A.size() > 0) {
5378 // Copy A in C
5379 memcpy(C.data, A.data, sizeof(double) * A.size());
5380 }
5381
5382 if (C.data != NULL && B.data != NULL && B.size() > 0) {
5383 // Copy B in C
5384 memcpy(C.data + A.size(), B.data, sizeof(double) * B.size());
5385 }
5386 }
5387
5388 /*!
5389 Stack row vector \e r to matrix \e A and return the resulting matrix [ A r ]^T
5390
5391 \param A : Upper matrix.
5392 \param r : Lower row vector.
5393 \return Stacked matrix [ A r ]^T
5394
5395 \warning \e A and \e r must have the same number of columns.
5396 */
stack(const vpMatrix & A,const vpRowVector & r)5397 vpMatrix vpMatrix::stack(const vpMatrix &A, const vpRowVector &r)
5398 {
5399 vpMatrix C;
5400 vpMatrix::stack(A, r, C);
5401
5402 return C;
5403 }
5404
5405 /*!
5406 Stack row vector \e r to the end of matrix \e A and return the resulting
5407 matrix in \e C.
5408
5409 \param A : Upper matrix.
5410 \param r : Lower row vector.
5411 \param C : Stacked matrix C = [ A r ]^T
5412
5413 \warning A and r must have the same number of columns. A and C must be two
5414 different objects.
5415 */
stack(const vpMatrix & A,const vpRowVector & r,vpMatrix & C)5416 void vpMatrix::stack(const vpMatrix &A, const vpRowVector &r, vpMatrix &C)
5417 {
5418 if (A.data != NULL && A.data == C.data) {
5419 std::cerr << "A and C must be two different objects!" << std::endl;
5420 return;
5421 }
5422
5423 C = A;
5424 C.stack(r);
5425 }
5426
5427 /*!
5428 Stack column vector \e c to matrix \e A and return the resulting matrix [ A c ]
5429
5430 \param A : Left matrix.
5431 \param c : Right column vector.
5432 \return Stacked matrix [ A c ]
5433
5434 \warning \e A and \e c must have the same number of rows.
5435 */
stack(const vpMatrix & A,const vpColVector & c)5436 vpMatrix vpMatrix::stack(const vpMatrix &A, const vpColVector &c)
5437 {
5438 vpMatrix C;
5439 vpMatrix::stack(A, c, C);
5440
5441 return C;
5442 }
5443
5444 /*!
5445 Stack column vector \e c to the end of matrix \e A and return the resulting
5446 matrix in \e C.
5447
5448 \param A : Left matrix.
5449 \param c : Right column vector.
5450 \param C : Stacked matrix C = [ A c ]
5451
5452 \warning A and c must have the same number of rows. A and C must be two
5453 different objects.
5454 */
stack(const vpMatrix & A,const vpColVector & c,vpMatrix & C)5455 void vpMatrix::stack(const vpMatrix &A, const vpColVector &c, vpMatrix &C)
5456 {
5457 if (A.data != NULL && A.data == C.data) {
5458 std::cerr << "A and C must be two different objects!" << std::endl;
5459 return;
5460 }
5461
5462 C = A;
5463 C.stack(c);
5464 }
5465
5466 /*!
5467 Insert matrix B in matrix A at the given position.
5468
5469 \param A : Main matrix.
5470 \param B : Matrix to insert.
5471 \param r : Index of the row where to add the matrix.
5472 \param c : Index of the column where to add the matrix.
5473 \return Matrix with B insert in A.
5474
5475 \warning Throw exception if the sizes of the matrices do not allow the
5476 insertion.
5477 */
insert(const vpMatrix & A,const vpMatrix & B,unsigned int r,unsigned int c)5478 vpMatrix vpMatrix::insert(const vpMatrix &A, const vpMatrix &B, unsigned int r, unsigned int c)
5479 {
5480 vpMatrix C;
5481
5482 insert(A, B, C, r, c);
5483
5484 return C;
5485 }
5486
5487 /*!
5488 \relates vpMatrix
5489 Insert matrix B in matrix A at the given position.
5490
5491 \param A : Main matrix.
5492 \param B : Matrix to insert.
5493 \param C : Result matrix.
5494 \param r : Index of the row where to insert matrix B.
5495 \param c : Index of the column where to insert matrix B.
5496
5497 \warning Throw exception if the sizes of the matrices do not
5498 allow the insertion.
5499 */
insert(const vpMatrix & A,const vpMatrix & B,vpMatrix & C,unsigned int r,unsigned int c)5500 void vpMatrix::insert(const vpMatrix &A, const vpMatrix &B, vpMatrix &C, unsigned int r, unsigned int c)
5501 {
5502 if (((r + B.getRows()) <= A.getRows()) && ((c + B.getCols()) <= A.getCols())) {
5503 C.resize(A.getRows(), A.getCols(), false, false);
5504
5505 for (unsigned int i = 0; i < A.getRows(); i++) {
5506 for (unsigned int j = 0; j < A.getCols(); j++) {
5507 if (i >= r && i < (r + B.getRows()) && j >= c && j < (c + B.getCols())) {
5508 C[i][j] = B[i - r][j - c];
5509 } else {
5510 C[i][j] = A[i][j];
5511 }
5512 }
5513 }
5514 } else {
5515 throw vpException(vpException::dimensionError, "Cannot insert (%dx%d) matrix in (%dx%d) matrix at position (%d,%d)",
5516 B.getRows(), B.getCols(), A.getCols(), A.getRows(), r, c);
5517 }
5518 }
5519
5520 /*!
5521 Juxtapose to matrices C = [ A B ].
5522
5523 \f$ C = \left( \begin{array}{cc} A & B \end{array}\right) \f$
5524
5525 \param A : Left matrix.
5526 \param B : Right matrix.
5527 \return Juxtaposed matrix C = [ A B ]
5528
5529 \warning A and B must have the same number of rows.
5530 */
juxtaposeMatrices(const vpMatrix & A,const vpMatrix & B)5531 vpMatrix vpMatrix::juxtaposeMatrices(const vpMatrix &A, const vpMatrix &B)
5532 {
5533 vpMatrix C;
5534
5535 juxtaposeMatrices(A, B, C);
5536
5537 return C;
5538 }
5539
5540 /*!
5541 \relates vpMatrix
5542 Juxtapose to matrices C = [ A B ].
5543
5544 \f$ C = \left( \begin{array}{cc} A & B \end{array}\right) \f$
5545
5546 \param A : Left matrix.
5547 \param B : Right matrix.
5548 \param C : Juxtaposed matrix C = [ A B ]
5549
5550 \warning A and B must have the same number of rows.
5551 */
juxtaposeMatrices(const vpMatrix & A,const vpMatrix & B,vpMatrix & C)5552 void vpMatrix::juxtaposeMatrices(const vpMatrix &A, const vpMatrix &B, vpMatrix &C)
5553 {
5554 unsigned int nca = A.getCols();
5555 unsigned int ncb = B.getCols();
5556
5557 if (nca != 0) {
5558 if (A.getRows() != B.getRows()) {
5559 throw(vpException(vpException::dimensionError, "Cannot juxtapose (%dx%d) matrix with (%dx%d) matrix", A.getRows(),
5560 A.getCols(), B.getRows(), B.getCols()));
5561 }
5562 }
5563
5564 if (B.getRows() == 0 || nca + ncb == 0) {
5565 std::cerr << "B.getRows() == 0 || nca+ncb == 0" << std::endl;
5566 return;
5567 }
5568
5569 C.resize(B.getRows(), nca + ncb, false, false);
5570
5571 C.insert(A, 0, 0);
5572 C.insert(B, 0, nca);
5573 }
5574
5575 //--------------------------------------------------------------------
5576 // Output
5577 //--------------------------------------------------------------------
5578
5579 /*!
5580
5581 Pretty print a matrix. The data are tabulated.
5582 The common widths before and after the decimal point
5583 are set with respect to the parameter maxlen.
5584
5585 \param s Stream used for the printing.
5586
5587 \param length The suggested width of each matrix element.
5588 The actual width grows in order to accomodate the whole integral part,
5589 and shrinks if the whole extent is not needed for all the numbers.
5590 \param intro The introduction which is printed before the matrix.
5591 Can be set to zero (or omitted), in which case
5592 the introduction is not printed.
5593
5594 \return Returns the common total width for all matrix elements
5595
5596 \sa std::ostream &operator<<(std::ostream &s, const vpArray2D<Type> &A)
5597 */
print(std::ostream & s,unsigned int length,const std::string & intro) const5598 int vpMatrix::print(std::ostream &s, unsigned int length, const std::string &intro) const
5599 {
5600 typedef std::string::size_type size_type;
5601
5602 unsigned int m = getRows();
5603 unsigned int n = getCols();
5604
5605 std::vector<std::string> values(m * n);
5606 std::ostringstream oss;
5607 std::ostringstream ossFixed;
5608 std::ios_base::fmtflags original_flags = oss.flags();
5609
5610 // ossFixed <<std::fixed;
5611 ossFixed.setf(std::ios::fixed, std::ios::floatfield);
5612
5613 size_type maxBefore = 0; // the length of the integral part
5614 size_type maxAfter = 0; // number of decimals plus
5615 // one place for the decimal point
5616 for (unsigned int i = 0; i < m; ++i) {
5617 for (unsigned int j = 0; j < n; ++j) {
5618 oss.str("");
5619 oss << (*this)[i][j];
5620 if (oss.str().find("e") != std::string::npos) {
5621 ossFixed.str("");
5622 ossFixed << (*this)[i][j];
5623 oss.str(ossFixed.str());
5624 }
5625
5626 values[i * n + j] = oss.str();
5627 size_type thislen = values[i * n + j].size();
5628 size_type p = values[i * n + j].find('.');
5629
5630 if (p == std::string::npos) {
5631 maxBefore = vpMath::maximum(maxBefore, thislen);
5632 // maxAfter remains the same
5633 } else {
5634 maxBefore = vpMath::maximum(maxBefore, p);
5635 maxAfter = vpMath::maximum(maxAfter, thislen - p - 1);
5636 }
5637 }
5638 }
5639
5640 size_type totalLength = length;
5641 // increase totalLength according to maxBefore
5642 totalLength = vpMath::maximum(totalLength, maxBefore);
5643 // decrease maxAfter according to totalLength
5644 maxAfter = (std::min)(maxAfter, totalLength - maxBefore);
5645 if (maxAfter == 1)
5646 maxAfter = 0;
5647
5648 // the following line is useful for debugging
5649 // std::cerr <<totalLength <<" " <<maxBefore <<" " <<maxAfter <<"\n";
5650
5651 if (! intro.empty())
5652 s << intro;
5653 s << "[" << m << "," << n << "]=\n";
5654
5655 for (unsigned int i = 0; i < m; i++) {
5656 s << " ";
5657 for (unsigned int j = 0; j < n; j++) {
5658 size_type p = values[i * n + j].find('.');
5659 s.setf(std::ios::right, std::ios::adjustfield);
5660 s.width((std::streamsize)maxBefore);
5661 s << values[i * n + j].substr(0, p).c_str();
5662
5663 if (maxAfter > 0) {
5664 s.setf(std::ios::left, std::ios::adjustfield);
5665 if (p != std::string::npos) {
5666 s.width((std::streamsize)maxAfter);
5667 s << values[i * n + j].substr(p, maxAfter).c_str();
5668 } else {
5669 assert(maxAfter > 1);
5670 s.width((std::streamsize)maxAfter);
5671 s << ".0";
5672 }
5673 }
5674
5675 s << ' ';
5676 }
5677 s << std::endl;
5678 }
5679
5680 s.flags(original_flags); // restore s to standard state
5681
5682 return (int)(maxBefore + maxAfter);
5683 }
5684
5685 /*!
5686 Print using Matlab syntax, to copy/paste in Matlab later.
5687
5688 The following code
5689 \code
5690 #include <visp3/core/vpMatrix.h>
5691
5692 int main()
5693 {
5694 vpMatrix M(2,3);
5695 int cpt = 0;
5696 for (unsigned int i=0; i<M.getRows(); i++)
5697 for (unsigned int j=0; j<M.getCols(); j++)
5698 M[i][j] = cpt++;
5699
5700 std::cout << "M = "; M.matlabPrint(std::cout);
5701 }
5702 \endcode
5703 produces this output:
5704 \code
5705 M = [ 0, 1, 2, ;
5706 3, 4, 5, ]
5707 \endcode
5708 that could be copy/paste in Matlab:
5709 \code
5710 >> M = [ 0, 1, 2, ;
5711 3, 4, 5, ]
5712
5713 M =
5714
5715 0 1 2
5716 3 4 5
5717
5718 >>
5719 \endcode
5720 */
matlabPrint(std::ostream & os) const5721 std::ostream &vpMatrix::matlabPrint(std::ostream &os) const
5722 {
5723 os << "[ ";
5724 for (unsigned int i = 0; i < this->getRows(); ++i) {
5725 for (unsigned int j = 0; j < this->getCols(); ++j) {
5726 os << (*this)[i][j] << ", ";
5727 }
5728 if (this->getRows() != i + 1) {
5729 os << ";" << std::endl;
5730 } else {
5731 os << "]" << std::endl;
5732 }
5733 }
5734 return os;
5735 }
5736
5737 /*!
5738 Print using Maple syntax, to copy/paste in Maple later.
5739
5740 The following code
5741 \code
5742 #include <visp3/core/vpMatrix.h>
5743
5744 int main()
5745 {
5746 vpMatrix M(2,3);
5747 int cpt = 0;
5748 for (unsigned int i=0; i<M.getRows(); i++)
5749 for (unsigned int j=0; j<M.getCols(); j++)
5750 M[i][j] = cpt++;
5751
5752 std::cout << "M = "; M.maplePrint(std::cout);
5753 }
5754 \endcode
5755 produces this output:
5756 \code
5757 M = ([
5758 [0, 1, 2, ],
5759 [3, 4, 5, ],
5760 ])
5761 \endcode
5762 that could be copy/paste in Maple.
5763
5764 */
maplePrint(std::ostream & os) const5765 std::ostream &vpMatrix::maplePrint(std::ostream &os) const
5766 {
5767 os << "([ " << std::endl;
5768 for (unsigned int i = 0; i < this->getRows(); ++i) {
5769 os << "[";
5770 for (unsigned int j = 0; j < this->getCols(); ++j) {
5771 os << (*this)[i][j] << ", ";
5772 }
5773 os << "]," << std::endl;
5774 }
5775 os << "])" << std::endl;
5776 return os;
5777 }
5778
5779 /*!
5780 Print/save a matrix in csv format.
5781
5782 The following code
5783 \code
5784 #include <visp3/core/vpMatrix.h>
5785
5786 int main()
5787 {
5788 std::ofstream ofs("log.csv", std::ofstream::out);
5789 vpMatrix M(2,3);
5790 int cpt = 0;
5791 for (unsigned int i=0; i<M.getRows(); i++)
5792 for (unsigned int j=0; j<M.getCols(); j++)
5793 M[i][j] = cpt++;
5794
5795 M.csvPrint(ofs);
5796
5797 ofs.close();
5798 }
5799 \endcode
5800 produces log.csv file that contains:
5801 \code
5802 0, 1, 2
5803 3, 4, 5
5804 \endcode
5805 */
csvPrint(std::ostream & os) const5806 std::ostream &vpMatrix::csvPrint(std::ostream &os) const
5807 {
5808 for (unsigned int i = 0; i < this->getRows(); ++i) {
5809 for (unsigned int j = 0; j < this->getCols(); ++j) {
5810 os << (*this)[i][j];
5811 if (!(j == (this->getCols() - 1)))
5812 os << ", ";
5813 }
5814 os << std::endl;
5815 }
5816 return os;
5817 }
5818
5819 /*!
5820 Print to be used as part of a C++ code later.
5821
5822 \param os : the stream to be printed in.
5823 \param matrixName : name of the matrix, "A" by default.
5824 \param octet : if false, print using double, if true, print byte per byte
5825 each bytes of the double array.
5826
5827 The following code shows how to use this function:
5828 \code
5829 #include <visp3/core/vpMatrix.h>
5830
5831 int main()
5832 {
5833 vpMatrix M(2,3);
5834 int cpt = 0;
5835 for (unsigned int i=0; i<M.getRows(); i++)
5836 for (unsigned int j=0; j<M.getCols(); j++)
5837 M[i][j] = cpt++;
5838
5839 M.cppPrint(std::cout, "M");
5840 }
5841 \endcode
5842 It produces the following output that could be copy/paste in a C++ code:
5843 \code
5844 vpMatrix M (2, 3);
5845 M[0][0] = 0;
5846 M[0][1] = 1;
5847 M[0][2] = 2;
5848
5849 M[1][0] = 3;
5850 M[1][1] = 4;
5851 M[1][2] = 5;
5852
5853 \endcode
5854 */
cppPrint(std::ostream & os,const std::string & matrixName,bool octet) const5855 std::ostream &vpMatrix::cppPrint(std::ostream &os, const std::string &matrixName, bool octet) const
5856 {
5857 os << "vpMatrix " << matrixName << " (" << this->getRows() << ", " << this->getCols() << "); " << std::endl;
5858
5859 for (unsigned int i = 0; i < this->getRows(); ++i) {
5860 for (unsigned int j = 0; j < this->getCols(); ++j) {
5861 if (!octet) {
5862 os << matrixName << "[" << i << "][" << j << "] = " << (*this)[i][j] << "; " << std::endl;
5863 } else {
5864 for (unsigned int k = 0; k < sizeof(double); ++k) {
5865 os << "((unsigned char*)&(" << matrixName << "[" << i << "][" << j << "]) )[" << k << "] = 0x" << std::hex
5866 << (unsigned int)((unsigned char *)&((*this)[i][j]))[k] << "; " << std::endl;
5867 }
5868 }
5869 }
5870 os << std::endl;
5871 }
5872 return os;
5873 }
5874
5875 /*!
5876 Stack A at the end of the current matrix, or copy if the matrix has no
5877 dimensions : this = [ this A ]^T.
5878 */
stack(const vpMatrix & A)5879 void vpMatrix::stack(const vpMatrix &A)
5880 {
5881 if (rowNum == 0) {
5882 *this = A;
5883 } else if (A.getRows() > 0) {
5884 if (colNum != A.getCols()) {
5885 throw(vpException(vpException::dimensionError, "Cannot stack (%dx%d) matrix with (%dx%d) matrix", rowNum, colNum,
5886 A.getRows(), A.getCols()));
5887 }
5888
5889 unsigned int rowNumOld = rowNum;
5890 resize(rowNum + A.getRows(), colNum, false, false);
5891 insert(A, rowNumOld, 0);
5892 }
5893 }
5894
5895 /*!
5896 Stack row vector \e r at the end of the current matrix, or copy if the
5897 matrix has no dimensions: this = [ this r ]^T.
5898
5899 Here an example for a robot velocity log :
5900 \code
5901 vpMatrix A;
5902 vpColVector v(6);
5903 for(unsigned int i = 0;i<100;i++)
5904 {
5905 robot.getVelocity(vpRobot::ARTICULAR_FRAME, v);
5906 Velocities.stack(v.t());
5907 }
5908 \endcode
5909 */
stack(const vpRowVector & r)5910 void vpMatrix::stack(const vpRowVector &r)
5911 {
5912 if (rowNum == 0) {
5913 *this = r;
5914 } else {
5915 if (colNum != r.getCols()) {
5916 throw(vpException(vpException::dimensionError, "Cannot stack (%dx%d) matrix with (1x%d) row vector", rowNum,
5917 colNum, r.getCols()));
5918 }
5919
5920 if (r.size() == 0) {
5921 return;
5922 }
5923
5924 unsigned int oldSize = size();
5925 resize(rowNum + 1, colNum, false, false);
5926
5927 if (data != NULL && r.data != NULL && data != r.data) {
5928 // Copy r in data
5929 memcpy(data + oldSize, r.data, sizeof(double) * r.size());
5930 }
5931 }
5932 }
5933
5934 /*!
5935 Stack column vector \e c at the right of the current matrix, or copy if the
5936 matrix has no dimensions: this = [ this c ].
5937
5938 Here an example for a robot velocity log matrix:
5939 \code
5940 vpMatrix log;
5941 vpColVector v(6);
5942 for(unsigned int i = 0; i<100;i++)
5943 {
5944 robot.getVelocity(vpRobot::ARTICULAR_FRAME, v);
5945 log.stack(v);
5946 }
5947 \endcode
5948 Here the log matrix has size 6 rows by 100 columns.
5949 */
stack(const vpColVector & c)5950 void vpMatrix::stack(const vpColVector &c)
5951 {
5952 if (colNum == 0) {
5953 *this = c;
5954 } else {
5955 if (rowNum != c.getRows()) {
5956 throw(vpException(vpException::dimensionError, "Cannot stack (%dx%d) matrix with (%dx1) column vector", rowNum,
5957 colNum, c.getRows()));
5958 }
5959
5960 if (c.size() == 0) {
5961 return;
5962 }
5963
5964 vpMatrix tmp = *this;
5965 unsigned int oldColNum = colNum;
5966 resize(rowNum, colNum + 1, false, false);
5967
5968 if (data != NULL && tmp.data != NULL && data != tmp.data) {
5969 // Copy c in data
5970 for (unsigned int i = 0; i < rowNum; i++) {
5971 memcpy(data + i*colNum, tmp.data + i*oldColNum, sizeof(double) * oldColNum);
5972 rowPtrs[i][oldColNum] = c[i];
5973 }
5974 }
5975 }
5976 }
5977
5978 /*!
5979 Insert matrix A at the given position in the current matrix.
5980
5981 \warning Throw vpException::dimensionError if the
5982 dimensions of the matrices do not allow the operation.
5983
5984 \param A : The matrix to insert.
5985 \param r : The index of the row to begin to insert data.
5986 \param c : The index of the column to begin to insert data.
5987 */
insert(const vpMatrix & A,unsigned int r,unsigned int c)5988 void vpMatrix::insert(const vpMatrix &A, unsigned int r, unsigned int c)
5989 {
5990 if ((r + A.getRows()) <= rowNum && (c + A.getCols()) <= colNum) {
5991 if (A.colNum == colNum && data != NULL && A.data != NULL && A.data != data) {
5992 memcpy(data + r * colNum, A.data, sizeof(double) * A.size());
5993 } else if (data != NULL && A.data != NULL && A.data != data) {
5994 for (unsigned int i = r; i < (r + A.getRows()); i++) {
5995 memcpy(data + i * colNum + c, A.data + (i - r) * A.colNum, sizeof(double) * A.colNum);
5996 }
5997 }
5998 } else {
5999 throw vpException(vpException::dimensionError, "Cannot insert (%dx%d) matrix in (%dx%d) matrix at position (%d,%d)",
6000 A.getRows(), A.getCols(), rowNum, colNum, r, c);
6001 }
6002 }
6003
6004 /*!
6005 Compute the eigenvalues of a n-by-n real symmetric matrix using
6006 Lapack 3rd party.
6007
6008 \return The eigenvalues of a n-by-n real symmetric matrix, sorted in ascending order.
6009
6010 \exception vpException::dimensionError If the matrix is not square.
6011 \exception vpException::fatalError If the matrix is not symmetric.
6012 \exception vpException::functionNotImplementedError If the Lapack 3rd party
6013 is not detected.
6014
6015 Here an example:
6016 \code
6017 #include <iostream>
6018
6019 #include <visp3/core/vpColVector.h>
6020 #include <visp3/core/vpMatrix.h>
6021
6022 int main()
6023 {
6024 vpMatrix A(3,3); // A is a symmetric matrix
6025 A[0][0] = 1/1.; A[0][1] = 1/2.; A[0][2] = 1/3.;
6026 A[1][0] = 1/2.; A[1][1] = 1/3.; A[1][2] = 1/4.;
6027 A[2][0] = 1/3.; A[2][1] = 1/4.; A[2][2] = 1/5.;
6028 std::cout << "Initial symmetric matrix: \n" << A << std::endl;
6029
6030 // Compute the eigen values
6031 vpColVector evalue; // Eigenvalues
6032 evalue = A.eigenValues();
6033 std::cout << "Eigen values: \n" << evalue << std::endl;
6034 }
6035 \endcode
6036
6037 \sa eigenValues(vpColVector &, vpMatrix &)
6038
6039 */
eigenValues() const6040 vpColVector vpMatrix::eigenValues() const
6041 {
6042 vpColVector evalue(rowNum); // Eigen values
6043
6044 if (rowNum != colNum) {
6045 throw(vpException(vpException::dimensionError,
6046 "Cannot compute eigen values on a non square matrix (%dx%d)",
6047 rowNum, colNum));
6048 }
6049
6050 // Check if the matrix is symetric: At - A = 0
6051 vpMatrix At_A = (*this).t() - (*this);
6052 for (unsigned int i = 0; i < rowNum; i++) {
6053 for (unsigned int j = 0; j < rowNum; j++) {
6054 // if (At_A[i][j] != 0) {
6055 if (std::fabs(At_A[i][j]) > std::numeric_limits<double>::epsilon()) {
6056 throw(vpException(vpException::fatalError, "Cannot compute eigen values on a non symetric matrix"));
6057 }
6058 }
6059 }
6060
6061 #if defined(VISP_HAVE_LAPACK)
6062 #if defined(VISP_HAVE_GSL) /* be careful of the copy below */
6063 {
6064 gsl_vector *eval = gsl_vector_alloc(rowNum);
6065 gsl_matrix *evec = gsl_matrix_alloc(rowNum, colNum);
6066
6067 gsl_eigen_symmv_workspace *w = gsl_eigen_symmv_alloc(rowNum);
6068 gsl_matrix *m = gsl_matrix_alloc(rowNum, colNum);
6069
6070 unsigned int Atda = (unsigned int)m->tda;
6071 for (unsigned int i = 0; i < rowNum; i++) {
6072 unsigned int k = i * Atda;
6073 for (unsigned int j = 0; j < colNum; j++)
6074 m->data[k + j] = (*this)[i][j];
6075 }
6076 gsl_eigen_symmv(m, eval, evec, w);
6077
6078 gsl_eigen_symmv_sort(eval, evec, GSL_EIGEN_SORT_ABS_ASC);
6079
6080 for (unsigned int i = 0; i < rowNum; i++) {
6081 evalue[i] = gsl_vector_get(eval, i);
6082 }
6083
6084 gsl_eigen_symmv_free(w);
6085 gsl_vector_free(eval);
6086 gsl_matrix_free(m);
6087 gsl_matrix_free(evec);
6088 }
6089 #else
6090 {
6091 const char jobz = 'N';
6092 const char uplo = 'U';
6093 vpMatrix A = (*this);
6094 vpColVector WORK;
6095 int lwork = -1;
6096 int info;
6097 double wkopt;
6098 vpMatrix::blas_dsyev(jobz, uplo, rowNum, A.data, colNum, evalue.data, &wkopt, lwork, info);
6099 lwork = static_cast<int>(wkopt);
6100 WORK.resize(lwork);
6101 vpMatrix::blas_dsyev(jobz, uplo, rowNum, A.data, colNum, evalue.data, WORK.data, lwork, info);
6102 }
6103 #endif
6104 #else
6105 {
6106 throw(vpException(vpException::functionNotImplementedError,
6107 "Eigen values computation is not implemented. "
6108 "You should install Lapack 3rd party"));
6109 }
6110 #endif
6111 return evalue;
6112 }
6113
6114 /*!
6115 Compute the eigenvalues of a n-by-n real symmetric matrix using
6116 Lapack 3rd party.
6117 \return The eigenvalues of a n-by-n real symmetric matrix.
6118
6119 \param evalue : Eigenvalues of the matrix, sorted in ascending order.
6120
6121 \param evector : Corresponding eigenvectors of the matrix.
6122
6123 \exception vpException::dimensionError If the matrix is not square.
6124 \exception vpException::fatalError If the matrix is not symmetric.
6125 \exception vpException::functionNotImplementedError If Lapack 3rd party is
6126 not detected.
6127
6128 Here an example:
6129 \code
6130 #include <iostream>
6131
6132 #include <visp3/core/vpColVector.h>
6133 #include <visp3/core/vpMatrix.h>
6134
6135 int main()
6136 {
6137 vpMatrix A(4,4); // A is a symmetric matrix
6138 A[0][0] = 1/1.; A[0][1] = 1/2.; A[0][2] = 1/3.; A[0][3] = 1/4.;
6139 A[1][0] = 1/2.; A[1][1] = 1/3.; A[1][2] = 1/4.; A[1][3] = 1/5.;
6140 A[2][0] = 1/3.; A[2][1] = 1/4.; A[2][2] = 1/5.; A[2][3] = 1/6.;
6141 A[3][0] = 1/4.; A[3][1] = 1/5.; A[3][2] = 1/6.; A[3][3] = 1/7.;
6142 std::cout << "Initial symmetric matrix: \n" << A << std::endl;
6143
6144 vpColVector d; // Eigenvalues
6145 vpMatrix V; // Eigenvectors
6146
6147 // Compute the eigenvalues and eigenvectors
6148 A.eigenValues(d, V);
6149 std::cout << "Eigen values: \n" << d << std::endl;
6150 std::cout << "Eigen vectors: \n" << V << std::endl;
6151
6152 vpMatrix D;
6153 D.diag(d); // Eigenvalues are on the diagonal
6154
6155 std::cout << "D: " << D << std::endl;
6156
6157 // Verification: A * V = V * D
6158 std::cout << "AV-VD = 0 ? \n" << (A*V) - (V*D) << std::endl;
6159 }
6160 \endcode
6161
6162 \sa eigenValues()
6163 */
eigenValues(vpColVector & evalue,vpMatrix & evector) const6164 void vpMatrix::eigenValues(vpColVector &evalue, vpMatrix &evector) const
6165 {
6166 if (rowNum != colNum) {
6167 throw(vpException(vpException::dimensionError,
6168 "Cannot compute eigen values on a non square matrix (%dx%d)",
6169 rowNum, colNum));
6170 }
6171
6172 // Check if the matrix is symetric: At - A = 0
6173 vpMatrix At_A = (*this).t() - (*this);
6174 for (unsigned int i = 0; i < rowNum; i++) {
6175 for (unsigned int j = 0; j < rowNum; j++) {
6176 // if (At_A[i][j] != 0) {
6177 if (std::fabs(At_A[i][j]) > std::numeric_limits<double>::epsilon()) {
6178 throw(vpException(vpException::fatalError, "Cannot compute eigen values on a non symetric matrix"));
6179 }
6180 }
6181 }
6182
6183 // Resize the output matrices
6184 evalue.resize(rowNum);
6185 evector.resize(rowNum, colNum);
6186
6187 #if defined(VISP_HAVE_LAPACK)
6188 #if defined(VISP_HAVE_GSL) /* be careful of the copy below */
6189 {
6190 gsl_vector *eval = gsl_vector_alloc(rowNum);
6191 gsl_matrix *evec = gsl_matrix_alloc(rowNum, colNum);
6192
6193 gsl_eigen_symmv_workspace *w = gsl_eigen_symmv_alloc(rowNum);
6194 gsl_matrix *m = gsl_matrix_alloc(rowNum, colNum);
6195
6196 unsigned int Atda = (unsigned int)m->tda;
6197 for (unsigned int i = 0; i < rowNum; i++) {
6198 unsigned int k = i * Atda;
6199 for (unsigned int j = 0; j < colNum; j++)
6200 m->data[k + j] = (*this)[i][j];
6201 }
6202 gsl_eigen_symmv(m, eval, evec, w);
6203
6204 gsl_eigen_symmv_sort(eval, evec, GSL_EIGEN_SORT_ABS_ASC);
6205
6206 for (unsigned int i = 0; i < rowNum; i++) {
6207 evalue[i] = gsl_vector_get(eval, i);
6208 }
6209 Atda = (unsigned int)evec->tda;
6210 for (unsigned int i = 0; i < rowNum; i++) {
6211 unsigned int k = i * Atda;
6212 for (unsigned int j = 0; j < rowNum; j++) {
6213 evector[i][j] = evec->data[k + j];
6214 }
6215 }
6216
6217 gsl_eigen_symmv_free(w);
6218 gsl_vector_free(eval);
6219 gsl_matrix_free(m);
6220 gsl_matrix_free(evec);
6221 }
6222 #else // defined(VISP_HAVE_GSL)
6223 {
6224 const char jobz = 'V';
6225 const char uplo = 'U';
6226 vpMatrix A = (*this);
6227 vpColVector WORK;
6228 int lwork = -1;
6229 int info;
6230 double wkopt;
6231 vpMatrix::blas_dsyev(jobz, uplo, rowNum, A.data, colNum, evalue.data, &wkopt, lwork, info);
6232 lwork = static_cast<int>(wkopt);
6233 WORK.resize(lwork);
6234 vpMatrix::blas_dsyev(jobz, uplo, rowNum, A.data, colNum, evalue.data, WORK.data, lwork, info);
6235 evector = A.t();
6236 }
6237 #endif // defined(VISP_HAVE_GSL)
6238 #else
6239 {
6240 throw(vpException(vpException::functionNotImplementedError,
6241 "Eigen values computation is not implemented. "
6242 "You should install Lapack 3rd party"));
6243 }
6244 #endif
6245 }
6246
6247 /*!
6248 Function to compute the null space (the kernel) of a m-by-n matrix \f$\bf
6249 A\f$.
6250
6251 The null space of a matrix \f$\bf A\f$ is defined as \f$\mbox{Ker}({\bf A})
6252 = { {\bf X} : {\bf A}*{\bf X} = {\bf 0}}\f$.
6253
6254 \param kerAt: The matrix that contains the null space (kernel) of \f$\bf
6255 A\f$ defined by the matrix \f${\bf X}^T\f$. If matrix \f$\bf A\f$ is full
6256 rank, the dimension of \c kerAt is (0, n), otherwise the dimension is (n-r,
6257 n). This matrix is thus the transpose of \f$\mbox{Ker}({\bf A})\f$.
6258
6259 \param svThreshold: Threshold used to test the singular values. If
6260 a singular value is lower than this threshold we consider that the
6261 matrix is not full rank.
6262
6263 \return The rank of the matrix.
6264 */
kernel(vpMatrix & kerAt,double svThreshold) const6265 unsigned int vpMatrix::kernel(vpMatrix &kerAt, double svThreshold) const
6266 {
6267 unsigned int nbline = getRows();
6268 unsigned int nbcol = getCols();
6269
6270 vpMatrix U, V; // Copy of the matrix, SVD function is destructive
6271 vpColVector sv;
6272 sv.resize(nbcol, false); // singular values
6273 V.resize(nbcol, nbcol, false); // V matrix of singular value decomposition
6274
6275 // Copy and resize matrix to have at least as many rows as columns
6276 // kernel is computed in svd method only if the matrix has more rows than
6277 // columns
6278
6279 if (nbline < nbcol)
6280 U.resize(nbcol, nbcol, true);
6281 else
6282 U.resize(nbline, nbcol, false);
6283
6284 U.insert(*this, 0, 0);
6285
6286 U.svd(sv, V);
6287
6288 // Compute the highest singular value and rank of the matrix
6289 double maxsv = 0;
6290 for (unsigned int i = 0; i < nbcol; i++) {
6291 if (sv[i] > maxsv) {
6292 maxsv = sv[i];
6293 }
6294 }
6295
6296 unsigned int rank = 0;
6297 for (unsigned int i = 0; i < nbcol; i++) {
6298 if (sv[i] > maxsv * svThreshold) {
6299 rank++;
6300 }
6301 }
6302
6303 kerAt.resize(nbcol - rank, nbcol);
6304 if (rank != nbcol) {
6305 for (unsigned int j = 0, k = 0; j < nbcol; j++) {
6306 // if( v.col(j) in kernel and non zero )
6307 if ((sv[j] <= maxsv * svThreshold) &&
6308 (std::fabs(V.getCol(j).sumSquare()) > std::numeric_limits<double>::epsilon())) {
6309 for (unsigned int i = 0; i < V.getRows(); i++) {
6310 kerAt[k][i] = V[i][j];
6311 }
6312 k++;
6313 }
6314 }
6315 }
6316
6317 return rank;
6318 }
6319
6320 /*!
6321 Function to compute the null space (the kernel) of a m-by-n matrix \f$\bf
6322 A\f$.
6323
6324 The null space of a matrix \f$\bf A\f$ is defined as \f$\mbox{Ker}({\bf A})
6325 = { {\bf X} : {\bf A}*{\bf X} = {\bf 0}}\f$.
6326
6327 \param kerA: The matrix that contains the null space (kernel) of \f$\bf
6328 A\f$. If matrix \f$\bf A\f$ is full rank, the dimension of \c kerA is (n, 0),
6329 otherwise its dimension is (n, n-r).
6330
6331 \param svThreshold: Threshold used to test the singular values. The dimension
6332 of kerA corresponds to the number of singular values lower than this threshold
6333
6334 \return The dimension of the nullspace, that is \f$ n - r \f$.
6335 */
nullSpace(vpMatrix & kerA,double svThreshold) const6336 unsigned int vpMatrix::nullSpace(vpMatrix &kerA, double svThreshold) const
6337 {
6338 unsigned int nbrow = getRows();
6339 unsigned int nbcol = getCols();
6340
6341 vpMatrix U, V; // Copy of the matrix, SVD function is destructive
6342 vpColVector sv;
6343 sv.resize(nbcol, false); // singular values
6344 V.resize(nbcol, nbcol, false); // V matrix of singular value decomposition
6345
6346 // Copy and resize matrix to have at least as many rows as columns
6347 // kernel is computed in svd method only if the matrix has more rows than
6348 // columns
6349
6350 if (nbrow < nbcol)
6351 U.resize(nbcol, nbcol, true);
6352 else
6353 U.resize(nbrow, nbcol, false);
6354
6355 U.insert(*this, 0, 0);
6356
6357 U.svd(sv, V);
6358
6359 // Compute the highest singular value and rank of the matrix
6360 double maxsv = sv[0];
6361
6362 unsigned int rank = 0;
6363 for (unsigned int i = 0; i < nbcol; i++) {
6364 if (sv[i] > maxsv * svThreshold) {
6365 rank++;
6366 }
6367 }
6368
6369 kerA.resize(nbcol, nbcol - rank);
6370 if (rank != nbcol) {
6371 for (unsigned int j = 0, k = 0; j < nbcol; j++) {
6372 // if( v.col(j) in kernel and non zero )
6373 if (sv[j] <= maxsv * svThreshold) {
6374 for (unsigned int i = 0; i < nbcol; i++) {
6375 kerA[i][k] = V[i][j];
6376 }
6377 k++;
6378 }
6379 }
6380 }
6381
6382 return (nbcol - rank);
6383 }
6384
6385 /*!
6386 Function to compute the null space (the kernel) of a m-by-n matrix \f$\bf
6387 A\f$.
6388
6389 The null space of a matrix \f$\bf A\f$ is defined as \f$\mbox{Ker}({\bf A})
6390 = { {\bf X} : {\bf A}*{\bf X} = {\bf 0}}\f$.
6391
6392 \param kerA: The matrix that contains the null space (kernel) of \f$\bf
6393 A\f$. If matrix \f$\bf A\f$ is full rank, the dimension of \c kerA is (n, 0),
6394 otherwise its dimension is (n, n-r).
6395
6396 \param dim: the dimension of the null space when it is known a priori
6397
6398 \return The estimated dimension of the nullspace, that is \f$ n - r \f$, by
6399 using 1e-6 as threshold for the sigular values.
6400 */
nullSpace(vpMatrix & kerA,int dim) const6401 unsigned int vpMatrix::nullSpace(vpMatrix &kerA, int dim) const
6402 {
6403 unsigned int nbrow = getRows();
6404 unsigned int nbcol = getCols();
6405 unsigned int dim_ = static_cast<unsigned int>(dim);
6406
6407 vpMatrix U, V; // Copy of the matrix, SVD function is destructive
6408 vpColVector sv;
6409 sv.resize(nbcol, false); // singular values
6410 V.resize(nbcol, nbcol, false); // V matrix of singular value decomposition
6411
6412 // Copy and resize matrix to have at least as many rows as columns
6413 // kernel is computed in svd method only if the matrix has more rows than
6414 // columns
6415
6416 if (nbrow < nbcol)
6417 U.resize(nbcol, nbcol, true);
6418 else
6419 U.resize(nbrow, nbcol, false);
6420
6421 U.insert(*this, 0, 0);
6422
6423 U.svd(sv, V);
6424
6425 kerA.resize(nbcol, dim_);
6426 if (dim_ != 0) {
6427 unsigned int rank = nbcol - dim_;
6428 for (unsigned int k = 0; k < dim_; k++) {
6429 unsigned int j = k + rank;
6430 for (unsigned int i = 0; i < nbcol; i++) {
6431 kerA[i][k] = V[i][j];
6432 }
6433 }
6434 }
6435
6436 double maxsv = sv[0];
6437 unsigned int rank = 0;
6438 for (unsigned int i = 0; i < nbcol; i++) {
6439 if (sv[i] > maxsv * 1e-6) {
6440 rank++;
6441 }
6442 }
6443 return (nbcol - rank);
6444 }
6445
6446 /*!
6447 Compute the determinant of a n-by-n matrix.
6448
6449 \param method : Method used to compute the determinant. Default LU
6450 decomposition method is faster than the method based on Gaussian
6451 elimination.
6452
6453 \return Determinant of the matrix.
6454
6455 \code
6456 #include <iostream>
6457
6458 #include <visp3/core/vpMatrix.h>
6459
6460 int main()
6461 {
6462 vpMatrix A(3,3);
6463 A[0][0] = 1/1.; A[0][1] = 1/2.; A[0][2] = 1/3.;
6464 A[1][0] = 1/3.; A[1][1] = 1/4.; A[1][2] = 1/5.;
6465 A[2][0] = 1/6.; A[2][1] = 1/7.; A[2][2] = 1/8.;
6466 std::cout << "Initial matrix: \n" << A << std::endl;
6467
6468 // Compute the determinant
6469 std:: cout << "Determinant by default method : " << A.det() << std::endl;
6470 std:: cout << "Determinant by LU decomposition : " << A.detByLU() << std::endl;
6471 std:: cout << "Determinant by LU decomposition (Lapack): " << A.detByLULapack() << std::endl;
6472 std:: cout << "Determinant by LU decomposition (OpenCV): " << A.detByLUOpenCV() << std::endl;
6473 std:: cout << "Determinant by LU decomposition (Eigen3): " << A.detByLUEigen3() << std::endl;
6474 }
6475 \endcode
6476 */
det(vpDetMethod method) const6477 double vpMatrix::det(vpDetMethod method) const
6478 {
6479 double det = 0.;
6480
6481 if (method == LU_DECOMPOSITION) {
6482 det = this->detByLU();
6483 }
6484
6485 return (det);
6486 }
6487
6488 /*!
6489
6490 Compute the exponential matrix of a square matrix.
6491
6492 \return Return the exponential matrix.
6493
6494 */
expm() const6495 vpMatrix vpMatrix::expm() const
6496 {
6497 if (colNum != rowNum) {
6498 throw(vpException(vpException::dimensionError, "Cannot compute the exponential of a non square (%dx%d) matrix",
6499 rowNum, colNum));
6500 } else {
6501 #ifdef VISP_HAVE_GSL
6502 size_t size_ = rowNum * colNum;
6503 double *b = new double[size_];
6504 for (size_t i = 0; i < size_; i++)
6505 b[i] = 0.;
6506 gsl_matrix_view m = gsl_matrix_view_array(this->data, rowNum, colNum);
6507 gsl_matrix_view em = gsl_matrix_view_array(b, rowNum, colNum);
6508 gsl_linalg_exponential_ss(&m.matrix, &em.matrix, 0);
6509 // gsl_matrix_fprintf(stdout, &em.matrix, "%g");
6510 vpMatrix expA;
6511 expA.resize(rowNum, colNum, false);
6512 memcpy(expA.data, b, size_ * sizeof(double));
6513
6514 delete[] b;
6515 return expA;
6516 #else
6517 vpMatrix _expE(rowNum, colNum, false);
6518 vpMatrix _expD(rowNum, colNum, false);
6519 vpMatrix _expX(rowNum, colNum, false);
6520 vpMatrix _expcX(rowNum, colNum, false);
6521 vpMatrix _eye(rowNum, colNum, false);
6522
6523 _eye.eye();
6524 vpMatrix exp(*this);
6525
6526 // double f;
6527 int e;
6528 double c = 0.5;
6529 int q = 6;
6530 int p = 1;
6531
6532 double nA = 0;
6533 for (unsigned int i = 0; i < rowNum; i++) {
6534 double sum = 0;
6535 for (unsigned int j = 0; j < colNum; j++) {
6536 sum += fabs((*this)[i][j]);
6537 }
6538 if (sum > nA || i == 0) {
6539 nA = sum;
6540 }
6541 }
6542
6543 /* f = */ frexp(nA, &e);
6544 // double s = (0 > e+1)?0:e+1;
6545 double s = e + 1;
6546
6547 double sca = 1.0 / pow(2.0, s);
6548 exp = sca * exp;
6549 _expX = *this;
6550 _expE = c * exp + _eye;
6551 _expD = -c * exp + _eye;
6552 for (int k = 2; k <= q; k++) {
6553 c = c * ((double)(q - k + 1)) / ((double)(k * (2 * q - k + 1)));
6554 _expcX = exp * _expX;
6555 _expX = _expcX;
6556 _expcX = c * _expX;
6557 _expE = _expE + _expcX;
6558 if (p)
6559 _expD = _expD + _expcX;
6560 else
6561 _expD = _expD - _expcX;
6562 p = !p;
6563 }
6564 _expX = _expD.inverseByLU();
6565 exp = _expX * _expE;
6566 for (int k = 1; k <= s; k++) {
6567 _expE = exp * exp;
6568 exp = _expE;
6569 }
6570 return exp;
6571 #endif
6572 }
6573 }
6574
6575 /**************************************************************************************************************/
6576 /**************************************************************************************************************/
6577
6578 // Specific functions
6579
6580 /*
6581 input:: matrix M(nCols,nRows), nCols > 3, nRows > 3 , nCols == nRows.
6582
6583 output:: the complement matrix of the element (rowNo,colNo).
6584 This is the matrix obtained from M after elimenating the row rowNo and column
6585 colNo
6586
6587 example:
6588 1 2 3
6589 M = 4 5 6
6590 7 8 9
6591 1 3
6592 subblock(M, 1, 1) give the matrix 7 9
6593 */
subblock(const vpMatrix & M,unsigned int col,unsigned int row)6594 vpMatrix subblock(const vpMatrix &M, unsigned int col, unsigned int row)
6595 {
6596 vpMatrix M_comp;
6597 M_comp.resize(M.getRows() - 1, M.getCols() - 1, false);
6598
6599 for (unsigned int i = 0; i < col; i++) {
6600 for (unsigned int j = 0; j < row; j++)
6601 M_comp[i][j] = M[i][j];
6602 for (unsigned int j = row + 1; j < M.getRows(); j++)
6603 M_comp[i][j - 1] = M[i][j];
6604 }
6605 for (unsigned int i = col + 1; i < M.getCols(); i++) {
6606 for (unsigned int j = 0; j < row; j++)
6607 M_comp[i - 1][j] = M[i][j];
6608 for (unsigned int j = row + 1; j < M.getRows(); j++)
6609 M_comp[i - 1][j - 1] = M[i][j];
6610 }
6611 return M_comp;
6612 }
6613
6614 /*!
6615 \return The condition number, the ratio of the largest singular value of
6616 the matrix to the smallest.
6617
6618 \param svThreshold: Threshold used to test the singular values. If
6619 a singular value is lower than this threshold we consider that the
6620 matrix is not full rank.
6621
6622 */
cond(double svThreshold) const6623 double vpMatrix::cond(double svThreshold) const
6624 {
6625 unsigned int nbline = getRows();
6626 unsigned int nbcol = getCols();
6627
6628 vpMatrix U, V; // Copy of the matrix, SVD function is destructive
6629 vpColVector sv;
6630 sv.resize(nbcol); // singular values
6631 V.resize(nbcol, nbcol, false); // V matrix of singular value decomposition
6632
6633 // Copy and resize matrix to have at least as many rows as columns
6634 // kernel is computed in svd method only if the matrix has more rows than
6635 // columns
6636
6637 if (nbline < nbcol)
6638 U.resize(nbcol, nbcol, true);
6639 else
6640 U.resize(nbline, nbcol, false);
6641
6642 U.insert(*this, 0, 0);
6643
6644 U.svd(sv, V);
6645
6646 // Compute the highest singular value
6647 double maxsv = 0;
6648 for (unsigned int i = 0; i < nbcol; i++) {
6649 if (sv[i] > maxsv) {
6650 maxsv = sv[i];
6651 }
6652 }
6653
6654 // Compute the rank of the matrix
6655 unsigned int rank = 0;
6656 for (unsigned int i = 0; i < nbcol; i++) {
6657 if (sv[i] > maxsv * svThreshold) {
6658 rank++;
6659 }
6660 }
6661
6662 // Compute the lowest singular value
6663 double minsv = maxsv;
6664 for (unsigned int i = 0; i < rank; i++) {
6665 if (sv[i] < minsv) {
6666 minsv = sv[i];
6667 }
6668 }
6669
6670 if (std::fabs(minsv) > std::numeric_limits<double>::epsilon()) {
6671 return maxsv / minsv;
6672 }
6673 else {
6674 return std::numeric_limits<double>::infinity();
6675 }
6676 }
6677
6678 /*!
6679 Compute \f${\bf H} + \alpha * diag({\bf H})\f$
6680 \param H : input Matrix \f${\bf H}\f$. This matrix should be square.
6681 \param alpha : Scalar \f$\alpha\f$
6682 \param HLM : Resulting operation.
6683 */
computeHLM(const vpMatrix & H,const double & alpha,vpMatrix & HLM)6684 void vpMatrix::computeHLM(const vpMatrix &H, const double &alpha, vpMatrix &HLM)
6685 {
6686 if (H.getCols() != H.getRows()) {
6687 throw(vpException(vpException::dimensionError, "Cannot compute HLM on a non square matrix (%dx%d)", H.getRows(),
6688 H.getCols()));
6689 }
6690
6691 HLM = H;
6692 for (unsigned int i = 0; i < H.getCols(); i++) {
6693 HLM[i][i] += alpha * H[i][i];
6694 }
6695 }
6696
6697 /*!
6698 Compute and return the Frobenius norm (also called Euclidean norm) \f$||A|| = \sqrt{ \sum{A_{ij}^2}}\f$.
6699
6700 \return The Frobenius norm (also called Euclidean norm) if the matrix is initialized, 0 otherwise.
6701
6702 \sa infinityNorm(), inducedL2Norm()
6703 */
frobeniusNorm() const6704 double vpMatrix::frobeniusNorm() const
6705 {
6706 double norm = 0.0;
6707 for (unsigned int i = 0; i < dsize; i++) {
6708 double x = *(data + i);
6709 norm += x * x;
6710 }
6711
6712 return sqrt(norm);
6713 }
6714
6715 /*!
6716 Compute and return the induced L2 norm \f$||A|| = \Sigma_{max}(A)\f$ which is equal to
6717 the maximum singular value of the matrix.
6718
6719 \return The induced L2 norm if the matrix is initialized, 0 otherwise.
6720
6721 \sa infinityNorm(), frobeniusNorm()
6722 */
inducedL2Norm() const6723 double vpMatrix::inducedL2Norm() const
6724 {
6725 if(this->dsize != 0){
6726 vpMatrix v;
6727 vpColVector w;
6728
6729 vpMatrix M = *this;
6730
6731 M.svd(w, v);
6732
6733 double max = w[0];
6734 unsigned int maxRank = std::min(this->getCols(), this->getRows());
6735 // The maximum reachable rank is either the number of columns or the number of rows
6736 // of the matrix.
6737 unsigned int boundary = std::min(maxRank, w.size());
6738 // boundary is here to ensure that the number of singular values used for the com-
6739 // putation of the euclidean norm of the matrix is not greater than the maximum
6740 // reachable rank. Indeed, some svd library pad the singular values vector with 0s
6741 // if the input matrix is non-square.
6742 for (unsigned int i = 0; i < boundary; i++) {
6743 if (max < w[i]) {
6744 max = w[i];
6745 }
6746 }
6747 return max;
6748 }
6749 else {
6750 return 0.;
6751 }
6752 }
6753
6754 /*!
6755
6756 Compute and return the infinity norm \f$ {||A||}_{\infty} =
6757 max\left(\sum_{j=0}^{n}{\mid A_{ij} \mid}\right) \f$ with \f$i \in
6758 \{0, ..., m\}\f$ where \f$(m,n)\f$ is the matrix size.
6759
6760 \return The infinity norm if the matrix is initialized, 0 otherwise.
6761
6762 \sa frobeniusNorm(), inducedL2Norm()
6763 */
infinityNorm() const6764 double vpMatrix::infinityNorm() const
6765 {
6766 double norm = 0.0;
6767 for (unsigned int i = 0; i < rowNum; i++) {
6768 double x = 0;
6769 for (unsigned int j = 0; j < colNum; j++) {
6770 x += fabs(*(*(rowPtrs + i) + j));
6771 }
6772 if (x > norm) {
6773 norm = x;
6774 }
6775 }
6776 return norm;
6777 }
6778
6779 /*!
6780 Return the sum square of all the \f$A_{ij}\f$ elements of the matrix \f$A(m,
6781 n)\f$.
6782
6783 \return The value \f$\sum A_{ij}^{2}\f$.
6784 */
sumSquare() const6785 double vpMatrix::sumSquare() const
6786 {
6787 double sum_square = 0.0;
6788 double x;
6789
6790 for (unsigned int i = 0; i < rowNum; i++) {
6791 for (unsigned int j = 0; j < colNum; j++) {
6792 x = rowPtrs[i][j];
6793 sum_square += x * x;
6794 }
6795 }
6796
6797 return sum_square;
6798 }
6799
6800 /*!
6801 Perform a 2D convolution similar to Matlab conv2 function: \f$ M \star kernel \f$.
6802
6803 \param M : First matrix.
6804 \param kernel : Second matrix.
6805 \param mode : Convolution mode: "full" (default), "same", "valid".
6806
6807 \image html vpMatrix-conv2-mode.jpg "Convolution mode: full, same, valid (image credit: Theano doc)."
6808
6809 \note This is a very basic implementation that does not use FFT.
6810 */
conv2(const vpMatrix & M,const vpMatrix & kernel,const std::string & mode)6811 vpMatrix vpMatrix::conv2(const vpMatrix &M, const vpMatrix &kernel, const std::string &mode)
6812 {
6813 vpMatrix res;
6814 conv2(M, kernel, res, mode);
6815 return res;
6816 }
6817
6818 /*!
6819 Perform a 2D convolution similar to Matlab conv2 function: \f$ M \star kernel \f$.
6820
6821 \param M : First matrix.
6822 \param kernel : Second matrix.
6823 \param res : Result.
6824 \param mode : Convolution mode: "full" (default), "same", "valid".
6825
6826 \image html vpMatrix-conv2-mode.jpg "Convolution mode: full, same, valid (image credit: Theano doc)."
6827
6828 \note This is a very basic implementation that does not use FFT.
6829 */
conv2(const vpMatrix & M,const vpMatrix & kernel,vpMatrix & res,const std::string & mode)6830 void vpMatrix::conv2(const vpMatrix &M, const vpMatrix &kernel, vpMatrix &res, const std::string &mode)
6831 {
6832 if (M.getRows()*M.getCols() == 0 || kernel.getRows()*kernel.getCols() == 0)
6833 return;
6834
6835 if (mode == "valid") {
6836 if (kernel.getRows() > M.getRows() || kernel.getCols() > M.getCols())
6837 return;
6838 }
6839
6840 vpMatrix M_padded, res_same;
6841
6842 if (mode == "full" || mode == "same") {
6843 const unsigned int pad_x = kernel.getCols()-1;
6844 const unsigned int pad_y = kernel.getRows()-1;
6845 M_padded.resize(M.getRows() + 2*pad_y, M.getCols() + 2*pad_x, true, false);
6846 M_padded.insert(M, pad_y, pad_x);
6847
6848 if (mode == "same") {
6849 res.resize(M.getRows(), M.getCols(), false, false);
6850 res_same.resize(M.getRows() + pad_y, M.getCols() + pad_x, true, false);
6851 } else {
6852 res.resize(M.getRows() + pad_y, M.getCols() + pad_x, true, false);
6853 }
6854 } else if (mode == "valid") {
6855 M_padded = M;
6856 res.resize(M.getRows()-kernel.getRows()+1, M.getCols()-kernel.getCols()+1);
6857 } else {
6858 return;
6859 }
6860
6861 if (mode == "same") {
6862 for (unsigned int i = 0; i < res_same.getRows(); i++) {
6863 for (unsigned int j = 0; j < res_same.getCols(); j++) {
6864 for (unsigned int k = 0; k < kernel.getRows(); k++) {
6865 for (unsigned int l = 0; l < kernel.getCols(); l++) {
6866 res_same[i][j] += M_padded[i+k][j+l] * kernel[kernel.getRows()-k-1][kernel.getCols()-l-1];
6867 }
6868 }
6869 }
6870 }
6871
6872 const unsigned int start_i = kernel.getRows()/2;
6873 const unsigned int start_j = kernel.getCols()/2;
6874 for (unsigned int i = 0; i < M.getRows(); i++) {
6875 memcpy(res.data + i*M.getCols(), res_same.data + (i+start_i)*res_same.getCols() + start_j, sizeof(double)*M.getCols());
6876 }
6877 } else {
6878 for (unsigned int i = 0; i < res.getRows(); i++) {
6879 for (unsigned int j = 0; j < res.getCols(); j++) {
6880 for (unsigned int k = 0; k < kernel.getRows(); k++) {
6881 for (unsigned int l = 0; l < kernel.getCols(); l++) {
6882 res[i][j] += M_padded[i+k][j+l] * kernel[kernel.getRows()-k-1][kernel.getCols()-l-1];
6883 }
6884 }
6885 }
6886 }
6887 }
6888 }
6889
6890 #if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
6891 /*!
6892 \deprecated This function is deprecated. You should rather use frobeniusNorm().
6893
6894 Compute and return the Euclidean norm (also called Frobenius norm) \f$||A|| = \sqrt{ \sum{A_{ij}^2}}\f$.
6895
6896 \return The Euclidean norm (also called Frobenius norm) if the matrix is initialized, 0 otherwise.
6897
6898 \sa frobeniusNorm(), infinityNorm(), inducedL2Norm()
6899 */
euclideanNorm() const6900 vp_deprecated double vpMatrix::euclideanNorm() const
6901 {
6902 return frobeniusNorm();
6903 }
6904
stackMatrices(const vpColVector & A,const vpColVector & B)6905 vpMatrix vpMatrix::stackMatrices(const vpColVector &A, const vpColVector &B)
6906 {
6907 return (vpMatrix)(vpColVector::stack(A, B));
6908 }
6909
stackMatrices(const vpColVector & A,const vpColVector & B,vpColVector & C)6910 void vpMatrix::stackMatrices(const vpColVector &A, const vpColVector &B, vpColVector &C)
6911 {
6912 vpColVector::stack(A, B, C);
6913 }
6914
stackMatrices(const vpMatrix & A,const vpRowVector & B)6915 vpMatrix vpMatrix::stackMatrices(const vpMatrix &A, const vpRowVector &B) { return vpMatrix::stack(A, B); }
6916
stackMatrices(const vpMatrix & A,const vpRowVector & B,vpMatrix & C)6917 void vpMatrix::stackMatrices(const vpMatrix &A, const vpRowVector &B, vpMatrix &C) { vpMatrix::stack(A, B, C); }
6918
6919 /*!
6920 \deprecated This method is deprecated. You should rather use getRow().
6921 More precisely, the following code:
6922 \code
6923 vpMatrix L;
6924 unsigned int row_index = ...;
6925 ... = L.row(row_index);
6926 \endcode
6927 should be replaced with:
6928 \code
6929 ... = L.getRow(row_index - 1);
6930 \endcode
6931
6932 \warning Notice row(1) is the 0th row.
6933 This function returns the i-th row of the matrix.
6934 \param i : Index of the row to extract noting that row index start at 1 to get the first row.
6935
6936 */
row(unsigned int i)6937 vpRowVector vpMatrix::row(unsigned int i)
6938 {
6939 vpRowVector c(getCols());
6940
6941 for (unsigned int j = 0; j < getCols(); j++)
6942 c[j] = (*this)[i - 1][j];
6943 return c;
6944 }
6945
6946 /*!
6947 \deprecated This method is deprecated. You should rather use getCol().
6948 More precisely, the following code:
6949 \code
6950 vpMatrix L;
6951 unsigned int column_index = ...;
6952 ... = L.column(column_index);
6953 \endcode
6954 should be replaced with:
6955 \code
6956 ... = L.getCol(column_index - 1);
6957 \endcode
6958
6959 \warning Notice column(1) is the 0-th column.
6960 This function returns the j-th columns of the matrix.
6961 \param j : Index of the column to extract noting that column index start at 1 to get the first column.
6962 */
column(unsigned int j)6963 vpColVector vpMatrix::column(unsigned int j)
6964 {
6965 vpColVector c(getRows());
6966
6967 for (unsigned int i = 0; i < getRows(); i++)
6968 c[i] = (*this)[i][j - 1];
6969 return c;
6970 }
6971
6972 /*!
6973 \deprecated You should rather use diag(const double &)
6974
6975 Set the matrix diagonal elements to \e val.
6976 More generally set M[i][i] = val.
6977 */
setIdentity(const double & val)6978 void vpMatrix::setIdentity(const double &val)
6979 {
6980 for (unsigned int i = 0; i < rowNum; i++)
6981 for (unsigned int j = 0; j < colNum; j++)
6982 if (i == j)
6983 (*this)[i][j] = val;
6984 else
6985 (*this)[i][j] = 0;
6986 }
6987
6988 #endif //#if defined(VISP_BUILD_DEPRECATED_FUNCTIONS)
6989