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